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 * Format and print bootp packets.
22 *
23 * $FreeBSD$
24 */
25#ifndef lint
26static const char rcsid[] _U_ =
27    "@(#) $Header: /tcpdump/master/tcpdump/print-bootp.c,v 1.89 2008-04-22 09:45:08 hannes Exp $ (LBL)";
28#endif
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <tcpdump-stdinc.h>
35
36#include <stdio.h>
37#include <string.h>
38
39#include "interface.h"
40#include "addrtoname.h"
41#include "extract.h"
42#include "ether.h"
43#include "bootp.h"
44
45static void rfc1048_print(const u_char *);
46static void cmu_print(const u_char *);
47static char *client_fqdn_flags(u_int flags);
48
49static char tstr[] = " [|bootp]";
50
51static const struct tok bootp_flag_values[] = {
52    { 0x8000,                   "Broadcast" },
53    { 0, NULL}
54};
55
56static const struct tok bootp_op_values[] = {
57    { BOOTPREQUEST,             "Request" },
58    { BOOTPREPLY,               "Reply" },
59    { 0, NULL}
60};
61
62/*
63 * Print bootp requests
64 */
65void
66bootp_print(register const u_char *cp, u_int length)
67{
68	register const struct bootp *bp;
69	static const u_char vm_cmu[4] = VM_CMU;
70	static const u_char vm_rfc1048[4] = VM_RFC1048;
71
72	bp = (const struct bootp *)cp;
73	TCHECK(bp->bp_op);
74
75        printf("BOOTP/DHCP, %s",
76	       tok2str(bootp_op_values, "unknown (0x%02x)", bp->bp_op));
77
78	if (bp->bp_htype == 1 && bp->bp_hlen == 6 && bp->bp_op == BOOTPREQUEST) {
79		TCHECK2(bp->bp_chaddr[0], 6);
80		printf(" from %s", etheraddr_string(bp->bp_chaddr));
81	}
82
83        printf(", length %u", length);
84
85        if (!vflag)
86            return;
87
88	TCHECK(bp->bp_secs);
89
90	/* The usual hardware address type is 1 (10Mb Ethernet) */
91	if (bp->bp_htype != 1)
92		printf(", htype %d", bp->bp_htype);
93
94	/* The usual length for 10Mb Ethernet address is 6 bytes */
95	if (bp->bp_htype != 1 || bp->bp_hlen != 6)
96		printf(", hlen %d", bp->bp_hlen);
97
98	/* Only print interesting fields */
99	if (bp->bp_hops)
100		printf(", hops %d", bp->bp_hops);
101	if (bp->bp_xid)
102		printf(", xid 0x%x", EXTRACT_32BITS(&bp->bp_xid));
103	if (bp->bp_secs)
104		printf(", secs %d", EXTRACT_16BITS(&bp->bp_secs));
105
106	printf(", Flags [%s]",
107		bittok2str(bootp_flag_values, "none", EXTRACT_16BITS(&bp->bp_flags)));
108	if (vflag > 1)
109		printf(" (0x%04x)", EXTRACT_16BITS(&bp->bp_flags));
110
111	/* Client's ip address */
112	TCHECK(bp->bp_ciaddr);
113	if (bp->bp_ciaddr.s_addr)
114		printf("\n\t  Client-IP %s", ipaddr_string(&bp->bp_ciaddr));
115
116	/* 'your' ip address (bootp client) */
117	TCHECK(bp->bp_yiaddr);
118	if (bp->bp_yiaddr.s_addr)
119		printf("\n\t  Your-IP %s", ipaddr_string(&bp->bp_yiaddr));
120
121	/* Server's ip address */
122	TCHECK(bp->bp_siaddr);
123	if (bp->bp_siaddr.s_addr)
124		printf("\n\t  Server-IP %s", ipaddr_string(&bp->bp_siaddr));
125
126	/* Gateway's ip address */
127	TCHECK(bp->bp_giaddr);
128	if (bp->bp_giaddr.s_addr)
129		printf("\n\t  Gateway-IP %s", ipaddr_string(&bp->bp_giaddr));
130
131	/* Client's Ethernet address */
132	if (bp->bp_htype == 1 && bp->bp_hlen == 6) {
133		TCHECK2(bp->bp_chaddr[0], 6);
134		printf("\n\t  Client-Ethernet-Address %s", etheraddr_string(bp->bp_chaddr));
135	}
136
137	TCHECK2(bp->bp_sname[0], 1);		/* check first char only */
138	if (*bp->bp_sname) {
139		printf("\n\t  sname \"");
140		if (fn_print(bp->bp_sname, snapend)) {
141			putchar('"');
142			fputs(tstr + 1, stdout);
143			return;
144		}
145		putchar('"');
146	}
147	TCHECK2(bp->bp_file[0], 1);		/* check first char only */
148	if (*bp->bp_file) {
149		printf("\n\t  file \"");
150		if (fn_print(bp->bp_file, snapend)) {
151			putchar('"');
152			fputs(tstr + 1, stdout);
153			return;
154		}
155		putchar('"');
156	}
157
158	/* Decode the vendor buffer */
159	TCHECK(bp->bp_vend[0]);
160	if (memcmp((const char *)bp->bp_vend, vm_rfc1048,
161		 sizeof(u_int32_t)) == 0)
162		rfc1048_print(bp->bp_vend);
163	else if (memcmp((const char *)bp->bp_vend, vm_cmu,
164		      sizeof(u_int32_t)) == 0)
165		cmu_print(bp->bp_vend);
166	else {
167		u_int32_t ul;
168
169		ul = EXTRACT_32BITS(&bp->bp_vend);
170		if (ul != 0)
171			printf("\n\t  Vendor-#0x%x", ul);
172	}
173
174	return;
175trunc:
176	fputs(tstr, stdout);
177}
178
179/*
180 * The first character specifies the format to print:
181 *     i - ip address (32 bits)
182 *     p - ip address pairs (32 bits + 32 bits)
183 *     l - long (32 bits)
184 *     L - unsigned long (32 bits)
185 *     s - short (16 bits)
186 *     b - period-seperated decimal bytes (variable length)
187 *     x - colon-seperated hex bytes (variable length)
188 *     a - ascii string (variable length)
189 *     B - on/off (8 bits)
190 *     $ - special (explicit code to handle)
191 */
192static struct tok tag2str[] = {
193/* RFC1048 tags */
194	{ TAG_PAD,		" PAD" },
195	{ TAG_SUBNET_MASK,	"iSubnet-Mask" },	/* subnet mask (RFC950) */
196	{ TAG_TIME_OFFSET,	"LTime-Zone" },	/* seconds from UTC */
197	{ TAG_GATEWAY,		"iDefault-Gateway" },	/* default gateway */
198	{ TAG_TIME_SERVER,	"iTime-Server" },	/* time servers (RFC868) */
199	{ TAG_NAME_SERVER,	"iIEN-Name-Server" },	/* IEN name servers (IEN116) */
200	{ TAG_DOMAIN_SERVER,	"iDomain-Name-Server" },	/* domain name (RFC1035) */
201	{ TAG_LOG_SERVER,	"iLOG" },	/* MIT log servers */
202	{ TAG_COOKIE_SERVER,	"iCS" },	/* cookie servers (RFC865) */
203	{ TAG_LPR_SERVER,	"iLPR-Server" },	/* lpr server (RFC1179) */
204	{ TAG_IMPRESS_SERVER,	"iIM" },	/* impress servers (Imagen) */
205	{ TAG_RLP_SERVER,	"iRL" },	/* resource location (RFC887) */
206	{ TAG_HOSTNAME,		"aHostname" },	/* ascii hostname */
207	{ TAG_BOOTSIZE,		"sBS" },	/* 512 byte blocks */
208	{ TAG_END,		" END" },
209/* RFC1497 tags */
210	{ TAG_DUMPPATH,		"aDP" },
211	{ TAG_DOMAINNAME,	"aDomain-Name" },
212	{ TAG_SWAP_SERVER,	"iSS" },
213	{ TAG_ROOTPATH,		"aRP" },
214	{ TAG_EXTPATH,		"aEP" },
215/* RFC2132 tags */
216	{ TAG_IP_FORWARD,	"BIPF" },
217	{ TAG_NL_SRCRT,		"BSRT" },
218	{ TAG_PFILTERS,		"pPF" },
219	{ TAG_REASS_SIZE,	"sRSZ" },
220	{ TAG_DEF_TTL,		"bTTL" },
221	{ TAG_MTU_TIMEOUT,	"lMTU-Timeout" },
222	{ TAG_MTU_TABLE,	"sMTU-Table" },
223	{ TAG_INT_MTU,		"sMTU" },
224	{ TAG_LOCAL_SUBNETS,	"BLSN" },
225	{ TAG_BROAD_ADDR,	"iBR" },
226	{ TAG_DO_MASK_DISC,	"BMD" },
227	{ TAG_SUPPLY_MASK,	"BMS" },
228	{ TAG_DO_RDISC,		"BRouter-Discovery" },
229	{ TAG_RTR_SOL_ADDR,	"iRSA" },
230	{ TAG_STATIC_ROUTE,	"pStatic-Route" },
231	{ TAG_USE_TRAILERS,	"BUT" },
232	{ TAG_ARP_TIMEOUT,	"lAT" },
233	{ TAG_ETH_ENCAP,	"BIE" },
234	{ TAG_TCP_TTL,		"bTT" },
235	{ TAG_TCP_KEEPALIVE,	"lKI" },
236	{ TAG_KEEPALIVE_GO,	"BKG" },
237	{ TAG_NIS_DOMAIN,	"aYD" },
238	{ TAG_NIS_SERVERS,	"iYS" },
239	{ TAG_NTP_SERVERS,	"iNTP" },
240	{ TAG_VENDOR_OPTS,	"bVendor-Option" },
241	{ TAG_NETBIOS_NS,	"iNetbios-Name-Server" },
242	{ TAG_NETBIOS_DDS,	"iWDD" },
243	{ TAG_NETBIOS_NODE,	"$Netbios-Node" },
244	{ TAG_NETBIOS_SCOPE,	"aNetbios-Scope" },
245	{ TAG_XWIN_FS,		"iXFS" },
246	{ TAG_XWIN_DM,		"iXDM" },
247	{ TAG_NIS_P_DOMAIN,	"sN+D" },
248	{ TAG_NIS_P_SERVERS,	"iN+S" },
249	{ TAG_MOBILE_HOME,	"iMH" },
250	{ TAG_SMPT_SERVER,	"iSMTP" },
251	{ TAG_POP3_SERVER,	"iPOP3" },
252	{ TAG_NNTP_SERVER,	"iNNTP" },
253	{ TAG_WWW_SERVER,	"iWWW" },
254	{ TAG_FINGER_SERVER,	"iFG" },
255	{ TAG_IRC_SERVER,	"iIRC" },
256	{ TAG_STREETTALK_SRVR,	"iSTS" },
257	{ TAG_STREETTALK_STDA,	"iSTDA" },
258	{ TAG_REQUESTED_IP,	"iRequested-IP" },
259	{ TAG_IP_LEASE,		"lLease-Time" },
260	{ TAG_OPT_OVERLOAD,	"$OO" },
261	{ TAG_TFTP_SERVER,	"aTFTP" },
262	{ TAG_BOOTFILENAME,	"aBF" },
263	{ TAG_DHCP_MESSAGE,	" DHCP-Message" },
264	{ TAG_SERVER_ID,	"iServer-ID" },
265	{ TAG_PARM_REQUEST,	"bParameter-Request" },
266	{ TAG_MESSAGE,		"aMSG" },
267	{ TAG_MAX_MSG_SIZE,	"sMSZ" },
268	{ TAG_RENEWAL_TIME,	"lRN" },
269	{ TAG_REBIND_TIME,	"lRB" },
270	{ TAG_VENDOR_CLASS,	"aVendor-Class" },
271	{ TAG_CLIENT_ID,	"$Client-ID" },
272/* RFC 2485 */
273	{ TAG_OPEN_GROUP_UAP,	"aUAP" },
274/* RFC 2563 */
275	{ TAG_DISABLE_AUTOCONF,	"BNOAUTO" },
276/* RFC 2610 */
277	{ TAG_SLP_DA,		"bSLP-DA" },	/*"b" is a little wrong */
278	{ TAG_SLP_SCOPE,	"bSLP-SCOPE" },	/*"b" is a little wrong */
279/* RFC 2937 */
280	{ TAG_NS_SEARCH,	"sNSSEARCH" },	/* XXX 's' */
281/* RFC 3011 */
282	{ TAG_IP4_SUBNET_SELECT, "iSUBNET" },
283/* RFC 3442 */
284	{ TAG_CLASSLESS_STATIC_RT, "$Classless-Static-Route" },
285	{ TAG_CLASSLESS_STA_RT_MS, "$Classless-Static-Route-Microsoft" },
286/* http://www.iana.org/assignments/bootp-dhcp-extensions/index.htm */
287	{ TAG_USER_CLASS,	"aCLASS" },
288	{ TAG_SLP_NAMING_AUTH,	"aSLP-NA" },
289	{ TAG_CLIENT_FQDN,	"$FQDN" },
290	{ TAG_AGENT_CIRCUIT,	"$Agent-Information" },
291	{ TAG_AGENT_REMOTE,	"bARMT" },
292	{ TAG_AGENT_MASK,	"bAMSK" },
293	{ TAG_TZ_STRING,	"aTZSTR" },
294	{ TAG_FQDN_OPTION,	"bFQDNS" },	/* XXX 'b' */
295	{ TAG_AUTH,		"bAUTH" },	/* XXX 'b' */
296	{ TAG_VINES_SERVERS,	"iVINES" },
297	{ TAG_SERVER_RANK,	"sRANK" },
298	{ TAG_CLIENT_ARCH,	"sARCH" },
299	{ TAG_CLIENT_NDI,	"bNDI" },	/* XXX 'b' */
300	{ TAG_CLIENT_GUID,	"bGUID" },	/* XXX 'b' */
301	{ TAG_LDAP_URL,		"aLDAP" },
302	{ TAG_6OVER4,		"i6o4" },
303	{ TAG_PRINTER_NAME,	"aPRTR" },
304	{ TAG_MDHCP_SERVER,	"bMDHCP" },	/* XXX 'b' */
305	{ TAG_IPX_COMPAT,	"bIPX" },	/* XXX 'b' */
306	{ TAG_NETINFO_PARENT,	"iNI" },
307	{ TAG_NETINFO_PARENT_TAG, "aNITAG" },
308	{ TAG_URL,		"aURL" },
309	{ TAG_FAILOVER,		"bFAIL" },	/* XXX 'b' */
310	{ 0,			NULL }
311};
312/* 2-byte extended tags */
313static struct tok xtag2str[] = {
314	{ 0,			NULL }
315};
316
317/* DHCP "options overload" types */
318static struct tok oo2str[] = {
319	{ 1,			"file" },
320	{ 2,			"sname" },
321	{ 3,			"file+sname" },
322	{ 0,			NULL }
323};
324
325/* NETBIOS over TCP/IP node type options */
326static struct tok nbo2str[] = {
327	{ 0x1,			"b-node" },
328	{ 0x2,			"p-node" },
329	{ 0x4,			"m-node" },
330	{ 0x8,			"h-node" },
331	{ 0,			NULL }
332};
333
334/* ARP Hardware types, for Client-ID option */
335static struct tok arp2str[] = {
336	{ 0x1,			"ether" },
337	{ 0x6,			"ieee802" },
338	{ 0x7,			"arcnet" },
339	{ 0xf,			"frelay" },
340	{ 0x17,			"strip" },
341	{ 0x18,			"ieee1394" },
342	{ 0,			NULL }
343};
344
345static struct tok dhcp_msg_values[] = {
346        { DHCPDISCOVER, "Discover" },
347        { DHCPOFFER, "Offer" },
348        { DHCPREQUEST, "Request" },
349        { DHCPDECLINE, "Decline" },
350        { DHCPACK, "ACK" },
351        { DHCPNAK, "NACK" },
352        { DHCPRELEASE, "Release" },
353        { DHCPINFORM, "Inform" },
354        { 0,			NULL }
355};
356
357#define AGENT_SUBOPTION_CIRCUIT_ID 	1	/* RFC 3046 */
358#define AGENT_SUBOPTION_REMOTE_ID  	2	/* RFC 3046 */
359#define AGENT_SUBOPTION_SUBSCRIBER_ID 	6	/* RFC 3993 */
360static struct tok agent_suboption_values[] = {
361        { AGENT_SUBOPTION_CIRCUIT_ID, "Circuit-ID" },
362        { AGENT_SUBOPTION_REMOTE_ID, "Remote-ID" },
363        { AGENT_SUBOPTION_SUBSCRIBER_ID, "Subscriber-ID" },
364        { 0,			NULL }
365};
366
367
368static void
369rfc1048_print(register const u_char *bp)
370{
371	register u_int16_t tag;
372	register u_int len;
373	register const char *cp;
374	register char c;
375	int first, idx;
376	u_int32_t ul;
377	u_int16_t us;
378	u_int8_t uc, subopt, suboptlen;
379
380	printf("\n\t  Vendor-rfc1048 Extensions");
381
382	/* Step over magic cookie */
383        printf("\n\t    Magic Cookie 0x%08x", EXTRACT_32BITS(bp));
384	bp += sizeof(int32_t);
385
386	/* Loop while we there is a tag left in the buffer */
387	while (TTEST2(*bp, 1)) {
388		tag = *bp++;
389		if (tag == TAG_PAD && vflag < 3)
390			continue;
391		if (tag == TAG_END && vflag < 3)
392			return;
393		if (tag == TAG_EXTENDED_OPTION) {
394			TCHECK2(*(bp + 1), 2);
395			tag = EXTRACT_16BITS(bp + 1);
396			/* XXX we don't know yet if the IANA will
397			 * preclude overlap of 1-byte and 2-byte spaces.
398			 * If not, we need to offset tag after this step.
399			 */
400			cp = tok2str(xtag2str, "?xT%u", tag);
401		} else
402			cp = tok2str(tag2str, "?T%u", tag);
403		c = *cp++;
404
405		if (tag == TAG_PAD || tag == TAG_END)
406			len = 0;
407		else {
408			/* Get the length; check for truncation */
409			TCHECK2(*bp, 1);
410			len = *bp++;
411		}
412
413		printf("\n\t    %s Option %u, length %u%s", cp, tag, len,
414		    len > 0 ? ": " : "");
415
416		if (tag == TAG_PAD && vflag > 2) {
417			u_int ntag = 1;
418			while (TTEST2(*bp, 1) && *bp == TAG_PAD) {
419				bp++;
420				ntag++;
421			}
422			if (ntag > 1)
423				printf(", occurs %u", ntag);
424		}
425
426		if (!TTEST2(*bp, len)) {
427			printf("[|rfc1048 %u]", len);
428			return;
429		}
430
431		if (tag == TAG_DHCP_MESSAGE && len == 1) {
432			uc = *bp++;
433                        printf("%s", tok2str(dhcp_msg_values, "Unknown (%u)", uc));
434                        continue;
435		}
436
437		if (tag == TAG_PARM_REQUEST) {
438			idx = 0;
439			while (len-- > 0) {
440				uc = *bp++;
441				cp = tok2str(tag2str, "?Option %u", uc);
442				if (idx % 4 == 0)
443					printf("\n\t      ");
444				else
445					printf(", ");
446				printf("%s", cp + 1);
447				idx++;
448			}
449			continue;
450		}
451
452		if (tag == TAG_EXTENDED_REQUEST) {
453			first = 1;
454			while (len > 1) {
455				len -= 2;
456				us = EXTRACT_16BITS(bp);
457				bp += 2;
458				cp = tok2str(xtag2str, "?xT%u", us);
459				if (!first)
460					putchar('+');
461				printf("%s", cp + 1);
462				first = 0;
463			}
464			continue;
465		}
466
467		/* Print data */
468		if (c == '?') {
469			/* Base default formats for unknown tags on data size */
470			if (len & 1)
471				c = 'b';
472			else if (len & 2)
473				c = 's';
474			else
475				c = 'l';
476		}
477		first = 1;
478		switch (c) {
479
480		case 'a':
481			/* ascii strings */
482			putchar('"');
483			if (fn_printn(bp, len, snapend)) {
484				putchar('"');
485				goto trunc;
486			}
487			putchar('"');
488			bp += len;
489			len = 0;
490			break;
491
492		case 'i':
493		case 'l':
494		case 'L':
495			/* ip addresses/32-bit words */
496			while (len >= sizeof(ul)) {
497				if (!first)
498					putchar(',');
499				ul = EXTRACT_32BITS(bp);
500				if (c == 'i') {
501					ul = htonl(ul);
502					printf("%s", ipaddr_string(&ul));
503				} else if (c == 'L')
504					printf("%d", ul);
505				else
506					printf("%u", ul);
507				bp += sizeof(ul);
508				len -= sizeof(ul);
509				first = 0;
510			}
511			break;
512
513		case 'p':
514			/* IP address pairs */
515			while (len >= 2*sizeof(ul)) {
516				if (!first)
517					putchar(',');
518				memcpy((char *)&ul, (const char *)bp, sizeof(ul));
519				printf("(%s:", ipaddr_string(&ul));
520				bp += sizeof(ul);
521				memcpy((char *)&ul, (const char *)bp, sizeof(ul));
522				printf("%s)", ipaddr_string(&ul));
523				bp += sizeof(ul);
524				len -= 2*sizeof(ul);
525				first = 0;
526			}
527			break;
528
529		case 's':
530			/* shorts */
531			while (len >= sizeof(us)) {
532				if (!first)
533					putchar(',');
534				us = EXTRACT_16BITS(bp);
535				printf("%u", us);
536				bp += sizeof(us);
537				len -= sizeof(us);
538				first = 0;
539			}
540			break;
541
542		case 'B':
543			/* boolean */
544			while (len > 0) {
545				if (!first)
546					putchar(',');
547				switch (*bp) {
548				case 0:
549					putchar('N');
550					break;
551				case 1:
552					putchar('Y');
553					break;
554				default:
555					printf("%u?", *bp);
556					break;
557				}
558				++bp;
559				--len;
560				first = 0;
561			}
562			break;
563
564		case 'b':
565		case 'x':
566		default:
567			/* Bytes */
568			while (len > 0) {
569				if (!first)
570					putchar(c == 'x' ? ':' : '.');
571				if (c == 'x')
572					printf("%02x", *bp);
573				else
574					printf("%u", *bp);
575				++bp;
576				--len;
577				first = 0;
578			}
579			break;
580
581		case '$':
582			/* Guys we can't handle with one of the usual cases */
583			switch (tag) {
584
585			case TAG_NETBIOS_NODE:
586				/* this option should be at least 1 byte long */
587				if (len < 1)  {
588					printf("ERROR: option %u len %u < 1 bytes",
589					    TAG_NETBIOS_NODE, len);
590					break;
591				}
592				tag = *bp++;
593				--len;
594				fputs(tok2str(nbo2str, NULL, tag), stdout);
595				break;
596
597			case TAG_OPT_OVERLOAD:
598				/* this option should be at least 1 byte long */
599				if (len < 1)  {
600					printf("ERROR: option %u len %u < 1 bytes",
601					    TAG_OPT_OVERLOAD, len);
602					break;
603				}
604				tag = *bp++;
605				--len;
606				fputs(tok2str(oo2str, NULL, tag), stdout);
607				break;
608
609			case TAG_CLIENT_FQDN:
610				/* this option should be at least 3 bytes long */
611				if (len < 3)  {
612					printf("ERROR: option %u len %u < 3 bytes",
613					    TAG_CLIENT_FQDN, len);
614					bp += len;
615					len = 0;
616					break;
617				}
618				if (*bp)
619					printf("[%s] ", client_fqdn_flags(*bp));
620				bp++;
621				if (*bp || *(bp+1))
622					printf("%u/%u ", *bp, *(bp+1));
623				bp += 2;
624				putchar('"');
625				if (fn_printn(bp, len - 3, snapend)) {
626					putchar('"');
627					goto trunc;
628				}
629				putchar('"');
630				bp += len - 3;
631				len = 0;
632				break;
633
634			case TAG_CLIENT_ID:
635			    {	int type;
636
637				/* this option should be at least 1 byte long */
638				if (len < 1)  {
639					printf("ERROR: option %u len %u < 1 bytes",
640					    TAG_CLIENT_ID, len);
641					break;
642				}
643				type = *bp++;
644				len--;
645				if (type == 0) {
646					putchar('"');
647					if (fn_printn(bp, len, snapend)) {
648						putchar('"');
649						goto trunc;
650					}
651					putchar('"');
652					bp += len;
653					len = 0;
654					break;
655				} else {
656					printf("%s ", tok2str(arp2str, "hardware-type %u,", type));
657					while (len > 0) {
658						if (!first)
659							putchar(':');
660						printf("%02x", *bp);
661						++bp;
662						--len;
663						first = 0;
664					}
665				}
666				break;
667			    }
668
669			case TAG_AGENT_CIRCUIT:
670				while (len >= 2) {
671					subopt = *bp++;
672					suboptlen = *bp++;
673					len -= 2;
674					if (suboptlen > len) {
675						printf("\n\t      %s SubOption %u, length %u: length goes past end of option",
676						   tok2str(agent_suboption_values, "Unknown", subopt),
677						   subopt,
678						   suboptlen);
679						bp += len;
680						len = 0;
681						break;
682					}
683					printf("\n\t      %s SubOption %u, length %u: ",
684					   tok2str(agent_suboption_values, "Unknown", subopt),
685					   subopt,
686					   suboptlen);
687					switch (subopt) {
688
689                                        case AGENT_SUBOPTION_CIRCUIT_ID: /* fall through */
690                                        case AGENT_SUBOPTION_REMOTE_ID:
691                                        case AGENT_SUBOPTION_SUBSCRIBER_ID:
692                                                fn_printn(bp, suboptlen, NULL);
693                                                break;
694
695					default:
696						print_unknown_data(bp, "\n\t\t", suboptlen);
697					}
698
699					len -= suboptlen;
700					bp += suboptlen;
701			    }
702			    break;
703
704			case TAG_CLASSLESS_STATIC_RT:
705			case TAG_CLASSLESS_STA_RT_MS:
706			{
707				u_int mask_width, significant_octets, i;
708
709				/* this option should be at least 5 bytes long */
710				if (len < 5)  {
711					printf("ERROR: option %u len %u < 5 bytes",
712					    TAG_CLASSLESS_STATIC_RT, len);
713					bp += len;
714					len = 0;
715					break;
716				}
717				while (len > 0) {
718					if (!first)
719						putchar(',');
720					mask_width = *bp++;
721					len--;
722					/* mask_width <= 32 */
723					if (mask_width > 32) {
724						printf("[ERROR: Mask width (%d) > 32]",  mask_width);
725						bp += len;
726						len = 0;
727						break;
728					}
729					significant_octets = (mask_width + 7) / 8;
730					/* significant octets + router(4) */
731					if (len < significant_octets + 4) {
732						printf("[ERROR: Remaining length (%u) < %u bytes]",  len, significant_octets + 4);
733						bp += len;
734						len = 0;
735						break;
736					}
737					putchar('(');
738					if (mask_width == 0)
739						printf("default");
740					else {
741						for (i = 0; i < significant_octets ; i++) {
742							if (i > 0)
743								putchar('.');
744							printf("%d", *bp++);
745						}
746						for (i = significant_octets ; i < 4 ; i++)
747							printf(".0");
748						printf("/%d", mask_width);
749					}
750					memcpy((char *)&ul, (const char *)bp, sizeof(ul));
751					printf(":%s)", ipaddr_string(&ul));
752					bp += sizeof(ul);
753					len -= (significant_octets + 4);
754					first = 0;
755				}
756			}
757			break;
758
759			default:
760				printf("[unknown special tag %u, size %u]",
761				    tag, len);
762				bp += len;
763				len = 0;
764				break;
765			}
766			break;
767		}
768		/* Data left over? */
769		if (len) {
770			printf("\n\t  trailing data length %u", len);
771			bp += len;
772		}
773	}
774	return;
775trunc:
776	printf("|[rfc1048]");
777}
778
779static void
780cmu_print(register const u_char *bp)
781{
782	register const struct cmu_vend *cmu;
783
784#define PRINTCMUADDR(m, s) { TCHECK(cmu->m); \
785    if (cmu->m.s_addr != 0) \
786	printf(" %s:%s", s, ipaddr_string(&cmu->m.s_addr)); }
787
788	printf(" vend-cmu");
789	cmu = (const struct cmu_vend *)bp;
790
791	/* Only print if there are unknown bits */
792	TCHECK(cmu->v_flags);
793	if ((cmu->v_flags & ~(VF_SMASK)) != 0)
794		printf(" F:0x%x", cmu->v_flags);
795	PRINTCMUADDR(v_dgate, "DG");
796	PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*");
797	PRINTCMUADDR(v_dns1, "NS1");
798	PRINTCMUADDR(v_dns2, "NS2");
799	PRINTCMUADDR(v_ins1, "IEN1");
800	PRINTCMUADDR(v_ins2, "IEN2");
801	PRINTCMUADDR(v_ts1, "TS1");
802	PRINTCMUADDR(v_ts2, "TS2");
803	return;
804
805trunc:
806	fputs(tstr, stdout);
807#undef PRINTCMUADDR
808}
809
810static char *
811client_fqdn_flags(u_int flags)
812{
813	static char buf[8+1];
814	int i = 0;
815
816	if (flags & CLIENT_FQDN_FLAGS_S)
817		buf[i++] = 'S';
818	if (flags & CLIENT_FQDN_FLAGS_O)
819		buf[i++] = 'O';
820	if (flags & CLIENT_FQDN_FLAGS_E)
821		buf[i++] = 'E';
822	if (flags & CLIENT_FQDN_FLAGS_N)
823		buf[i++] = 'N';
824	buf[i] = '\0';
825
826	return buf;
827}
828