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