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
44static int interpret_ppp_cp(int, uchar_t *, int, ppp_protoinfo_t *);
45static int interpret_cp_options(uchar_t *, int, ppp_protoinfo_t *);
46static int interpret_ppp_chap(int, uchar_t *, int, ppp_protoinfo_t *);
47static int interpret_ppp_pap(int, uchar_t *, int, ppp_protoinfo_t *);
48static int interpret_ppp_lqr(int, uchar_t *, int, ppp_protoinfo_t *);
49static ppp_protoinfo_t *ppp_getprotoinfo(uint16_t);
50static cp_optinfo_t *ppp_getoptinfo(cp_optinfo_t *, uint16_t);
51static optformat_func_t opt_format_vendor;
52static optformat_func_t opt_format_mru;
53static optformat_func_t opt_format_accm;
54static optformat_func_t opt_format_authproto;
55static optformat_func_t opt_format_qualproto;
56static optformat_func_t opt_format_magicnum;
57static optformat_func_t opt_format_fcs;
58static optformat_func_t opt_format_sdp;
59static optformat_func_t opt_format_nummode;
60static optformat_func_t opt_format_callback;
61static optformat_func_t opt_format_mrru;
62static optformat_func_t opt_format_epdisc;
63static optformat_func_t opt_format_dce;
64static optformat_func_t opt_format_linkdisc;
65static optformat_func_t opt_format_i18n;
66static optformat_func_t opt_format_ipaddresses;
67static optformat_func_t opt_format_ipcompproto;
68static optformat_func_t opt_format_ipaddress;
69static optformat_func_t opt_format_mobileipv4;
70static optformat_func_t opt_format_ifaceid;
71static optformat_func_t opt_format_ipv6compproto;
72static optformat_func_t opt_format_compoui;
73static optformat_func_t opt_format_bsdcomp;
74static optformat_func_t opt_format_staclzs;
75static optformat_func_t opt_format_mppc;
76static optformat_func_t opt_format_gandalf;
77static optformat_func_t opt_format_lzsdcp;
78static optformat_func_t opt_format_magnalink;
79static optformat_func_t opt_format_deflate;
80static optformat_func_t opt_format_encroui;
81static optformat_func_t opt_format_dese;
82static optformat_func_t opt_format_muxpid;
83
84/*
85 * Many strings below are initialized with "Unknown".
86 */
87static 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 */
98static 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
157static 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
207static 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
229static 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
237static 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
263static 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
275static cp_optinfo_t muxcp_optinfo[] = {
276	{ OPT_MUXCP_DEFAULTPID,	"Default PID",			4,
277	    opt_format_muxpid },
278	{ 0,			unknown_string,			0,	NULL }
279};
280
281static 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
301static 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
309static 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
319int
320interpret_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 */
359static int
360interpret_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 */
542static int
543interpret_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
617static int
618interpret_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
701static int
702interpret_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
804static int
805interpret_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
852static ppp_protoinfo_t *
853ppp_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
865static cp_optinfo_t *
866ppp_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*/
897static void
898opt_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*/
926static void
927opt_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*/
947static void
948opt_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 */
970static void
971opt_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 */
1028static void
1029opt_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*/
1070static void
1071opt_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*/
1089static void
1090opt_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*/
1115static void
1116opt_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*/
1135static void
1136opt_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 */
1153static void
1154opt_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*/
1202static void
1203opt_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 */
1220static void
1221opt_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*/
1309static void
1310opt_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*/
1340static void
1341opt_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 */
1362static void
1363opt_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*/
1393static void
1394opt_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 */
1441static void
1442opt_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*/
1514static void
1515opt_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*/
1538static void
1539opt_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*/
1565static void
1566opt_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 */
1590static void
1591opt_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*/
1648static void
1649opt_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*/
1678static void
1679opt_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*/
1705static void
1706opt_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*/
1723static void
1724opt_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*/
1743static void
1744opt_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*/
1770static void
1771opt_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*/
1828static void
1829opt_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*/
1859static void
1860opt_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*/
1890static void
1891opt_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*/
1919static void
1920opt_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*/
1939static void
1940opt_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