Home | History | Annotate | Download | only in snoop
      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