1/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Extensively modified by Motonori Shindo (mshindo@mshindo.net) for more
22 * complete PPP support.
23 */
24
25/* \summary: Point to Point Protocol (PPP) printer */
26
27/*
28 * TODO:
29 * o resolve XXX as much as possible
30 * o MP support
31 * o BAP support
32 */
33
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
37
38#include "netdissect-stdinc.h"
39
40#ifdef __bsdi__
41#include <net/slcompress.h>
42#include <net/if_ppp.h>
43#endif
44
45#include "netdissect.h"
46#include "extract.h"
47#include "addrtoname.h"
48#include "ppp.h"
49#include "chdlc.h"
50#include "ethertype.h"
51#include "oui.h"
52#include "netdissect-alloc.h"
53
54/*
55 * The following constants are defined by IANA. Please refer to
56 *    https://www.isi.edu/in-notes/iana/assignments/ppp-numbers
57 * for the up-to-date information.
58 */
59
60/* Protocol Codes defined in ppp.h */
61
62static const struct tok ppptype2str[] = {
63        { PPP_IP,	  "IP" },
64        { PPP_OSI,	  "OSI" },
65        { PPP_NS,	  "NS" },
66        { PPP_DECNET,	  "DECNET" },
67        { PPP_APPLE,	  "APPLE" },
68	{ PPP_IPX,	  "IPX" },
69	{ PPP_VJC,	  "VJC IP" },
70	{ PPP_VJNC,	  "VJNC IP" },
71	{ PPP_BRPDU,	  "BRPDU" },
72	{ PPP_STII,	  "STII" },
73	{ PPP_VINES,	  "VINES" },
74	{ PPP_MPLS_UCAST, "MPLS" },
75	{ PPP_MPLS_MCAST, "MPLS" },
76        { PPP_COMP,       "Compressed"},
77        { PPP_ML,         "MLPPP"},
78        { PPP_IPV6,       "IP6"},
79
80	{ PPP_HELLO,	  "HELLO" },
81	{ PPP_LUXCOM,	  "LUXCOM" },
82	{ PPP_SNS,	  "SNS" },
83	{ PPP_IPCP,	  "IPCP" },
84	{ PPP_OSICP,	  "OSICP" },
85	{ PPP_NSCP,	  "NSCP" },
86	{ PPP_DECNETCP,   "DECNETCP" },
87	{ PPP_APPLECP,	  "APPLECP" },
88	{ PPP_IPXCP,	  "IPXCP" },
89	{ PPP_STIICP,	  "STIICP" },
90	{ PPP_VINESCP,	  "VINESCP" },
91        { PPP_IPV6CP,     "IP6CP" },
92	{ PPP_MPLSCP,	  "MPLSCP" },
93
94	{ PPP_LCP,	  "LCP" },
95	{ PPP_PAP,	  "PAP" },
96	{ PPP_LQM,	  "LQM" },
97	{ PPP_CHAP,	  "CHAP" },
98	{ PPP_EAP,	  "EAP" },
99	{ PPP_SPAP,	  "SPAP" },
100	{ PPP_SPAP_OLD,	  "Old-SPAP" },
101	{ PPP_BACP,	  "BACP" },
102	{ PPP_BAP,	  "BAP" },
103	{ PPP_MPCP,	  "MLPPP-CP" },
104	{ PPP_CCP,	  "CCP" },
105	{ 0,		  NULL }
106};
107
108/* Control Protocols (LCP/IPCP/CCP etc.) Codes defined in RFC 1661 */
109
110#define CPCODES_VEXT		0	/* Vendor-Specific (RFC2153) */
111#define CPCODES_CONF_REQ	1	/* Configure-Request */
112#define CPCODES_CONF_ACK	2	/* Configure-Ack */
113#define CPCODES_CONF_NAK	3	/* Configure-Nak */
114#define CPCODES_CONF_REJ	4	/* Configure-Reject */
115#define CPCODES_TERM_REQ	5	/* Terminate-Request */
116#define CPCODES_TERM_ACK	6	/* Terminate-Ack */
117#define CPCODES_CODE_REJ	7	/* Code-Reject */
118#define CPCODES_PROT_REJ	8	/* Protocol-Reject (LCP only) */
119#define CPCODES_ECHO_REQ	9	/* Echo-Request (LCP only) */
120#define CPCODES_ECHO_RPL	10	/* Echo-Reply (LCP only) */
121#define CPCODES_DISC_REQ	11	/* Discard-Request (LCP only) */
122#define CPCODES_ID		12	/* Identification (LCP only) RFC1570 */
123#define CPCODES_TIME_REM	13	/* Time-Remaining (LCP only) RFC1570 */
124#define CPCODES_RESET_REQ	14	/* Reset-Request (CCP only) RFC1962 */
125#define CPCODES_RESET_REP	15	/* Reset-Reply (CCP only) */
126
127static const struct tok cpcodes[] = {
128	{CPCODES_VEXT,      "Vendor-Extension"}, /* RFC2153 */
129	{CPCODES_CONF_REQ,  "Conf-Request"},
130        {CPCODES_CONF_ACK,  "Conf-Ack"},
131	{CPCODES_CONF_NAK,  "Conf-Nack"},
132	{CPCODES_CONF_REJ,  "Conf-Reject"},
133	{CPCODES_TERM_REQ,  "Term-Request"},
134	{CPCODES_TERM_ACK,  "Term-Ack"},
135	{CPCODES_CODE_REJ,  "Code-Reject"},
136	{CPCODES_PROT_REJ,  "Prot-Reject"},
137	{CPCODES_ECHO_REQ,  "Echo-Request"},
138	{CPCODES_ECHO_RPL,  "Echo-Reply"},
139	{CPCODES_DISC_REQ,  "Disc-Req"},
140	{CPCODES_ID,        "Ident"},            /* RFC1570 */
141	{CPCODES_TIME_REM,  "Time-Rem"},         /* RFC1570 */
142	{CPCODES_RESET_REQ, "Reset-Req"},        /* RFC1962 */
143	{CPCODES_RESET_REP, "Reset-Ack"},        /* RFC1962 */
144        {0,                 NULL}
145};
146
147/* LCP Config Options */
148
149#define LCPOPT_VEXT	0
150#define LCPOPT_MRU	1
151#define LCPOPT_ACCM	2
152#define LCPOPT_AP	3
153#define LCPOPT_QP	4
154#define LCPOPT_MN	5
155#define LCPOPT_DEP6	6
156#define LCPOPT_PFC	7
157#define LCPOPT_ACFC	8
158#define LCPOPT_FCSALT	9
159#define LCPOPT_SDP	10
160#define LCPOPT_NUMMODE	11
161#define LCPOPT_DEP12	12
162#define LCPOPT_CBACK	13
163#define LCPOPT_DEP14	14
164#define LCPOPT_DEP15	15
165#define LCPOPT_DEP16	16
166#define LCPOPT_MLMRRU	17
167#define LCPOPT_MLSSNHF	18
168#define LCPOPT_MLED	19
169#define LCPOPT_PROP	20
170#define LCPOPT_DCEID	21
171#define LCPOPT_MPP	22
172#define LCPOPT_LD	23
173#define LCPOPT_LCPAOPT	24
174#define LCPOPT_COBS	25
175#define LCPOPT_PE	26
176#define LCPOPT_MLHF	27
177#define LCPOPT_I18N	28
178#define LCPOPT_SDLOS	29
179#define LCPOPT_PPPMUX	30
180
181static const char *lcpconfopts[] = {
182	"Vend-Ext",		/* (0) */
183	"MRU",			/* (1) */
184	"ACCM",			/* (2) */
185	"Auth-Prot",		/* (3) */
186	"Qual-Prot",		/* (4) */
187	"Magic-Num",		/* (5) */
188	"deprecated(6)",	/* used to be a Quality Protocol */
189	"PFC",			/* (7) */
190	"ACFC",			/* (8) */
191	"FCS-Alt",		/* (9) */
192	"SDP",			/* (10) */
193	"Num-Mode",		/* (11) */
194	"deprecated(12)",	/* used to be a Multi-Link-Procedure*/
195	"Call-Back",		/* (13) */
196	"deprecated(14)",	/* used to be a Connect-Time */
197	"deprecated(15)",	/* used to be a Compund-Frames */
198	"deprecated(16)",	/* used to be a Nominal-Data-Encap */
199	"MRRU",			/* (17) */
200	"12-Bit seq #",		/* (18) */
201	"End-Disc",		/* (19) */
202	"Proprietary",		/* (20) */
203	"DCE-Id",		/* (21) */
204	"MP+",			/* (22) */
205	"Link-Disc",		/* (23) */
206	"LCP-Auth-Opt",		/* (24) */
207	"COBS",			/* (25) */
208	"Prefix-elision",	/* (26) */
209	"Multilink-header-Form",/* (27) */
210	"I18N",			/* (28) */
211	"SDL-over-SONET/SDH",	/* (29) */
212	"PPP-Muxing",		/* (30) */
213};
214
215#define NUM_LCPOPTS	(sizeof(lcpconfopts) / sizeof(lcpconfopts[0]))
216
217/* ECP - to be supported */
218
219/* CCP Config Options */
220
221#define CCPOPT_OUI	0	/* RFC1962 */
222#define CCPOPT_PRED1	1	/* RFC1962 */
223#define CCPOPT_PRED2	2	/* RFC1962 */
224#define CCPOPT_PJUMP	3	/* RFC1962 */
225/* 4-15 unassigned */
226#define CCPOPT_HPPPC	16	/* RFC1962 */
227#define CCPOPT_STACLZS	17	/* RFC1974 */
228#define CCPOPT_MPPC	18	/* RFC2118 */
229#define CCPOPT_GFZA	19	/* RFC1962 */
230#define CCPOPT_V42BIS	20	/* RFC1962 */
231#define CCPOPT_BSDCOMP	21	/* RFC1977 */
232/* 22 unassigned */
233#define CCPOPT_LZSDCP	23	/* RFC1967 */
234#define CCPOPT_MVRCA	24	/* RFC1975 */
235#define CCPOPT_DEC	25	/* RFC1976 */
236#define CCPOPT_DEFLATE	26	/* RFC1979 */
237/* 27-254 unassigned */
238#define CCPOPT_RESV	255	/* RFC1962 */
239
240static const struct tok ccpconfopts_values[] = {
241        { CCPOPT_OUI, "OUI" },
242        { CCPOPT_PRED1, "Pred-1" },
243        { CCPOPT_PRED2, "Pred-2" },
244        { CCPOPT_PJUMP, "Puddle" },
245        { CCPOPT_HPPPC, "HP-PPC" },
246        { CCPOPT_STACLZS, "Stac-LZS" },
247        { CCPOPT_MPPC, "MPPC" },
248        { CCPOPT_GFZA, "Gand-FZA" },
249        { CCPOPT_V42BIS, "V.42bis" },
250        { CCPOPT_BSDCOMP, "BSD-Comp" },
251        { CCPOPT_LZSDCP, "LZS-DCP" },
252        { CCPOPT_MVRCA, "MVRCA" },
253        { CCPOPT_DEC, "DEC" },
254        { CCPOPT_DEFLATE, "Deflate" },
255        { CCPOPT_RESV, "Reserved"},
256        {0,                 NULL}
257};
258
259/* BACP Config Options */
260
261#define BACPOPT_FPEER	1	/* RFC2125 */
262
263static const struct tok bacconfopts_values[] = {
264        { BACPOPT_FPEER, "Favored-Peer" },
265        {0,                 NULL}
266};
267
268
269/* SDCP - to be supported */
270
271/* IPCP Config Options */
272#define IPCPOPT_2ADDR	1	/* RFC1172, RFC1332 (deprecated) */
273#define IPCPOPT_IPCOMP	2	/* RFC1332 */
274#define IPCPOPT_ADDR	3	/* RFC1332 */
275#define IPCPOPT_MOBILE4	4	/* RFC2290 */
276#define IPCPOPT_PRIDNS	129	/* RFC1877 */
277#define IPCPOPT_PRINBNS	130	/* RFC1877 */
278#define IPCPOPT_SECDNS	131	/* RFC1877 */
279#define IPCPOPT_SECNBNS	132	/* RFC1877 */
280
281static const struct tok ipcpopt_values[] = {
282        { IPCPOPT_2ADDR, "IP-Addrs" },
283        { IPCPOPT_IPCOMP, "IP-Comp" },
284        { IPCPOPT_ADDR, "IP-Addr" },
285        { IPCPOPT_MOBILE4, "Home-Addr" },
286        { IPCPOPT_PRIDNS, "Pri-DNS" },
287        { IPCPOPT_PRINBNS, "Pri-NBNS" },
288        { IPCPOPT_SECDNS, "Sec-DNS" },
289        { IPCPOPT_SECNBNS, "Sec-NBNS" },
290	{ 0,		  NULL }
291};
292
293#define IPCPOPT_IPCOMP_HDRCOMP 0x61  /* rfc3544 */
294#define IPCPOPT_IPCOMP_MINLEN    14
295
296static const struct tok ipcpopt_compproto_values[] = {
297        { PPP_VJC, "VJ-Comp" },
298        { IPCPOPT_IPCOMP_HDRCOMP, "IP Header Compression" },
299	{ 0,		  NULL }
300};
301
302static const struct tok ipcpopt_compproto_subopt_values[] = {
303        { 1, "RTP-Compression" },
304        { 2, "Enhanced RTP-Compression" },
305	{ 0,		  NULL }
306};
307
308/* IP6CP Config Options */
309#define IP6CP_IFID      1
310
311static const struct tok ip6cpopt_values[] = {
312        { IP6CP_IFID, "Interface-ID" },
313	{ 0,		  NULL }
314};
315
316/* ATCP - to be supported */
317/* OSINLCP - to be supported */
318/* BVCP - to be supported */
319/* BCP - to be supported */
320/* IPXCP - to be supported */
321/* MPLSCP - to be supported */
322
323/* Auth Algorithms */
324
325/* 0-4 Reserved (RFC1994) */
326#define AUTHALG_CHAPMD5	5	/* RFC1994 */
327#define AUTHALG_MSCHAP1	128	/* RFC2433 */
328#define AUTHALG_MSCHAP2	129	/* RFC2795 */
329
330static const struct tok authalg_values[] = {
331        { AUTHALG_CHAPMD5, "MD5" },
332        { AUTHALG_MSCHAP1, "MS-CHAPv1" },
333        { AUTHALG_MSCHAP2, "MS-CHAPv2" },
334	{ 0,		  NULL }
335};
336
337/* FCS Alternatives - to be supported */
338
339/* Multilink Endpoint Discriminator (RFC1717) */
340#define MEDCLASS_NULL	0	/* Null Class */
341#define MEDCLASS_LOCAL	1	/* Locally Assigned */
342#define MEDCLASS_IPV4	2	/* Internet Protocol (IPv4) */
343#define MEDCLASS_MAC	3	/* IEEE 802.1 global MAC address */
344#define MEDCLASS_MNB	4	/* PPP Magic Number Block */
345#define MEDCLASS_PSNDN	5	/* Public Switched Network Director Number */
346
347/* PPP LCP Callback */
348#define CALLBACK_AUTH	0	/* Location determined by user auth */
349#define CALLBACK_DSTR	1	/* Dialing string */
350#define CALLBACK_LID	2	/* Location identifier */
351#define CALLBACK_E164	3	/* E.164 number */
352#define CALLBACK_X500	4	/* X.500 distinguished name */
353#define CALLBACK_CBCP	6	/* Location is determined during CBCP nego */
354
355static const struct tok ppp_callback_values[] = {
356        { CALLBACK_AUTH, "UserAuth" },
357        { CALLBACK_DSTR, "DialString" },
358        { CALLBACK_LID, "LocalID" },
359        { CALLBACK_E164, "E.164" },
360        { CALLBACK_X500, "X.500" },
361        { CALLBACK_CBCP, "CBCP" },
362	{ 0,		  NULL }
363};
364
365/* CHAP */
366
367#define CHAP_CHAL	1
368#define CHAP_RESP	2
369#define CHAP_SUCC	3
370#define CHAP_FAIL	4
371
372static const struct tok chapcode_values[] = {
373	{ CHAP_CHAL, "Challenge" },
374	{ CHAP_RESP, "Response" },
375	{ CHAP_SUCC, "Success" },
376	{ CHAP_FAIL, "Fail" },
377        { 0, NULL}
378};
379
380/* PAP */
381
382#define PAP_AREQ	1
383#define PAP_AACK	2
384#define PAP_ANAK	3
385
386static const struct tok papcode_values[] = {
387        { PAP_AREQ, "Auth-Req" },
388        { PAP_AACK, "Auth-ACK" },
389        { PAP_ANAK, "Auth-NACK" },
390        { 0, NULL }
391};
392
393/* BAP */
394#define BAP_CALLREQ	1
395#define BAP_CALLRES	2
396#define BAP_CBREQ	3
397#define BAP_CBRES	4
398#define BAP_LDQREQ	5
399#define BAP_LDQRES	6
400#define BAP_CSIND	7
401#define BAP_CSRES	8
402
403static u_int print_lcp_config_options(netdissect_options *, const u_char *p, u_int);
404static u_int print_ipcp_config_options(netdissect_options *, const u_char *p, u_int);
405static u_int print_ip6cp_config_options(netdissect_options *, const u_char *p, u_int);
406static u_int print_ccp_config_options(netdissect_options *, const u_char *p, u_int);
407static u_int print_bacp_config_options(netdissect_options *, const u_char *p, u_int);
408static void handle_ppp(netdissect_options *, u_int proto, const u_char *p, u_int length);
409
410/* generic Control Protocol (e.g. LCP, IPCP, CCP, etc.) handler */
411static void
412handle_ctrl_proto(netdissect_options *ndo,
413                  u_int proto, const u_char *pptr, u_int length)
414{
415	const char *typestr;
416	u_int code, len;
417	u_int (*pfunc)(netdissect_options *, const u_char *, u_int);
418	u_int tlen, advance;
419        const u_char *tptr;
420
421        tptr=pptr;
422
423        typestr = tok2str(ppptype2str, "unknown ctrl-proto (0x%04x)", proto);
424	ND_PRINT("%s, ", typestr);
425
426	if (length < 4) /* FIXME weak boundary checking */
427		goto trunc;
428	ND_TCHECK_2(tptr);
429
430	code = GET_U_1(tptr);
431	tptr++;
432
433	ND_PRINT("%s (0x%02x), id %u, length %u",
434	          tok2str(cpcodes, "Unknown Opcode",code),
435	          code,
436	          GET_U_1(tptr), /* ID */
437	          length + 2);
438	tptr++;
439
440	if (!ndo->ndo_vflag)
441		return;
442
443	len = GET_BE_U_2(tptr);
444	tptr += 2;
445
446	if (len < 4) {
447		ND_PRINT("\n\tencoded length %u (< 4))", len);
448		return;
449	}
450
451	if (len > length) {
452		ND_PRINT("\n\tencoded length %u (> packet length %u))", len, length);
453		return;
454	}
455	length = len;
456
457	ND_PRINT("\n\tencoded length %u (=Option(s) length %u)", len, len - 4);
458
459	if (length == 4)
460		return;    /* there may be a NULL confreq etc. */
461
462	if (ndo->ndo_vflag > 1)
463		print_unknown_data(ndo, pptr - 2, "\n\t", 6);
464
465
466	switch (code) {
467	case CPCODES_VEXT:
468		if (length < 11)
469			break;
470		ND_PRINT("\n\t  Magic-Num 0x%08x", GET_BE_U_4(tptr));
471		tptr += 4;
472		ND_PRINT(" Vendor: %s (%u)",
473                       tok2str(oui_values,"Unknown",GET_BE_U_3(tptr)),
474                       GET_BE_U_3(tptr));
475		/* XXX: need to decode Kind and Value(s)? */
476		break;
477	case CPCODES_CONF_REQ:
478	case CPCODES_CONF_ACK:
479	case CPCODES_CONF_NAK:
480	case CPCODES_CONF_REJ:
481		tlen = len - 4;	/* Code(1), Identifier(1) and Length(2) */
482		do {
483			switch (proto) {
484			case PPP_LCP:
485				pfunc = print_lcp_config_options;
486				break;
487			case PPP_IPCP:
488				pfunc = print_ipcp_config_options;
489				break;
490			case PPP_IPV6CP:
491				pfunc = print_ip6cp_config_options;
492				break;
493			case PPP_CCP:
494				pfunc = print_ccp_config_options;
495				break;
496			case PPP_BACP:
497				pfunc = print_bacp_config_options;
498				break;
499			default:
500				/*
501				 * No print routine for the options for
502				 * this protocol.
503				 */
504				pfunc = NULL;
505				break;
506			}
507
508			if (pfunc == NULL) /* catch the above null pointer if unknown CP */
509				break;
510
511			if ((advance = (*pfunc)(ndo, tptr, len)) == 0)
512				break;
513			if (tlen < advance) {
514				ND_PRINT(" [remaining options length %u < %u]",
515					 tlen, advance);
516				nd_print_invalid(ndo);
517				break;
518			}
519			tlen -= advance;
520			tptr += advance;
521		} while (tlen != 0);
522		break;
523
524	case CPCODES_TERM_REQ:
525	case CPCODES_TERM_ACK:
526		/* XXX: need to decode Data? */
527		break;
528	case CPCODES_CODE_REJ:
529		/* XXX: need to decode Rejected-Packet? */
530		break;
531	case CPCODES_PROT_REJ:
532		if (length < 6)
533			break;
534		ND_PRINT("\n\t  Rejected %s Protocol (0x%04x)",
535		       tok2str(ppptype2str,"unknown", GET_BE_U_2(tptr)),
536		       GET_BE_U_2(tptr));
537		/* XXX: need to decode Rejected-Information? - hexdump for now */
538		if (len > 6) {
539			ND_PRINT("\n\t  Rejected Packet");
540			print_unknown_data(ndo, tptr + 2, "\n\t    ", len - 2);
541		}
542		break;
543	case CPCODES_ECHO_REQ:
544	case CPCODES_ECHO_RPL:
545	case CPCODES_DISC_REQ:
546		if (length < 8)
547			break;
548		ND_PRINT("\n\t  Magic-Num 0x%08x", GET_BE_U_4(tptr));
549		/* XXX: need to decode Data? - hexdump for now */
550		if (len > 8) {
551			ND_PRINT("\n\t  -----trailing data-----");
552			ND_TCHECK_LEN(tptr + 4, len - 8);
553			print_unknown_data(ndo, tptr + 4, "\n\t  ", len - 8);
554		}
555		break;
556	case CPCODES_ID:
557		if (length < 8)
558			break;
559		ND_PRINT("\n\t  Magic-Num 0x%08x", GET_BE_U_4(tptr));
560		/* RFC 1661 says this is intended to be human readable */
561		if (len > 8) {
562			ND_PRINT("\n\t  Message\n\t    ");
563			if (nd_printn(ndo, tptr + 4, len - 4, ndo->ndo_snapend))
564				goto trunc;
565		}
566		break;
567	case CPCODES_TIME_REM:
568		if (length < 12)
569			break;
570		ND_PRINT("\n\t  Magic-Num 0x%08x", GET_BE_U_4(tptr));
571		ND_PRINT(", Seconds-Remaining %us", GET_BE_U_4(tptr + 4));
572		/* XXX: need to decode Message? */
573		break;
574	default:
575		/* XXX this is dirty but we do not get the
576		 * original pointer passed to the begin
577		 * the PPP packet */
578		if (ndo->ndo_vflag <= 1)
579			print_unknown_data(ndo, pptr - 2, "\n\t  ", length + 2);
580		break;
581	}
582	return;
583
584trunc:
585	ND_PRINT("[|%s]", typestr);
586}
587
588/* LCP config options */
589static u_int
590print_lcp_config_options(netdissect_options *ndo,
591                         const u_char *p, u_int length)
592{
593	u_int opt, len;
594
595	if (length < 2)
596		return 0;
597	ND_TCHECK_2(p);
598	opt = GET_U_1(p);
599	len = GET_U_1(p + 1);
600	if (length < len)
601		return 0;
602	if (len < 2) {
603		if (opt < NUM_LCPOPTS)
604			ND_PRINT("\n\t  %s Option (0x%02x), length %u (length bogus, should be >= 2)",
605			          lcpconfopts[opt], opt, len);
606		else
607			ND_PRINT("\n\tunknown LCP option 0x%02x", opt);
608		return 0;
609	}
610	if (opt < NUM_LCPOPTS)
611		ND_PRINT("\n\t  %s Option (0x%02x), length %u", lcpconfopts[opt], opt, len);
612	else {
613		ND_PRINT("\n\tunknown LCP option 0x%02x", opt);
614		return len;
615	}
616
617	switch (opt) {
618	case LCPOPT_VEXT:
619		if (len < 6) {
620			ND_PRINT(" (length bogus, should be >= 6)");
621			return len;
622		}
623		ND_PRINT(": Vendor: %s (%u)",
624			tok2str(oui_values,"Unknown",GET_BE_U_3(p + 2)),
625			GET_BE_U_3(p + 2));
626#if 0
627		ND_PRINT(", kind: 0x%02x", GET_U_1(p + 5));
628		ND_PRINT(", Value: 0x");
629		for (i = 0; i < len - 6; i++) {
630			ND_PRINT("%02x", GET_U_1(p + 6 + i));
631		}
632#endif
633		break;
634	case LCPOPT_MRU:
635		if (len != 4) {
636			ND_PRINT(" (length bogus, should be = 4)");
637			return len;
638		}
639		ND_PRINT(": %u", GET_BE_U_2(p + 2));
640		break;
641	case LCPOPT_ACCM:
642		if (len != 6) {
643			ND_PRINT(" (length bogus, should be = 6)");
644			return len;
645		}
646		ND_PRINT(": 0x%08x", GET_BE_U_4(p + 2));
647		break;
648	case LCPOPT_AP:
649		if (len < 4) {
650			ND_PRINT(" (length bogus, should be >= 4)");
651			return len;
652		}
653		ND_PRINT(": %s",
654			 tok2str(ppptype2str, "Unknown Auth Proto (0x04x)", GET_BE_U_2(p + 2)));
655
656		switch (GET_BE_U_2(p + 2)) {
657		case PPP_CHAP:
658			ND_PRINT(", %s",
659				 tok2str(authalg_values, "Unknown Auth Alg %u", GET_U_1(p + 4)));
660			break;
661		case PPP_PAP: /* fall through */
662		case PPP_EAP:
663		case PPP_SPAP:
664		case PPP_SPAP_OLD:
665                        break;
666		default:
667			print_unknown_data(ndo, p, "\n\t", len);
668		}
669		break;
670	case LCPOPT_QP:
671		if (len < 4) {
672			ND_PRINT(" (length bogus, should be >= 4)");
673			return 0;
674		}
675		if (GET_BE_U_2(p + 2) == PPP_LQM)
676			ND_PRINT(": LQR");
677		else
678			ND_PRINT(": unknown");
679		break;
680	case LCPOPT_MN:
681		if (len != 6) {
682			ND_PRINT(" (length bogus, should be = 6)");
683			return 0;
684		}
685		ND_PRINT(": 0x%08x", GET_BE_U_4(p + 2));
686		break;
687	case LCPOPT_PFC:
688		break;
689	case LCPOPT_ACFC:
690		break;
691	case LCPOPT_LD:
692		if (len != 4) {
693			ND_PRINT(" (length bogus, should be = 4)");
694			return 0;
695		}
696		ND_PRINT(": 0x%04x", GET_BE_U_2(p + 2));
697		break;
698	case LCPOPT_CBACK:
699		if (len < 3) {
700			ND_PRINT(" (length bogus, should be >= 3)");
701			return 0;
702		}
703		ND_PRINT(": ");
704		ND_PRINT(": Callback Operation %s (%u)",
705                       tok2str(ppp_callback_values, "Unknown", GET_U_1(p + 2)),
706                       GET_U_1(p + 2));
707		break;
708	case LCPOPT_MLMRRU:
709		if (len != 4) {
710			ND_PRINT(" (length bogus, should be = 4)");
711			return 0;
712		}
713		ND_PRINT(": %u", GET_BE_U_2(p + 2));
714		break;
715	case LCPOPT_MLED:
716		if (len < 3) {
717			ND_PRINT(" (length bogus, should be >= 3)");
718			return 0;
719		}
720		switch (GET_U_1(p + 2)) {		/* class */
721		case MEDCLASS_NULL:
722			ND_PRINT(": Null");
723			break;
724		case MEDCLASS_LOCAL:
725			ND_PRINT(": Local"); /* XXX */
726			break;
727		case MEDCLASS_IPV4:
728			if (len != 7) {
729				ND_PRINT(" (length bogus, should be = 7)");
730				return 0;
731			}
732			ND_PRINT(": IPv4 %s", GET_IPADDR_STRING(p + 3));
733			break;
734		case MEDCLASS_MAC:
735			if (len != 9) {
736				ND_PRINT(" (length bogus, should be = 9)");
737				return 0;
738			}
739			ND_PRINT(": MAC %s", GET_ETHERADDR_STRING(p + 3));
740			break;
741		case MEDCLASS_MNB:
742			ND_PRINT(": Magic-Num-Block"); /* XXX */
743			break;
744		case MEDCLASS_PSNDN:
745			ND_PRINT(": PSNDN"); /* XXX */
746			break;
747		default:
748			ND_PRINT(": Unknown class %u", GET_U_1(p + 2));
749			break;
750		}
751		break;
752
753/* XXX: to be supported */
754#if 0
755	case LCPOPT_DEP6:
756	case LCPOPT_FCSALT:
757	case LCPOPT_SDP:
758	case LCPOPT_NUMMODE:
759	case LCPOPT_DEP12:
760	case LCPOPT_DEP14:
761	case LCPOPT_DEP15:
762	case LCPOPT_DEP16:
763        case LCPOPT_MLSSNHF:
764	case LCPOPT_PROP:
765	case LCPOPT_DCEID:
766	case LCPOPT_MPP:
767	case LCPOPT_LCPAOPT:
768	case LCPOPT_COBS:
769	case LCPOPT_PE:
770	case LCPOPT_MLHF:
771	case LCPOPT_I18N:
772	case LCPOPT_SDLOS:
773	case LCPOPT_PPPMUX:
774		break;
775#endif
776	default:
777		/*
778		 * Unknown option; dump it as raw bytes now if we're
779		 * not going to do so below.
780		 */
781		if (ndo->ndo_vflag < 2)
782			print_unknown_data(ndo, p + 2, "\n\t    ", len - 2);
783		break;
784	}
785
786	if (ndo->ndo_vflag > 1)
787		print_unknown_data(ndo, p + 2, "\n\t    ", len - 2); /* exclude TLV header */
788
789	return len;
790
791trunc:
792	ND_PRINT("[|lcp]");
793	return 0;
794}
795
796/* ML-PPP*/
797static const struct tok ppp_ml_flag_values[] = {
798    { 0x80, "begin" },
799    { 0x40, "end" },
800    { 0, NULL }
801};
802
803static void
804handle_mlppp(netdissect_options *ndo,
805             const u_char *p, u_int length)
806{
807    if (!ndo->ndo_eflag)
808        ND_PRINT("MLPPP, ");
809
810    if (length < 2) {
811        ND_PRINT("[|mlppp]");
812        return;
813    }
814    if (!ND_TTEST_2(p)) {
815        ND_PRINT("[|mlppp]");
816        return;
817    }
818
819    ND_PRINT("seq 0x%03x, Flags [%s], length %u",
820           (GET_BE_U_2(p))&0x0fff,
821           /* only support 12-Bit sequence space for now */
822           bittok2str(ppp_ml_flag_values, "none", GET_U_1(p) & 0xc0),
823           length);
824}
825
826/* CHAP */
827static void
828handle_chap(netdissect_options *ndo,
829            const u_char *p, u_int length)
830{
831	u_int code, len;
832	u_int val_size, name_size, msg_size;
833	const u_char *p0;
834	u_int i;
835
836	p0 = p;
837	if (length < 1) {
838		ND_PRINT("[|chap]");
839		return;
840	} else if (length < 4) {
841		ND_PRINT("[|chap 0x%02x]", GET_U_1(p));
842		return;
843	}
844
845	code = GET_U_1(p);
846	ND_PRINT("CHAP, %s (0x%02x)",
847               tok2str(chapcode_values,"unknown",code),
848               code);
849	p++;
850
851	ND_PRINT(", id %u", GET_U_1(p));	/* ID */
852	p++;
853
854	len = GET_BE_U_2(p);
855	p += 2;
856
857	/*
858	 * Note that this is a generic CHAP decoding routine. Since we
859	 * don't know which flavor of CHAP (i.e. CHAP-MD5, MS-CHAPv1,
860	 * MS-CHAPv2) is used at this point, we can't decode packet
861	 * specifically to each algorithms. Instead, we simply decode
862	 * the GCD (Gratest Common Denominator) for all algorithms.
863	 */
864	switch (code) {
865	case CHAP_CHAL:
866	case CHAP_RESP:
867		if (length - (p - p0) < 1)
868			return;
869		val_size = GET_U_1(p);	/* value size */
870		p++;
871		if (length - (p - p0) < val_size)
872			return;
873		ND_PRINT(", Value ");
874		for (i = 0; i < val_size; i++) {
875			ND_PRINT("%02x", GET_U_1(p));
876			p++;
877		}
878		name_size = len - (u_int)(p - p0);
879		ND_PRINT(", Name ");
880		for (i = 0; i < name_size; i++) {
881			fn_print_char(ndo, GET_U_1(p));
882			p++;
883		}
884		break;
885	case CHAP_SUCC:
886	case CHAP_FAIL:
887		msg_size = len - (u_int)(p - p0);
888		ND_PRINT(", Msg ");
889		for (i = 0; i< msg_size; i++) {
890			fn_print_char(ndo, GET_U_1(p));
891			p++;
892		}
893		break;
894	}
895}
896
897/* PAP (see RFC 1334) */
898static void
899handle_pap(netdissect_options *ndo,
900           const u_char *p, u_int length)
901{
902	u_int code, len;
903	u_int peerid_len, passwd_len, msg_len;
904	const u_char *p0;
905	u_int i;
906
907	p0 = p;
908	if (length < 1) {
909		ND_PRINT("[|pap]");
910		return;
911	} else if (length < 4) {
912		ND_PRINT("[|pap 0x%02x]", GET_U_1(p));
913		return;
914	}
915
916	code = GET_U_1(p);
917	ND_PRINT("PAP, %s (0x%02x)",
918	          tok2str(papcode_values, "unknown", code),
919	          code);
920	p++;
921
922	ND_PRINT(", id %u", GET_U_1(p));	/* ID */
923	p++;
924
925	len = GET_BE_U_2(p);
926	p += 2;
927
928	if (len > length) {
929		ND_PRINT(", length %u > packet size", len);
930		return;
931	}
932	length = len;
933	if (length < (size_t)(p - p0)) {
934		ND_PRINT(", length %u < PAP header length", length);
935		return;
936	}
937
938	switch (code) {
939	case PAP_AREQ:
940		/* A valid Authenticate-Request is 6 or more octets long. */
941		if (len < 6)
942			goto trunc;
943		if (length - (p - p0) < 1)
944			return;
945		peerid_len = GET_U_1(p);	/* Peer-ID Length */
946		p++;
947		if (length - (p - p0) < peerid_len)
948			return;
949		ND_PRINT(", Peer ");
950		for (i = 0; i < peerid_len; i++) {
951			fn_print_char(ndo, GET_U_1(p));
952			p++;
953		}
954
955		if (length - (p - p0) < 1)
956			return;
957		passwd_len = GET_U_1(p);	/* Password Length */
958		p++;
959		if (length - (p - p0) < passwd_len)
960			return;
961		ND_PRINT(", Name ");
962		for (i = 0; i < passwd_len; i++) {
963			fn_print_char(ndo, GET_U_1(p));
964			p++;
965		}
966		break;
967	case PAP_AACK:
968	case PAP_ANAK:
969		/* Although some implementations ignore truncation at
970		 * this point and at least one generates a truncated
971		 * packet, RFC 1334 section 2.2.2 clearly states that
972		 * both AACK and ANAK are at least 5 bytes long.
973		 */
974		if (len < 5)
975			goto trunc;
976		if (length - (p - p0) < 1)
977			return;
978		msg_len = GET_U_1(p);	/* Msg-Length */
979		p++;
980		if (length - (p - p0) < msg_len)
981			return;
982		ND_PRINT(", Msg ");
983		for (i = 0; i< msg_len; i++) {
984			fn_print_char(ndo, GET_U_1(p));
985			p++;
986		}
987		break;
988	}
989	return;
990
991trunc:
992	ND_PRINT("[|pap]");
993}
994
995/* BAP */
996static void
997handle_bap(netdissect_options *ndo _U_,
998           const u_char *p _U_, u_int length _U_)
999{
1000	/* XXX: to be supported!! */
1001}
1002
1003
1004/* IPCP config options */
1005static u_int
1006print_ipcp_config_options(netdissect_options *ndo,
1007                          const u_char *p, u_int length)
1008{
1009	u_int opt, len;
1010        u_int compproto, ipcomp_subopttotallen, ipcomp_subopt, ipcomp_suboptlen;
1011
1012	if (length < 2)
1013		return 0;
1014	ND_TCHECK_2(p);
1015	opt = GET_U_1(p);
1016	len = GET_U_1(p + 1);
1017	if (length < len)
1018		return 0;
1019	if (len < 2) {
1020		ND_PRINT("\n\t  %s Option (0x%02x), length %u (length bogus, should be >= 2)",
1021		       tok2str(ipcpopt_values,"unknown",opt),
1022		       opt,
1023		       len);
1024		return 0;
1025	}
1026
1027	ND_PRINT("\n\t  %s Option (0x%02x), length %u",
1028	       tok2str(ipcpopt_values,"unknown",opt),
1029	       opt,
1030	       len);
1031
1032	switch (opt) {
1033	case IPCPOPT_2ADDR:		/* deprecated */
1034		if (len != 10) {
1035			ND_PRINT(" (length bogus, should be = 10)");
1036			return len;
1037		}
1038		ND_PRINT(": src %s, dst %s",
1039		       GET_IPADDR_STRING(p + 2),
1040		       GET_IPADDR_STRING(p + 6));
1041		break;
1042	case IPCPOPT_IPCOMP:
1043		if (len < 4) {
1044			ND_PRINT(" (length bogus, should be >= 4)");
1045			return 0;
1046		}
1047		compproto = GET_BE_U_2(p + 2);
1048
1049		ND_PRINT(": %s (0x%02x):",
1050		          tok2str(ipcpopt_compproto_values, "Unknown", compproto),
1051		          compproto);
1052
1053		switch (compproto) {
1054                case PPP_VJC:
1055			/* XXX: VJ-Comp parameters should be decoded */
1056                        break;
1057                case IPCPOPT_IPCOMP_HDRCOMP:
1058                        if (len < IPCPOPT_IPCOMP_MINLEN) {
1059                                ND_PRINT(" (length bogus, should be >= %u)",
1060                                         IPCPOPT_IPCOMP_MINLEN);
1061                                return 0;
1062                        }
1063
1064                        ND_TCHECK_LEN(p + 2, IPCPOPT_IPCOMP_MINLEN);
1065                        ND_PRINT("\n\t    TCP Space %u, non-TCP Space %u"
1066                               ", maxPeriod %u, maxTime %u, maxHdr %u",
1067                               GET_BE_U_2(p + 4),
1068                               GET_BE_U_2(p + 6),
1069                               GET_BE_U_2(p + 8),
1070                               GET_BE_U_2(p + 10),
1071                               GET_BE_U_2(p + 12));
1072
1073                        /* suboptions present ? */
1074                        if (len > IPCPOPT_IPCOMP_MINLEN) {
1075                                ipcomp_subopttotallen = len - IPCPOPT_IPCOMP_MINLEN;
1076                                p += IPCPOPT_IPCOMP_MINLEN;
1077
1078                                ND_PRINT("\n\t      Suboptions, length %u", ipcomp_subopttotallen);
1079
1080                                while (ipcomp_subopttotallen >= 2) {
1081                                        ND_TCHECK_2(p);
1082                                        ipcomp_subopt = GET_U_1(p);
1083                                        ipcomp_suboptlen = GET_U_1(p + 1);
1084
1085                                        /* sanity check */
1086                                        if (ipcomp_subopt == 0 ||
1087                                            ipcomp_suboptlen == 0 )
1088                                                break;
1089
1090                                        /* XXX: just display the suboptions for now */
1091                                        ND_PRINT("\n\t\t%s Suboption #%u, length %u",
1092                                               tok2str(ipcpopt_compproto_subopt_values,
1093                                                       "Unknown",
1094                                                       ipcomp_subopt),
1095                                               ipcomp_subopt,
1096                                               ipcomp_suboptlen);
1097                                        if (ipcomp_subopttotallen < ipcomp_suboptlen) {
1098                                                ND_PRINT(" [remaining suboptions length %u < %u]",
1099                                                         ipcomp_subopttotallen, ipcomp_suboptlen);
1100                                                nd_print_invalid(ndo);
1101                                                break;
1102                                        }
1103                                        ipcomp_subopttotallen -= ipcomp_suboptlen;
1104                                        p += ipcomp_suboptlen;
1105                                }
1106                        }
1107                        break;
1108                default:
1109                        break;
1110		}
1111		break;
1112
1113	case IPCPOPT_ADDR:     /* those options share the same format - fall through */
1114	case IPCPOPT_MOBILE4:
1115	case IPCPOPT_PRIDNS:
1116	case IPCPOPT_PRINBNS:
1117	case IPCPOPT_SECDNS:
1118	case IPCPOPT_SECNBNS:
1119		if (len != 6) {
1120			ND_PRINT(" (length bogus, should be = 6)");
1121			return 0;
1122		}
1123		ND_PRINT(": %s", GET_IPADDR_STRING(p + 2));
1124		break;
1125	default:
1126		/*
1127		 * Unknown option; dump it as raw bytes now if we're
1128		 * not going to do so below.
1129		 */
1130		if (ndo->ndo_vflag < 2)
1131			print_unknown_data(ndo, p + 2, "\n\t    ", len - 2);
1132		break;
1133	}
1134	if (ndo->ndo_vflag > 1)
1135		print_unknown_data(ndo, p + 2, "\n\t    ", len - 2); /* exclude TLV header */
1136	return len;
1137
1138trunc:
1139	ND_PRINT("[|ipcp]");
1140	return 0;
1141}
1142
1143/* IP6CP config options */
1144static u_int
1145print_ip6cp_config_options(netdissect_options *ndo,
1146                           const u_char *p, u_int length)
1147{
1148	u_int opt, len;
1149
1150	if (length < 2)
1151		return 0;
1152	ND_TCHECK_2(p);
1153	opt = GET_U_1(p);
1154	len = GET_U_1(p + 1);
1155	if (length < len)
1156		return 0;
1157	if (len < 2) {
1158		ND_PRINT("\n\t  %s Option (0x%02x), length %u (length bogus, should be >= 2)",
1159		       tok2str(ip6cpopt_values,"unknown",opt),
1160		       opt,
1161		       len);
1162		return 0;
1163	}
1164
1165	ND_PRINT("\n\t  %s Option (0x%02x), length %u",
1166	       tok2str(ip6cpopt_values,"unknown",opt),
1167	       opt,
1168	       len);
1169
1170	switch (opt) {
1171	case IP6CP_IFID:
1172		if (len != 10) {
1173			ND_PRINT(" (length bogus, should be = 10)");
1174			return len;
1175		}
1176		ND_TCHECK_8(p + 2);
1177		ND_PRINT(": %04x:%04x:%04x:%04x",
1178		       GET_BE_U_2(p + 2),
1179		       GET_BE_U_2(p + 4),
1180		       GET_BE_U_2(p + 6),
1181		       GET_BE_U_2(p + 8));
1182		break;
1183	default:
1184		/*
1185		 * Unknown option; dump it as raw bytes now if we're
1186		 * not going to do so below.
1187		 */
1188		if (ndo->ndo_vflag < 2)
1189			print_unknown_data(ndo, p + 2, "\n\t    ", len - 2);
1190		break;
1191	}
1192	if (ndo->ndo_vflag > 1)
1193		print_unknown_data(ndo, p + 2, "\n\t    ", len - 2); /* exclude TLV header */
1194
1195	return len;
1196
1197trunc:
1198	ND_PRINT("[|ip6cp]");
1199	return 0;
1200}
1201
1202
1203/* CCP config options */
1204static u_int
1205print_ccp_config_options(netdissect_options *ndo,
1206                         const u_char *p, u_int length)
1207{
1208	u_int opt, len;
1209
1210	if (length < 2)
1211		return 0;
1212	ND_TCHECK_2(p);
1213	opt = GET_U_1(p);
1214	len = GET_U_1(p + 1);
1215	if (length < len)
1216		return 0;
1217	if (len < 2) {
1218		ND_PRINT("\n\t  %s Option (0x%02x), length %u (length bogus, should be >= 2)",
1219		          tok2str(ccpconfopts_values, "Unknown", opt),
1220		          opt,
1221		          len);
1222		return 0;
1223	}
1224
1225	ND_PRINT("\n\t  %s Option (0x%02x), length %u",
1226	          tok2str(ccpconfopts_values, "Unknown", opt),
1227	          opt,
1228	          len);
1229
1230	switch (opt) {
1231	case CCPOPT_BSDCOMP:
1232		if (len < 3) {
1233			ND_PRINT(" (length bogus, should be >= 3)");
1234			return len;
1235		}
1236		ND_PRINT(": Version: %u, Dictionary Bits: %u",
1237			GET_U_1(p + 2) >> 5,
1238			GET_U_1(p + 2) & 0x1f);
1239		break;
1240	case CCPOPT_MVRCA:
1241		if (len < 4) {
1242			ND_PRINT(" (length bogus, should be >= 4)");
1243			return len;
1244		}
1245		ND_PRINT(": Features: %u, PxP: %s, History: %u, #CTX-ID: %u",
1246				(GET_U_1(p + 2) & 0xc0) >> 6,
1247				(GET_U_1(p + 2) & 0x20) ? "Enabled" : "Disabled",
1248				GET_U_1(p + 2) & 0x1f,
1249				GET_U_1(p + 3));
1250		break;
1251	case CCPOPT_DEFLATE:
1252		if (len < 4) {
1253			ND_PRINT(" (length bogus, should be >= 4)");
1254			return len;
1255		}
1256		ND_PRINT(": Window: %uK, Method: %s (0x%x), MBZ: %u, CHK: %u",
1257			(GET_U_1(p + 2) & 0xf0) >> 4,
1258			((GET_U_1(p + 2) & 0x0f) == 8) ? "zlib" : "unknown",
1259			GET_U_1(p + 2) & 0x0f,
1260			(GET_U_1(p + 3) & 0xfc) >> 2,
1261			GET_U_1(p + 3) & 0x03);
1262		break;
1263
1264/* XXX: to be supported */
1265#if 0
1266	case CCPOPT_OUI:
1267	case CCPOPT_PRED1:
1268	case CCPOPT_PRED2:
1269	case CCPOPT_PJUMP:
1270	case CCPOPT_HPPPC:
1271	case CCPOPT_STACLZS:
1272	case CCPOPT_MPPC:
1273	case CCPOPT_GFZA:
1274	case CCPOPT_V42BIS:
1275	case CCPOPT_LZSDCP:
1276	case CCPOPT_DEC:
1277	case CCPOPT_RESV:
1278		break;
1279#endif
1280	default:
1281		/*
1282		 * Unknown option; dump it as raw bytes now if we're
1283		 * not going to do so below.
1284		 */
1285		if (ndo->ndo_vflag < 2)
1286			print_unknown_data(ndo, p + 2, "\n\t    ", len - 2);
1287		break;
1288	}
1289	if (ndo->ndo_vflag > 1)
1290		print_unknown_data(ndo, p + 2, "\n\t    ", len - 2); /* exclude TLV header */
1291
1292	return len;
1293
1294trunc:
1295	ND_PRINT("[|ccp]");
1296	return 0;
1297}
1298
1299/* BACP config options */
1300static u_int
1301print_bacp_config_options(netdissect_options *ndo,
1302                          const u_char *p, u_int length)
1303{
1304	u_int opt, len;
1305
1306	if (length < 2)
1307		return 0;
1308	ND_TCHECK_2(p);
1309	opt = GET_U_1(p);
1310	len = GET_U_1(p + 1);
1311	if (length < len)
1312		return 0;
1313	if (len < 2) {
1314		ND_PRINT("\n\t  %s Option (0x%02x), length %u (length bogus, should be >= 2)",
1315		          tok2str(bacconfopts_values, "Unknown", opt),
1316		          opt,
1317		          len);
1318		return 0;
1319	}
1320
1321	ND_PRINT("\n\t  %s Option (0x%02x), length %u",
1322	          tok2str(bacconfopts_values, "Unknown", opt),
1323	          opt,
1324	          len);
1325
1326	switch (opt) {
1327	case BACPOPT_FPEER:
1328		if (len != 6) {
1329			ND_PRINT(" (length bogus, should be = 6)");
1330			return len;
1331		}
1332		ND_PRINT(": Magic-Num 0x%08x", GET_BE_U_4(p + 2));
1333		break;
1334	default:
1335		/*
1336		 * Unknown option; dump it as raw bytes now if we're
1337		 * not going to do so below.
1338		 */
1339		if (ndo->ndo_vflag < 2)
1340			print_unknown_data(ndo, p + 2, "\n\t    ", len - 2);
1341		break;
1342	}
1343	if (ndo->ndo_vflag > 1)
1344		print_unknown_data(ndo, p + 2, "\n\t    ", len - 2); /* exclude TLV header */
1345
1346	return len;
1347
1348trunc:
1349	ND_PRINT("[|bacp]");
1350	return 0;
1351}
1352
1353/*
1354 * Un-escape RFC 1662 PPP in HDLC-like framing, with octet escapes.
1355 * The length argument is the on-the-wire length, not the captured
1356 * length; we can only un-escape the captured part.
1357 */
1358static void
1359ppp_hdlc(netdissect_options *ndo,
1360         const u_char *p, u_int length)
1361{
1362	u_int caplen = ND_BYTES_AVAILABLE_AFTER(p);
1363	u_char *b, *t, c;
1364	const u_char *s;
1365	u_int i, proto;
1366	const void *sb, *se;
1367
1368	if (caplen == 0)
1369		return;
1370
1371        if (length == 0)
1372                return;
1373
1374	b = (u_char *)nd_malloc(ndo, caplen);
1375	if (b == NULL)
1376		return;
1377
1378	/*
1379	 * Unescape all the data into a temporary, private, buffer.
1380	 * Do this so that we don't overwrite the original packet
1381	 * contents.
1382	 */
1383	for (s = p, t = b, i = caplen; i != 0; i--) {
1384		c = GET_U_1(s);
1385		s++;
1386		if (c == 0x7d) {
1387			if (i <= 1)
1388				break;
1389			i--;
1390			c = GET_U_1(s) ^ 0x20;
1391			s++;
1392		}
1393		*t++ = c;
1394	}
1395
1396	/*
1397	 * Change the end pointer, so bounds checks work.
1398	 * Change the pointer to packet data to help debugging.
1399	 */
1400	sb = ndo->ndo_packetp;
1401	se = ndo->ndo_snapend;
1402	ndo->ndo_packetp = b;
1403	ndo->ndo_snapend = t;
1404	length = ND_BYTES_AVAILABLE_AFTER(b);
1405
1406        /* now lets guess about the payload codepoint format */
1407        if (length < 1)
1408                goto trunc;
1409        proto = GET_U_1(b); /* start with a one-octet codepoint guess */
1410
1411        switch (proto) {
1412        case PPP_IP:
1413		ip_print(ndo, b + 1, length - 1);
1414		goto cleanup;
1415        case PPP_IPV6:
1416		ip6_print(ndo, b + 1, length - 1);
1417		goto cleanup;
1418        default: /* no luck - try next guess */
1419		break;
1420        }
1421
1422        if (length < 2)
1423                goto trunc;
1424        proto = GET_BE_U_2(b); /* next guess - load two octets */
1425
1426        switch (proto) {
1427        case (PPP_ADDRESS << 8 | PPP_CONTROL): /* looks like a PPP frame */
1428            if (length < 4)
1429                goto trunc;
1430            proto = GET_BE_U_2(b + 2); /* load the PPP proto-id */
1431            if ((proto & 0xff00) == 0x7e00)
1432                ND_PRINT("(protocol 0x%04x invalid)", proto);
1433            else
1434                handle_ppp(ndo, proto, b + 4, length - 4);
1435            break;
1436        default: /* last guess - proto must be a PPP proto-id */
1437            if ((proto & 0xff00) == 0x7e00)
1438                ND_PRINT("(protocol 0x%04x invalid)", proto);
1439            else
1440                handle_ppp(ndo, proto, b + 2, length - 2);
1441            break;
1442        }
1443
1444cleanup:
1445	ndo->ndo_packetp = sb;
1446	ndo->ndo_snapend = se;
1447        return;
1448
1449trunc:
1450	ndo->ndo_packetp = sb;
1451	ndo->ndo_snapend = se;
1452	nd_print_trunc(ndo);
1453}
1454
1455
1456/* PPP */
1457static void
1458handle_ppp(netdissect_options *ndo,
1459           u_int proto, const u_char *p, u_int length)
1460{
1461	if ((proto & 0xff00) == 0x7e00) { /* is this an escape code ? */
1462		ppp_hdlc(ndo, p - 1, length);
1463		return;
1464	}
1465
1466	switch (proto) {
1467	case PPP_LCP: /* fall through */
1468	case PPP_IPCP:
1469	case PPP_OSICP:
1470	case PPP_MPLSCP:
1471	case PPP_IPV6CP:
1472	case PPP_CCP:
1473	case PPP_BACP:
1474		handle_ctrl_proto(ndo, proto, p, length);
1475		break;
1476	case PPP_ML:
1477		handle_mlppp(ndo, p, length);
1478		break;
1479	case PPP_CHAP:
1480		handle_chap(ndo, p, length);
1481		break;
1482	case PPP_PAP:
1483		handle_pap(ndo, p, length);
1484		break;
1485	case PPP_BAP:		/* XXX: not yet completed */
1486		handle_bap(ndo, p, length);
1487		break;
1488	case ETHERTYPE_IP:	/*XXX*/
1489        case PPP_VJNC:
1490	case PPP_IP:
1491		ip_print(ndo, p, length);
1492		break;
1493	case ETHERTYPE_IPV6:	/*XXX*/
1494	case PPP_IPV6:
1495		ip6_print(ndo, p, length);
1496		break;
1497	case ETHERTYPE_IPX:	/*XXX*/
1498	case PPP_IPX:
1499		ipx_print(ndo, p, length);
1500		break;
1501	case PPP_OSI:
1502		isoclns_print(ndo, p, length);
1503		break;
1504	case PPP_MPLS_UCAST:
1505	case PPP_MPLS_MCAST:
1506		mpls_print(ndo, p, length);
1507		break;
1508	case PPP_COMP:
1509		ND_PRINT("compressed PPP data");
1510		break;
1511	default:
1512		ND_PRINT("%s ", tok2str(ppptype2str, "unknown PPP protocol (0x%04x)", proto));
1513		print_unknown_data(ndo, p, "\n\t", length);
1514		break;
1515	}
1516}
1517
1518/* Standard PPP printer */
1519u_int
1520ppp_print(netdissect_options *ndo,
1521          const u_char *p, u_int length)
1522{
1523	u_int proto,ppp_header;
1524        u_int olen = length; /* _o_riginal length */
1525	u_int hdr_len = 0;
1526
1527	ndo->ndo_protocol = "ppp";
1528	/*
1529	 * Here, we assume that p points to the Address and Control
1530	 * field (if they present).
1531	 */
1532	if (length < 2)
1533		goto trunc;
1534        ppp_header = GET_BE_U_2(p);
1535
1536        switch(ppp_header) {
1537        case (PPP_PPPD_IN  << 8 | PPP_CONTROL):
1538            if (ndo->ndo_eflag) ND_PRINT("In  ");
1539            p += 2;
1540            length -= 2;
1541            hdr_len += 2;
1542            break;
1543        case (PPP_PPPD_OUT << 8 | PPP_CONTROL):
1544            if (ndo->ndo_eflag) ND_PRINT("Out ");
1545            p += 2;
1546            length -= 2;
1547            hdr_len += 2;
1548            break;
1549        case (PPP_ADDRESS << 8 | PPP_CONTROL):
1550            p += 2;			/* ACFC not used */
1551            length -= 2;
1552            hdr_len += 2;
1553            break;
1554
1555        default:
1556            break;
1557        }
1558
1559	if (length < 2)
1560		goto trunc;
1561	if (GET_U_1(p) % 2) {
1562		proto = GET_U_1(p);	/* PFC is used */
1563		p++;
1564		length--;
1565		hdr_len++;
1566	} else {
1567		proto = GET_BE_U_2(p);
1568		p += 2;
1569		length -= 2;
1570		hdr_len += 2;
1571	}
1572
1573	if (ndo->ndo_eflag) {
1574		const char *typestr;
1575		typestr = tok2str(ppptype2str, "unknown", proto);
1576		ND_PRINT("%s (0x%04x), length %u",
1577		          typestr,
1578		          proto,
1579		          olen);
1580		if (*typestr == 'u')	/* "unknown" */
1581			return hdr_len;
1582
1583		ND_PRINT(": ");
1584	}
1585
1586	handle_ppp(ndo, proto, p, length);
1587	return (hdr_len);
1588trunc:
1589	nd_print_trunc(ndo);
1590	return (0);
1591}
1592
1593
1594/* PPP I/F printer */
1595void
1596ppp_if_print(netdissect_options *ndo,
1597             const struct pcap_pkthdr *h, const u_char *p)
1598{
1599	u_int length = h->len;
1600	u_int caplen = h->caplen;
1601
1602	ndo->ndo_protocol = "ppp";
1603	if (caplen < PPP_HDRLEN) {
1604		nd_print_trunc(ndo);
1605		ndo->ndo_ll_hdr_len += caplen;
1606		return;
1607	}
1608	ndo->ndo_ll_hdr_len += PPP_HDRLEN;
1609
1610#if 0
1611	/*
1612	 * XXX: seems to assume that there are 2 octets prepended to an
1613	 * actual PPP frame. The 1st octet looks like Input/Output flag
1614	 * while 2nd octet is unknown, at least to me
1615	 * (mshindo@mshindo.net).
1616	 *
1617	 * That was what the original tcpdump code did.
1618	 *
1619	 * FreeBSD's "if_ppp.c" *does* set the first octet to 1 for outbound
1620	 * packets and 0 for inbound packets - but only if the
1621	 * protocol field has the 0x8000 bit set (i.e., it's a network
1622	 * control protocol); it does so before running the packet through
1623	 * "bpf_filter" to see if it should be discarded, and to see
1624	 * if we should update the time we sent the most recent packet...
1625	 *
1626	 * ...but it puts the original address field back after doing
1627	 * so.
1628	 *
1629	 * NetBSD's "if_ppp.c" doesn't set the first octet in that fashion.
1630	 *
1631	 * I don't know if any PPP implementation handed up to a BPF
1632	 * device packets with the first octet being 1 for outbound and
1633	 * 0 for inbound packets, so I (guy@alum.mit.edu) don't know
1634	 * whether that ever needs to be checked or not.
1635	 *
1636	 * Note that NetBSD has a DLT_PPP_SERIAL, which it uses for PPP,
1637	 * and its tcpdump appears to assume that the frame always
1638	 * begins with an address field and a control field, and that
1639	 * the address field might be 0x0f or 0x8f, for Cisco
1640	 * point-to-point with HDLC framing as per section 4.3.1 of RFC
1641	 * 1547, as well as 0xff, for PPP in HDLC-like framing as per
1642	 * RFC 1662.
1643	 *
1644	 * (Is the Cisco framing in question what DLT_C_HDLC, in
1645	 * BSD/OS, is?)
1646	 */
1647	if (ndo->ndo_eflag)
1648		ND_PRINT("%c %4d %02x ", GET_U_1(p) ? 'O' : 'I',
1649			 length, GET_U_1(p + 1));
1650#endif
1651
1652	ppp_print(ndo, p, length);
1653}
1654
1655/*
1656 * PPP I/F printer to use if we know that RFC 1662-style PPP in HDLC-like
1657 * framing, or Cisco PPP with HDLC framing as per section 4.3.1 of RFC 1547,
1658 * is being used (i.e., we don't check for PPP_ADDRESS and PPP_CONTROL,
1659 * discard them *if* those are the first two octets, and parse the remaining
1660 * packet as a PPP packet, as "ppp_print()" does).
1661 *
1662 * This handles, for example, DLT_PPP_SERIAL in NetBSD.
1663 */
1664void
1665ppp_hdlc_if_print(netdissect_options *ndo,
1666                  const struct pcap_pkthdr *h, const u_char *p)
1667{
1668	u_int length = h->len;
1669	u_int caplen = h->caplen;
1670	u_int proto;
1671	u_int hdrlen = 0;
1672
1673	ndo->ndo_protocol = "ppp_hdlc";
1674	if (caplen < 2) {
1675		nd_print_trunc(ndo);
1676		ndo->ndo_ll_hdr_len += caplen;
1677		return;
1678	}
1679
1680	switch (GET_U_1(p)) {
1681
1682	case PPP_ADDRESS:
1683		if (caplen < 4) {
1684			nd_print_trunc(ndo);
1685			ndo->ndo_ll_hdr_len += caplen;
1686			return;
1687		}
1688
1689		if (ndo->ndo_eflag)
1690			ND_PRINT("%02x %02x %u ", GET_U_1(p),
1691				 GET_U_1(p + 1), length);
1692		p += 2;
1693		length -= 2;
1694		hdrlen += 2;
1695
1696		proto = GET_BE_U_2(p);
1697		p += 2;
1698		length -= 2;
1699		hdrlen += 2;
1700		ND_PRINT("%s: ", tok2str(ppptype2str, "unknown PPP protocol (0x%04x)", proto));
1701
1702		handle_ppp(ndo, proto, p, length);
1703		break;
1704
1705	case CHDLC_UNICAST:
1706	case CHDLC_BCAST:
1707		chdlc_if_print(ndo, h, p);
1708		return;
1709
1710	default:
1711		if (caplen < 4) {
1712			nd_print_trunc(ndo);
1713			ndo->ndo_ll_hdr_len += caplen;
1714			return;
1715		}
1716
1717		if (ndo->ndo_eflag)
1718			ND_PRINT("%02x %02x %u ", GET_U_1(p),
1719				 GET_U_1(p + 1), length);
1720		p += 2;
1721		hdrlen += 2;
1722
1723		/*
1724		 * XXX - NetBSD's "ppp_netbsd_serial_if_print()" treats
1725		 * the next two octets as an Ethernet type; does that
1726		 * ever happen?
1727		 */
1728		ND_PRINT("unknown addr %02x; ctrl %02x", GET_U_1(p),
1729			 GET_U_1(p + 1));
1730		break;
1731	}
1732
1733	ndo->ndo_ll_hdr_len += hdrlen;
1734}
1735
1736#define PPP_BSDI_HDRLEN 24
1737
1738/* BSD/OS specific PPP printer */
1739void
1740ppp_bsdos_if_print(netdissect_options *ndo,
1741                   const struct pcap_pkthdr *h _U_, const u_char *p _U_)
1742{
1743	u_int hdrlength;
1744#ifdef __bsdi__
1745	u_int length = h->len;
1746	u_int caplen = h->caplen;
1747	uint16_t ptype;
1748	uint8_t llhl;
1749	const u_char *q;
1750	u_int i;
1751
1752	ndo->ndo_protocol = "ppp_bsdos";
1753	if (caplen < PPP_BSDI_HDRLEN) {
1754		nd_print_trunc(ndo);
1755		ndo->ndo_ll_hdr_len += caplen;
1756		return;
1757	}
1758
1759	hdrlength = 0;
1760
1761#if 0
1762	if (GET_U_1(p) == PPP_ADDRESS &&
1763	    GET_U_1(p + 1) == PPP_CONTROL) {
1764		if (ndo->ndo_eflag)
1765			ND_PRINT("%02x %02x ", GET_U_1(p),
1766				 GET_U_1(p + 1));
1767		p += 2;
1768		hdrlength = 2;
1769	}
1770
1771	if (ndo->ndo_eflag)
1772		ND_PRINT("%u ", length);
1773	/* Retrieve the protocol type */
1774	if (GET_U_1(p) & 01) {
1775		/* Compressed protocol field */
1776		ptype = GET_U_1(p);
1777		if (ndo->ndo_eflag)
1778			ND_PRINT("%02x ", ptype);
1779		p++;
1780		hdrlength += 1;
1781	} else {
1782		/* Un-compressed protocol field */
1783		ptype = GET_BE_U_2(p);
1784		if (ndo->ndo_eflag)
1785			ND_PRINT("%04x ", ptype);
1786		p += 2;
1787		hdrlength += 2;
1788	}
1789#else
1790	ptype = 0;	/*XXX*/
1791	if (ndo->ndo_eflag)
1792		ND_PRINT("%c ", GET_U_1(p + SLC_DIR) ? 'O' : 'I');
1793	llhl = GET_U_1(p + SLC_LLHL);
1794	if (llhl) {
1795		/* link level header */
1796		struct ppp_header *ph;
1797
1798		q = p + SLC_BPFHDRLEN;
1799		ph = (struct ppp_header *)q;
1800		if (ph->phdr_addr == PPP_ADDRESS
1801		 && ph->phdr_ctl == PPP_CONTROL) {
1802			if (ndo->ndo_eflag)
1803				ND_PRINT("%02x %02x ", GET_U_1(q),
1804					 GET_U_1(q + 1));
1805			ptype = GET_BE_U_2(&ph->phdr_type);
1806			if (ndo->ndo_eflag && (ptype == PPP_VJC || ptype == PPP_VJNC)) {
1807				ND_PRINT("%s ", tok2str(ppptype2str,
1808						"proto-#%u", ptype));
1809			}
1810		} else {
1811			if (ndo->ndo_eflag) {
1812				ND_PRINT("LLH=[");
1813				for (i = 0; i < llhl; i++)
1814					ND_PRINT("%02x", GET_U_1(q + i));
1815				ND_PRINT("] ");
1816			}
1817		}
1818	}
1819	if (ndo->ndo_eflag)
1820		ND_PRINT("%u ", length);
1821	if (GET_U_1(p + SLC_CHL)) {
1822		q = p + SLC_BPFHDRLEN + llhl;
1823
1824		switch (ptype) {
1825		case PPP_VJC:
1826			ptype = vjc_print(ndo, q, ptype);
1827			hdrlength = PPP_BSDI_HDRLEN;
1828			p += hdrlength;
1829			switch (ptype) {
1830			case PPP_IP:
1831				ip_print(ndo, p, length);
1832				break;
1833			case PPP_IPV6:
1834				ip6_print(ndo, p, length);
1835				break;
1836			case PPP_MPLS_UCAST:
1837			case PPP_MPLS_MCAST:
1838				mpls_print(ndo, p, length);
1839				break;
1840			}
1841			goto printx;
1842		case PPP_VJNC:
1843			ptype = vjc_print(ndo, q, ptype);
1844			hdrlength = PPP_BSDI_HDRLEN;
1845			p += hdrlength;
1846			switch (ptype) {
1847			case PPP_IP:
1848				ip_print(ndo, p, length);
1849				break;
1850			case PPP_IPV6:
1851				ip6_print(ndo, p, length);
1852				break;
1853			case PPP_MPLS_UCAST:
1854			case PPP_MPLS_MCAST:
1855				mpls_print(ndo, p, length);
1856				break;
1857			}
1858			goto printx;
1859		default:
1860			if (ndo->ndo_eflag) {
1861				ND_PRINT("CH=[");
1862				for (i = 0; i < llhl; i++)
1863					ND_PRINT("%02x",
1864					    GET_U_1(q + i));
1865				ND_PRINT("] ");
1866			}
1867			break;
1868		}
1869	}
1870
1871	hdrlength = PPP_BSDI_HDRLEN;
1872#endif
1873
1874	length -= hdrlength;
1875	p += hdrlength;
1876
1877	switch (ptype) {
1878	case PPP_IP:
1879		ip_print(p, length);
1880		break;
1881	case PPP_IPV6:
1882		ip6_print(ndo, p, length);
1883		break;
1884	case PPP_MPLS_UCAST:
1885	case PPP_MPLS_MCAST:
1886		mpls_print(ndo, p, length);
1887		break;
1888	default:
1889		ND_PRINT("%s ", tok2str(ppptype2str, "unknown PPP protocol (0x%04x)", ptype));
1890	}
1891
1892printx:
1893#else /* __bsdi */
1894	hdrlength = 0;
1895#endif /* __bsdi__ */
1896	ndo->ndo_ll_hdr_len += hdrlength;
1897}
1898