xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ppp.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2001-2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/sysmacros.h>
33 #include <net/ppp_defs.h>
34 #include <net/ppp-comp.h>
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <netinet/if_ether.h>
38 #include <arpa/inet.h>
39 #include "snoop.h"
40 #include "snoop_ppp.h"
41 
42 static int interpret_ppp_cp(int, uchar_t *, int, ppp_protoinfo_t *);
43 static int interpret_cp_options(uchar_t *, int, ppp_protoinfo_t *);
44 static int interpret_ppp_chap(int, uchar_t *, int, ppp_protoinfo_t *);
45 static int interpret_ppp_pap(int, uchar_t *, int, ppp_protoinfo_t *);
46 static int interpret_ppp_lqr(int, uchar_t *, int, ppp_protoinfo_t *);
47 static ppp_protoinfo_t *ppp_getprotoinfo(uint16_t);
48 static cp_optinfo_t *ppp_getoptinfo(cp_optinfo_t *, uint16_t);
49 static optformat_func_t opt_format_vendor;
50 static optformat_func_t opt_format_mru;
51 static optformat_func_t opt_format_accm;
52 static optformat_func_t opt_format_authproto;
53 static optformat_func_t opt_format_qualproto;
54 static optformat_func_t opt_format_magicnum;
55 static optformat_func_t opt_format_fcs;
56 static optformat_func_t opt_format_sdp;
57 static optformat_func_t opt_format_nummode;
58 static optformat_func_t opt_format_callback;
59 static optformat_func_t opt_format_mrru;
60 static optformat_func_t opt_format_epdisc;
61 static optformat_func_t opt_format_dce;
62 static optformat_func_t opt_format_linkdisc;
63 static optformat_func_t opt_format_i18n;
64 static optformat_func_t opt_format_ipaddresses;
65 static optformat_func_t opt_format_ipcompproto;
66 static optformat_func_t opt_format_ipaddress;
67 static optformat_func_t opt_format_mobileipv4;
68 static optformat_func_t opt_format_ifaceid;
69 static optformat_func_t opt_format_ipv6compproto;
70 static optformat_func_t opt_format_compoui;
71 static optformat_func_t opt_format_bsdcomp;
72 static optformat_func_t opt_format_staclzs;
73 static optformat_func_t opt_format_mppc;
74 static optformat_func_t opt_format_gandalf;
75 static optformat_func_t opt_format_lzsdcp;
76 static optformat_func_t opt_format_magnalink;
77 static optformat_func_t opt_format_deflate;
78 static optformat_func_t opt_format_encroui;
79 static optformat_func_t opt_format_dese;
80 static optformat_func_t opt_format_muxpid;
81 
82 /*
83  * Many strings below are initialized with "Unknown".
84  */
85 static char unknown_string[] = "Unknown";
86 
87 /*
88  * Each known PPP protocol has an associated ppp_protoinfo_t in this array.
89  * Even if we can't decode the protocol (interpret_proto() == NULL),
90  * interpret_ppp() will at least print the protocol's name.  There is no
91  * dependency on the ordering of the entries in this array.  They have been
92  * ordered such that the most commonly used protocols are near the front.
93  * The array is delimited by a last entry of protocol of type
94  * PPP_PROTO_UNKNOWN.
95  */
96 static ppp_protoinfo_t protoinfo_array[] = {
97 	{ PPP_IP,	"IP",		interpret_ip,	NULL,	NULL },
98 	{ PPP_IPV6,	"IPv6",		interpret_ipv6,	NULL,	NULL },
99 	{ PPP_COMP,	"Compressed Data",	NULL,	NULL,	NULL },
100 	{ PPP_OSI,	"OSI",			NULL,	NULL,	NULL },
101 	{ PPP_AT,	"AppleTalk",		NULL,	NULL,	NULL },
102 	{ PPP_IPX,	"IPX",			NULL,	NULL,	NULL },
103 	{ PPP_VJC_COMP,	"VJ Compressed TCP",    NULL,	NULL,	NULL },
104 	{ PPP_VJC_UNCOMP, "VJ Uncompressed TCP", NULL,	NULL,	NULL },
105 	{ PPP_BRIDGE,	"Bridging",		NULL,	NULL,	NULL },
106 	{ PPP_802HELLO,	"802.1d Hello",		NULL,	NULL,	NULL },
107 	{ PPP_MP,	"MP",			NULL,	NULL,	NULL },
108 	{ PPP_ENCRYPT,	"Encryption",		NULL,	NULL,	NULL },
109 	{ PPP_ENCRYPTFRAG, "Individual Link Encryption", NULL,	NULL,	NULL },
110 	{ PPP_MUX,	"PPP Muxing",		NULL,	NULL,	NULL },
111 	{ PPP_COMPFRAG,	"Single Link Compressed Data",	NULL,	NULL,	NULL },
112 	{ PPP_FULLHDR,	"IP Compression",	NULL,	NULL,	NULL },
113 	{ PPP_COMPTCP,	"IP Compression",	NULL,	NULL,	NULL },
114 	{ PPP_COMPNONTCP, "IP Compression",	NULL,	NULL,	NULL },
115 	{ PPP_COMPUDP8,	"IP Compression",	NULL,	NULL,	NULL },
116 	{ PPP_COMPRTP8,	"IP Compression",	NULL,	NULL,	NULL },
117 	{ PPP_COMPTCPND, "IP Compression",	NULL,	NULL,	NULL },
118 	{ PPP_COMPSTATE, "IP Compression",	NULL,	NULL,	NULL },
119 	{ PPP_COMPUDP16, "IP Compression",	NULL,	NULL,	NULL },
120 	{ PPP_COMPRTP16, "IP Compression",	NULL,	NULL,	NULL },
121 	{ PPP_MPLS,	"MPLS",			NULL,	NULL,	NULL },
122 	{ PPP_MPLSMC,	"MPLS M/C",		NULL,	NULL,	NULL },
123 	{ PPP_LQR,	"LQR",		interpret_ppp_lqr,	"PPP-LQR:  ",
124 	    "Link Quality Report" },
125 	{ PPP_LCP,	"LCP",		interpret_ppp_cp,	"PPP-LCP:  ",
126 	    "Link Control Protocol" },
127 	{ PPP_IPCP,	"IPCP",		interpret_ppp_cp,	"PPP-IPCP: ",
128 	    "IP Control Protocol" },
129 	{ PPP_IPV6CP,	"IPV6CP",	interpret_ppp_cp,	"PPP-IPV6CP:  ",
130 	    "IPv6 Control Protocol" },
131 	{ PPP_CCP,	"CCP",		interpret_ppp_cp,	"PPP-CCP:  ",
132 	    "Compression Control Protocol" },
133 	{ PPP_CCPFRAG,	"CCP-Link",	interpret_ppp_cp, "PPP-CCP-Link:  ",
134 	    "Per-Link Compression Control Protocol" },
135 	{ PPP_ECP,	"ECP",		interpret_ppp_cp,	"PPP-ECP:  ",
136 	    "Encryption Control Protocol" },
137 	{ PPP_ECPFRAG,	"ECP-Link",	interpret_ppp_cp, "PPP-ECP-Link:  ",
138 	    "Per-Link Encryption Control Protocol" },
139 	{ PPP_MPLSCP,	"MPLSCP",		NULL,	NULL,	NULL },
140 	{ PPP_OSINLCP,	"OSINLCP",		NULL,	NULL,	NULL },
141 	{ PPP_ATCP,	"ATCP",			NULL,	NULL,	NULL },
142 	{ PPP_IPXCP,	"IPXCP",		NULL,	NULL,	NULL },
143 	{ PPP_BACP,	"BACP",			NULL,	NULL,	NULL },
144 	{ PPP_BCP,	"BCP",			NULL,	NULL,	NULL },
145 	{ PPP_CBCP,	"CBCP",			NULL,	NULL,	NULL },
146 	{ PPP_BAP,	"BAP",			NULL,	NULL,	NULL },
147 	{ PPP_CHAP,	"CHAP",		interpret_ppp_chap,	"CHAP:  ",
148 	    "Challenge Handshake Authentication Protocl" },
149 	{ PPP_PAP,	"PAP",		interpret_ppp_pap,	"PAP:   ",
150 	    "Password Authentication Protocol" },
151 	{ PPP_EAP,	"EAP",			NULL,	NULL,	NULL },
152 	{ 0,		unknown_string,		NULL,	NULL,	NULL }
153 };
154 
155 static cp_optinfo_t lcp_optinfo[] = {
156 	{ OPT_LCP_VENDOR,	"Vendor-Specific",		6,
157 	    opt_format_vendor },
158 	{ OPT_LCP_MRU,		"Maximum-Receive-Unit",		4,
159 	    opt_format_mru },
160 	{ OPT_LCP_ASYNCMAP,	"Async-Control-Character-Map",	6,
161 	    opt_format_accm },
162 	{ OPT_LCP_AUTHTYPE,	"Authentication-Protocol",	4,
163 	    opt_format_authproto },
164 	{ OPT_LCP_QUALITY,	"Quality-Protocol",		4,
165 	    opt_format_qualproto },
166 	{ OPT_LCP_MAGICNUMBER,	"Magic-Number",			6,
167 	    opt_format_magicnum },
168 	{ OPT_LCP_PCOMPRESSION,	"Protocol-Field-Compression",	2,	NULL },
169 	{ OPT_LCP_ACCOMPRESSION, "Address-and-Control-Field-Compression", 2,
170 	    NULL },
171 	{ OPT_LCP_FCSALTERN,	"FCS-Alternative",		3,
172 	    opt_format_fcs },
173 	{ OPT_LCP_SELFDESCPAD,	"Self-Describing-Padding",	3,
174 	    opt_format_sdp },
175 	{ OPT_LCP_NUMBERED,	"Numbered-Mode",		3,
176 	    opt_format_nummode },
177 	{ OPT_LCP_MULTILINKPROC, "Multi-Link-Procedure",	2,	NULL },
178 	{ OPT_LCP_CALLBACK,	"Callback",			3,
179 	    opt_format_callback },
180 	{ OPT_LCP_CONNECTTIME,	"Connect-Time",			2,	NULL },
181 	{ OPT_LCP_COMPOUNDFRAMES, "Compound-Frames",		2,	NULL },
182 	{ OPT_LCP_DATAENCAP,	"Nominal-Data-Encapsulation",	2,	NULL },
183 	{ OPT_LCP_MRRU,		"Multilink-MRRU",		4,
184 	    opt_format_mrru },
185 	{ OPT_LCP_SSNHF,	"Multilink-Short-Sequence-Number-Header-Format",
186 	    2, NULL },
187 	{ OPT_LCP_EPDISC,	"Multilink-Endpoint-Discriminator",	3,
188 	    opt_format_epdisc },
189 	{ OPT_LCP_DCEIDENT,	"DCE-Identifier",		3,
190 	    opt_format_dce },
191 	{ OPT_LCP_MLPLUSPROC,	"Multi-Link-Plus-Procedure",	2,	NULL },
192 	{ OPT_LCP_LINKDISC,	"Link Discriminator for BACP",	4,
193 	    opt_format_linkdisc },
194 	{ OPT_LCP_AUTH,		"LCP-Authentication-Option",	2,	NULL },
195 	{ OPT_LCP_COBS,		"COBS",				2,	NULL },
196 	{ OPT_LCP_PFXELISION,	"Prefix elision",		2,	NULL },
197 	{ OPT_LCP_MPHDRFMT,	"Multilink header format",	2,	NULL },
198 	{ OPT_LCP_I18N,		"Internationalization",		6,
199 	    opt_format_i18n },
200 	{ OPT_LCP_SDL,		"Simple Data Link on SONET/SDH", 2,	NULL },
201 	{ OPT_LCP_MUXING,	"Old PPP Multiplexing",		2,	NULL },
202 	{ 0,			unknown_string,			0,	NULL }
203 };
204 
205 static cp_optinfo_t ipcp_optinfo[] = {
206 	{ OPT_IPCP_ADDRS,	"IP-Addresses",			10,
207 	    opt_format_ipaddresses },
208 	{ OPT_IPCP_COMPRESSTYPE, "IP-Compression-Protocol",	4,
209 	    opt_format_ipcompproto },
210 	{ OPT_IPCP_ADDR,	"IP-Address",			6,
211 	    opt_format_ipaddress },
212 	{ OPT_IPCP_MOBILEIPV4,	"Mobile-IPv4",			6,
213 	    opt_format_mobileipv4 },
214 	{ OPT_IPCP_DNS1,	"Primary DNS Address",		6,
215 	    opt_format_ipaddress },
216 	{ OPT_IPCP_NBNS1,	"Primary NBNS Address",		6,
217 	    opt_format_ipaddress },
218 	{ OPT_IPCP_DNS2,	"Secondary DNS Address", 	6,
219 	    opt_format_ipaddress },
220 	{ OPT_IPCP_NBNS2,	"Secondary NBNS Address",	6,
221 	    opt_format_ipaddress },
222 	{ OPT_IPCP_SUBNET,	"IP-Subnet",			6,
223 	    opt_format_ipaddress },
224 	{ 0,			unknown_string,			0,	NULL }
225 };
226 
227 static cp_optinfo_t ipv6cp_optinfo[] = {
228 	{ OPT_IPV6CP_IFACEID,	"Interface-Identifier",		10,
229 	    opt_format_ifaceid },
230 	{ OPT_IPV6CP_COMPRESSTYPE, "IPv6-Compression-Protocol",	4,
231 	    opt_format_ipv6compproto },
232 	{ 0,			unknown_string,			0,	NULL }
233 };
234 
235 static cp_optinfo_t ccp_optinfo[] = {
236 	{ OPT_CCP_PROPRIETARY,	"Proprietary Compression OUI",	6,
237 	    opt_format_compoui },
238 	{ OPT_CCP_PREDICTOR1,	"Predictor type 1",		2,	NULL },
239 	{ OPT_CCP_PREDICTOR2,	"Predictor type 2",		2,	NULL },
240 	{ OPT_CCP_PUDDLEJUMP,	"Puddle Jumper",		2,	NULL },
241 	{ OPT_CCP_HPPPC,	"Hewlett-Packard PPC",		2,	NULL },
242 	{ OPT_CCP_STACLZS,	"Stac Electronics LZS",		5,
243 	    opt_format_staclzs },
244 	{ OPT_CCP_MPPC,		"Microsoft PPC",		6,
245 	    opt_format_mppc },
246 	{ OPT_CCP_GANDALFFZA,	"Gandalf FZA",			3,
247 	    opt_format_gandalf },
248 	{ OPT_CCP_V42BIS,	"V.42bis compression",		2,
249 	    NULL },
250 	{ OPT_CCP_BSDCOMP,	"BSD LZW Compress",		3,
251 	    opt_format_bsdcomp },
252 	{ OPT_CCP_LZSDCP,	"LZS-DCP",			6,
253 	    opt_format_lzsdcp },
254 	{ OPT_CCP_MAGNALINK,	"Magnalink",			4,
255 	    opt_format_magnalink },
256 	{ OPT_CCP_DEFLATE,	"Deflate",			4,
257 	    opt_format_deflate },
258 	{ 0,			unknown_string,			0,	NULL }
259 };
260 
261 static cp_optinfo_t ecp_optinfo[] = {
262 	{ OPT_ECP_PROPRIETARY,	"Proprietary Encryption OUI",	6,
263 	    opt_format_encroui },
264 	{ OPT_ECP_DESE,		"DESE",				10,
265 	    opt_format_dese },
266 	{ OPT_ECP_3DESE,	"3DESE",			10,
267 	    opt_format_dese },
268 	{ OPT_ECP_DESEBIS,	"DESE-bis",			10,
269 	    opt_format_dese },
270 	{ 0,			unknown_string,			0,	NULL }
271 };
272 
273 static cp_optinfo_t muxcp_optinfo[] = {
274 	{ OPT_MUXCP_DEFAULTPID,	"Default PID",			4,
275 	    opt_format_muxpid },
276 	{ 0,			unknown_string,			0,	NULL }
277 };
278 
279 static char *cp_codearray[] = {
280 	"(Vendor Specific)",
281 	"(Configure-Request)",
282 	"(Configure-Ack)",
283 	"(Configure-Nak)",
284 	"(Configure-Reject)",
285 	"(Terminate-Request)",
286 	"(Terminate-Ack)",
287 	"(Code-Reject)",
288 	"(Protocol-Reject)",
289 	"(Echo-Request)",
290 	"(Echo-Reply)",
291 	"(Discard-Request)",
292 	"(Identification)",
293 	"(Time-Remaining)",
294 	"(Reset-Request)",
295 	"(Reset-Ack)"
296 };
297 #define	MAX_CPCODE	((sizeof (cp_codearray) / sizeof (char *)) - 1)
298 
299 static char *pap_codearray[] = {
300 	"(Unknown)",
301 	"(Authenticate-Request)",
302 	"(Authenticate-Ack)",
303 	"(Authenticate-Nak)"
304 };
305 #define	MAX_PAPCODE	((sizeof (pap_codearray) / sizeof (char *)) - 1)
306 
307 static char *chap_codearray[] = {
308 	"(Unknown)",
309 	"(Challenge)",
310 	"(Response)",
311 	"(Success)",
312 	"(Failure)"
313 };
314 #define	MAX_CHAPCODE	((sizeof (chap_codearray) / sizeof (char *)) - 1)
315 
316 
317 int
318 interpret_ppp(int flags, uchar_t *data, int len)
319 {
320 	uint16_t protocol;
321 	ppp_protoinfo_t *protoinfo;
322 	uchar_t *payload = data;
323 
324 	if (len < 2)
325 		return (len);
326 
327 	GETINT16(protocol, payload);
328 	len -= sizeof (uint16_t);
329 
330 	protoinfo = ppp_getprotoinfo(protocol);
331 
332 	if (flags & F_SUM) {
333 		(void) sprintf(get_sum_line(),
334 		    "PPP Protocol=0x%x (%s)", protocol, protoinfo->name);
335 	} else { /* F_DTAIL */
336 		show_header("PPP:    ", "Point-to-Point Protocol", len);
337 		show_space();
338 		(void) sprintf(get_line(0, 0), "Protocol = 0x%x (%s)",
339 		    protocol, protoinfo->name);
340 		show_space();
341 	}
342 
343 	if (protoinfo->interpret_proto != NULL) {
344 		len = protoinfo->interpret_proto(flags, payload, len,
345 		    protoinfo);
346 	}
347 
348 	return (len);
349 }
350 
351 /*
352  * interpret_ppp_cp() - Interpret PPP control protocols.  It is convenient
353  * to do some of the decoding of these protocols in a common function since
354  * they share packet formats.  This function expects to receive data
355  * starting with the code field.
356  */
357 static int
358 interpret_ppp_cp(int flags, uchar_t *data, int len, ppp_protoinfo_t *protoinfo)
359 {
360 	uint8_t code;
361 	uint8_t id;
362 	char *codestr;
363 	uint16_t length;
364 	uchar_t *datap = data;
365 
366 	if (len < sizeof (ppp_pkt_t))
367 		return (len);
368 
369 	GETINT8(code, datap);
370 	GETINT8(id, datap);
371 	GETINT16(length, datap);
372 
373 	len -= sizeof (ppp_pkt_t);
374 
375 	if (code <= MAX_CPCODE)
376 		codestr = cp_codearray[code];
377 	else
378 		codestr = "";
379 
380 	if (flags & F_SUM) {
381 		(void) sprintf(get_sum_line(),
382 		    "%s%s", protoinfo->prefix, codestr);
383 	} else { /* (flags & F_DTAIL) */
384 		show_header(protoinfo->prefix, protoinfo->description, len);
385 		show_space();
386 
387 		(void) sprintf(get_line(0, 0), "Code = %d %s", code, codestr);
388 		(void) sprintf(get_line(0, 0), "Identifier = %d", id);
389 		(void) sprintf(get_line(0, 0), "Length = %d", length);
390 
391 		show_space();
392 
393 		len = MIN(len, length - sizeof (ppp_pkt_t));
394 		if (len == 0)
395 			return (len);
396 
397 		switch (code) {
398 		case CODE_VENDOR: {
399 			uint32_t magicnum;
400 			uint32_t oui;
401 			char *ouistr;
402 			uint8_t kind;
403 
404 			if (len < sizeof (magicnum) + sizeof (oui))
405 				return (len);
406 
407 			GETINT32(magicnum, datap);
408 			(void) sprintf(get_line(0, 0), "Magic-Number = 0x%08x",
409 			    magicnum);
410 
411 			GETINT32(oui, datap);
412 			kind = oui & 0x000000ff;
413 			oui >>= 8;
414 
415 			ouistr = ether_ouiname(oui);
416 			if (ouistr == NULL)
417 				ouistr = unknown_string;
418 
419 			(void) sprintf(get_line(0, 0), "OUI = 0x%06x (%s)",
420 			    oui, ouistr);
421 			(void) sprintf(get_line(0, 0), "Kind = %d", kind);
422 			show_space();
423 			break;
424 		}
425 
426 		case CODE_CONFREQ:
427 		case CODE_CONFACK:
428 		case CODE_CONFNAK:
429 		case CODE_CONFREJ:
430 			/*
431 			 * The above all contain protocol specific
432 			 * configuration options.  Parse these options.
433 			 */
434 			interpret_cp_options(datap, len, protoinfo);
435 			break;
436 
437 		case CODE_TERMREQ:
438 		case CODE_TERMACK:
439 			/*
440 			 * The arbitrary data in these two packet types
441 			 * is almost always plain text.  Print it as such.
442 			 */
443 			(void) sprintf(get_line(0, 0), "Data = %.*s",
444 			    length - sizeof (ppp_pkt_t), datap);
445 			show_space();
446 			break;
447 
448 		case CODE_CODEREJ:
449 			/*
450 			 * What follows is the rejected control protocol
451 			 * packet, starting with the code field.
452 			 * Conveniently, we can call interpret_ppp_cp() to
453 			 * decode this.
454 			 */
455 			prot_nest_prefix = protoinfo->prefix;
456 			interpret_ppp_cp(flags, datap, len, protoinfo);
457 			prot_nest_prefix = "";
458 			break;
459 
460 		case CODE_PROTREJ:
461 			/*
462 			 * We don't print the rejected-protocol field
463 			 * explicitely.  Instead, we cheat and pretend that
464 			 * the rejected-protocol field is actually the
465 			 * protocol field in the included PPP packet.  This
466 			 * way, we can invoke interpret_ppp() and have it
467 			 * treat the included packet normally.
468 			 */
469 			prot_nest_prefix = protoinfo->prefix;
470 			interpret_ppp(flags, datap, len);
471 			prot_nest_prefix = "";
472 			break;
473 
474 		case CODE_ECHOREQ:
475 		case CODE_ECHOREP:
476 		case CODE_DISCREQ:
477 		case CODE_IDENT:
478 		case CODE_TIMEREMAIN: {
479 			uint32_t magicnum;
480 			char *message_label = "Identification = %.*s";
481 
482 			if (len < sizeof (uint32_t))
483 				break;
484 
485 			GETINT32(magicnum, datap);
486 			len -= sizeof (uint32_t);
487 			(void) sprintf(get_line(0, 0), "Magic-Number = 0x%08x",
488 			    magicnum);
489 			/*
490 			 * Unless this is an identification or
491 			 * time-remaining packet, arbitrary data follows
492 			 * the magic number field.  The user can take a
493 			 * look at the hex dump for enlightenment.
494 			 */
495 			if (code == CODE_TIMEREMAIN) {
496 				uint32_t timeremaining;
497 
498 				if (len < sizeof (uint32_t))
499 					break;
500 
501 				message_label = "Message = %.*s";
502 
503 				GETINT32(timeremaining, datap);
504 				len -= sizeof (uint32_t);
505 				(void) sprintf(get_line(0, 0),
506 				    "Seconds Remaining = %d", timeremaining);
507 			}
508 
509 			if (code == CODE_IDENT || code == CODE_TIMEREMAIN) {
510 				if (len == 0)
511 					break;
512 
513 				(void) sprintf(get_line(0, 0), message_label,
514 				    len, datap);
515 			}
516 			show_space();
517 			break;
518 		}
519 
520 		/*
521 		 * Reset-Request and Reset-Ack contain arbitrary data which
522 		 * the user can sift through using the -x option.
523 		 */
524 		case CODE_RESETREQ:
525 		case CODE_RESETACK:
526 		default:
527 			break;
528 		}
529 	}
530 	return (len);
531 }
532 
533 
534 /*
535  * interpret_cp_options() decodes control protocol configuration options.
536  * Since each control protocol has a different set of options whose type
537  * numbers overlap, the protoinfo parameter is used to get a handle on
538  * which option set to use for decoding.
539  */
540 static int
541 interpret_cp_options(uchar_t *optptr, int len, ppp_protoinfo_t *protoinfo)
542 {
543 	cp_optinfo_t *optinfo;
544 	cp_optinfo_t *optinfo_ptr;
545 	uint8_t optlen;
546 	uint8_t opttype;
547 
548 	switch (protoinfo->proto) {
549 	case PPP_LCP:
550 		optinfo = lcp_optinfo;
551 		break;
552 	case PPP_IPCP:
553 		optinfo = ipcp_optinfo;
554 		break;
555 	case PPP_IPV6CP:
556 		optinfo = ipv6cp_optinfo;
557 		break;
558 	case PPP_CCP:
559 		optinfo = ccp_optinfo;
560 		break;
561 	case PPP_ECP:
562 		optinfo = ecp_optinfo;
563 		break;
564 	case PPP_MUXCP:
565 		optinfo = muxcp_optinfo;
566 		break;
567 	default:
568 		return (len);
569 		break;
570 	}
571 
572 	if (len >= 2) {
573 		(void) sprintf(get_line(0, 0), "%s Configuration Options",
574 		    protoinfo->name);
575 		show_space();
576 	}
577 
578 	while (len >= 2) {
579 		GETINT8(opttype, optptr);
580 		GETINT8(optlen, optptr);
581 
582 		optinfo_ptr = ppp_getoptinfo(optinfo, opttype);
583 
584 		(void) sprintf(get_line(0, 0), "Option Type = %d (%s)", opttype,
585 		    optinfo_ptr->opt_name);
586 		(void) sprintf(get_line(0, 0), "Option Length = %d", optlen);
587 
588 		/*
589 		 * Don't continue if there isn't enough data to
590 		 * contain this option, or if this type of option
591 		 * should contain more data than the length field
592 		 * claims there is.
593 		 */
594 		if (optlen > len || optlen < optinfo_ptr->opt_minsize) {
595 			(void) sprintf(get_line(0, 0),
596 			    "Warning: Incomplete Option");
597 			show_space();
598 			break;
599 		}
600 
601 		if (optinfo_ptr->opt_formatdata != NULL) {
602 			optinfo_ptr->opt_formatdata(optptr,
603 			    MIN(optlen - 2, len - 2));
604 		}
605 
606 		len -= optlen;
607 		optptr += optlen - 2;
608 
609 		show_space();
610 	}
611 
612 	return (len);
613 }
614 
615 static int
616 interpret_ppp_chap(int flags, uchar_t *data, int len,
617     ppp_protoinfo_t *protoinfo)
618 {
619 	uint8_t code;
620 	uint8_t id;
621 	char *codestr;
622 	uint16_t length;
623 	int lengthleft;
624 	uchar_t *datap = data;
625 
626 
627 	if (len < sizeof (ppp_pkt_t))
628 		return (len);
629 
630 	GETINT8(code, datap);
631 	GETINT8(id, datap);
632 	GETINT8(length, datap);
633 
634 	if (code <= MAX_CHAPCODE)
635 		codestr = chap_codearray[code];
636 	else
637 		codestr = "";
638 
639 	if (flags & F_SUM) {
640 		(void) sprintf(get_sum_line(),
641 		    "%s%s", protoinfo->prefix, codestr);
642 	} else { /* (flags & F_DTAIL) */
643 		show_header(protoinfo->prefix, protoinfo->description, len);
644 		show_space();
645 
646 		(void) sprintf(get_line(0, 0), "Code = %d %s", code, codestr);
647 		(void) sprintf(get_line(0, 0), "Identifier = %d", id);
648 		(void) sprintf(get_line(0, 0), "Length = %d", length);
649 
650 		show_space();
651 
652 		if (len < length)
653 			return (len);
654 
655 		lengthleft = len - sizeof (ppp_pkt_t);
656 
657 		switch (code) {
658 		case CODE_CHALLENGE:
659 		case CODE_RESPONSE: {
660 			uint8_t value_size;
661 			uint16_t peername_size;
662 
663 			if (lengthleft < sizeof (value_size))
664 				break;
665 
666 			GETINT8(value_size, datap);
667 			lengthleft -= sizeof (value_size);
668 			(void) sprintf(get_line(0, 0), "Value-Size = %d",
669 			    value_size);
670 
671 			if (lengthleft < sizeof (peername_size))
672 				break;
673 			peername_size = MIN(length - sizeof (ppp_pkt_t) -
674 			    value_size, lengthleft);
675 			(void) sprintf(get_line(0, 0), "Name = %.*s",
676 			    peername_size, datap + value_size);
677 
678 			break;
679 		}
680 		case CODE_SUCCESS:
681 		case CODE_FAILURE: {
682 			uint16_t message_size = MIN(length - sizeof (ppp_pkt_t),
683 			    lengthleft);
684 
685 			(void) sprintf(get_line(0, 0), "Message = %.*s",
686 			    message_size, datap);
687 			break;
688 		}
689 		default:
690 			break;
691 		}
692 	}
693 
694 	show_space();
695 	len -= length;
696 	return (len);
697 }
698 
699 static int
700 interpret_ppp_pap(int flags, uchar_t *data, int len,
701     ppp_protoinfo_t *protoinfo)
702 {
703 	uint8_t code;
704 	uint8_t id;
705 	char *codestr;
706 	uint16_t length;
707 	int lengthleft;
708 	uchar_t *datap = data;
709 
710 	if (len < sizeof (ppp_pkt_t))
711 		return (len);
712 
713 	GETINT8(code, datap);
714 	GETINT8(id, datap);
715 	GETINT16(length, datap);
716 
717 	lengthleft = len - sizeof (ppp_pkt_t);
718 
719 	if (code <= MAX_PAPCODE)
720 		codestr = pap_codearray[code];
721 	else
722 		codestr = "";
723 
724 	if (flags & F_SUM) {
725 		(void) sprintf(get_sum_line(),
726 		    "%s%s", protoinfo->prefix, codestr);
727 	} else { /* (flags & F_DTAIL) */
728 		show_header(protoinfo->prefix, protoinfo->description, len);
729 		show_space();
730 
731 		(void) sprintf(get_line(0, 0), "Code = %d %s", code, codestr);
732 		(void) sprintf(get_line(0, 0), "Identifier = %d", id);
733 		(void) sprintf(get_line(0, 0), "Length = %d", length);
734 
735 		show_space();
736 
737 		if (len < length)
738 			return (len);
739 
740 		switch (code) {
741 		case CODE_AUTHREQ: {
742 			uint8_t fieldlen;
743 
744 			if (lengthleft < sizeof (fieldlen))
745 				break;
746 			GETINT8(fieldlen, datap);
747 			(void) sprintf(get_line(0, 0), "Peer-Id Length = %d",
748 			    fieldlen);
749 			lengthleft -= sizeof (fieldlen);
750 
751 			if (lengthleft < fieldlen)
752 				break;
753 			(void) sprintf(get_line(0, 0), "Peer-Id = %.*s",
754 			    fieldlen, datap);
755 			lengthleft -= fieldlen;
756 
757 			datap += fieldlen;
758 
759 			if (lengthleft < sizeof (fieldlen))
760 				break;
761 			GETINT8(fieldlen, datap);
762 			(void) sprintf(get_line(0, 0), "Password Length = %d",
763 			    fieldlen);
764 			lengthleft -= sizeof (fieldlen);
765 
766 			if (lengthleft < fieldlen)
767 				break;
768 			(void) sprintf(get_line(0, 0), "Password = %.*s",
769 			    fieldlen, datap);
770 
771 			break;
772 		}
773 		case CODE_AUTHACK:
774 		case CODE_AUTHNAK: {
775 			uint8_t msglen;
776 
777 			if (lengthleft < sizeof (msglen))
778 				break;
779 			GETINT8(msglen, datap);
780 			(void) sprintf(get_line(0, 0), "Msg-Length = %d",
781 			    msglen);
782 			lengthleft -= sizeof (msglen);
783 
784 			if (lengthleft < msglen)
785 				break;
786 			(void) sprintf(get_line(0, 0), "Message = %.*s",
787 			    msglen, datap);
788 
789 			break;
790 		}
791 		default:
792 			break;
793 		}
794 	}
795 
796 	show_space();
797 	len -= length;
798 	return (len);
799 }
800 
801 
802 static int
803 interpret_ppp_lqr(int flags, uchar_t *data, int len,
804     ppp_protoinfo_t *protoinfo)
805 {
806 	lqr_pkt_t lqr_pkt;
807 	if (len < sizeof (lqr_pkt_t))
808 		return (len);
809 
810 	(void) memcpy(&lqr_pkt, data, sizeof (lqr_pkt_t));
811 
812 	if (flags & F_SUM) {
813 		(void) sprintf(get_sum_line(), protoinfo->prefix);
814 	} else { /* (flags & F_DTAIL) */
815 		show_header(protoinfo->prefix, protoinfo->description, len);
816 		show_space();
817 
818 		(void) sprintf(get_line(0, 0), "Magic-Number =   0x%08x",
819 		    ntohl(lqr_pkt.lqr_magic));
820 		(void) sprintf(get_line(0, 0), "LastOutLQRs =    %d",
821 		    ntohl(lqr_pkt.lqr_lastoutlqrs));
822 		(void) sprintf(get_line(0, 0), "LastOutPackets = %d",
823 		    ntohl(lqr_pkt.lqr_lastoutpackets));
824 		(void) sprintf(get_line(0, 0), "LastOutOctets =  %d",
825 		    ntohl(lqr_pkt.lqr_lastoutoctets));
826 		(void) sprintf(get_line(0, 0), "PeerInLQRs =     %d",
827 		    ntohl(lqr_pkt.lqr_peerinlqrs));
828 		(void) sprintf(get_line(0, 0), "PeerInPackets =  %d",
829 		    ntohl(lqr_pkt.lqr_peerinpackets));
830 		(void) sprintf(get_line(0, 0), "PeerInDiscards = %d",
831 		    ntohl(lqr_pkt.lqr_peerindiscards));
832 		(void) sprintf(get_line(0, 0), "PeerInErrors =   %d",
833 		    ntohl(lqr_pkt.lqr_peerinerrors));
834 		(void) sprintf(get_line(0, 0), "PeerInOctets =   %d",
835 		    ntohl(lqr_pkt.lqr_peerinoctets));
836 		(void) sprintf(get_line(0, 0), "PeerOutLQRs =    %d",
837 		    ntohl(lqr_pkt.lqr_peeroutlqrs));
838 		(void) sprintf(get_line(0, 0), "PeerOutPackets = %d",
839 		    ntohl(lqr_pkt.lqr_peeroutpackets));
840 		(void) sprintf(get_line(0, 0), "PeerOutOctets =  %d",
841 		    ntohl(lqr_pkt.lqr_peeroutoctets));
842 
843 		show_space();
844 	}
845 
846 	len -= sizeof (lqr_pkt_t);
847 	return (len);
848 }
849 
850 static ppp_protoinfo_t *
851 ppp_getprotoinfo(uint16_t proto)
852 {
853 	ppp_protoinfo_t *protoinfo_ptr = &protoinfo_array[0];
854 
855 	while (protoinfo_ptr->proto != proto && protoinfo_ptr->proto != 0) {
856 		protoinfo_ptr++;
857 	}
858 
859 	return (protoinfo_ptr);
860 }
861 
862 
863 static cp_optinfo_t *
864 ppp_getoptinfo(cp_optinfo_t optinfo_list[], uint16_t opt_type)
865 {
866 	cp_optinfo_t *optinfo_ptr = &optinfo_list[0];
867 
868 	while (optinfo_ptr->opt_type != opt_type &&
869 	    optinfo_ptr->opt_name != unknown_string) {
870 		optinfo_ptr++;
871 	}
872 
873 	return (optinfo_ptr);
874 }
875 
876 
877 /*
878  * Below are the functions which parse control protocol configuration
879  * options.  The first argument to these functions (optdata) points to the
880  * first byte of the option after the length field.  The second argument
881  * (size) is the number of bytes in the option after the length field
882  * (length - 2).
883  */
884 
885 /*
886  * The format of the Vendor-Specific option (rfc2153) is:
887  *
888  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
889  * |     Type      |    Length     |              OUI
890  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
891  *        ...      |     Kind      |  Value(s) ...
892  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
893  */
894 /*ARGSUSED1*/
895 static void
896 opt_format_vendor(uchar_t *optdata, uint8_t size)
897 {
898 	uint32_t oui;
899 	char *ouistr;
900 	uint8_t kind;
901 
902 	GETINT32(oui, optdata);
903 	kind = oui & 0x000000ff;
904 	oui >>= 8;
905 
906 	ouistr = ether_ouiname(oui);
907 	if (ouistr == NULL)
908 		ouistr = unknown_string;
909 
910 	(void) sprintf(get_line(0, 0), "OUI = 0x%06x (%s)", oui, ouistr);
911 	(void) sprintf(get_line(0, 0), "Kind = %d", kind);
912 }
913 
914 /*
915  * The format of the MRU option (rfc1661) is:
916  *
917  *  0                   1                   2                   3
918  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
919  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920  * |     Type      |    Length     |      Maximum-Receive-Unit     |
921  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
922  */
923 /*ARGSUSED1*/
924 static void
925 opt_format_mru(uchar_t *optdata, uint8_t size)
926 {
927 	uint16_t mru;
928 
929 	GETINT16(mru, optdata);
930 	(void) sprintf(get_line(0, 0), "MRU = %d", mru);
931 }
932 
933 /*
934  * The format of the accm option (rfc1662) is:
935  *
936  *  0                   1                   2                   3
937  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
938  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939  * |     Type      |    Length     |               ACCM
940  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941  *           ACCM (cont)           |
942  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
943  */
944 /*ARGSUSED1*/
945 static void
946 opt_format_accm(uchar_t *optdata, uint8_t size)
947 {
948 	uint32_t accm;
949 
950 	GETINT32(accm, optdata);
951 	(void) sprintf(get_line(0, 0), "ACCM = 0x%08x", accm);
952 }
953 
954 /*
955  * The format of the Authentication-Protocol option (rfc1661) is:
956  *
957  *  0                   1                   2                   3
958  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
959  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
960  * |     Type      |    Length     |     Authentication-Protocol   |
961  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
962  * |    Data ...
963  * +-+-+-+-+
964  *
965  * For PAP (rfc1334), there is no data.  For CHAP (rfc1994), there is one
966  * byte of data representing the algorithm.
967  */
968 static void
969 opt_format_authproto(uchar_t *optdata, uint8_t size)
970 {
971 	uint16_t proto;
972 	ppp_protoinfo_t *auth_protoinfo;
973 
974 	GETINT16(proto, optdata);
975 
976 	auth_protoinfo = ppp_getprotoinfo(proto);
977 
978 	(void) sprintf(get_line(0, 0), "Protocol = 0x%x (%s)", proto,
979 	    auth_protoinfo->name);
980 
981 	switch (proto) {
982 	case PPP_CHAP: {
983 		uint8_t algo;
984 		char *algostr;
985 
986 		if (size < sizeof (proto) + sizeof (algo))
987 			return;
988 
989 		GETINT8(algo, optdata);
990 		switch (algo) {
991 		case 5:
992 			algostr = "CHAP with MD5";
993 			break;
994 		case 128:
995 			algostr = "MS-CHAP";
996 			break;
997 		case 129:
998 			algostr = "MS-CHAP-2";
999 			break;
1000 		default:
1001 			algostr = unknown_string;
1002 			break;
1003 		}
1004 		(void) sprintf(get_line(0, 0), "Algorithm = %d (%s)", algo,
1005 		    algostr);
1006 		break;
1007 	}
1008 	default:
1009 		break;
1010 	}
1011 }
1012 
1013 /*
1014  * The format of the Quality Protocol option (rfc1661) is:
1015  *
1016  *  0                   1                   2                   3
1017  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1018  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1019  * |     Type      |    Length     |        Quality-Protocol       |
1020  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1021  * |    Data ...
1022  * +-+-+-+-+
1023  *
1024  * For LQR, the data consists of a 4 byte reporting period.
1025  */
1026 static void
1027 opt_format_qualproto(uchar_t *optdata, uint8_t size)
1028 {
1029 	uint16_t proto;
1030 	ppp_protoinfo_t *qual_protoinfo;
1031 
1032 	GETINT16(proto, optdata);
1033 
1034 	qual_protoinfo = ppp_getprotoinfo(proto);
1035 
1036 	(void) sprintf(get_line(0, 0), "Protocol = 0x%x (%s)", proto,
1037 	    qual_protoinfo->name);
1038 
1039 	switch (proto) {
1040 	case PPP_LQR: {
1041 		uint32_t reporting_period;
1042 
1043 		if (size < sizeof (proto) + sizeof (reporting_period))
1044 			return;
1045 
1046 		GETINT32(reporting_period, optdata);
1047 		(void) sprintf(get_line(0, 0), "Reporting-Period = %d",
1048 		    reporting_period);
1049 		break;
1050 	}
1051 	default:
1052 		break;
1053 	}
1054 }
1055 
1056 /*
1057  * The format of the Magic Number option (rfc1661) is:
1058  *
1059  *  0                   1                   2                   3
1060  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1061  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1062  * |     Type      |    Length     |          Magic-Number
1063  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1064  *       Magic-Number (cont)       |
1065  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1066  */
1067 /*ARGSUSED1*/
1068 static void
1069 opt_format_magicnum(uchar_t *optdata, uint8_t size)
1070 {
1071 	uint32_t magicnum;
1072 
1073 	GETINT32(magicnum, optdata);
1074 	(void) sprintf(get_line(0, 0), "Magic Number = 0x%08x", magicnum);
1075 }
1076 
1077 /*
1078  * The format of the FCS-Alternatives option (rfc1570) is:
1079  *
1080  *  0                   1                   2
1081  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
1082  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1083  * |     Type      |    Length     |    Options    |
1084  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1085  */
1086 /*ARGSUSED1*/
1087 static void
1088 opt_format_fcs(uchar_t *optdata, uint8_t size)
1089 {
1090 	uint8_t options;
1091 
1092 	GETINT8(options, optdata);
1093 
1094 	(void) sprintf(get_line(0, 0), "Options = 0x%02x", options);
1095 	(void) sprintf(get_line(0, 0), "     %s",
1096 	    getflag(options, 0x01, "NULL FCS", ""));
1097 	(void) sprintf(get_line(0, 0), "     %s",
1098 	    getflag(options, 0x02, "CCITT 16-bit FCS", ""));
1099 	(void) sprintf(get_line(0, 0), "     %s",
1100 	    getflag(options, 0x04, "CCITT 32-bit FCS", ""));
1101 }
1102 
1103 /*
1104  * The format of the Self-Describing-Padding option (rfc1570) is:
1105  *
1106  *  0                   1                   2
1107  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
1108  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1109  * |     Type      |    Length     |    Maximum    |
1110  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1111  */
1112 /*ARGSUSED1*/
1113 static void
1114 opt_format_sdp(uchar_t *optdata, uint8_t size)
1115 {
1116 	uint8_t max;
1117 
1118 	GETINT8(max, optdata);
1119 
1120 	(void) sprintf(get_line(0, 0), "Maximum = %d", max);
1121 }
1122 
1123 /*
1124  * The format of the Numbered-Mode option (rfc1663) is:
1125  *
1126  *  0                   1                   2                   3
1127  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1128  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1129  * |     Type      |     Length    |    Window     |   Address...
1130  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1131  */
1132 /*ARGSUSED1*/
1133 static void
1134 opt_format_nummode(uchar_t *optdata, uint8_t size)
1135 {
1136 	uint8_t window;
1137 
1138 	GETINT8(window, optdata);
1139 	(void) sprintf(get_line(0, 0), "Window = %d", window);
1140 }
1141 
1142 /*
1143  * The format of the Callback option (rfc1570) is:
1144  *
1145  *  0                   1                   2                   3
1146  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1147  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1148  * |     Type      |    Length     |   Operation   |  Message ...
1149  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1150  */
1151 static void
1152 opt_format_callback(uchar_t *optdata, uint8_t size)
1153 {
1154 	uint8_t operation;
1155 	char *opstr;
1156 
1157 	GETINT8(operation, optdata);
1158 	switch (operation) {
1159 	case 0:
1160 		opstr = "User Authentication";
1161 		break;
1162 	case 1:
1163 		opstr = "Dialing String";
1164 		break;
1165 	case 2:
1166 		opstr = "Location Identifier";
1167 		break;
1168 	case 3:
1169 		opstr = "E.164 Number";
1170 		break;
1171 	case 4:
1172 		opstr = "X.500 Distinguished Name";
1173 		break;
1174 	case 6:
1175 		opstr = "CBCP Negotiation";
1176 		break;
1177 	default:
1178 		opstr = unknown_string;
1179 		break;
1180 	}
1181 
1182 	(void) sprintf(get_line(0, 0), "Operation = %d (%s)", operation, opstr);
1183 
1184 	if (size > sizeof (operation)) {
1185 		(void) sprintf(get_line(0, 0), "Message = %.*s",
1186 		    size - sizeof (operation), optdata);
1187 	}
1188 }
1189 
1190 /*
1191  * The format of the Multilink-MRRU option (rfc1990) is:
1192  *
1193  *  0                   1                   2                   3
1194  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1195  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1196  * |   Type = 17   |   Length = 4  | Max-Receive-Reconstructed-Unit|
1197  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1198  */
1199 /*ARGSUSED1*/
1200 static void
1201 opt_format_mrru(uchar_t *optdata, uint8_t size)
1202 {
1203 	uint16_t mrru;
1204 
1205 	GETINT16(mrru, optdata);
1206 	(void) sprintf(get_line(0, 0), "MRRU = %d", mrru);
1207 }
1208 
1209 /*
1210  * The format of the Endpoint Discriminator option (rfc1990) is:
1211  *
1212  *  0                   1                   2                   3
1213  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1214  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1215  * |   Type = 19   |     Length    |    Class      |  Address ...
1216  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1217  */
1218 static void
1219 opt_format_epdisc(uchar_t *optdata, uint8_t size)
1220 {
1221 	uint8_t class;
1222 	char *classstr;
1223 	uint8_t addrlen = size - sizeof (class);
1224 	char *addr;
1225 
1226 	GETINT8(class, optdata);
1227 
1228 	switch (class) {
1229 	case 0:
1230 		classstr = "Null Class";
1231 		break;
1232 	case 1:
1233 		classstr = "Locally Assigned Address";
1234 		break;
1235 	case 2:
1236 		classstr = "IPv4 Address";
1237 		break;
1238 	case 3:
1239 		classstr = "IEE 802.1 Global MAC Address";
1240 		break;
1241 	case 4:
1242 		classstr = "PPP Magic-Number Block";
1243 		break;
1244 	case 5:
1245 		classstr = "Public Switched Network Directory Number";
1246 		break;
1247 	default:
1248 		classstr = unknown_string;
1249 		break;
1250 	}
1251 
1252 	(void) sprintf(get_line(0, 0), "Address Class = %d (%s)", class,
1253 	    classstr);
1254 
1255 	if (addrlen == 0)
1256 		return;
1257 
1258 	addr = (char *)malloc(addrlen);
1259 	(void) memcpy(addr, optdata, addrlen);
1260 	switch (class) {
1261 	case 2: {
1262 		char addrstr[INET_ADDRSTRLEN];
1263 
1264 		if (addrlen != sizeof (in_addr_t))
1265 			break;
1266 		if (inet_ntop(AF_INET, addr, addrstr, INET_ADDRSTRLEN) !=
1267 		    NULL) {
1268 			(void) sprintf(get_line(0, 0), "Address = %s", addrstr);
1269 		}
1270 		break;
1271 	}
1272 	case 3: {
1273 		char *addrstr;
1274 
1275 		if (addrlen != sizeof (struct ether_addr))
1276 			break;
1277 		if ((addrstr = ether_ntoa((struct ether_addr *)addr)) != NULL) {
1278 			(void) sprintf(get_line(0, 0), "Address = %s", addrstr);
1279 		}
1280 		break;
1281 	}
1282 	case 5: {
1283 		/*
1284 		 * For this case, the address is supposed to be a plain
1285 		 * text telephone number.
1286 		 */
1287 		(void) sprintf(get_line(0, 0), "Address = %.*s", addrlen,
1288 		    addr);
1289 	}
1290 	default:
1291 		break;
1292 	}
1293 
1294 	free(addr);
1295 }
1296 
1297 /*
1298  * The DCE identifier option has the following format (from rfc1976):
1299  *
1300  *     0                   1                   2
1301  *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
1302  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1303  *    |     Type      |    Length     |      Mode     |
1304  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1305  */
1306 /*ARGSUSED1*/
1307 static void
1308 opt_format_dce(uchar_t *optdata, uint8_t size)
1309 {
1310 	uint8_t mode;
1311 	char *modestr;
1312 
1313 	GETINT8(mode, optdata);
1314 	switch (mode) {
1315 	case 1:
1316 		modestr = "No Additional Negotiation";
1317 		break;
1318 	case 2:
1319 		modestr = "Full PPP Negotiation and State Machine";
1320 		break;
1321 	default:
1322 		modestr = unknown_string;
1323 		break;
1324 	}
1325 	(void) sprintf(get_line(0, 0), "Mode = %d (%s)", mode, modestr);
1326 }
1327 
1328 /*
1329  * The format of the Link Discriminator option (rfc2125) is:
1330  *
1331  *  0                   1                   2                   3
1332  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1333  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1334  * |     Type      |     Length    |       Link Discriminator      |
1335  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1336  */
1337 /*ARGSUSED1*/
1338 static void
1339 opt_format_linkdisc(uchar_t *optdata, uint8_t size)
1340 {
1341 	uint16_t discrim;
1342 
1343 	GETINT16(discrim, optdata);
1344 
1345 	(void) sprintf(get_line(0, 0), "Link Discriminator = %d", discrim);
1346 }
1347 
1348 
1349 /*
1350  * The format of the Internationalization option (rfc2484) is:
1351  *
1352  *  0                   1                   2                   3
1353  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1354  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1355  * |     Type      |    Length     |          MIBenum
1356  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1357  *           MIBenum (cont)        |        Language-Tag...
1358  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1359  */
1360 static void
1361 opt_format_i18n(uchar_t *optdata, uint8_t size)
1362 {
1363 	uint32_t mibenum;
1364 	uint8_t taglen;
1365 
1366 	taglen = size - sizeof (mibenum);
1367 
1368 	GETINT32(mibenum, optdata);
1369 	(void) sprintf(get_line(0, 0), "MIBenum = %d", mibenum);
1370 
1371 	if (taglen > 0) {
1372 		(void) sprintf(get_line(0, 0), "Language Tag = %.*s", taglen,
1373 		    optdata);
1374 	}
1375 }
1376 
1377 /*
1378  * The format of the obsolete IP-Addresses option (rfc1172) is:
1379  *
1380  *  0                   1                   2                   3
1381  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1382  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1383  * |     Type      |    Length     |     Source-IP-Address
1384  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1385  *   Source-IP-Address (cont)      |  Destination-IP-Address
1386  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1387  *  Destination-IP-Address (cont)  |
1388  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1389  */
1390 /*ARGSUSED1*/
1391 static void
1392 opt_format_ipaddresses(uchar_t *optdata, uint8_t size)
1393 {
1394 	in_addr_t addr;
1395 	char addrstr[INET_ADDRSTRLEN];
1396 
1397 	(void) memcpy(&addr, optdata, sizeof (in_addr_t));
1398 	if (inet_ntop(AF_INET, &addr, addrstr, INET_ADDRSTRLEN) != NULL) {
1399 		(void) sprintf(get_line(0, 0), "Source Address =      %s",
1400 		    addrstr);
1401 	}
1402 
1403 	optdata += sizeof (in_addr_t);
1404 
1405 	(void) memcpy(&addr, optdata, sizeof (in_addr_t));
1406 	if (inet_ntop(AF_INET, &addr, addrstr, INET_ADDRSTRLEN) != NULL) {
1407 		(void) sprintf(get_line(0, 0), "Destination Address = %s",
1408 		    addrstr);
1409 	}
1410 }
1411 
1412 /*
1413  * The format of the IP-Compression-Protocol option (rfc1332) is:
1414  *
1415  *  0                   1                   2                   3
1416  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1417  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1418  * |     Type      |    Length     |     IP-Compression-Protocol   |
1419  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1420  * |    Data ...
1421  * +-+-+-+-+
1422  *
1423  * For VJ Compressed TCP/IP, data consists of:
1424  *
1425  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1426  * |  Max-Slot-Id  | Comp-Slot-Id  |
1427  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1428  *
1429  * For IPHC (rfc2509), data consists of:
1430  *
1431  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1432  * |           TCP_SPACE           |         NON_TCP_SPACE         |
1433  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1434  * |         F_MAX_PERIOD          |          F_MAX_TIME           |
1435  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1436  * |           MAX_HEADER          |          suboptions...
1437  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1438  */
1439 static void
1440 opt_format_ipcompproto(uchar_t *optdata, uint8_t size)
1441 {
1442 	uint16_t proto;
1443 	ppp_protoinfo_t *comp_protoinfo;
1444 
1445 	GETINT16(proto, optdata);
1446 
1447 	comp_protoinfo = ppp_getprotoinfo(proto);
1448 
1449 	(void) sprintf(get_line(0, 0), "Protocol = 0x%x (%s)", proto,
1450 	    comp_protoinfo->name);
1451 
1452 	switch (proto) {
1453 	case PPP_VJC_COMP: {
1454 		uint8_t maxslotid;
1455 		uint8_t compslotid;
1456 
1457 		if (size < sizeof (proto) + sizeof (maxslotid) +
1458 		    sizeof (compslotid))
1459 			break;
1460 
1461 		GETINT8(maxslotid, optdata);
1462 		GETINT8(compslotid, optdata);
1463 		(void) sprintf(get_line(0, 0), "Max-Slot-Id = %d", maxslotid);
1464 		(void) sprintf(get_line(0, 0), "Comp-Slot Flag = 0x%x",
1465 		    compslotid);
1466 		break;
1467 	}
1468 	case PPP_FULLHDR: {
1469 		uint16_t tcp_space;
1470 		uint16_t non_tcp_space;
1471 		uint16_t f_max_period;
1472 		uint16_t f_max_time;
1473 		uint16_t max_header;
1474 
1475 		if (size < sizeof (proto) + sizeof (tcp_space) +
1476 		    sizeof (non_tcp_space) + sizeof (f_max_period) +
1477 		    sizeof (f_max_time) + sizeof (max_header))
1478 			break;
1479 
1480 		GETINT16(tcp_space, optdata);
1481 		GETINT16(non_tcp_space, optdata);
1482 		GETINT16(f_max_period, optdata);
1483 		GETINT16(f_max_time, optdata);
1484 		GETINT16(max_header, optdata);
1485 
1486 		(void) sprintf(get_line(0, 0), "TCP_SPACE = %d", tcp_space);
1487 		(void) sprintf(get_line(0, 0), "NON_TCP_SPACE = %d",
1488 		    non_tcp_space);
1489 		(void) sprintf(get_line(0, 0), "F_MAX_PERIOD = %d",
1490 		    f_max_period);
1491 		(void) sprintf(get_line(0, 0), "F_MAX_TIME = %d", f_max_time);
1492 		(void) sprintf(get_line(0, 0), "MAX_HEADER = %d octets",
1493 		    max_header);
1494 	}
1495 	default:
1496 		break;
1497 	}
1498 }
1499 
1500 /*
1501  * The format of the IP-Address option (rfc1332) is:
1502  *
1503  *  0                   1                   2                   3
1504  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1505  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1506  * |     Type      |    Length     |           IP-Address
1507  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1508  *         IP-Address (cont)       |
1509  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1510  */
1511 /*ARGSUSED1*/
1512 static void
1513 opt_format_ipaddress(uchar_t *optdata, uint8_t size)
1514 {
1515 	in_addr_t ipaddr;
1516 	char addrstr[INET_ADDRSTRLEN];
1517 
1518 	(void) memcpy(&ipaddr, optdata, sizeof (in_addr_t));
1519 	if (inet_ntop(AF_INET, &ipaddr, addrstr, INET_ADDRSTRLEN) != NULL) {
1520 		(void) sprintf(get_line(0, 0), "Address = %s", addrstr);
1521 	}
1522 }
1523 
1524 /*
1525  * The format of the Mobile-IPv4 option (rfc2290) is:
1526  *
1527  *  0                   1                   2                   3
1528  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1529  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1530  * |     Type      |    Length     |         Mobile Node's ...
1531  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1532  *       ...  Home Address         |
1533  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1534  */
1535 /*ARGSUSED1*/
1536 static void
1537 opt_format_mobileipv4(uchar_t *optdata, uint8_t size)
1538 {
1539 	in_addr_t ipaddr;
1540 	char addrstr[INET_ADDRSTRLEN];
1541 
1542 	(void) memcpy(&ipaddr, optdata, sizeof (in_addr_t));
1543 	if (inet_ntop(AF_INET, &ipaddr, addrstr, INET_ADDRSTRLEN) != NULL) {
1544 		(void) sprintf(get_line(0, 0),
1545 		    "Mobile Node's Home Address = %s", addrstr);
1546 	}
1547 }
1548 
1549 /*
1550  * The format of the Interface-Identifier option (rfc2472) is:
1551  *
1552  * 0                   1                   2                   3
1553  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1554  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1555  * |     Type      |    Length     | Interface-Identifier (MS Bytes)
1556  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1557  *                      Interface-Identifier (cont)
1558  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1559  * Interface-Identifier (LS Bytes) |
1560  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1561  */
1562 /*ARGSUSED1*/
1563 static void
1564 opt_format_ifaceid(uchar_t *optdata, uint8_t size)
1565 {
1566 	in6_addr_t id;
1567 	char idstr[INET6_ADDRSTRLEN];
1568 
1569 	(void) memset(&id, 0, sizeof (in6_addr_t));
1570 	(void) memcpy(&id.s6_addr[8], optdata, 8);
1571 
1572 	if (inet_ntop(AF_INET6, &id, idstr, INET6_ADDRSTRLEN) != NULL) {
1573 		(void) sprintf(get_line(0, 0), "Interface ID = %s", idstr);
1574 	}
1575 }
1576 
1577 /*
1578  * The format of the IPv6-Compression-Protocol option (rfc2472) is:
1579  *
1580  * 0                   1                   2                   3
1581  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1582  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1583  * |     Type      |    Length     |   IPv6-Compression-Protocol   |
1584  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1585  * |    Data ...
1586  * +-+-+-+-+
1587  */
1588 static void
1589 opt_format_ipv6compproto(uchar_t *optdata, uint8_t size)
1590 {
1591 	uint16_t proto;
1592 	ppp_protoinfo_t *comp_protoinfo;
1593 
1594 	GETINT16(proto, optdata);
1595 
1596 	comp_protoinfo = ppp_getprotoinfo(proto);
1597 
1598 	(void) sprintf(get_line(0, 0), "Protocol = 0x%x (%s)", proto,
1599 	    comp_protoinfo->name);
1600 
1601 	switch (proto) {
1602 	case PPP_FULLHDR: {
1603 		uint16_t tcp_space;
1604 		uint16_t non_tcp_space;
1605 		uint16_t f_max_period;
1606 		uint16_t f_max_time;
1607 		uint16_t max_header;
1608 
1609 		if (size < sizeof (proto) + sizeof (tcp_space) +
1610 		    sizeof (non_tcp_space) + sizeof (f_max_period) +
1611 		    sizeof (f_max_time) + sizeof (max_header))
1612 			return;
1613 
1614 		GETINT16(tcp_space, optdata);
1615 		GETINT16(non_tcp_space, optdata);
1616 		GETINT16(f_max_period, optdata);
1617 		GETINT16(f_max_time, optdata);
1618 		GETINT16(max_header, optdata);
1619 
1620 		(void) sprintf(get_line(0, 0), "TCP_SPACE = %d", tcp_space);
1621 		(void) sprintf(get_line(0, 0), "NON_TCP_SPACE = %d",
1622 		    non_tcp_space);
1623 		(void) sprintf(get_line(0, 0), "F_MAX_PERIOD = %d",
1624 		    f_max_period);
1625 		(void) sprintf(get_line(0, 0), "F_MAX_TIME = %d", f_max_time);
1626 		(void) sprintf(get_line(0, 0), "MAX_HEADER = %d octets",
1627 		    max_header);
1628 	}
1629 	default:
1630 		break;
1631 	}
1632 }
1633 
1634 /*
1635  * The format of the Proprietary Compression OUI option (rfc1962) is:
1636  *
1637  *  0                   1                   2                   3
1638  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1639  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1640  * |     Type      |    Length     |       OUI ...
1641  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1642  *       OUI       |    Subtype    |  Values...
1643  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
1644  */
1645 /*ARGSUSED1*/
1646 static void
1647 opt_format_compoui(uchar_t *optdata, uint8_t size)
1648 {
1649 	uint32_t oui;
1650 	uint8_t subtype;
1651 	char *ouistr;
1652 
1653 	GETINT32(oui, optdata);
1654 	subtype = oui & 0x000000ff;
1655 	oui >>= 8;
1656 
1657 	ouistr = ether_ouiname(oui);
1658 	if (ouistr == NULL)
1659 		ouistr = unknown_string;
1660 	(void) sprintf(get_line(0, 0), "OUI = 0x%06x (%s)", oui, ouistr);
1661 	(void) sprintf(get_line(0, 0), "Subtype = 0x%x", subtype);
1662 }
1663 
1664 /*
1665  * The format of the Stac LZS configuration option (rfc1974) is:
1666  *
1667  *  0                   1                   2                   3
1668  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1669  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1670  * |     Type      |    Length     |        History Count          |
1671  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1672  * |   Check Mode  |
1673  * +-+-+-+-+-+-+-+-+
1674  */
1675 /*ARGSUSED1*/
1676 static void
1677 opt_format_staclzs(uchar_t *optdata, uint8_t size)
1678 {
1679 	uint16_t hcount;
1680 	uint8_t cmode;
1681 
1682 	GETINT16(hcount, optdata);
1683 	GETINT8(cmode, optdata);
1684 
1685 	cmode &= 0x07;
1686 
1687 	(void) sprintf(get_line(0, 0), "History Count = %d", hcount);
1688 	(void) sprintf(get_line(0, 0), "Check Mode = %d", cmode);
1689 }
1690 
1691 /*
1692  * The format of MPPC configuration option (rfc2118) is:
1693  *
1694  *  0                   1                   2                   3
1695  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1696  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1697  * |     Type      |    Length     |        Supported Bits         |
1698  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1699  * |       Supported Bits          |
1700  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1701  */
1702 /*ARGSUSED1*/
1703 static void
1704 opt_format_mppc(uchar_t *optdata, uint8_t size)
1705 {
1706 	uint32_t sb;
1707 
1708 	GETINT32(sb, optdata);
1709 
1710 	(void) sprintf(get_line(0, 0), "Supported Bits = 0x%x", sb);
1711 }
1712 
1713 /*
1714  * The format of the Gandalf FZA configuration option (rfc1993) is:
1715  *
1716  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1717  * |     Type      |    Length     |   History   |    Version ...
1718  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1719  */
1720 /*ARGSUSED1*/
1721 static void
1722 opt_format_gandalf(uchar_t *optdata, uint8_t size)
1723 {
1724 	uint8_t history;
1725 
1726 	GETINT8(history, optdata);
1727 	(void) sprintf(get_line(0, 0), "Maximum History Size = %d bits",
1728 	    history);
1729 }
1730 
1731 /*
1732  * The format of the BSD Compress configuration option (rfc1977) is:
1733  *
1734  *  0                   1                   2
1735  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
1736  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1737  * |     Type      |    Length     | Vers|   Dict  |
1738  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1739  */
1740 /*ARGSUSED1*/
1741 static void
1742 opt_format_bsdcomp(uchar_t *optdata, uint8_t size)
1743 {
1744 	uint8_t version;
1745 	uint8_t codesize;
1746 
1747 	GETINT8(codesize, optdata);
1748 
1749 	version = codesize >> 5;
1750 	codesize &= 0x1f;
1751 
1752 	(void) sprintf(get_line(0, 0), "Version = 0x%x", version);
1753 	(void) sprintf(get_line(0, 0), "Maximum Code Size = %d bits", codesize);
1754 }
1755 
1756 /*
1757  * The format of the LZS-DCP configuration option (rfc1967) is:
1758  *
1759  *  0                   1                   2                   3
1760  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1761  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1762  * |     Type      |    Length     |        History Count          |
1763  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1764  * |   Check Mode  | Process Mode  |
1765  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1766  */
1767 /*ARGSUSED1*/
1768 static void
1769 opt_format_lzsdcp(uchar_t *optdata, uint8_t size)
1770 {
1771 	uint16_t history;
1772 	uint8_t mode;
1773 	char *modestr;
1774 
1775 	GETINT16(history, optdata);
1776 	(void) sprintf(get_line(0, 0), "History Count = %d", history);
1777 
1778 	/* check mode */
1779 	GETINT8(mode, optdata);
1780 	switch (mode) {
1781 	case 0:
1782 		modestr = "None";
1783 		break;
1784 	case 1:
1785 		modestr = "LCB";
1786 		break;
1787 	case 2:
1788 		modestr = "Sequence Number";
1789 		break;
1790 	case 3:
1791 		modestr = "Sequence Number + LCB (default)";
1792 		break;
1793 	default:
1794 		modestr = unknown_string;
1795 		break;
1796 	}
1797 	(void) sprintf(get_line(0, 0), "Check Mode = %d (%s)", mode, modestr);
1798 
1799 	/* process mode */
1800 	GETINT8(mode, optdata);
1801 	switch (mode) {
1802 	case 0:
1803 		modestr = "None (default)";
1804 		break;
1805 	case 1:
1806 		modestr = "Process-Uncompressed";
1807 		break;
1808 	default:
1809 		modestr = unknown_string;
1810 		break;
1811 	}
1812 	(void) sprintf(get_line(0, 0), "Process Mode = %d (%s)", mode, modestr);
1813 
1814 }
1815 
1816 /*
1817  * The format of the Magnalink configuration option (rfc1975) is:
1818  *
1819  *  0                   1                   2                   3
1820  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1821  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1822  * |     Type      |    Length     |FE |P| History |  # Contexts   |
1823  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1824  */
1825 /*ARGSUSED1*/
1826 static void
1827 opt_format_magnalink(uchar_t *optdata, uint8_t size)
1828 {
1829 	uint8_t features;
1830 	uint8_t pflag;
1831 	uint8_t history;
1832 	uint8_t contexts;
1833 
1834 	GETINT8(history, optdata);
1835 	GETINT8(contexts, optdata);
1836 
1837 	features = history >> 6;
1838 	pflag = (history >> 5) & 0x01;
1839 	history &= 0x1f;
1840 
1841 	(void) sprintf(get_line(0, 0), "Features = 0x%d", features);
1842 	(void) sprintf(get_line(0, 0), "Packet Flag = %d", pflag);
1843 	(void) sprintf(get_line(0, 0), "History Size = %d", history);
1844 	(void) sprintf(get_line(0, 0), "Contexts = %d", contexts);
1845 }
1846 
1847 /*
1848  * The format of the Deflate configuration option (rfc1979) is:
1849  *
1850  *  0                   1                   2                   3
1851  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1852  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1853  * |     Type      |    Length     |Window | Method|    MBZ    |Chk|
1854  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1855  */
1856 /*ARGSUSED1*/
1857 static void
1858 opt_format_deflate(uchar_t *optdata, uint8_t size)
1859 {
1860 	uint8_t window;
1861 	uint8_t method;
1862 	uint8_t chk;
1863 
1864 	GETINT8(method, optdata);
1865 	window = method >> 4;
1866 	method &= 0x0f;
1867 
1868 	GETINT8(chk, optdata);
1869 	chk &= 0x03;
1870 
1871 	(void) sprintf(get_line(0, 0), "Maximum Window Size = %d", window);
1872 	(void) sprintf(get_line(0, 0), "Compression Method = 0x%x", method);
1873 	(void) sprintf(get_line(0, 0), "Check Method = 0x%x", chk);
1874 }
1875 
1876 /*
1877  * The format of the Proprietary Encryption OUI option (rfc1968) is:
1878  *
1879  * 0                   1                   2                   3
1880  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1881  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1882  * |     Type      |    Length     |       OUI ...
1883  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1884  *       OUI       |    Subtype    |  Values...
1885  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
1886  */
1887 /*ARGSUSED1*/
1888 static void
1889 opt_format_encroui(uchar_t *optdata, uint8_t size)
1890 {
1891 	uint32_t oui;
1892 	uint8_t subtype;
1893 	char *ouistr;
1894 
1895 	GETINT32(oui, optdata);
1896 	subtype = oui & 0x000000ff;
1897 	oui >>= 8;
1898 
1899 	ouistr = ether_ouiname(oui);
1900 	if (ouistr == NULL)
1901 		ouistr = unknown_string;
1902 	(void) sprintf(get_line(0, 0), "OUI = 0x%06x (%s)", oui, ouistr);
1903 	(void) sprintf(get_line(0, 0), "Subtype = 0x%x", subtype);
1904 }
1905 
1906 /*
1907  * The format of the DESE, DESE-bis, and 3DESE configuration options
1908  * (rfc1969, rfc2419, and rfc2420) are:
1909  *
1910  * 0                   1                   2                   3
1911  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1912  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1913  * |   Type = 3    |    Length     |         Initial Nonce ...
1914  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1915  */
1916 /*ARGSUSED1*/
1917 static void
1918 opt_format_dese(uchar_t *optdata, uint8_t size)
1919 {
1920 	(void) sprintf(get_line(0, 0),
1921 	    "Initial Nonce = 0x%02x%02x%02x%02x%02x%02x%02x%02x",
1922 	    optdata[0], optdata[1], optdata[2], optdata[3], optdata[4],
1923 	    optdata[5], optdata[6], optdata[7]);
1924 }
1925 
1926 /*
1927  * The format of the PPPMux Default Protocol Id option
1928  * (draft-ietf-pppext-pppmux-02.txt) is:
1929  *
1930  *  0                   1                   2                   3
1931  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1932  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1933  * |   Type = 1    |   Length = 4  |        Default PID            |
1934  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1935  */
1936 /*ARGSUSED1*/
1937 static void
1938 opt_format_muxpid(uchar_t *optdata, uint8_t size)
1939 {
1940 	uint16_t defpid;
1941 
1942 	GETINT16(defpid, optdata);
1943 	(void) sprintf(get_line(0, 0), "Default PID = %d", defpid);
1944 }
1945