openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

decode.c (61690B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * Routines to Decode ethernet/ip packets and print various amounts of 
      8  * information.
      9  */
     10 
     11 #ifndef GHS
     12 #ifndef NO_SAL_APPL
     13 #ifndef __KERNEL__ 
     14 
     15 #ifdef linux
     16 #undef  _POSIX_SOURCE
     17 #undef  _POSIX_C_SOURCE
     18 #undef _GNU_SOURCE
     19 #undef _SVID_SOURCE
     20 #define _BSD_SOURCE
     21 #endif
     22 
     23 #include <sal/types.h>
     24 #include <sys/socket.h>
     25 #include <sys/types.h>
     26 #include <net/if.h>
     27 #include <netinet/in.h>
     28 #include <netinet/tcp.h>
     29 
     30 #include <appl/diag/system.h>
     31 #include <appl/diag/decode.h>
     32 
     33 #if defined(BCM_ESW_SUPPORT)
     34 #include <soc/dcbformats.h>
     35 #include <bcm_int/esw/oam.h>
     36 #endif
     37 
     38 /*
     39  * Macro: 	HDR_DECL
     40  * Purpose:	Used for declaration of a local header pointer. 
     41  * Parameters:	t - type of header
     42  *		h - pointer variable to declare
     43  *		p - pointer to header in packet.
     44  *
     45  * 
     46  * This macro is used as follows:
     47  *
     48  * HDR_DECL(struct foo, local_variable, parameter_pointer)
     49  * 
     50  * Where a variable "struct foo *local_variable" is declared locally, 
     51  * and if p is not 4-byte aligned, a local variable of type "struct foo"
     52  * is also declared, and "local_variable" points to it, otherwise, 
     53  * local_variable will point  directly into the packet. If a local
     54  * variable is used to hold the header, the passed in header is 
     55  * copied into it.
     56  */
     57 #define	HDR_DECL(_t, _h, _p) 					\
     58     _t _h##_aligned_structure;					\
     59     _t *_h = (PTR_TO_INT(_p) & 0x3) ? 				\
     60         (_t *)memcpy(&_h##_aligned_structure, _p, sizeof(_t))	\
     61         : (_t *)(_p)
     62 
     63 #define	DECODE_LIST(_l)	    (_l) , COUNTOF(_l)
     64 
     65 #define	DECODE_LIST_NULL	NULL, 0
     66 
     67 typedef struct decode_list_s {
     68     uint32 		dl_low;		/* Low compare value*/
     69     uint32		dl_high;	/* Hi compare value */
     70     struct decode_s	*dl_decode;	/* Next layer decode */
     71     char		*dl_string;	/* Desciption */
     72 } decode_list_t;
     73 
     74 typedef	struct decode_s {
     75     char		*d_name;	/* Decode "name" ie, IP/Ethernet */
     76     char  		*(*d_df)(const char *, char *, void *, 
     77 				 int, decode_list_t *, void *); 
     78     int			(*d_compare)(decode_list_t *, void *);
     79     int			(*d_length)(decode_list_t *, void *);
     80     decode_list_t	*d_dl;		/* Decode list this type */
     81     int			d_dl_cnt;	/* # entires in decode list */
     82 } decode_t;
     83 
     84 /************************************************************************
     85  ************************************************************************
     86  ************************************************************************
     87  *									*
     88  *	    	      Forward declare decode tables			*
     89  */
     90 
     91 static decode_t d_ether_table;		/* Ethernet Decode */
     92 static decode_t d_arp_table;		/* ARP Decode */
     93 static decode_t	d_ip_table;		/* IP Decode */
     94 static decode_t	d_tcp_table;		/* TCP Decode */
     95 static decode_t d_icmp_table;		/* ICMP Decode */
     96 static decode_t d_oam_table;		/* OAM Decode */
     97 
     98 #if defined(BCM_ESW_SUPPORT)
     99 static decode_t d_oam_lmm_table;		/* OAM LM Decode */
    100 static decode_t d_oam_lmr_table;		/* OAM LM Decode */
    101 static decode_t d_oam_dmm_table;		/* OAM DM Decode */
    102 static decode_t d_oam_dmr_table;		/* OAM DM Decode */
    103 #endif
    104 
    105 static	char	*
    106 d_skip(char *d)
    107 /*
    108  * Function: 	d_skip
    109  * Purpose:	Skip passed all chars in current string.
    110  * Parameters:	d - pointer to string to skip 
    111  * Returns:	Pointer to \0 in d.
    112  */
    113 {
    114     while (*d++)
    115 	;
    116     return(d - 1);
    117 }
    118 
    119 static	char	*
    120 d_strcat(char *d, char *s)
    121 /*
    122  * Function:	d_strcat
    123  * Purpose:	Our local strcat that returns a pointer to the end of
    124  *		the destination string.
    125  * Parameters:	d - destination
    126  *		s - source
    127  * Returns:	Pointer to the end of the destination string (ie. a 
    128  *		pointer to the '\0'
    129  */
    130 {
    131     d = d_skip(d);
    132     while ('\0' != (*d++ = *s++))
    133 	;
    134     return(d - 1);
    135 }
    136 
    137 static	char	*
    138 d_strnl(char *s, const char *pfx)
    139 /*
    140  * Function: 	d_strnl
    141  * Purpose:	Add a newline to the end of a buffer.
    142  * Parameters:	s - pointer to string formatting into.
    143  *		pfx - prefix for output.
    144  * Returns:	Pointer to end of string.
    145  */
    146 {
    147     s = d_skip(s);
    148     s = d_strcat(s, "\n");
    149     s = d_strcat(s, (char *)pfx);
    150     return(s);
    151 }
    152 
    153 static	char	*
    154 d_vformat_bytes(char *s, unsigned char *d, int l, int brk, char sep)
    155 /*
    156  * Function:	p_vformat_bytes
    157  * Pupose:	Format raw hex output.
    158  * Parameters:	s - pointer to string to format into.
    159  *		d - pointer to bytes to format
    160  *		l - length (# bytes to format)
    161  *		brk - # bytes to format before "sep" character inserted.
    162  *		sep - character used to break up stream of bytes.
    163  * Returns:	Pointer to end of string ('\0')
    164  */
    165 {
    166     int	i;
    167 
    168     s = d_skip(s);
    169     for (i = 0; i < l; i++, d++) {
    170 	*s++ = (char)i2xdigit(*d >> 4);
    171 	*s++ = (char)i2xdigit(*d & 0xf);
    172 	if (((i % brk) == (brk - 1)) && (i != (l-1))) {
    173 	    *s++ = sep;
    174 	}
    175     }
    176     *s = '\0';
    177     return(s);
    178 }
    179 
    180 static	char	*
    181 d_strcat_dec_cvt(char *s, unsigned int n)
    182 /*
    183  * Function:	d_strcat_dec_cvt
    184  * Purpose:	Concat a decimal number into a string, but does not
    185  *		null terminate.
    186  * Parameters:	s - pointer to string to concat into.
    187  *		n - number to format.
    188  * Returns:	Pointer to char after end of string.
    189  */
    190 {
    191     if (10 > n) {			/* Bottom out condition */
    192 	*s++ = (char)(n + '0');
    193     } else {
    194 	s = d_strcat_dec_cvt(s, n / 10);
    195 	*s++ = (char)((n % 10) + '0');
    196     }
    197     return(s);
    198 }
    199 
    200 static	char	*
    201 d_strcat_dec(char *s, char *b, unsigned int n, char *a)
    202 /*
    203  * Function:	d_strcat_dec
    204  * Purpose:	Concat a decimal number ito a string.
    205  * Parameters:	s - pointer to string to concat into.
    206  *		b - string to prepend to number (Before)
    207  *		n - number to format.
    208  *		a - string to concat after number (After)
    209  * Returns:	Pointer to end of string ('\0')
    210  */
    211 {
    212     s = d_skip(s);
    213     if (b) {
    214 	s = d_strcat(s, b);
    215     }
    216     if (0 == n) {
    217 	*s++ = '0';
    218     } else {
    219 	s = d_strcat_dec_cvt(s, n);
    220     }
    221     *s = '\0';
    222     if (a) {
    223 	s = d_strcat(s, a);
    224     }
    225     return(s);
    226 }
    227 
    228 static	char	*
    229 d_vformat_dec(char *s, unsigned char *d, int l, int brk, char sep)
    230 /*
    231  * Function:	p_vformat_dev
    232  * Pupose:	Format raw hex output.
    233  * Parameters:	s - pointer to string to format into.
    234  *		d - pointer to bytes to format
    235  *		l - length (# bytes to format)
    236  *		brk - # bytes to format before "sep" character inserted.
    237  *		sep - character used to break up stream of bytes.
    238  * Returns:	Pointer to end of string ('\0')
    239  */
    240 {
    241     int	i;
    242 
    243     for (i = 0; i < l; i++, d++) {
    244 	s = d_strcat_dec(s, NULL, (uint32)*d, NULL);
    245 	if (((i % brk) == (brk -1)) && (i != (l-1))) {
    246 	    *s++ = sep;
    247 	    *s   = '\0';		/* Needed for strcat */
    248 	}
    249     }
    250     *s = '\0';
    251     return(s);
    252 }
    253 
    254 static	char	*
    255 d_vformat_hex(char *s, unsigned int x, int digits, int pfx)
    256 /*
    257  * Function: 	d_vformat_hex
    258  * Purpose:	Format a number of hex digits into a string.
    259  * Parameters:	s - pointer to string to format into.
    260  *		x - number to format
    261  *		digits - number of hex digits, low order nibbles 
    262  *			used to form number.
    263  * Returns:
    264  */
    265 {
    266     if (pfx) {
    267         *s++ = '0';
    268         *s++ = 'x';
    269     }
    270     while (digits--) {
    271 	*s++ = i2xdigit(x >> (digits * 4));
    272     }
    273     *s = '\0';
    274     return(s);
    275 }
    276 
    277 static decode_list_t *
    278 d_find_decode(decode_t *decode, void *hdr, int l)
    279 /*
    280  * Function:	d_find_decode
    281  * Purpose:	Locate an entry in a decode list corresponding to the 
    282  *		current header.
    283  * Parameters:	decode - pointer to decode list.
    284  *		hdr - pointer to current header.
    285  * 		l   - length of current header.
    286  * Returns:	Pointer to decode list entry or NULL if not found.
    287  */
    288 {
    289     int	lo, hi, cur;			/* Binary search values */
    290     decode_list_t *rv = NULL;
    291 
    292     COMPILER_REFERENCE(l);
    293 
    294     /* Perform simple binary search on packet */
    295 
    296     if (decode->d_dl) {			/* If no list, give up now */
    297 	lo   = 0;
    298 	hi = decode->d_dl_cnt - 1;
    299 
    300 	do {
    301 	    cur = lo + (hi - lo) / 2;
    302 	    switch(decode->d_compare(&decode->d_dl[cur], hdr)) {
    303 	    case -1:			/* low */
    304 		hi = cur - 1;
    305 		break;
    306 	    case 0:			/* found */
    307 		rv = &decode->d_dl[cur];
    308 		break;
    309 	    case 1:			/* high */
    310 		lo = cur + 1;
    311 		break;
    312 	    }
    313 	} while (!rv && ((hi - lo) > 0));
    314 
    315 	/* Check if we have just landed on it */ 
    316 	if (!rv && (0 == decode->d_compare(&decode->d_dl[lo], hdr))) {
    317 	    rv = &decode->d_dl[lo];
    318 	}	    
    319     }
    320     return(rv);
    321 }
    322 
    323 static char *
    324 d_decode(const char *pfx, char *s, decode_t *decode, void *hdr, int l, void *pd)
    325 /*
    326  * Function: 	d_decode
    327  * Purpose:	Decode multiple levels of a packet.
    328  * Parameters:	pfx - prefix string attached to each line.
    329  *		s - pointer to string to format into.
    330  *		decode - pointer to decode entry to start from
    331  *		hdr - pointer to shere to start i packet.
    332  *		l - # bytes i packet valid starting at hdr.
    333  * Returns:	Pointer to end of string.
    334  */
    335 {
    336     decode_list_t	*dl;
    337     int			hl;		/* header length */
    338 
    339     if (decode->d_name) {
    340 	s = d_strnl(s, pfx);
    341 	s = d_strcat(s, "  ");
    342 	s = d_strcat(s, decode->d_name);
    343 	s = d_strcat(s, ": ");
    344     }
    345     dl = d_find_decode(decode, hdr, l); /* Find this level decode */
    346     if (decode->d_df) {
    347 	/*
    348 	 * May or may not be further decode function at a given 
    349 	 * level.
    350 	 */
    351 	s = decode->d_df(pfx, s, hdr, l, dl, pd);
    352     }
    353     if (dl) {
    354 	hl = decode->d_length(dl, hdr);
    355 	hdr = (void *)((char *)hdr + hl);
    356 	l -= hl;			/* Remove our header */
    357 	if (dl->dl_decode) {		/* Next level if there */
    358 	    s = d_decode(pfx, s, dl->dl_decode, hdr, l, pd);
    359 	}
    360     } else {				/* end of the line */
    361 	if (!decode->d_df) {
    362 	s = d_strcat(s, ": ");
    363 	s = d_vformat_bytes(s, hdr, 20, 1, ' ');
    364     }
    365     }
    366     return(s);
    367 }
    368 
    369 /************************************************************************
    370  ************************************************************************
    371  ************************************************************************
    372  *									*
    373  *			       	Ethernet 				*
    374  */
    375 
    376 #include <soc/enet.h>
    377 
    378 static	int
    379 d_ether_compare(decode_list_t *dl, void *hdr)
    380 /*
    381  * Function:	d_ether_compare
    382  * Purpose:    	Compare routine for ethernet packet type.
    383  * Parameters:	dl - pointer to entry to compare.
    384  *		hdr - pointer to ethernet header to compare.
    385  * Returns:	-1 - hdr LESS than hdr
    386  *		0  - hdr EQUAL hdr
    387  *		1  - hdr GREATER than hdr
    388  * Notes:	If LEN < 0x600, it is an 802.3 packet, otherwise
    389  *		type field indicates packet type. The 802.3 "entry" is 
    390  *		the first entry so we make sure we zoom in on it.
    391  */
    392 {
    393     enet_hdr_t *eh = (enet_hdr_t *)hdr;
    394     uint16	t;
    395 
    396     if (ENET_TAGGED(eh)) {
    397 	t = bcm_ntohs(eh->en_tag_len);
    398     } else {
    399 	t = bcm_ntohs(eh->en_untagged_len);
    400     }
    401 	
    402     if (dl->dl_low > t) {
    403 	return(-1);
    404     } else if (dl->dl_high < t) {
    405 	return(1);
    406     } else {
    407 	return(0);
    408     }
    409 }
    410 
    411 char *
    412 d_ether_decode(const char *pfx, char *s, void *ehp, int el, decode_list_t *dl, void *pd)
    413 /*
    414  * Function:	p_ether_decode
    415  * Purpose: 	Format ethernet header into string.
    416  * Parameters:	pfx - prefix for output.
    417  *		s - pointer to string to format into
    418  *		ehp - ethernet header
    419  *		el - length of packet starting at eh
    420  *		dl - pointer to data list entry matching
    421  * Returns:	Pointer to where string ends ('\0')
    422  */
    423 {
    424     enet_hdr_t *eh = (enet_hdr_t *)ehp;
    425 
    426     COMPILER_REFERENCE(pfx);
    427     COMPILER_REFERENCE(pd);
    428 
    429     /*
    430      * Make a best guess at if the header is a valid length, if it
    431      * is less that min length (UNTAGGED) or if it is less that
    432      * a calculated length it is in error. This is not perfect, but it is
    433      * close enough for now.
    434      */
    435     if ((el < ENET_UNTAGGED_HDR_LEN) ||
    436 	(el < ENET_HDR_LEN(eh))) {
    437 	s = d_strcat_dec(s, "ETHER (***INVALID LENGTH ", el, "***):");
    438 	s = d_vformat_bytes(s, (unsigned char *)eh, el, 1, ' ');
    439 	return(s);
    440     }
    441 
    442     s = d_strcat(s, "dst<");
    443     s = d_vformat_bytes(s,(unsigned char *)&eh->en_dhost, 
    444 			sizeof(eh->en_dhost), 1, ':');
    445     s = d_strcat(s, "> src<");
    446     s = d_vformat_bytes(s,(unsigned char *)&eh->en_shost, 
    447 			sizeof(eh->en_shost), 1, ':');
    448     s = d_strcat(s, "> ");
    449 
    450     if (ENET_SNAP(eh)) {
    451 	s = d_strcat(s, "SNAP Packet ");
    452     } else if (ENET_TAGGED(eh)) {
    453 	s = d_strcat(s, "Tagged Packet ");
    454     } else {
    455 	s = d_strcat(s, "Untagged Packet ");
    456     }
    457 
    458     if (ENET_SNAP(eh) || (ENET_TAGGED(eh))) {
    459 	s = d_strcat(s, "ProtID<");
    460 	s = d_vformat_hex(s, bcm_ntohs(eh->en_tag_tpid), 4, 1);
    461 	s = d_strcat(s, "> Ctrl<");
    462 	s = d_vformat_hex(s, bcm_ntohs(eh->en_tag_ctrl), 4, 1);
    463 	s = d_strcat(s, "> ");
    464     } else if (bcm_ntohs(eh->en_untagged_len) < 0x600) {
    465 	s = d_strcat_dec(s, "Length<",bcm_ntohs(eh->en_untagged_len),"-bytes> ");
    466     }
    467    
    468     if (dl) {
    469 	s = d_strcat(s, dl->dl_string);
    470     } else {
    471 	s = d_strcat(s, "* Unknown/Experimental format * ");
    472 	s = d_vformat_bytes(s, (unsigned char *)eh, 64 > el ? el : 64, 1, 
    473 			    ' ');
    474     }
    475 
    476     return(s);
    477 }
    478 
    479 /*ARGSUSED*/
    480 static	int
    481 d_ether_length(decode_list_t *dl, void *ehp)
    482 /*
    483  * Function:	d_ether_length
    484  * Purpose:	Determine the length of the ethernet header.
    485  * Parameters:	dl - pointer to decode list entry.
    486  *		ehp - pointer to ethernet header.
    487  * Returns:	Integer length.
    488  * Notes:	For tagged packets, the ethernet header is larger.
    489  */
    490 {
    491     enet_hdr_t	*eh = (enet_hdr_t *)ehp;
    492 
    493     COMPILER_REFERENCE(dl);
    494     return(ENET_HDR_LEN(eh));
    495 }
    496 
    497 static decode_list_t	d_ether_type[] = {
    498     {0x0000,	0x0600,	&d_ip_table,"802.3 Packet"},
    499     {0x0800,	0x0800,	&d_ip_table,"Internet Protocol (IP)"},
    500     {0x0801,	0x0801,	NULL,	"X.75 Internet"},
    501     {0x0802,	0x0802,	NULL,	"NBS Internet"},
    502     {0x0803,	0x0803,	NULL,	"ECMA Internet"},
    503     {0x0804,	0x0804,	NULL,	"CHAOSnet"},
    504     {0x0805,	0x0805,	NULL,	"X.25 Level 3"},
    505     {0x0806,	0x0806,	&d_arp_table,	"ARP (IP and CHAOS)"},
    506     {0x0807,	0x0807,	NULL,	"XNS Compatibility"},
    507     {0x081C,	0x081C,	NULL,	"Symbolics Private"},
    508     {0x0888,	0x088a,	NULL,	"Xyplex"},
    509     {0x0900,	0x0900,	NULL,	"Ungermann-Bass network debugger"},
    510     {0x0A00,	0x0A00,	NULL,	"Xerox IEEE802.3 PUP"},
    511     {0x0A01,	0x0A01,	NULL,	"Xerox IEEE802.3 PUP Address Translation"},
    512     {0x0BAD,	0x0BAD,	NULL,	"Banyan Systems"},
    513     {0x0BAF,	0x0BAF,	NULL,	"Banyon VINES Echo"},
    514     {0x1000,	0x100f,	NULL,	"Berkeley Trailer negotiation"},
    515     {0x1234,	0x1234,	NULL,	"DCA - Multicast"},
    516     {0x1600,	0x1600,	NULL,	"VALID system protocol"},
    517     {0x1989,	0x1989,	NULL,	"Artificial Horizons (\"Aviator\" dogfight "
    518 	                        "simulator [on Sun])"},
    519     {0x1995,	0x1995,	NULL,	"Datapoint Corporation (RCL lan protocol)"},
    520     {0x3C00,	0x3C00,	NULL,	"3Com NBP virtual circuit datagram (like "
    521 	                        "XNS SPP) not registered"},
    522     {0x3C01,	0x3C01,	NULL,	"3Com NBP System control datagram not "
    523 	                        "registered"},
    524     {0x3C02,	0x3C02,	NULL,	"3Com NBP Connect request (virtual cct) "
    525 	                        "not registered"},
    526     {0x3C03,	0x3C03,	NULL,	"3Com NBP Connect response not registered"},
    527     {0x3C04,	0x3C04,	NULL,	"3Com NBP Connect complete not registered"},
    528     {0x3C05,	0x3C05,	NULL,	"3Com NBP Close request (virtual cct) "
    529 	                        "not registered"},
    530     {0x3C06,	0x3C06,	NULL,	"3Com NBP Close response not registered"},
    531     {0x3C07,	0x3C07,	NULL,	"3Com NBP Datagram (like XNS IDP) not "
    532 	                        "registered"},
    533     {0x3C08,	0x3C08,	NULL,	"3Com NBP Datagram broadcast not "
    534 	                        "registered"},
    535     {0x3C09,	0x3C09,	NULL,	"3Com NBP Claim NetBIOS name not "
    536 	                        "registered"},
    537     {0x3C0A,	0x3C0A,	NULL,	"3Com NBP Delete Netbios name not "
    538 	                        "registered"},
    539     {0x3C0B,	0x3C0B,	NULL,	"3Com NBP Remote adaptor status request "
    540 	                        "not registered"},
    541     {0x3C0C,	0x3C0C,	NULL,	"3Com NBP Remote adaptor response not "
    542 	                        "registered"},
    543     {0x3C0D,	0x3C0D,	NULL,	"3Com NBP Reset not registered"},
    544     {0x4242,	0x4242,	NULL,	"PCS Basic Block Protocol"},
    545     {0x424C,	0x424C,	NULL,	"Information Modes Little Big LAN "
    546 	                        "diagnostic"},
    547     {0x4321,	0x4321,	NULL,	"THD - Diddle"},
    548     {0x4C42,	0x4C42,	NULL,	"Information Modes Little Big LAN"},
    549     {0x5208,	0x5208,	NULL,	"BBN Simnet Private"},
    550     {0x6000,	0x6000,	NULL,	"DEC unassigned, experimental"},
    551     {0x6001,	0x6001,	NULL,	"DEC Maintenance Operation Protocol (MOP) "
    552 	                        "Dump/Load Assistance"},
    553     {0x6002,	0x6002,	NULL,	"DEC Maintenance Operation Protocol (MOP) "
    554 	                        "Remote Console"},
    555     {0x6003,	0x6003,	NULL,	"DECNET Phase IV, DNA Routing"},
    556     {0x6004,	0x6004,	NULL,	"DEC Local Area Transport (LAT)"},
    557     {0x6005,	0x6005,	NULL,	"DEC diagnostic protocol (at interface "
    558 	                        "initialization)"},
    559     {0x6006,	0x6006,	NULL,	"DEC customer protocol"},
    560     {0x6007,	0x6007,	NULL,	"DEC Local Area VAX Cluster,System "
    561 	                        "Communication Architecture"},
    562     {0x6008,	0x6008,	NULL,	"DEC AMBER"},
    563     {0x6009,	0x6009,	NULL,	"DEC MUMPS"},
    564     {0x6010,	0x6014,	NULL,	"3Com Corporation"},
    565     {0x7000,	0x7000,	NULL,	"Ungermann-Bass download"},
    566     {0x7001,	0x7001,	NULL,	"Ungermann-Bass NIUs"},
    567     {0x7002,	0x7002,	NULL,	"Ungermann-Bass diagnostic/loopback"},
    568     {0x7003,	0x7003,	NULL,	"Ungermann-Bass (NMC to/from UB Bridge)"},
    569     {0x7005,	0x7005,	NULL,	"Ungermann-Bass Bridge Spanning Tree"},
    570     {0x7007,	0x7007,	NULL,	"OS/9 Microware"},
    571     {0x7009,	0x7009,	NULL,	"OS/9 Net"},
    572     {0x7020,	0x7029,	NULL,	"LRT (England) (now Sintrom)"},
    573     {0x7030,	0x7030,	NULL,	"Racal-Interlan"},
    574     {0x7031,	0x7031,	NULL,	"Prime NTS (Network Terminal Service)"},
    575     {0x7034,	0x7034,	NULL,	"Cabletron"},
    576     {0x8003,	0x8003,	NULL,	"Cronus VLN"},
    577     {0x8004,	0x8004,	NULL,	"Cronus Direct"},
    578     {0x8005,	0x8005,	NULL,	"HP Probe protocol"},
    579     {0x8006,	0x8006,	NULL,	"Nestar"},
    580     {0x8008,	0x8008,	NULL,	"AT&T/Stanford University"},
    581     {0x8010,	0x8010,	NULL,	"Excelan"},
    582     {0x8013,	0x8013,	NULL,	"Silicon Graphics diagnostic"},
    583     {0x8014,	0x8014,	NULL,	"Silicon Graphics network games"},
    584     {0x8015,	0x8015,	NULL,	"Silicon Graphics reserved"},
    585     {0x8016,	0x8016,	NULL,	"Silicon Graphics XNS NameServer, bounce " 
    586 	                        "server"},
    587     {0x8019,	0x8019,	NULL,	"Apollo DOMAIN"},
    588     {0x802E,	0x802E,	NULL,	"Tymshare"},
    589     {0x802F,	0x802F,	NULL,	"Tigan, Inc."},
    590     {0x8035,	0x8035,	NULL,	"Reverse Address Resolution Protocol "
    591 	                        "(RARP)"},
    592     {0x8036,	0x8036,	NULL,	"Aeonic Systems"},
    593     {0x8037,	0x8037,	NULL,	"IPX (Novell Netware)"},
    594     {0x8038,	0x8038,	NULL,	"DEC LanBridge Management"},
    595     {0x8039,	0x8039,	NULL,	"DEC DSM/DDP"},
    596     {0x803A,	0x803A,	NULL,	"DEC Argonaut Console"},
    597     {0x803B,	0x803B,	NULL,	"DEC VAXELN"},
    598     {0x803C,	0x803C,	NULL,	"DEC DNS Naming Service"},
    599     {0x803D,	0x803D,	NULL,	"DEC Ethernet CSMA/CD Encryption Protocol"},
    600     {0x803E,	0x803E,	NULL,	"DEC Distributed Time Service"},
    601     {0x803F,	0x803F,	NULL,	"DEC LAN Traffic Monitor Protocol"},
    602     {0x8040,	0x8040,	NULL,	"DEC PATHWORKS DECnet NETBIOS Emulation"},
    603     {0x8041,	0x8041,	NULL,	"DEC Local Area System Transport"},
    604     {0x8042,	0x8042,	NULL,	"DEC unassigned"},
    605     {0x8044,	0x8044,	NULL,	"Planning Research Corp."},
    606     {0x8046,	0x8046,	NULL,	"AT&T"},
    607     {0x8047,	0x8047,	NULL,	"AT&T"},
    608     {0x8048,	0x8048,	NULL,	"DEC Availability Manager for Distributed "
    609 	                        "Systems DECamds"},
    610     {0x8049,	0x8049,	NULL,	"ExperData"},
    611     {0x805B,	0x805B,	NULL,	"VMTP (Versatile Message Transaction "
    612 	                        "Protocol,RFC-1045) (Stanford)"},
    613     {0x805C,	0x805C,	NULL,	"Stanford V Kernel, version 6.0"},
    614     {0x805D,	0x805D,	NULL,	"Evans & Sutherland"},
    615     {0x8060,	0x8060,	NULL,	"Little Machines"},
    616     {0x8062,	0x8062,	NULL,	"Counterpoint Computers"},
    617     {0x8065,	0x8065,	NULL,	"University of Mass. at Amherst"},
    618     {0x8066,	0x8066,	NULL,	"University of Mass. at Amherst"},
    619     {0x8067,	0x8067,	NULL,	"Veeco Integrated Automation"},
    620     {0x8068,	0x8068,	NULL,	"General Dynamics"},
    621     {0x8069,	0x8069,	NULL,	"AT&T"},
    622     {0x806A,	0x806A,	NULL,	"Autophon"},
    623     {0x806C,	0x806C,	NULL,	"ComDesign"},
    624     {0x806D,	0x806D,	NULL,	"Compugraphic Corporation"},
    625     {0x806E,	0x8077,	NULL,	"Landmark Graphics Corporation"},
    626     {0x807A,	0x807A,	NULL,	"Matra"},
    627     {0x807B,	0x807B,	NULL,	"Dansk Data Elektronik"},
    628     {0x807C,	0x807C,	NULL,	"Merit Internodal (or Univ of Michigan)"},
    629     {0x807D,	0x807f,	NULL,	"Vitalink Communications"},
    630     {0x8080,	0x8080,	NULL,	"Vitalink TransLAN III Management"},
    631     {0x8081,	0x8083,	NULL,	"Counterpoint Computers"},
    632     {0x8088,	0x808a,	NULL,	"Xyplex"},
    633     {0x809B,	0x809B,	NULL,	"EtherTalk (AppleTalk over Ethernet)"},
    634     {0x809C,	0x809C,	NULL,	"Datability"},
    635     {0x809D,	0x809D,	NULL,	"Datability"},
    636     {0x809E,	0x809E,	NULL,	"Datability"},
    637     {0x809F,	0x809F,	NULL,	"Spider Systems Ltd."},
    638     {0x80A3,	0x80A3,	NULL,	"Nixdorf Computers"},
    639     {0x80A4,	0x80b3,	NULL,	"Siemens Gammasonics Inc."},
    640     {0x80C0,	0x80c3,	NULL,	"DCA (Digital Comm. Assoc.) Data Exchange "
    641 	                        "Cluster"},
    642     {0x80C6,	0x80C6,	NULL,	"Pacer Software"},
    643     {0x80C7,	0x80C7,	NULL,	"Applitek Corporation"},
    644     {0x80C8,	0x80cc,	NULL,	"Intergraph Corporation"},
    645     {0x80CD,	0x80CD,	NULL,	"Harris Corporation"},
    646     {0x80CE,	0x80CE,	NULL,	"Harris Corporation"},
    647     {0x80CF,	0x80d2,	NULL,	"Taylor Instrument"},
    648     {0x80D3,	0x80D4,	NULL,	"Rosemount Corporation"},
    649     {0x80D5,	0x80D5,	NULL,	"IBM SNA Services over Ethernet"},
    650     {0x80DD,	0x80DD,	NULL,	"Varian Associates"},
    651     {0x80DE,	0x80DE,	NULL,	"TRFS (Integrated Solutions Transparent "
    652 	                        "Remote File System)"},
    653     {0x80DF,	0x80DF,	NULL,	"TRFS (Integrated Solutions Transparent "
    654 	                        "Remote File System)"},
    655     {0x80E0,	0x80E3,	NULL,	"Allen-Bradley"},
    656     {0x80E4,	0x80ed,	NULL,	"Datability"},
    657     {0x80EF,	0x80f0,	NULL,	"Datability"},
    658     {0x80F2,	0x80F2,	NULL,	"Retix"},
    659     {0x80F3,	0x80F3,	NULL,	"AppleTalk Address Resolution Protocol "
    660 	                        "(AARP)"},
    661     {0x80F4,	0x80F4,	NULL,	"Kinetics"},
    662     {0x80F5,	0x80F5,	NULL,	"Kinetics"},
    663     {0x80F7,	0x80F7,	NULL,	"Apollo Computer"},
    664     {0x80FF,	0x8101,	NULL,	"Wellfleet Communications"},
    665     {0x8102,	0x8102,	NULL,	"Wellfleet; BOFL (Breath OF Life) pkts "
    666 	                        "[every 5-10 secs.]"},
    667     {0x8103,	0x8103,	NULL,	"Wellfleet Communications"},
    668     {0x8107,	0x8109,	NULL,	"Symbolics Private"},
    669     {0x812B,	0x812B,	NULL,	"Talaris"},
    670     {0x8130,	0x8130,	NULL,	"Waterloo Microsystems Inc."},
    671     {0x8131,	0x8131,	NULL,	"VG Laboratory Systems"},
    672     {0x8137,	0x8137,	NULL,	"Novell (old) NetWare IPX (ECONFIG E "
    673 	                        "option)"},
    674     {0x8138,	0x8138,	NULL,	"Novell, Inc."},
    675     {0x8139,	0x8139,	NULL,	"KTI"},
    676     {0x813a,	0x813a,	NULL,	"KTI"},
    677     {0x813b,	0x813b,	NULL,	"KTI"},
    678     {0x813c,	0x813c,	NULL,	"KTI"},
    679     {0x813d,	0x813d,	NULL,	"KTI"},
    680     {0x813F,	0x813F,	NULL,	"M/MUMPS data sharing"},
    681     {0x8145,	0x8147,	NULL,	"Vrije Universiteit (NL"},
    682     {0x814C,	0x814C,	NULL,	"SNMP over Ethernet (see RFC1089)"},
    683     {0x814F,	0x814F,	NULL,	"Technically Elite Concept"},
    684     {0x8191,	0x8191,	NULL,	"PowerLA"},
    685     {0x817D,	0x817D,	NULL,	"XTP"},
    686     {0x81D6,	0x81D6,	NULL,	"Artisoft Lantastic"},
    687     {0x81D7,	0x81D7,	NULL,	"Artisoft Lantastic"},
    688     {0x8203,	0x8205,	NULL,	"QNX Software Systems Ltd."},
    689     {0x8390,	0x8390,	NULL,	"Accton Technologies (unregistered)"},
    690     {0x852B,	0x852B,	NULL,	"Talaris multicast"},
    691     {0x8582,	0x8582,	NULL,	"Kalpana"},
    692     {0x86DD,	0x86DD,	NULL,	"IP version 6"},
    693     {0x8739,	0x8739,	NULL,	"Control Technology Inc"},
    694     {0x873A,	0x873A,	NULL,	"Control Technology Inc"},
    695     {0x873B,	0x873B,	NULL,	"Control Technology Inc"},
    696     {0x873C,	0x873C,	NULL,	"Control Technology Inc"},
    697     {0x8820,	0x8820,	NULL,	"Hitachi Cable (Optoelectronic Systems "
    698 	                        "Laboratory)"},
    699     {0x8856,	0x8856,	NULL,	"Axis Communications AB"},
    700     {0x8888,	0x8888,	NULL,	"HP LanProbe test"},
    701     {0x8902,	0x8902,	&d_oam_table,"OAM"},
    702     {0x9000,	0x9000,	NULL,	"Loopback (Configuration Test Protocol)"},
    703     {0x9001,	0x9001,	NULL,	"3Com (Formerly Bridge Communications), "
    704 	                        "XNS Systems Management"},
    705     {0x9002,	0x9002,	NULL,	"3Com (Formerly Bridge Communications), "
    706 	                        "TCP/IP Systems Management"},
    707     {0x9003,	0x9003,	NULL,	"3Com (Formerly Bridge Communications), "
    708 	                        "loopback detection"},
    709     {0xAAAA,	0xAAAA,	NULL,	"DECNET"},
    710     {0xFAF5,	0xFAF5,	NULL,	"Sonix Arpeggio"},
    711     {0xFF00,	0xFF00,	NULL,	"BBN VITAL-LanBridge cache wakeups"},
    712 };
    713 /*
    714  * Ethernet decode table.
    715  */
    716 static decode_t d_ether_table = {
    717     "Ethernet",
    718     d_ether_decode, 
    719     d_ether_compare,
    720     d_ether_length, 
    721     DECODE_LIST(d_ether_type)
    722 };
    723 
    724 /************************************************************************
    725  ************************************************************************
    726  ************************************************************************
    727  *									*
    728  *			       	ARP	 				*
    729  */
    730 /* From <net/if_arp.h> which does not exist on all systems */
    731 struct arphdr {
    732     uint16 ar_hrd;
    733     uint16 ar_pro;
    734     uint8 ar_hln;
    735     uint8 ar_pln;
    736     uint8 ar_op;
    737 };
    738 
    739 static	int
    740 d_arp_compare(decode_list_t *dl, void *ahp)
    741 /*
    742  * Function:	d_arp_compare
    743  * Purpose:    	Compare routine for arp packet type.
    744  * Parameters:	dl - pointer to entry to compare.
    745  *		hdr - pointer to arp header to compare.
    746  * Returns:	-1 - hdr LESS than dl
    747  *		0  - hdr EQUAL dl
    748  *		1  - hdr GREATER than dl
    749  */
    750 {
    751     HDR_DECL(struct arphdr, ah, ahp);
    752 
    753     if (dl->dl_low > bcm_ntohs(ah->ar_op)) {
    754 	return(-1);
    755     } else if (dl->dl_high < bcm_ntohs(ah->ar_op)) {
    756 	return(1);
    757     } else {
    758 	return(0);
    759     }
    760 }
    761 
    762 char *
    763 d_arp_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
    764 /*
    765  * Function:	p_arp_decode
    766  * Purpose: 	Format arp header into string.
    767  * Parameters:	pfx - output prefix
    768  *		s - pointer to string to format into
    769  *		ahp - arp header
    770  *		el - length of packet starting at ahp
    771  *		dl - pointer to data list entry matching
    772  * Returns:	Pointer to where string ends ('\0')
    773  */
    774 {
    775     HDR_DECL(struct arphdr, ah, ahp);
    776     unsigned char *aptr = (unsigned char *)ahp + sizeof(struct arphdr);
    777 
    778     COMPILER_REFERENCE(pfx);
    779     COMPILER_REFERENCE(pd);
    780 
    781     if (el < (int)sizeof(struct arphdr)) {
    782 	s = d_strcat(s, "ARP (***INVALID***):");
    783 	s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
    784 	return(s);
    785     }
    786 
    787     s = d_strcat(s, dl->dl_string);
    788     s = d_strcat_dec(s, " fmt<", bcm_ntohs(ah->ar_hrd), "> src-ha<");
    789     s = d_vformat_bytes(s, aptr, ah->ar_hln, 1, ':');
    790     aptr += ah->ar_hln;
    791     s = d_strcat(s, "> src_pa<");
    792     s = d_vformat_dec(s, aptr, ah->ar_pln, 1, ':');
    793     aptr += ah->ar_pln;
    794     s = d_strcat(s, "> tar_ha<");
    795     s = d_vformat_bytes(s, aptr, ah->ar_hln, 1, ':');
    796     aptr += ah->ar_hln;
    797     s = d_strcat(s, "> tar_pa<");
    798     s = d_vformat_dec(s, aptr, ah->ar_pln, 1, ':');
    799     aptr += ah->ar_pln;
    800     s = d_strcat(s, ">");
    801     
    802     return(s);
    803 }
    804 
    805 static	int
    806 d_arp_length(decode_list_t *dl, void *ahp)
    807 /*
    808  * Function:	d_arp_length
    809  * Purpose:	Determine the length of the arp header.
    810  * Parameters:	dl - pointer to decode list entry.
    811  *		ehp - pointer to arp header.
    812  * Returns:	Integer length.
    813  */
    814 {
    815     HDR_DECL(struct arphdr, ah, ahp);
    816 
    817     COMPILER_REFERENCE(dl);
    818 
    819     return(sizeof(struct arphdr) + ah->ar_hln * 2 + ah->ar_pln * 2);
    820 }
    821 
    822 static decode_list_t	d_arp_type[] = {
    823      {0, 0, 	NULL, 	"Invalid (0)"},
    824      {1, 1, 	NULL, 	"Request [RFC826]"},
    825      {2, 2,  	NULL,	"Reply [RFC826]"},
    826      {3, 3,  	NULL,	"Request Reverse (RARP) [RFC903]"},
    827      {4, 4,  	NULL,	"Reply Reverse (RARP) [RFC903]"},
    828      {5, 5,  	NULL,	"DRARP-Request [David Brownell]"},
    829      {6, 6,  	NULL,	"DRARP-Reply [David Brownell]"},
    830      {7, 7,  	NULL,	"DRARP-Error [David Brownell]"},
    831      {8, 8,  	NULL,	"InARP-Request [RFC1293]"},
    832      {9, 9,  	NULL,	"InARP-Reply [RFC1293]"},
    833     {10, 10,  	NULL,	"ARP-NAK [RFC1577]"},
    834     {11, 11,  	NULL,	"MARS-Request [Armitage]"},
    835     {12, 12,  	NULL,	"MARS-Multi [Armitage]"},
    836     {13, 13,  	NULL,	"MARS-MServ [Armitage]"},
    837     {14, 14,  	NULL,	"MARS-Join [Armitage]"},
    838     {15, 15,  	NULL,	"MARS-Leave [Armitage]"},
    839     {16, 16,  	NULL,	"MARS-NAK [Armitage]"},
    840     {17, 17,  	NULL,	"MARS-Unserv [Armitage]"},
    841     {18, 18,  	NULL,	"MARS-SJoin [Armitage]"},
    842     {19, 19,  	NULL,	"MARS-SLeave [Armitage]"},
    843     {20, 20,  	NULL,	"MARS-Grouplist-Request [Armitage]"},
    844     {21, 21,  	NULL,	"MARS-Grouplist-Reply [Armitage]"},
    845     {22, 22,  	NULL,	"MARS-Redirect-Map [Armitage]"},
    846     {23, 23,  	NULL,	"MAPOS-UNARP [Maruyama]"},
    847     {24, 0xffff,NULL, 	"Undefined"}
    848 };
    849     
    850 static decode_t d_arp_table = {
    851     "ARP",
    852     d_arp_decode, 
    853     d_arp_compare,
    854     d_arp_length, 
    855     DECODE_LIST(d_arp_type)
    856 };
    857 
    858 #if defined(BCM_ESW_SUPPORT)
    859 static	int
    860 d_oam_compare(decode_list_t *dl, void *ahp)
    861 /*
    862  * Function:	d_arp_compare
    863  * Purpose:    	Compare routine for arp packet type.
    864  * Parameters:	dl - pointer to entry to compare.
    865  *		hdr - pointer to arp header to compare.
    866  * Returns:	-1 - hdr LESS than dl
    867  *		0  - hdr EQUAL dl
    868  *		1  - hdr GREATER than dl
    869  */
    870 {
    871     HDR_DECL(oam_hdr_t, ah, ahp);
    872 
    873     if (dl->dl_low > ah->opcode) {
    874 	return(-1);
    875     } else if (dl->dl_high < ah->opcode) {
    876 	return(1);
    877     } else {
    878 	return(0);
    879     }
    880 }
    881 
    882 char *
    883 d_oam_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
    884 /*
    885  * Function:	p_arp_decode
    886  * Purpose: 	Format arp header into string.
    887  * Parameters:	pfx - output prefix
    888  *		s - pointer to string to format into
    889  *		ahp - arp header
    890  *		el - length of packet starting at ahp
    891  *		dl - pointer to data list entry matching
    892  * Returns:	Pointer to where string ends ('\0')
    893  */
    894 {
    895     HDR_DECL(oam_hdr_t, ah, ahp);
    896 
    897     COMPILER_REFERENCE(pfx);
    898     COMPILER_REFERENCE(pd);
    899 
    900     if (el < (int)sizeof(oam_hdr_t)) {
    901 	s = d_strcat(s, "OAM (***INVALID***):");
    902 	s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
    903 	return(s);
    904     }
    905 
    906     s = d_strcat(s, dl->dl_string);
    907     s = d_strcat_dec(s, " mdl<", (ah->mdl_ver >> 5), ">");
    908     s = d_strcat_dec(s, " opcode<", ah->opcode, ">");
    909     s = d_strcat_dec(s, " flag<", ah->flags, ">");
    910     s = d_strcat_dec(s, " first_tlvoffset<", ah->first_tlvoffset, ">");
    911     
    912     return(s);
    913 }
    914 
    915 static	int
    916 d_oam_length(decode_list_t *dl, void *ahp)
    917 /*
    918  * Function:	d_arp_length
    919  * Purpose:	Determine the length of the arp header.
    920  * Parameters:	dl - pointer to decode list entry.
    921  *		ehp - pointer to arp header.
    922  * Returns:	Integer length.
    923  */
    924 {
    925     COMPILER_REFERENCE(ahp);
    926     COMPILER_REFERENCE(dl);
    927 
    928     return(sizeof(oam_hdr_t));
    929 }
    930 
    931 char *
    932 d_oam_lmr_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
    933 /*
    934  * Function:	p_arp_decode
    935  * Purpose: 	Format arp header into string.
    936  * Parameters:	pfx - output prefix
    937  *		s - pointer to string to format into
    938  *		ahp - oam header
    939  *		el - length of packet starting at ahp
    940  *		dl - pointer to data list entry matching
    941  * Returns:	Pointer to where string ends ('\0')
    942  */
    943 {
    944 #ifdef BCM_ENDURO_SUPPORT
    945     dcb20_t *pdcb;
    946 #endif
    947     HDR_DECL(oam_lm_pkt_t, ah, ahp);
    948 
    949     COMPILER_REFERENCE(pfx);
    950 
    951     if (el < (int)sizeof(oam_lm_pkt_t)) {
    952         s = d_strcat(s, "LMR (***INVALID***):");
    953         s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
    954         return(s);
    955     }
    956     
    957     s = d_strcat(s, "TxFCf:<");
    958     s = d_vformat_hex(s, bcm_ntohl(ah->txfcf), 8, 1);
    959     s = d_strcat(s, "> RxFCf:<");
    960     s = d_vformat_hex(s, bcm_ntohl(ah->rxfcf), 8, 1);
    961     s = d_strcat(s, "> TxFCb:<");
    962     s = d_vformat_hex(s, bcm_ntohl(ah->txfcb), 8, 1);
    963     s = d_strcat(s, ">");
    964 #ifdef BCM_ENDURO_SUPPORT    
    965     if (pd) {
    966         pdcb = (dcb20_t *)pd;
    967         s = d_strcat(s, " RxFCb:<");
    968         s = d_vformat_hex(s, pdcb->timestamp, 8, 1);
    969         s = d_strcat(s, ">");
    970     }
    971 #endif    
    972     return(s);
    973 }
    974 
    975 char *
    976 d_oam_lmm_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
    977 /*
    978  * Function:	p_arp_decode
    979  * Purpose: 	Format arp header into string.
    980  * Parameters:	pfx - output prefix
    981  *		s - pointer to string to format into
    982  *		ahp - oam header
    983  *		el - length of packet starting at ahp
    984  *		dl - pointer to data list entry matching
    985  * Returns:	Pointer to where string ends ('\0')
    986  */
    987 {
    988 #ifdef BCM_ENDURO_SUPPORT
    989     dcb20_t *pdcb;
    990 #endif
    991     HDR_DECL(oam_lm_pkt_t, ah, ahp);
    992 
    993     COMPILER_REFERENCE(pfx);
    994 
    995     if (el < (int)sizeof(oam_lm_pkt_t)) {
    996         s = d_strcat(s, "LMM (***INVALID***):");
    997         s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
    998         return(s);
    999     }
   1000     
   1001     s = d_strcat(s, "TxFCf:<");
   1002     s = d_vformat_hex(s, bcm_ntohl(ah->txfcf), 8, 1);
   1003     s = d_strcat(s, "> RxFCf:<");
   1004 #ifdef BCM_ENDURO_SUPPORT
   1005     if (pd) {
   1006         pdcb = (dcb20_t *)pd;
   1007         s = d_vformat_hex(s, pdcb->timestamp, 8, 1);
   1008     } else 
   1009 #endif
   1010     {
   1011         s = d_vformat_hex(s, bcm_ntohl(ah->rxfcf), 8, 1);
   1012     }
   1013     s = d_strcat(s, "> TxFCb:<");
   1014     s = d_vformat_hex(s, bcm_ntohl(ah->txfcb), 8, 1);
   1015     s = d_strcat(s, ">");
   1016    
   1017     return(s);
   1018 }
   1019 
   1020 char *
   1021 d_oam_dmr_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
   1022 /*
   1023  * Function:	p_arp_decode
   1024  * Purpose: 	Format arp header into string.
   1025  * Parameters:	pfx - output prefix
   1026  *		s - pointer to string to format into
   1027  *		ahp - oam header
   1028  *		el - length of packet starting at ahp
   1029  *		dl - pointer to data list entry matching
   1030  * Returns:	Pointer to where string ends ('\0')
   1031  */
   1032 {
   1033 #ifdef BCM_ENDURO_SUPPORT
   1034     dcb20_t *pdcb;
   1035 #endif
   1036     HDR_DECL(oam_dm_pkt_t, ah, ahp);
   1037 
   1038     COMPILER_REFERENCE(pfx);
   1039 
   1040     if (el < (int)sizeof(oam_dm_pkt_t)) {
   1041         s = d_strcat(s, "DMR (***INVALID***):");
   1042         s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
   1043         return(s);
   1044     }
   1045     s = d_strcat(s, "TxTSf:<");
   1046     s = d_vformat_hex(s, bcm_ntohl(ah->txtsf_upper), 8, 1);
   1047     s = d_vformat_hex(s, bcm_ntohl(ah->txtsf), 8, 0);
   1048     s = d_strcat(s, "> RxTSf:<");
   1049     s = d_vformat_hex(s, bcm_ntohl(ah->rxtsf_upper), 8, 1);
   1050     s = d_vformat_hex(s, bcm_ntohl(ah->rxtsf), 8, 0);
   1051     s = d_strcat(s, "> TxTSb:<");
   1052     s = d_vformat_hex(s, bcm_ntohl(ah->txtsb_upper), 8, 1);
   1053     s = d_vformat_hex(s, bcm_ntohl(ah->txtsb), 8, 0);
   1054     s = d_strcat(s, "> RxTSb:<");
   1055 #ifdef BCM_ENDURO_SUPPORT
   1056     if (pd) {
   1057         pdcb = (dcb20_t *)pd;
   1058         s = d_vformat_hex(s, pdcb->timestamp_upper, 8, 1);
   1059         s = d_vformat_hex(s, pdcb->timestamp, 8, 0);
   1060     } else 
   1061 #endif
   1062     {
   1063         s = d_vformat_hex(s, bcm_ntohl(ah->rxtsb_upper), 8, 1);
   1064         s = d_vformat_hex(s, bcm_ntohl(ah->rxtsb), 8, 0);
   1065     }
   1066     s = d_strcat(s, ">");
   1067     
   1068     ahp = (void *)((char *)ahp + sizeof(oam_dm_pkt_t));
   1069     return(s);
   1070 }
   1071 
   1072 char *
   1073 d_oam_dmm_decode(const char *pfx, char *s, void *ahp, int el, decode_list_t *dl, void *pd)
   1074 /*
   1075  * Function:	p_arp_decode
   1076  * Purpose: 	Format arp header into string.
   1077  * Parameters:	pfx - output prefix
   1078  *		s - pointer to string to format into
   1079  *		ahp - oam header
   1080  *		el - length of packet starting at ahp
   1081  *		dl - pointer to data list entry matching
   1082  * Returns:	Pointer to where string ends ('\0')
   1083  */
   1084 {
   1085 #ifdef BCM_ENDURO_SUPPORT
   1086     dcb20_t *pdcb;
   1087 #endif
   1088     HDR_DECL(oam_dm_pkt_t, ah, ahp);
   1089 
   1090     COMPILER_REFERENCE(pfx);
   1091 
   1092     if (el < (int)sizeof(oam_dm_pkt_t)) {
   1093         s = d_strcat(s, "DMM (***INVALID***):");
   1094         s = d_vformat_bytes(s, (unsigned char *)ah, el, 1, ' ');
   1095         return(s);
   1096     }
   1097     s = d_strcat(s, "TxTSf:<");
   1098     s = d_vformat_hex(s, bcm_ntohl(ah->txtsf_upper), 8, 1);
   1099     s = d_vformat_hex(s, bcm_ntohl(ah->txtsf), 8, 0);
   1100     s = d_strcat(s, "> RxTSf:<");
   1101 #ifdef BCM_ENDURO_SUPPORT
   1102     if (pd) {
   1103         pdcb = (dcb20_t *)pd;
   1104         s = d_vformat_hex(s, pdcb->timestamp_upper, 8, 1);
   1105         s = d_vformat_hex(s, pdcb->timestamp, 8, 0);
   1106     } else 
   1107 #endif
   1108     {
   1109         s = d_vformat_hex(s, bcm_ntohl(ah->rxtsf_upper), 8, 1);
   1110         s = d_vformat_hex(s, bcm_ntohl(ah->rxtsf), 8, 0);
   1111     }
   1112     s = d_strcat(s, "> TxTSb:<");
   1113     s = d_vformat_hex(s, bcm_ntohl(ah->txtsb_upper), 8, 1);
   1114     s = d_vformat_hex(s, bcm_ntohl(ah->txtsb), 8, 0);
   1115     s = d_strcat(s, "> RxTSb:<");
   1116     s = d_vformat_hex(s, bcm_ntohl(ah->rxtsb_upper), 8, 1);
   1117     s = d_vformat_hex(s, bcm_ntohl(ah->rxtsb), 8, 0);
   1118     s = d_strcat(s, ">");
   1119     
   1120     ahp = (void *)((char *)ahp + sizeof(oam_dm_pkt_t));
   1121     return(s);
   1122 }
   1123 
   1124 static decode_list_t	d_oam_type[] = {
   1125     {0,  41, 	NULL, 	"Undefined"},
   1126     {42, 42, &d_oam_lmr_table, "LMR"},
   1127     {43, 43, &d_oam_lmm_table, "LMM"},
   1128     {46, 46, &d_oam_dmr_table, "DMR"},
   1129     {47, 47, &d_oam_dmm_table, "DMM"},
   1130     {48, 0xff,  NULL,   "Undefined"}
   1131 };
   1132 
   1133 static decode_t d_oam_table = {
   1134     "OAM",
   1135     d_oam_decode, 
   1136     d_oam_compare,
   1137     d_oam_length, 
   1138     DECODE_LIST(d_oam_type)
   1139 };
   1140 
   1141 static decode_t d_oam_lmr_table = {	/* OAM LMR*/
   1142     "LMR", 
   1143     d_oam_lmr_decode,
   1144     NULL,
   1145     NULL, 
   1146     DECODE_LIST_NULL
   1147 };
   1148 
   1149 static decode_t d_oam_lmm_table = {	/* OAM LMM */
   1150     "LMM", 
   1151     d_oam_lmm_decode,
   1152     NULL,
   1153     NULL, 
   1154     DECODE_LIST_NULL
   1155 };
   1156 
   1157 static decode_t d_oam_dmr_table = { /* OAM DMR */
   1158     "DMR", 
   1159     d_oam_dmr_decode, 
   1160     NULL,
   1161     NULL, 
   1162     DECODE_LIST_NULL
   1163 };
   1164 
   1165 static decode_t d_oam_dmm_table = { /* OAM DMM */
   1166     "DMM", 
   1167     d_oam_dmm_decode, 
   1168     NULL,
   1169     NULL, 
   1170     DECODE_LIST_NULL
   1171 };
   1172 #endif
   1173 
   1174 /************************************************************************
   1175  ************************************************************************
   1176  ************************************************************************
   1177  *									*
   1178  *			       	IP	 				*
   1179  */
   1180 struct ip {
   1181 #if defined(LE_HOST)
   1182     unsigned int ip_hl:4;
   1183     unsigned int ip_v:4;
   1184 #else /* !LE_HOST */
   1185     unsigned int ip_v:4;
   1186     unsigned int ip_hl:4;
   1187 #endif
   1188     uint8    ip_tos;
   1189     uint16   ip_len;
   1190     uint16   ip_id;
   1191     uint16   ip_off;
   1192     uint8    ip_ttl;
   1193     uint8    ip_p;
   1194     uint16   ip_sum;
   1195     struct in_addr ip_src;
   1196     struct in_addr ip_dst;
   1197 };
   1198 
   1199 static	int
   1200 d_ip_compare(decode_list_t *dl, void *ipp)
   1201 /*
   1202  * Function:	d_arp_compare
   1203  * Purpose:    	Compare routine for arp packet type.
   1204  * Parameters:	dl - pointer to entry to compare.
   1205  *		ipp - pointer to ip header to compare.
   1206  * Returns:	-1 - hdr LESS than dl
   1207  *		0  - hdr EQUAL dl
   1208  *		1  - hdr GREATER than dl
   1209  * Notes:	Comparing byte field so no alignment required.
   1210  */
   1211 {
   1212     struct ip *iph = (struct ip *)ipp;
   1213 
   1214     if (dl->dl_low > iph->ip_p) {
   1215 	return(-1);
   1216     } else if (dl->dl_high < iph->ip_p) {
   1217 	return(1);
   1218     } else {
   1219 	return(0);
   1220     }
   1221 }
   1222 
   1223 char *
   1224 d_ip_decode(const char *pfx, char *s, void *ihp, int il, decode_list_t *dl, void *pd)
   1225 /*
   1226  * Function:	p_ip_decode
   1227  * Purpose: 	Format ip header into string.
   1228  * Parameters:	pfx - output prefix
   1229  *		s - pointer to string to format into
   1230  *		ihp - ip header
   1231  *		il - length of packet starting at ihp
   1232  *		dl - pointer to data list entry matching
   1233  * Returns:	Pointer to where string ends ('\0')
   1234  */
   1235 {
   1236     HDR_DECL(struct ip, ih, ihp);
   1237 
   1238     COMPILER_REFERENCE(pfx);
   1239     COMPILER_REFERENCE(dl);
   1240     COMPILER_REFERENCE(pd);
   1241 
   1242     if (il < (int)sizeof(struct ip)) {
   1243 	s = d_strcat(s, "(***INVALID***):");
   1244 	s = d_vformat_bytes(s, (unsigned char *)ih, il, 1, ' ');
   1245 	return(s);
   1246     }
   1247 
   1248     s = d_strcat_dec(s, "V(", ih->ip_v, ") src<");
   1249     s = d_vformat_dec(s, (unsigned char *)&ih->ip_src, sizeof(ih->ip_src), 
   1250 		      1, '.');
   1251     s = d_strcat(s, "> dst<");
   1252     s = d_vformat_dec(s, (unsigned char *)&ih->ip_dst, sizeof(ih->ip_dst), 
   1253 		      1, '.');
   1254     s = d_strcat_dec(s, "> hl<", ih->ip_hl, "> ");
   1255     s = d_strcat_dec(s, "service-type<", ih->ip_tos, "> ");
   1256     s = d_strcat_dec(s, "tl<", bcm_ntohs(ih->ip_len), "> ");
   1257     s = d_strcat_dec(s, "id<", bcm_ntohs(ih->ip_id), "> ");
   1258     s = d_strcat_dec(s, "frg-off<", bcm_ntohs(ih->ip_off), "> ");
   1259     s = d_strcat_dec(s, "ttl<", ih->ip_ttl, "> ");
   1260     s = d_strcat(s, "> chk-sum<");
   1261     s = d_vformat_hex(s, bcm_ntohs(ih->ip_sum), 4, 1);
   1262     s = d_strcat(s, ">");
   1263 
   1264     return(s);
   1265 }
   1266 
   1267 /*ARGSUSED*/
   1268 static	int
   1269 d_ip_length(decode_list_t *dl, void *ihp)
   1270 /*
   1271  * Function:	d_ip_length
   1272  * Purpose:	Determine the length of the ip header.
   1273  * Parameters:	dl - pointer to decode list entry.
   1274  *		ihp - pointer to ip header.
   1275  * Returns:	Integer length.
   1276  */
   1277 {
   1278     HDR_DECL(struct ip, ih, ihp);
   1279 
   1280     COMPILER_REFERENCE(dl);
   1281 
   1282     if (ih->ip_hl < sizeof(struct ip)) {
   1283 	return(sizeof(struct ip));
   1284     }
   1285     return(ih->ip_hl);
   1286 }
   1287 
   1288 static decode_list_t	d_ip_type[] = {
   1289      {0, 0,	NULL,		"IPv6 Hop-by-Hop Option [RFC1883]"},
   1290      {1, 1,	&d_icmp_table,	"ICMP Internet Control Message [RFC792]"},
   1291      {2, 2,	NULL,		"Internet Group Management [RFC1112]"},
   1292      {3, 3,	NULL,		"Gateway-to-Gateway [RFC823]"},
   1293      {4, 4,	NULL,		"IP in IP (encapsulation) [RFC2003]"},
   1294      {5, 5,	NULL,		"Stream [RFC119,IEN119]"},
   1295      {6, 6,	&d_tcp_table,	"TCP (Transmission Control) [RFC793]"},
   1296      {7, 7,	NULL,		"CBT [Ballardie]"},
   1297      {8, 8,	NULL,		"Exterior Gateway Protocol [RFC88,DLM1]"},
   1298      {9, 9,	NULL,		"any private interior gateway [IANA]"},
   1299     {10, 10,	NULL,		"BBN-RCC-MON BBN RCC Monitoring [SGC]"},
   1300     {11, 11,	NULL,		"NVP-II Network Voice Protocol [RFC74,SC3]"},
   1301     {12, 12,	NULL,		"PUP [PU,XEROX]"},
   1302     {13, 13,	NULL,		"ARGUS [RWS4]"},
   1303     {14, 14,	NULL,		"EMCON [BN7]"},
   1304     {15, 15,	NULL,		"Cross Net Debugger [IEN158,JFH2]"},
   1305     {16, 16,	NULL,		"Chaos [NC3]"},
   1306     {17, 17,	NULL,		"User Datagram [RFC768,JBP]"},
   1307     {18, 18,	NULL,		"Multiplexing [IEN90,JBP]"},
   1308     {19, 19,	NULL,		"DCN Measurement Subsystems [DLM1]"},
   1309     {20, 20,	NULL,		"Host Monitoring [RFC869,RH6]"},
   1310     {21, 21,	NULL,		"Packet Radio Measurement [ZSU]"},
   1311     {22, 22,	NULL,		"XEROX NS IDP [ETHERNET,XEROX]"},
   1312     {23, 23,	NULL,		"Trunk-1 [BWB6]"},
   1313     {24, 24,	NULL,		"Trunk-2 [BWB6]"},
   1314     {25, 25,	NULL,		"Leaf-1 [BWB6]"},
   1315     {26, 26,	NULL,		"Leaf-2 [BWB6]"},
   1316     {27, 27,	NULL,		"Reliable Data Protocol [RFC908,RH6]"},
   1317     {28, 28,	NULL,		"Internet Reliable Transaction "
   1318 	                        "[RFC938,TXM]"},
   1319     {29, 29,	NULL,	   	"ISO Transport Protocol Class 4 "
   1320 	                        "[RFC969,DDC1]"},
   1321     {31, 31,	NULL,		"MFE Network Services Protocol"},
   1322     {32, 32,	NULL,		"MERIT Internodal Protocol [HWB]"},
   1323     {33, 33,	NULL,		"Sequential Exchange Protocol [JC120]"},
   1324     {34, 34,	NULL,		"Third Party Connect Protocol [SAF3]"},
   1325     {35, 35,	NULL,		"Inter-Domain Policy Routing Protocol "
   1326 	                        "[GXC]"},
   1327     {37, 37,	NULL,		"Datagram Delivery Protocol [WXC]"},
   1328     {38, 38,	NULL,		"IDPR Control Message Transport Proto "
   1329 	                        "[DXF]"},
   1330     {40, 40,	NULL,		"IL Transport Protocol [Presotto]"},
   1331     {41, 41,	NULL,		"Ipv6 [Deering]    "},
   1332     {42, 42,	NULL,		"Source Demand Routing Protocol [DXE1]"},
   1333     {43, 43,	NULL,		"Route  Routing Header for IPv6 [Deering]"},
   1334     {44, 44,	NULL,		"Frag   Fragment Header for IPv6 [Deering]"},
   1335     {45, 45,	NULL,		"Inter-Domain Routing Protocol [Sue Hares]"},
   1336     {46, 46,	NULL,		"Reservation Protocol [Bob Braden]"},
   1337     {47, 47,	NULL,		"General Routing Encapsulation [Tony Li]"},
   1338     {48, 48,	NULL,		"Mobile Host Routing Protocol"},
   1339     {50, 50,	NULL,		"Encap Security Payload for IPv6 [RFC1827]"},
   1340     {51, 51,	NULL,		"Authentication Header for IPv6 [RFC1826]"},
   1341     {52, 52,	NULL,		"Integrated Net Layer Security  TUBA [JI6]"},
   1342     {54, 54,	&d_arp_table,	"ARP Address Resolution Protocol [RFC1735]"},
   1343     {55, 55,	NULL,		"IP Mobility [Perkins]"},
   1344     {56, 56,	NULL,		"Transport Layer Security Protocol [Oberg]"},
   1345     {57, 57,	NULL,		"SKIP [Markson]"},
   1346     {58, 58,	NULL,		"ICMP for IPv6 [RFC1883]"},
   1347     {59, 59,	NULL,		"No Next Header for IPv6 [RFC1883]"},
   1348     {60, 60,	NULL,		"Destination Options for IPv6 [RFC1883]"},
   1349     {61, 61,	NULL,		"host internal protocol [IANA]"},
   1350     {62, 62,	NULL,		"CFTP [CFTP,HCF2]"},
   1351     {63, 63,	NULL,		"local network [IANA]"},
   1352     {64, 64,	NULL,		"SATNET and Backroom EXPAK [SHB]"},
   1353     {65, 65,	NULL,		"Kryptolan [PXL1]"},
   1354     {66, 66,	NULL,		"MIT Remote Virtual Disk Protocol [MBG]"},
   1355     {67, 67,	NULL,		"Internet Pluribus Packet Core [SHB]"},
   1356     {68, 68,	NULL,		"distributed file system [IANA]"},
   1357     {69, 69,	NULL,		"SATNET Monitoring [SHB]"},
   1358     {70, 70,	NULL,		"VISA Protocol [GXT1]"},
   1359     {71, 71,	NULL,		"Internet Packet Core Utility [SHB]"},
   1360     {72, 72,	NULL,		"Computer Protocol Network Executive "
   1361 	                        "[DXM2]"},
   1362     {73, 73,	NULL,		"Computer Protocol Heart Beat [DXM2]"},
   1363     {74, 74,	NULL,		"Wang Span Network [VXD]"},
   1364     {75, 75,	NULL,		"Packet Video Protocol [SC3]"},
   1365     {76, 76,	NULL,		"SAT-MON  Backroom SATNET Monitoring [SHB]"},
   1366     {77, 77,	NULL,		"SUN ND PROTOCOL-Temporary [WM3]"},
   1367     {78, 78,	NULL,		"WIDEBAND Monitoring [SHB]"},
   1368     {79, 79,	NULL,		"WIDEBAND EXPAK [SHB]"},
   1369     {80, 80,	NULL,		"ISO Internet Protocol [MTR]"},
   1370     {81, 81,	NULL,		"VMTP [DRC3]"},
   1371     {82, 82,	NULL,		"VMTP SECURE-VMTP [DRC3]"},
   1372     {83, 83,	NULL,		"VINES [BXH]"},
   1373     {84, 84,	NULL,		"TTP [JXS]"},
   1374     {85, 85,	NULL,		"IGP  NSFNET-IGP [HWB]"},
   1375     {86, 86,	NULL,		"Dissimilar Gateway Protocol [DGP,ML109]"},
   1376     {87, 87,	NULL,		"TCF [GAL5]"},
   1377     {89, 89,	NULL,		"OSPFIGP [RFC1583,JTM4]"},
   1378     {90, 90,	NULL,		"RPC  Sprite RPC Protocol [SPRITE,BXW] "},
   1379     {91, 91,	NULL,		"Locus Address Resolution Protocol [BXH]"},
   1380     {92, 92,	NULL,		"Multicast Transport Protocol [SXA]"},
   1381     {93, 93,	NULL,		"AX.25 Frames [BK29]"},
   1382     {94, 94,	NULL,		"IP-within-IP Encapsulation Protocol [JI6]"},
   1383     {95, 95,	NULL,		"Mobile Internetworking Control Pro [JI6]"},
   1384     {96, 96,	NULL,		"Semaphore Communications Sec. Pro [HXH]"},
   1385     {97, 97,	NULL,		"Ethernet-within-IP Encapsulation [RXH1]"},
   1386     {98, 98,	NULL,		"Encapsulation Header [RFC1241,RXB3]"},
   1387     {99, 99,	NULL,		"private encryption scheme [IANA]"},
   1388    {100, 100,	NULL,		"GMTP [RXB5]"},
   1389    {101, 101,	NULL,		"Ipsilon Flow Management Protocol [Hinden]"},
   1390    {102, 102,	NULL,		"PNNI over IP [Callon]"},
   1391    {103, 103,	NULL,		"Protocol Independent Multicast "
   1392 	                        "[Farinacci]"},
   1393    {104, 104,	NULL,		"ARIS [Feldman]"},
   1394    {105, 105,	NULL,		"SCPS [Durst]"},
   1395    {106, 106,	NULL,		"QNX [Hunter]"},
   1396    {107, 107,	NULL,		"Active Networks [Braden]"},
   1397    {108, 108,	NULL,		"IP Payload Compression Protocol [RFC2393]"},
   1398    {109, 109,	NULL,		"Sitara Networks Protocol"},
   1399    {110, 110,	NULL,		"Peer Compaq Peer Protocol"},
   1400    {111, 111,	NULL,		"in-IP   IPX in IP"},
   1401    {112, 112,	NULL,		"Virtual Router Redundancy Protocol"},
   1402    {114, 114,	NULL,		"0-hop protocol [IANA]"},
   1403    {115, 115,	NULL,		"Layer Two Tunneling Protocol [Aboba]"},
   1404    {116, 116,	NULL,		"D-II Data Exchange (DDX [Worley] "},
   1405    {117, 117,	NULL,		"Interactive Agent Transfer Protocol"},
   1406    {118, 118,	NULL,		"Schedule Transfer [JMP]"},
   1407    {119, 119,	NULL,		"SpectraLink Radio Protocol [Hamilton]"},
   1408    {120, 120,	NULL,		"UTI [Lothberg]"},
   1409    {121, 121,	NULL,		"Simple Message Protocol [Ekblad]"},
   1410    {122, 254,	NULL,		"Unassigned"},
   1411    {255, 255,	NULL,		"Reserved"}
   1412 };
   1413 
   1414 static decode_t d_ip_table = {
   1415     "IP",
   1416     d_ip_decode, 
   1417     d_ip_compare,
   1418     d_ip_length, 
   1419     DECODE_LIST(d_ip_type)
   1420 };
   1421 
   1422 /************************************************************************
   1423  ************************************************************************
   1424  ************************************************************************
   1425  *									*
   1426  *			       	ICMP	 				*
   1427  */
   1428 #define ICMP_MINLEN 8
   1429 struct icmp_ra_addr {
   1430     uint32 ira_addr;
   1431     uint32 ira_preference;
   1432 };
   1433 
   1434 struct icmp {
   1435   uint8  icmp_type;
   1436   uint8  icmp_code;
   1437   uint16 icmp_cksum;
   1438   union
   1439   {
   1440     uint8 ih_pptr;
   1441     struct in_addr ih_gwaddr;
   1442     struct ih_idseq
   1443     {
   1444       uint16 icd_id;
   1445       uint16 icd_seq;
   1446     } ih_idseq;
   1447     uint32 ih_void;
   1448     struct ih_pmtu
   1449     {
   1450       uint16 ipm_void;
   1451       uint16 ipm_nextmtu;
   1452     } ih_pmtu;
   1453     struct ih_rtradv
   1454     {
   1455       uint8 irt_num_addrs;
   1456       uint8 irt_wpa;
   1457       uint16 irt_lifetime;
   1458     } ih_rtradv;
   1459   } icmp_hun;
   1460   union
   1461   {
   1462     struct
   1463     {
   1464       uint32 its_otime;
   1465       uint32 its_rtime;
   1466       uint32 its_ttime;
   1467     } id_ts;
   1468     struct
   1469     {
   1470       struct ip idi_ip;
   1471       /* options and then 64 bits of data */
   1472     } id_ip;
   1473     struct icmp_ra_addr id_radv;
   1474     uint32   id_mask;
   1475     uint8    id_data[1];
   1476   } icmp_dun;
   1477 };
   1478 
   1479 static	int
   1480 d_icmp_compare(decode_list_t *dl, void *icp)
   1481 /*
   1482  * Function: 	d_icmp_compare
   1483  * Purpose:	Compare routine for ICMP packets.
   1484  * Parameters:	dl - pointer to entry to compare
   1485  *		icp - pointer to header to compare.
   1486  * Returns:	-1 - hdr LESS than dl
   1487  *		0  - hdr EQUAL dl
   1488  *		1  - hdr GREATER than dl
   1489  */
   1490 {
   1491     struct icmp *ic = (struct icmp *)icp;
   1492 
   1493     if (dl->dl_low > ic->icmp_type) {
   1494 	return(-1);
   1495     } else if (dl->dl_high < ic->icmp_type) {
   1496 	return(1);
   1497     } else {
   1498 	return(0);
   1499     }
   1500 }
   1501 
   1502 char *
   1503 d_icmp_decode(const char *pfx, char *s, void *icp, int il, decode_list_t *dl, void *pd)
   1504 /*
   1505  * Function:	p_icmp_decode
   1506  * Purpose: 	Format ICMP header into string.
   1507  * Parameters:	pfx - output prefix
   1508  *		s - pointer to string to format into
   1509  *		icp - icmp header pointer
   1510  *		il - length of packet starting at icp
   1511  *		dl - pointer to data list entry matching
   1512  * Returns:	Pointer to where string ends ('\0')
   1513  */
   1514 {
   1515     HDR_DECL(struct icmp, ic, icp);
   1516 
   1517     COMPILER_REFERENCE(pfx);
   1518     COMPILER_REFERENCE(il);
   1519     COMPILER_REFERENCE(pd);
   1520 
   1521     s = d_strcat_dec(s, "Type-", ic->icmp_type, " (");
   1522     if (dl) {
   1523 	s = d_strcat(s, dl->dl_string);
   1524 	s = d_strcat(s, ") ");
   1525 	s = d_strcat_dec(s, "Code-", ic->icmp_code, " ");
   1526     } else {
   1527 	s = d_strcat(s, "INVALID");
   1528 	s = d_strcat(s, ") ");
   1529 	return(s);
   1530     }
   1531 
   1532     return(s);
   1533 }
   1534 
   1535 static	int
   1536 d_icmp_compare_code(decode_list_t *dl, void *icp)
   1537 /*
   1538  * Function: 	d_icmp_compare_code
   1539  * Purpose:	Compare routine for ICMP packets on their "code".
   1540  * Parameters:	dl - pointer to entry to compare
   1541  *		icp - pointer to header to compare.
   1542  * Returns:	-1 - hdr LESS than dl
   1543  *		0  - hdr EQUAL dl
   1544  *		1  - hdr GREATER than dl
   1545  */
   1546 {
   1547     struct icmp *ic = (struct icmp *)icp;
   1548 
   1549     if (dl->dl_low > ic->icmp_code) {
   1550 	return(-1);
   1551     } else if (dl->dl_high < ic->icmp_code) {
   1552 	return(1);
   1553     } else {
   1554 	return(0);
   1555     }
   1556 }
   1557 
   1558 char *
   1559 d_icmp_decode_code(const char *pfx, char *s, void *icp, int il, 
   1560 		   decode_list_t *dl)
   1561 /*
   1562  * Function:	p_icmp_decode_code
   1563  * Purpose: 	Format ICMP output for a type/code match.
   1564  * Parameters:	pfx - output prefix
   1565  *		s - pointer to string to format into
   1566  *		icp - icmp header pointer
   1567  *		il - length of packet starting at icp
   1568  *		dl - pointer to data list entry matching
   1569  * Returns:	Pointer to where string ends ('\0')
   1570  */
   1571 {
   1572     HDR_DECL(struct icmp, ic, icp);
   1573 
   1574     COMPILER_REFERENCE(pfx);
   1575 
   1576     s = d_strcat_dec(s, "Code-", ic->icmp_code, " (");
   1577     if (dl) {
   1578 	s = d_strcat(s, dl->dl_string);
   1579 	s = d_strcat(s, ") ");
   1580     } else {
   1581 	s = d_strcat(s, "*Invalid*");
   1582 	s = d_strcat(s, ") ");
   1583 	s = d_vformat_bytes(s, (unsigned char *)ic, il, 1, ' ');
   1584 	return(s);
   1585     }
   1586 
   1587     return(s);
   1588 }
   1589 
   1590 /*ARGSUSED*/
   1591 static	int
   1592 d_icmp_length(decode_list_t *dl, void *icp)
   1593 /*
   1594  * Function:	d_icmp_length
   1595  * Purpose:	Determine the length of the icmp header.
   1596  * Parameters:	dl - pointer to decode list entry.
   1597  *		icp - pointer to ICMP header.
   1598  * Returns:	Integer length.
   1599  */
   1600 {
   1601     COMPILER_REFERENCE(dl);
   1602     COMPILER_REFERENCE(icp);
   1603 
   1604     return(ICMP_MINLEN);		/* Next layer decode handles it */
   1605 }
   1606 
   1607 static	char *
   1608 d_icmp_decode_default(const char *pfx, char *s, void *icp, int il, 
   1609 		      decode_list_t *dl, void *pd)
   1610 /*
   1611  * Function:	p_icmp_decode_default
   1612  * Purpose: 	Format ICMP output for an arbitrary ICMP packet, starting
   1613  *		with the "code". 
   1614  * Parameters:	pfx - output prefix
   1615  *		s - pointer to string to format into
   1616  *		icp - icmp header pointer
   1617  *		il - length of packet starting at icp
   1618  *		dl - pointer to data list entry matching, if NULL, 
   1619  *		     assumes code is not used.
   1620  * Returns:	Pointer to where string ends ('\0')
   1621  */
   1622 {
   1623     HDR_DECL(struct icmp, ic, icp);
   1624 
   1625     COMPILER_REFERENCE(pfx);
   1626     COMPILER_REFERENCE(il);
   1627 
   1628     if (dl) {
   1629 	s = d_strcat(s, " (");
   1630 	s = d_strcat(s, dl->dl_string);
   1631 	s = d_strcat(s, ")");
   1632     }
   1633     s = d_strcat_dec(s, "Code <", bcm_ntohs(ic->icmp_code), "> Checksum <");
   1634     s = d_vformat_hex(s, bcm_ntohs(ic->icmp_cksum), 4, 1);
   1635     s = d_strcat(s, "> hun <");
   1636     /* For now, simply display remainder in bytes */
   1637 
   1638     s = d_vformat_bytes(s, (unsigned char *)&ic->icmp_hun, 4, 1, ' ');
   1639     s = d_strcat(s, "> ");
   1640 
   1641     return(s);
   1642 }
   1643 
   1644 /* Forward declare local tables */
   1645 
   1646 static decode_t d_icmp_type3_table;
   1647 static decode_t d_icmp_type5_table;
   1648 static decode_t d_icmp_type11_table;
   1649 static decode_t d_icmp_type12_table;
   1650 static decode_t d_icmp_default_table;
   1651 
   1652 static decode_list_t	d_icmp_type[] = {
   1653     {0, 0,	&d_icmp_default_table,	"Echo Reply [RFC792]"},
   1654     {1, 1,	&d_icmp_default_table,	"Unassigned [JBP]"},
   1655     {2, 2,	&d_icmp_default_table,	"Unassigned [JBP]"},
   1656     {3, 3,	&d_icmp_type3_table,	"Destination Unreachable [RFC792]"},
   1657     {4, 4,	&d_icmp_default_table,	"Source Quench [RFC792]"},
   1658     {5, 5,	&d_icmp_type5_table,	"Redirect [RFC792]"},
   1659     {6, 6,	&d_icmp_default_table,	"Alternate Host Address [JBP]"},
   1660     {7, 7,	&d_icmp_default_table,	"Unassigned [JBP]"},
   1661     {8, 8,	&d_icmp_default_table,	"Echo [RFC792]"},
   1662     {9, 9,	&d_icmp_default_table,	"Router Advertisement [RFC1256]"},
   1663     {10, 10,	&d_icmp_default_table,	"Router Selection [RFC1256]"},
   1664     {11, 11,	&d_icmp_type11_table,	"Time Exceeded [RFC792]"},
   1665     {12, 12,	&d_icmp_type12_table,	"Parameter Problem [RFC792]"},
   1666     {13, 13,	&d_icmp_default_table,	"Timestamp [RFC792]"},
   1667     {14, 14,	&d_icmp_default_table,	"Timestamp Reply [RFC792]"},
   1668     {15, 15,	&d_icmp_default_table,	"Information Request [RFC792]"},
   1669     {16, 16,	&d_icmp_default_table,	"Information Reply [RFC792]"},
   1670     {17, 17,	&d_icmp_default_table,	"Address Mask Request [RFC950]"},
   1671     {18, 18,	&d_icmp_default_table,	"Address Mask Reply [RFC950]"},
   1672     {19, 19,	&d_icmp_default_table,	"Reserved (for Security [Solo]"},
   1673     {20, 20,	&d_icmp_default_table,	"Reserved (for Robustness "
   1674 	                                "Experiment [ZSu]"},
   1675     {21, 29, 	&d_icmp_default_table,  "Unknown"},	
   1676     {30, 30,	&d_icmp_default_table,	"Traceroute [RFC1393]"},
   1677     {31, 31,	&d_icmp_default_table,	"Datagram Conversion Error "
   1678 	                                "[RFC1475]"},
   1679     {32, 32,	&d_icmp_default_table,	"Mobile Host Redirect "
   1680 	                                "[David Johnson]"},
   1681     {33, 33,	&d_icmp_default_table,	"IPv6 Where-Are-You"},
   1682     {34, 34,	&d_icmp_default_table,	"IPv6 I-Am-Here"},
   1683     {35, 35,	&d_icmp_default_table,	"Mobile Registration Request"},
   1684     {36, 36,	&d_icmp_default_table,	"Mobile Registration Reply"},
   1685     {37, 37,	&d_icmp_default_table,	"Domain Name Request"},
   1686     {38, 38,	&d_icmp_default_table,	"Domain Name Reply"},
   1687     {39, 39,	&d_icmp_default_table,	"SKIP [Markson]"},
   1688     {40, 40,	&d_icmp_default_table,	"Photuris [Simpson]"},
   1689     {41, 255,	&d_icmp_default_table,	"Reserved"}
   1690 };
   1691     
   1692 static decode_list_t	d_icmp_type3[] = {
   1693     {0, 0,	NULL,		"Net Unreachable"},
   1694     {1, 1,	NULL,		"Host Unreachable"},
   1695     {2, 2,	NULL,		"Protocol Unreachable"},
   1696     {3, 3,	NULL,		"Port Unreachable"},
   1697     {4, 4,	NULL,		"Fragmentation Needed and Don't "
   1698 	                        "Fragment was Set"},
   1699     {5, 5,	NULL,		"Source Route Failed"},
   1700     {6, 6,	NULL,		"Destination Network Unknown"},
   1701     {7, 7,	NULL,		"Destination Host Unknown"},
   1702     {8, 8,	NULL,		"Source Host Isolated"},
   1703     {9, 9,	NULL,		"Communication with Destination Network is "
   1704 	                        "Administratively Prohibited"},
   1705     {10, 10,	NULL,		"Communication with Destination Host is "
   1706 	                        "Administratively Prohibited"},
   1707     {11, 11,	NULL,		"Destination Network Unreachable for Type "
   1708 	                        "of Service"},
   1709     {12, 12,	NULL,		"Destination Host Unreachable for Type "
   1710 	                        "of Service"},
   1711     {13, 13,	NULL,		"Communication Administratively Prohibited "
   1712 	                        "[RFC1812]"},
   1713     {14, 14,	NULL,		"Host Precedence Violation [RFC1812]"},
   1714     {15, 15,	NULL,		"Precedence cutoff in effect [RFC1812]"},
   1715     {16, 255,	NULL, 		"*Invalid*"}
   1716 };
   1717 
   1718 static decode_list_t	d_icmp_type5[] = {
   1719     {0, 0,	NULL,		"Redirect Datagram for the Network "
   1720 	                        "(or subnet)"},
   1721     {1, 1,	NULL,		"Redirect Datagram for the Host"},
   1722     {2, 2,	NULL,		"Redirect Datagram for the Type of "
   1723 	                        "Service and Network"},
   1724     {3, 3,	NULL,		"Redirect Datagram for the Type of "
   1725 	                        "Service and Host"},
   1726     {4, 255,	NULL, 		"*Invalid*"}
   1727 };
   1728 
   1729 static decode_list_t	d_icmp_type11[] = {
   1730     {0, 0,	NULL,		"Time to Live exceeded in Transit"},
   1731     {1, 1,	NULL,		"Fragment Reassembly Time Exceeded"},
   1732     {2, 255,	NULL, 		"*Invalid*"}
   1733 };
   1734 
   1735 static decode_list_t	d_icmp_type12[] = {
   1736     {0, 0,	NULL,		"Pointer indicates the error"},
   1737     {1, 1,	NULL,		"Missing a Required Option [RFC1108]"},
   1738     {2, 2,	NULL,		"Bad Length"},
   1739     {3, 255,	NULL, 		"*Invalid*"}
   1740     
   1741 };
   1742 
   1743 static decode_t d_icmp_table = {
   1744     "ICMP",
   1745     d_icmp_decode, 
   1746     d_icmp_compare,
   1747     d_icmp_length, 
   1748     DECODE_LIST(d_icmp_type)
   1749 };
   1750 
   1751 static decode_t d_icmp_type3_table = {	/* Type 3 CODE table */
   1752     "Type 3", 
   1753     d_icmp_decode_default, 
   1754     d_icmp_compare_code,
   1755     d_icmp_length, 
   1756     DECODE_LIST(d_icmp_type3)
   1757 };
   1758 
   1759 static decode_t d_icmp_type5_table = {	/* Type 5 CODE table */
   1760     "Type 5", 
   1761     d_icmp_decode_default,
   1762     d_icmp_compare_code,
   1763     d_icmp_length, 
   1764     DECODE_LIST(d_icmp_type5)
   1765 };
   1766 static decode_t d_icmp_type11_table = {	/* Type 11 CODE table */
   1767     "Type 11", 
   1768     d_icmp_decode_default,
   1769     d_icmp_compare_code,
   1770     d_icmp_length, 
   1771     DECODE_LIST(d_icmp_type11)
   1772 };
   1773 
   1774 static decode_t d_icmp_type12_table = {	/* Type 12 CODE table */
   1775     "Type 12", 
   1776     d_icmp_decode_default,
   1777     d_icmp_compare_code,
   1778     d_icmp_length, 
   1779     DECODE_LIST(d_icmp_type12)
   1780 };
   1781 
   1782 static decode_t d_icmp_default_table = { /* Generic code table */
   1783     "Generic", 
   1784     d_icmp_decode_default, 
   1785     d_icmp_compare_code,
   1786     d_icmp_length, 
   1787     DECODE_LIST_NULL
   1788 };
   1789 
   1790 /************************************************************************
   1791  ************************************************************************
   1792  ************************************************************************
   1793  *									*
   1794  *			       	TCP	 				*
   1795  */
   1796 
   1797 #include <netinet/tcp.h>
   1798 
   1799 static	int
   1800 d_tcp_length(decode_list_t *tl, void *tcpp)
   1801 /*
   1802  * Function: 
   1803  * Purpose:
   1804  * Parameters:
   1805  * Returns:
   1806  */
   1807 {
   1808     COMPILER_REFERENCE(tl);
   1809     COMPILER_REFERENCE(tcpp);
   1810     
   1811     return(sizeof(struct tcphdr));
   1812 }
   1813 
   1814 static	char	*
   1815 d_tcp_decode(const char *pfx, char *s, void *tcpp, int tl, decode_list_t *dl, void *pd)
   1816 /*
   1817  * Function: 	d_tcp_decode
   1818  * Purpose:	Format TCP header into string.
   1819  * Parameters:	pfx - prefix for output.
   1820  *		s - pointer to string to format into.
   1821  *		tcpp - pointer to tcp header.
   1822  *		tl - length remaining in packet.
   1823  *		tl - pointer to matching data list entry.
   1824  * Returns: 	Pointer to where string ends ('\0')
   1825  */
   1826 {
   1827     static const char *tcp_flags[] = {
   1828 	"FIN", "SYN", "RST", "PUSH", "ACK", "URG"
   1829     };
   1830     HDR_DECL(struct tcphdr, tcp, tcpp);
   1831     int	first, i;
   1832 
   1833     COMPILER_REFERENCE(pfx);
   1834     COMPILER_REFERENCE(pd);
   1835 
   1836     if (tl < d_tcp_length(dl, tcpp)) {	/* Invalid length */
   1837 	s = d_strcat_dec(s, "*Invalid Length for TCP packet* ", tl, "-bytes");
   1838     }
   1839 
   1840     s = d_strcat_dec(s, "sPort<", bcm_ntohs(tcp->th_sport), "> ");
   1841     s = d_strcat_dec(s, "dPort<", bcm_ntohs(tcp->th_dport), "> ");
   1842     s = d_strcat_dec(s, "Seq<", ntohl(tcp->th_seq), "> ");
   1843     s = d_strcat_dec(s, "Ack<", ntohl(tcp->th_ack), "> ");
   1844     s = d_strcat_dec(s, "Off<", tcp->th_off, "> Flags<");
   1845     s = d_vformat_hex(s, tcp->th_flags, 2, 1);
   1846     s = d_strcat(s, "=");
   1847     first = TRUE;
   1848     for (i = 0; i < COUNTOF(tcp_flags); i++) {
   1849 	if (tcp->th_flags & (1 << i)) {
   1850 	    if (first) {
   1851 		first = FALSE;
   1852 	    } else {
   1853 		s = d_strcat(s, ",");
   1854 	    }
   1855 	    s = d_strcat(s, (char *)tcp_flags[i]);
   1856 	}
   1857     }
   1858     s = d_strcat(s, "> Csum<");
   1859     s = d_vformat_hex(s, bcm_ntohs(tcp->th_sum), 4, 1);
   1860     s = d_strcat(s, "> Urp<");
   1861     s = d_vformat_hex(s, bcm_ntohs(tcp->th_urp), 4, 1);
   1862     s = d_strcat(s, ">");
   1863     return(s);
   1864 }
   1865 
   1866 static decode_t d_tcp_table = {
   1867     "TCP",
   1868     d_tcp_decode, 
   1869     NULL,
   1870     d_tcp_length, 
   1871     DECODE_LIST_NULL			/* Nothing more to decode */
   1872 };
   1873 
   1874 /************************************************************************
   1875  ************************************************************************
   1876  ************************************************************************
   1877  *									*
   1878  *			       	Main Decode 				*
   1879  */
   1880 
   1881 int
   1882 d_packet_vformat(char *pfx, char *s, int type, void *p, int pl, void *d)
   1883 /*
   1884  * Function:	d_packet_vformat
   1885  * Purpose:	Decode a packet into a buffer.
   1886  * Parameters:	pfx - output prefix
   1887  *		type - type of packet (DECODE_ETHER etc)
   1888  *		p - pointer to packet
   1889  *		pl - length of packet
   1890  * Returns:	0 - success, -1 failed.
   1891  * Notes:	Calls NO routines that require malloc/free etc, and can 
   1892  *		thus be called from an interrupt handler.
   1893  */
   1894 {
   1895     switch(type) {
   1896     case DECODE_ETHER:
   1897 	(void)d_decode(pfx, s, &d_ether_table, p, pl, d);
   1898 	break;
   1899     case DECODE_IP:
   1900 	(void)d_decode(pfx, s, &d_ip_table, p, pl, d);
   1901 	break;
   1902     case DECODE_TCP:
   1903 	(void)d_decode(pfx, s, &d_tcp_table, p, pl, d);
   1904 	break;
   1905     case DECODE_ARP:
   1906 	(void)d_decode(pfx, s, &d_arp_table, p, pl, d);
   1907 	break;
   1908     case DECODE_GB_ETHER:
   1909 	(void)d_decode(pfx, s, &d_ether_table, p, pl, d);
   1910 	break;
   1911     default:
   1912 	(void)d_strcat(s, "****** Invalid type ******");
   1913 	return(-1);
   1914     }
   1915     return(0);
   1916 }
   1917 
   1918 int
   1919 d_packet_format(char *pfx, int type, void *p, int pl, void *d)
   1920 /*
   1921  * Function:	d_packet_format
   1922  * Purpose:	Decode a packet and display results. 
   1923  * Parameters:	pfx - pointer to prefix string inserted at start of 
   1924  *			every line.
   1925  *		type - type of packet (DECODE_ETHER etc)
   1926  *		p - pointer to packet
   1927  *		pl - length of packet
   1928  * Returns:	0 - success
   1929  *		-1 - failed
   1930  * Notes:	Calls malloc and can not be used in interrupt handler.
   1931  */
   1932 {
   1933     int		rv;
   1934     char 	*s, *ts;
   1935 
   1936     if (NULL == (s = sal_alloc(4096,"decode"))) {
   1937 	rv = -1;
   1938     } else {
   1939 	*s = '\0';
   1940 	ts = d_strcat(s, pfx);
   1941 	rv = d_packet_vformat(pfx, ts, type, p, pl, d);
   1942 	if (0 == rv) {
   1943 	    sal_printf("%s\n", s);
   1944 	}
   1945 	sal_free(s);
   1946     }
   1947   
   1948     return(rv);
   1949 }
   1950 
   1951 #endif /* __KERNEL__ */
   1952 
   1953 #endif /* NO_SAL_APPL */
   1954 #endif /* GHS */