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