uint_t
interpret_tr(int flags, caddr_t e, int elen, int origlen)
{
	struct tr_header *mh;
	struct tr_ri *rh;
	uchar_t fc;
	struct llc_snap_hdr *snaphdr;
	char *off;
	int maclen, len;
	boolean_t data_copied = B_FALSE;
	extern char *dst_name, *src_name;
	int ethertype;
	int is_llc = 0, is_snap = 0, source_routing = 0;
	int blen = MAX(origlen, 17800);

	if (data != NULL && datalen != 0 && datalen < blen) {
		free(data);
		data = NULL;
		datalen = 0;
	}
	if (!data) {
		data = (char *)malloc(blen);
		if (!data)
			pr_err("Warning: malloc failure");
		datalen = blen;
	}

	if (origlen < ACFCDASA_LEN) {
		if (flags & F_SUM) {
			(void) sprintf(get_sum_line(),
			    "RUNT (short packet - %d bytes)",
			    origlen);
		}
		if (flags & F_DTAIL)
			show_header("RUNT:  ", "Short packet", origlen);
		return (elen);
	}
	if (elen < ACFCDASA_LEN)
		return (elen);

	mh = (struct tr_header *)e;
	rh = (struct tr_ri *)&mh->ri;
	fc = mh->fc;

	if (is_llc = tr_machdr_len(e, &maclen, &source_routing)) {
		snaphdr = (struct llc_snap_hdr *)(e + maclen);
		if (snaphdr->d_lsap == LSAP_SNAP &&
		    snaphdr->s_lsap == LSAP_SNAP &&
		    snaphdr->control == CNTL_LLC_UI) {
			is_snap = 1;
		}
	}

	if (memcmp(&mh->dhost, &ether_broadcast,
	    sizeof (struct ether_addr)) == 0)
		dst_name = "(broadcast)";
	else if (memcmp(&mh->dhost, &tokenbroadcastaddr2,
	    sizeof (struct ether_addr)) == 0)
		dst_name = "(mac broadcast)";
	else if (mh->dhost.ether_addr_octet[0] & TR_FN_ADDR)
		dst_name = "(functional)";

	if (is_snap)
		ethertype = ntohs(snaphdr->type);
	else {
		src_name =  print_etherinfo(&mh->shost);
		dst_name =  print_etherinfo(&mh->dhost);
	}

	/*
	 * The 14 byte ether header screws up alignment
	 * of the rest of the packet for 32 bit aligned
	 * architectures like SPARC. Alas, we have to copy
	 * the rest of the packet in order to align it.
	 */
	if (is_llc) {
		if (is_snap) {
			len = elen - (maclen + LLC_SNAP_HDR_LEN);
			off = (char *)(e + maclen + LLC_SNAP_HDR_LEN);
		} else {
			len = elen - (maclen + LLC_HDR1_LEN);
			off = (char *)(e + maclen + LLC_HDR1_LEN);
		}
	} else {
		len = elen - maclen;
		off = (char *)(e + maclen);
	}

	if (len > 0 && (off + len <= (char *)e + elen)) {
		(void) memcpy(data, off, len);
		data_copied = B_TRUE;
	}

	if (flags & F_SUM) {
		if (source_routing)
			sprintf(get_sum_line(), print_sr(rh));

		if (is_llc) {
			if (is_snap) {
				(void) sprintf(get_sum_line(), "TR LLC w/SNAP "
				    "Type=%04X (%s), size=%d bytes",
				    ethertype,
				    print_ethertype(ethertype),
				    origlen);
			} else {
				(void) sprintf(get_sum_line(), "TR LLC, but no "
				    "SNAP encoding, size = %d bytes",
				    origlen);
			}
		} else {
			(void) sprintf(get_sum_line(),
			    "TR MAC FC=%02X (%s), size = %d bytes",
			    fc, print_fc(fc), origlen);
		}
	}

	if (flags & F_DTAIL) {
		show_header("TR:  ", "TR Header", elen);
		show_space();
		(void) sprintf(get_line(0, 0),
		    "Packet %d arrived at %d:%02d:%d.%05d",
		    pi_frame,
		    pi_time_hour, pi_time_min, pi_time_sec,
		    pi_time_usec / 10);
		(void) sprintf(get_line(0, 0),
		    "Packet size = %d bytes",
		    elen);
		(void) sprintf(get_line(0, 1),
		    "Frame Control = %02x (%s)",
		    fc, print_fc(fc));
		(void) sprintf(get_line(2, 6),
		    "Destination = %s, %s",
		    printether(&mh->dhost),
		    print_etherinfo(&mh->dhost));
		(void) sprintf(get_line(8, 6),
		    "Source      = %s, %s",
		    printether(&mh->shost),
		    print_etherinfo(&mh->shost));

		if (source_routing)
			sprintf(get_line(ACFCDASA_LEN, rh->len), print_sr(rh));

		if (is_llc) {
			(void) sprintf(get_line(maclen, 1),
			    "Dest   Service Access Point = %02x",
			    snaphdr->d_lsap);
			(void) sprintf(get_line(maclen+1, 1),
			    "Source Service Access Point = %02x",
			    snaphdr->s_lsap);
			(void) sprintf(get_line(maclen+2, 1),
			    "Control = %02x",
			    snaphdr->control);
			if (is_snap) {
				(void) sprintf(get_line(maclen+3, 3),
				    "SNAP Protocol Id = %02x%02x%02x",
				    snaphdr->org[0], snaphdr->org[1],
				    snaphdr->org[2]);
			}
		}

		if (is_snap) {
			(void) sprintf(get_line(maclen+6, 2),
			    "SNAP Type = %04X (%s)",
			    ethertype, print_ethertype(ethertype));
		}

		show_space();
	}

	/* go to the next protocol layer */
	if (is_snap && data_copied) {
		switch (ethertype) {
		case ETHERTYPE_IP:
			(void) interpret_ip(flags, (struct ip *)data, len);
			break;
		/* Just in case it is decided to add this type */
		case ETHERTYPE_IPV6:
			(void) interpret_ipv6(flags, (ip6_t *)data, len);
			break;
		case ETHERTYPE_ARP:
		case ETHERTYPE_REVARP:
			interpret_arp(flags, (struct arphdr *)data, len);
			break;
		case ETHERTYPE_AARP:	/* AppleTalk */
			interpret_aarp(flags, data, len);
			break;
		case ETHERTYPE_AT:
			interpret_at(flags, (struct ddp_hdr *)data, len);
			break;
		default:
			break;
		}
	}

	return (elen);
}
static uint_t
interpret_ipnet(int flags, char *header, int elen, int origlen)
{
	dl_ipnetinfo_t dl;
	size_t len = elen - sizeof (dl_ipnetinfo_t);
	char *off = (char *)header + sizeof (dl_ipnetinfo_t);
	int blen = MAX(origlen, 8252);
	char szone[MAX_UINT64_STR];
	char dzone[MAX_UINT64_STR];

	(void) memcpy(&dl, header, sizeof (dl));
	if (data != NULL && datalen != 0 && datalen < blen) {
		free(data);
		data = NULL;
		datalen = 0;
	}
	if (data == NULL) {
		data = (char *)malloc(blen);
		if (!data)
			pr_err("Warning: malloc failure");
		datalen = blen;
	}

	if (dl.dli_zsrc == ALL_ZONES)
		sprintf(szone, "Unknown");
	else
		sprintf(szone, "%lu", BE_32(dl.dli_zsrc));

	if (dl.dli_zdst == ALL_ZONES)
		sprintf(dzone, "Unknown");
	else
		sprintf(dzone, "%lu", BE_32(dl.dli_zdst));

	if (flags & F_SUM) {
		(void) snprintf(get_sum_line(), MAXLINE,
		    "IPNET src zone %s dst zone %s", szone, dzone);
	}

	if (flags & F_DTAIL) {
		show_header("IPNET:  ", "IPNET Header", elen);
		show_space();
		(void) sprintf(get_line(0, 0),
		    "Packet %d arrived at %d:%02d:%d.%05d",
		    pi_frame,
		    pi_time_hour, pi_time_min, pi_time_sec,
		    pi_time_usec / 10);
		(void) sprintf(get_line(0, 0),
		    "Packet size = %d bytes",
		    elen);
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "dli_version = %d", dl.dli_version);
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "dli_family = %d", dl.dli_family);
		(void) snprintf(get_line(0, 2), get_line_remain(),
		    "dli_zsrc = %s", szone);
		(void) snprintf(get_line(0, 2), get_line_remain(),
		    "dli_zdst = %s", dzone);
		show_space();
	}
	memcpy(data, off, len);

	switch (dl.dli_family) {
	case AF_INET:
		(void) interpret_ip(flags, (struct ip *)data, len);
		break;
	case AF_INET6:
		(void) interpret_ipv6(flags, (ip6_t *)data, len);
		break;
	default:
		break;
	}

	return (0);
}
/* ARGSUSED */
uint_t
interpret_iptun(int flags, char *header, int elen, int origlen)
{
	(void) interpret_ip(flags, (struct ip *)header, elen);
	return (elen);
}
static uint_t
interpret_ib(int flags, char *header, int elen, int origlen)
{
	struct ipoib_header *hdr = (struct ipoib_header *)header;
	char *off;
	int len;
	unsigned short ethertype;
	int blen = MAX(origlen, 4096);

	if (data != NULL && datalen != 0 && datalen < blen) {
		free(data);
		data = NULL;
		datalen = 0;
	}
	if (data == NULL) {
		data = malloc(blen);
		if (data == NULL)
			pr_err("Warning: malloc failure");
		datalen = blen;
	}
	if (origlen < IPOIB_HDRSIZE) {
		if (flags & F_SUM)
			(void) snprintf(get_sum_line(), MAXLINE,
			    "RUNT (short packet - %d bytes)", origlen);
		if (flags & F_DTAIL)
			show_header("RUNT:  ", "Short packet", origlen);
		return (elen);
	}
	if (elen < IPOIB_HDRSIZE)
		return (elen);

	/*
	 * It is not possible to understand just by looking
	 * at the header whether this was a broad/multi cast
	 * packet; thus dst_name is not updated.
	 */
	ethertype = ntohs(hdr->ipoib_type);
	len = elen - IPOIB_HDRSIZE;
	off = (char *)(hdr + 1);
	(void) memcpy(data, off, len);

	if (flags & F_SUM) {
		(void) snprintf(get_sum_line(), MAXLINE,
		    "IPIB Type=%04X (%s), size = %d bytes",
		    ethertype,
		    print_ethertype(ethertype),
		    origlen);
	}

	if (flags & F_DTAIL) {
		show_header("IPIB:  ", "IPIB Header", elen);
		show_space();
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "Packet %d arrived at %d:%02d:%d.%02d",
		    pi_frame, pi_time_hour, pi_time_min,
		    pi_time_sec, pi_time_usec / 10000);
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "Packet size = %d bytes", elen, elen);
		(void) snprintf(get_line(0, 2), get_line_remain(),
		    "Ethertype = %04X (%s)", ethertype,
		    print_ethertype(ethertype));
		show_space();
	}

	/* Go to the next protocol layer */
	switch (ethertype) {
		case ETHERTYPE_IP:
			(void) interpret_ip(flags, (struct ip *)data, len);
			break;
		case ETHERTYPE_IPV6:
			(void) interpret_ipv6(flags, (ip6_t *)data, len);
			break;
		case ETHERTYPE_ARP:
		case ETHERTYPE_REVARP:
			interpret_arp(flags, (struct arphdr *)data, len);
			break;
	}

	return (elen);
}
uint_t
interpret_ether(int flags, char *header, int elen, int origlen)
{
	struct ether_header *e = (struct ether_header *)header;
	uchar_t *off, *ieeestart;
	int len;
	int ieee8023 = 0;
	extern char *dst_name;
	int ethertype;
	struct ether_vlan_extinfo *evx = NULL;
	int blen = MAX(origlen, ETHERMTU);
	boolean_t trillpkt = B_FALSE;
	uint16_t tci = 0;

	if (data != NULL && datalen != 0 && datalen < blen) {
		free(data);
		data = NULL;
		datalen = 0;
	}
	if (!data) {
		data = (char *)malloc(blen);
		if (!data)
			pr_err("Warning: malloc failure");
		datalen = blen;
	}
inner_pkt:
	if (origlen < 14) {
		if (flags & F_SUM) {
			(void) sprintf(get_sum_line(),
			    "RUNT (short packet - %d bytes)",
			    origlen);
		}
		if (flags & F_DTAIL)
			show_header("RUNT:  ", "Short packet", origlen);
		return (elen);
	}
	if (elen < 14)
		return (elen);

	if (memcmp(&e->ether_dhost, &ether_broadcast,
	    sizeof (struct ether_addr)) == 0)
		dst_name = "(broadcast)";
	else if (e->ether_dhost.ether_addr_octet[0] & 1)
		dst_name = "(multicast)";

	ethertype = ntohs(e->ether_type);

	/*
	 * The 14 byte ether header screws up alignment
	 * of the rest of the packet for 32 bit aligned
	 * architectures like SPARC. Alas, we have to copy
	 * the rest of the packet in order to align it.
	 */
	len = elen - sizeof (struct ether_header);
	off = (uchar_t *)(e + 1);

	if (ethertype == ETHERTYPE_VLAN) {
		if (origlen < sizeof (struct ether_vlan_header)) {
			if (flags & F_SUM) {
				(void) sprintf(get_sum_line(),
				    "RUNT (short VLAN packet - %d bytes)",
				    origlen);
			}
			if (flags & F_DTAIL) {
				show_header("RUNT:  ", "Short VLAN packet",
				    origlen);
			}
			return (elen);
		}
		if (len < sizeof (struct ether_vlan_extinfo))
			return (elen);

		evx = (struct ether_vlan_extinfo *)off;
		off += sizeof (struct ether_vlan_extinfo);
		len -= sizeof (struct ether_vlan_extinfo);

		ethertype = ntohs(evx->ether_type);
		tci = ntohs(evx->ether_tci);
	}

	if (ethertype <= 1514) {
		/*
		 * Fake out the IEEE 802.3 packets.
		 * Should be DSAP=0xAA, SSAP=0xAA, control=0x03
		 * then three padding bytes of zero (OUI),
		 * followed by a normal ethernet-type packet.
		 */
		ieee8023 = ethertype;
		ieeestart = off;
		if (off[0] == 0xAA && off[1] == 0xAA) {
			ethertype = ntohs(*(ushort_t *)(off + 6));
			off += 8;
			len -= 8;
		} else {
			ethertype = 0;
			off += 3;
			len -= 3;
		}
	}

	if (flags & F_SUM) {
		/*
		 * Set the flag that says don't display VLAN information.
		 * If it needs to change, that will be done later if the
		 * packet is VLAN tagged and if snoop is in its default
		 * summary mode.
		 */
		set_vlan_id(0);
		if (evx == NULL) {
			if (ethertype == 0 && ieee8023 > 0) {
				(void) sprintf(get_sum_line(),
				    "ETHER 802.3 SSAP %02X DSAP %02X, "
				    "size=%d bytes", ieeestart[0], ieeestart[1],
				    origlen);
			} else {
				(void) sprintf(get_sum_line(),
				    "ETHER Type=%04X (%s), size=%d bytes",
				    ethertype, print_ethertype(ethertype),
				    origlen);
			}
		} else {
			if (ethertype == 0 && ieee8023 > 0) {
				(void) sprintf(get_sum_line(),
				    "ETHER 802.3 SSAP %02X DSAP %02X, "
				    "VLAN ID=%hu, size=%d bytes", ieeestart[0],
				    ieeestart[1], VLAN_ID(tci), origlen);
			} else {
				(void) sprintf(get_sum_line(),
				    "ETHER Type=%04X (%s), VLAN ID=%hu, "
				    "size=%d bytes", ethertype,
				    print_ethertype(ethertype), VLAN_ID(tci),
				    origlen);
			}

			if (!(flags & F_ALLSUM))
				set_vlan_id(VLAN_ID(tci));
		}
	}

	if (flags & F_DTAIL) {
		show_header("ETHER:  ", "Ether Header", elen);
		show_space();
		if (!trillpkt) {
			(void) sprintf(get_line(0, 0),
			    "Packet %d arrived at %d:%02d:%d.%05d",
			    pi_frame,
			    pi_time_hour, pi_time_min, pi_time_sec,
			    pi_time_usec / 10);
			(void) sprintf(get_line(0, 0),
			    "Packet size = %d bytes",
			    elen, elen);
		}
		(void) sprintf(get_line(0, 6),
		    "Destination = %s, %s",
		    printether(&e->ether_dhost),
		    print_etherinfo(&e->ether_dhost));
		(void) sprintf(get_line(6, 6),
		    "Source      = %s, %s",
		    printether(&e->ether_shost),
		    print_etherinfo(&e->ether_shost));
		if (evx != NULL) {
			(void) sprintf(get_line(0, 0),
			    "VLAN ID     = %hu", VLAN_ID(tci));
			(void) sprintf(get_line(0, 0),
			    "VLAN Priority = %hu", VLAN_PRI(tci));
		}
		if (ieee8023 > 0) {
			(void) sprintf(get_line(12, 2),
			    "IEEE 802.3 length = %d bytes", ieee8023);
			/* Print LLC only for non-TCP/IP packets */
			if (ethertype == 0) {
				(void) snprintf(get_line(0, 0),
				    get_line_remain(),
				    "SSAP = %02X, DSAP = %02X, CTRL = %02X",
				    ieeestart[0], ieeestart[1], ieeestart[2]);
			}
		}
		if (ethertype != 0 || ieee8023 == 0)
			(void) sprintf(get_line(12, 2),
			    "Ethertype = %04X (%s)",
			    ethertype, print_ethertype(ethertype));
		show_space();
	}

	/*
	 * We cannot trust the length field in the header to be correct.
	 * But we should continue to process the packet.  Then user can
	 * notice something funny in the header.
	 * Go to the next protocol layer only if data have been
	 * copied.
	 */
	if (len > 0 && (off + len <= (uchar_t *)e + elen)) {
		(void) memmove(data, off, len);

		if (!trillpkt && ethertype == ETHERTYPE_TRILL) {
			ethertype = interpret_trill(flags, &e, data, &len);
			/* Decode inner Ethernet frame */
			if (ethertype != 0) {
				evx = NULL;
				trillpkt = B_TRUE;
				(void) memmove(data, e, len);
				e = (struct ether_header *)data;
				origlen = len;
				elen = len;
				goto inner_pkt;
			}
		}

		switch (ethertype) {
		case ETHERTYPE_IP:
			(void) interpret_ip(flags, (struct ip *)data, len);
			break;
		/* Just in case it is decided to add this type */
		case ETHERTYPE_IPV6:
			(void) interpret_ipv6(flags, (ip6_t *)data, len);
			break;
		case ETHERTYPE_ARP:
		case ETHERTYPE_REVARP:
			interpret_arp(flags, (struct arphdr *)data, len);
			break;
		case ETHERTYPE_PPPOED:
		case ETHERTYPE_PPPOES:
			(void) interpret_pppoe(flags, (poep_t *)data, len);
			break;
		case ETHERTYPE_AARP:    /* AppleTalk */
			interpret_aarp(flags, data, len);
			break;
		case ETHERTYPE_AT:
			interpret_at(flags, (struct ddp_hdr *)data, len);
			break;
		case 0:
			if (ieee8023 == 0)
				break;
			switch (ieeestart[0]) {
			case 0xFE:
				interpret_isis(flags, data, len,
				    memcmp(&e->ether_dhost, &all_isis_rbridges,
				    sizeof (struct ether_addr)) == 0);
				break;
			case 0x42:
				interpret_bpdu(flags, data, len);
				break;
			}
			break;
		}
	}

	return (elen);
}
uint_t
interpret_fddi(int flags, caddr_t e, int elen, int origlen)
{
	struct fddi_header fhdr, *f = &fhdr;
	char *off;
	int len;
	boolean_t data_copied = B_FALSE;
	extern char *dst_name, *src_name;
	int ethertype;
	int is_llc = 0, is_smt = 0, is_snap = 0;
	int blen = MAX(origlen, 4500);

	if (data != NULL && datalen != 0 && datalen < blen) {
		free(data);
		data = NULL;
		datalen = 0;
	}
	if (!data) {
		data = (char *)malloc(blen);
		if (!data)
			pr_err("Warning: malloc failure");
		datalen = blen;
	}

	if (origlen < 13) {
		if (flags & F_SUM) {
			(void) sprintf(get_sum_line(),
			    "RUNT (short packet - %d bytes)",
			    origlen);
		}
		if (flags & F_DTAIL)
			show_header("RUNT:  ", "Short packet", origlen);
		return (elen);
	}
	if (elen < 13)
		return (elen);

	(void) memcpy(&f->fc, e, sizeof (f->fc));
	addr_copy_swap(&f->dhost, (struct ether_addr *)(e+1));
	addr_copy_swap(&f->shost, (struct ether_addr *)(e+7));

	if ((f->fc&0x50) == 0x50) {
		is_llc = 1;
		(void) memcpy(&f->dsap, e+13, sizeof (f->dsap));
		(void) memcpy(&f->ssap, e+14, sizeof (f->ssap));
		(void) memcpy(&f->ctl, e+15, sizeof (f->ctl));
		if (f->dsap == 0xaa && f->ssap == 0xaa) {
			is_snap = 1;
			(void) memcpy(&f->proto_id, e+16, sizeof (f->proto_id));
			(void) memcpy(&f->type, e+19, sizeof (f->type));
		}
	} else {
		if ((f->fc&0x41) == 0x41 || (f->fc&0x4f) == 0x4f) {
			is_smt = 1;
		}
	}


	if (memcmp(&f->dhost, &ether_broadcast,
	    sizeof (struct ether_addr)) == 0)
		dst_name = "(broadcast)";
	else if (f->dhost.ether_addr_octet[0] & 0x01)
		dst_name = "(multicast)";

	if (is_snap)
		ethertype = ntohs(f->type);
	else {
		src_name = 	print_etherinfo(&f->shost);
		dst_name =  print_etherinfo(&f->dhost);
	}

	/*
	 * The 14 byte ether header screws up alignment
	 * of the rest of the packet for 32 bit aligned
	 * architectures like SPARC. Alas, we have to copy
	 * the rest of the packet in order to align it.
	 */
	if (is_llc) {
		if (is_snap) {
			len = elen - 21;
			off = (char *)(e + 21);
		} else {
			len = elen - 16;
			off = (char *)(e + 16);
		}
	} else {
		len = elen - 13;
		off = (char *)(e + 13);
	}

	if (len > 0 && (off + len <= (char *)e + elen)) {
		(void) memcpy(data, off, len);
		data_copied = B_TRUE;
	}

	if (flags & F_SUM) {
		if (is_llc) {
			if (is_snap) {
				(void) sprintf(get_sum_line(),
				    "FDDI LLC Type=%04X (%s), size = %d bytes",
				    ethertype,
				    print_ethertype(ethertype),
				    origlen);
			} else {
				(void) sprintf(get_sum_line(), "LLC, but no "
				    "SNAP encoding, size = %d bytes",
				    origlen);
			}
		} else if (is_smt) {
			(void) sprintf(get_sum_line(), "SMT Type=%02X (%s), "
			    "Class = %02X (%s), size = %d bytes",
			    *(uchar_t *)(data+1), print_smttype(*(data+1)),
			    *data, print_smtclass(*data), origlen);
		} else {
			(void) sprintf(get_sum_line(),
			    "FC=%02X (%s), size = %d bytes",
			    f->fc, print_fc(f->fc), origlen);
		}
	}

	if (flags & F_DTAIL) {
		show_header("FDDI:  ", "FDDI Header", elen);
		show_space();
		(void) sprintf(get_line(0, 0),
		    "Packet %d arrived at %d:%02d:%d.%05d",
		    pi_frame,
		    pi_time_hour, pi_time_min, pi_time_sec,
		    pi_time_usec / 10);
		(void) sprintf(get_line(0, 0),
		    "Packet size = %d bytes",
		    elen, elen);
		(void) sprintf(get_line(0, 6),
		    "Destination = %s, %s",
		    printether(&f->dhost),
		    print_etherinfo(&f->dhost));
		(void) sprintf(get_line(6, 6),
		    "Source      = %s, %s",
		    printether(&f->shost),
		    print_etherinfo(&f->shost));

		if (is_llc) {
			(void) sprintf(get_line(12, 2),
			    "Frame Control = %02x (%s)",
			    f->fc, print_fc(f->fc));
			(void) sprintf(get_line(12, 2),
			    "Dest   Service Access Point = %02x",
			    f->dsap);
			(void) sprintf(get_line(12, 2),
			    "Source Service Access Point = %02x",
			    f->ssap);
			(void) sprintf(get_line(12, 2),
			    "Control = %02x",
			    f->ctl);
			if (is_snap) {
				(void) sprintf(get_line(12, 2),
				    "Protocol Id = %02x%02x%02x",
				    f->proto_id[0], f->proto_id[1],
				    f->proto_id[2]);
			}
		} else if (is_smt) {
			(void) sprintf(get_line(12, 2),
			    "Frame Control = %02x (%s)",
			    f->fc, print_fc(f->fc));
			(void) sprintf(get_line(12, 2),
			    "Class = %02x (%s)",
			    (uchar_t)*data, print_smtclass(*data));
			(void) sprintf(get_line(12, 2),
			    "Type = %02x (%s)",
			    *(uchar_t *)(data+1), print_smttype(*(data+1)));
		} else {
			(void) sprintf(get_line(12, 2),
			    "FC=%02X (%s), size = %d bytes",
			    f->fc, print_fc(f->fc), origlen);
		}

		if (is_snap) {
			(void) sprintf(get_line(12, 2),
			    "LLC Type = %04X (%s)",
			    ethertype, print_ethertype(ethertype));
		}

		show_space();
	}

	/* go to the next protocol layer */
	if (is_llc && is_snap && f->ctl == 0x03 && data_copied) {
		switch (ethertype) {
		case ETHERTYPE_IP:
			(void) interpret_ip(flags, (struct ip *)data, len);
			break;
		/* Just in case it is decided to add this type */
		case ETHERTYPE_IPV6:
			(void) interpret_ipv6(flags, (ip6_t *)data, len);
			break;
		case ETHERTYPE_ARP:
		case ETHERTYPE_REVARP:
			interpret_arp(flags, (struct arphdr *)data, len);
			break;
		default:
			break;
		}

	}

	return (elen);
}
Beispiel #7
0
int
interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen)
{
	/* LINTED: alignment */
	ah_t *ah = (ah_t *)hdr;
	ah_t *aligned_ah;
	ah_t storage;	/* In case hdr isn't aligned. */
	char *line, *buff;
	uint_t ahlen, auth_data_len;
	uint8_t *auth_data, *data;
	int new_iplen;
	uint8_t proto;

	if (fraglen < sizeof (ah_t))
		return (fraglen);		/* incomplete header */

	if (!IS_P2ALIGNED(hdr, 4)) {
		aligned_ah = (ah_t *)&storage;
		bcopy(hdr, &storage, sizeof (ah_t));
	} else {
		aligned_ah = ah;
	}

	/*
	 * "+ 8" is for the "constant" part that's not included in the AH
	 * length.
	 *
	 * The AH RFC specifies the length field in "length in 4-byte units,
	 * not counting the first 8 bytes".  So if an AH is 24 bytes long,
	 * the length field will contain "4".  (4 * 4 + 8 == 24).
	 */
	ahlen = (aligned_ah->ah_length << 2) + 8;
	fraglen -= ahlen;
	if (fraglen < 0)
		return (fraglen + ahlen);	/* incomplete header */

	auth_data_len = ahlen - sizeof (ah_t);
	auth_data = (uint8_t *)(ah + 1);
	data = auth_data + auth_data_len;

	if (flags & F_SUM) {
		line = (char *)get_sum_line();
		(void) sprintf(line, "AH SPI=0x%x Replay=%u",
		    ntohl(aligned_ah->ah_spi), ntohl(aligned_ah->ah_replay));
		line += strlen(line);
	}

	if (flags & F_DTAIL) {
		show_header("AH:  ", "Authentication Header", ahlen);
		show_space();
		(void) sprintf(get_line((char *)&ah->ah_nexthdr - dlc_header,
		    1), "Next header = %d (%s)", aligned_ah->ah_nexthdr,
		    getproto(aligned_ah->ah_nexthdr));
		(void) sprintf(get_line((char *)&ah->ah_length - dlc_header, 1),
		    "AH length = %d (%d bytes)", aligned_ah->ah_length, ahlen);
		(void) sprintf(get_line((char *)&ah->ah_reserved - dlc_header,
		    2), "<Reserved field = 0x%x>",
		    ntohs(aligned_ah->ah_reserved));
		(void) sprintf(get_line((char *)&ah->ah_spi - dlc_header, 4),
		    "SPI = 0x%x", ntohl(aligned_ah->ah_spi));
		(void) sprintf(get_line((char *)&ah->ah_replay - dlc_header, 4),
		    "Replay = %u", ntohl(aligned_ah->ah_replay));

		/* * 2 for two hex digits per auth_data byte. */
		buff = malloc(auth_data_len * 2);
		if (buff != NULL) {
			int i;

			for (i = 0; i < auth_data_len; i++)
				sprintf(buff + i * 2, "%02x", auth_data[i]);
		}

		(void) sprintf(get_line((char *)auth_data - dlc_header,
		    auth_data_len), "ICV = %s",
		    (buff == NULL) ? "<out of memory>" : buff);

		/* malloc(3c) says I can call free even if buff == NULL */
		free(buff);

		show_space();
	}

	new_iplen = iplen - ahlen;
	proto = aligned_ah->ah_nexthdr;

	/*
	 * Print IPv6 Extension Headers, or skip them in the summary case.
	 */
	if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS ||
	    proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) {
		(void) print_ipv6_extensions(flags, &data, &proto, &iplen,
		    &fraglen);
	}

	if (fraglen > 0)
		switch (proto) {
			case IPPROTO_ENCAP:
				/* LINTED: alignment */
				(void) interpret_ip(flags, (struct ip *)data,
				    new_iplen);
				break;
			case IPPROTO_IPV6:
				(void) interpret_ipv6(flags, (ip6_t *)data,
				    new_iplen);
				break;
			case IPPROTO_ICMP:
				(void) interpret_icmp(flags,
				    /* LINTED: alignment */
				    (struct icmp *)data, new_iplen, fraglen);
				break;
			case IPPROTO_ICMPV6:
				/* LINTED: alignment */
				(void) interpret_icmpv6(flags, (icmp6_t *)data,
				    new_iplen, fraglen);
				break;
			case IPPROTO_TCP:
				(void) interpret_tcp(flags,
				    (struct tcphdr *)data, new_iplen, fraglen);
				break;

			case IPPROTO_ESP:
				(void) interpret_esp(flags, data, new_iplen,
				    fraglen);
				break;

			case IPPROTO_AH:
				(void) interpret_ah(flags, data, new_iplen,
				    fraglen);
				break;

			case IPPROTO_UDP:
				(void) interpret_udp(flags,
				    (struct udphdr *)data, new_iplen, fraglen);
				break;
			/* default case is to not print anything else */
		}

	return (ahlen);
}
Beispiel #8
0
/*ARGSUSED*/
void
interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen)
{
	char *pt, *pc, *px;
	char *line;
	char buff[67627];	/* Router adv. can have 256 routers ....   */
				/* Each router has a name 256 char long .. */
	char extbuff[MAXHOSTNAMELEN + 1];
	struct udphdr *orig_uhdr;
	int num_rtr_addrs = 0;
	extern char *prot_nest_prefix;

	if (ilen < ICMP_MINLEN)
		return;		/* incomplete header */

	pt = "Unknown";
	pc = "";
	px = "";

	switch (icmp->icmp_type) {
	case ICMP_ECHOREPLY:
		pt = "Echo reply";
		(void) sprintf(buff, "ID: %d Sequence number: %d",
		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
		pc = buff;
		break;
	case ICMP_UNREACH:
		pt = "Destination unreachable";
		switch (icmp->icmp_code) {
		case ICMP_UNREACH_NET:
			if (ilen >= ICMP_ADVLENMIN) {
				(void) sprintf(buff, "Net %s unreachable",
				    addrtoname(AF_INET,
				    &icmp->icmp_ip.ip_dst));
				pc = buff;
			} else {
				pc = "Bad net";
			}
			break;
		case ICMP_UNREACH_HOST:
			if (ilen >= ICMP_ADVLENMIN) {
				(void) sprintf(buff, "Host %s unreachable",
				    addrtoname(AF_INET,
				    &icmp->icmp_ip.ip_dst));
				pc = buff;
			} else {
				pc = "Bad host";
			}
			break;
		case ICMP_UNREACH_PROTOCOL:
			if (ilen >= ICMP_ADVLENMIN) {
				(void) sprintf(buff, "Bad protocol %d",
				    icmp->icmp_ip.ip_p);
				pc = buff;
			} else {
				pc = "Bad protocol";
			}
			break;
		case ICMP_UNREACH_PORT:
			if (ilen >= ICMP_ADVLENMIN) {
				orig_uhdr = (struct udphdr *)((uchar_t *)icmp +
				    ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4);
				switch (icmp->icmp_ip.ip_p) {
				case IPPROTO_TCP:
					(void) sprintf(buff, "TCP port %d"
					    " unreachable",
					    ntohs(orig_uhdr->uh_dport));
					pc = buff;
					break;
				case IPPROTO_UDP:
					(void) sprintf(buff, "UDP port %d"
					    " unreachable",
					    ntohs(orig_uhdr->uh_dport));
					pc = buff;
					break;
				default:
					pc = "Port unreachable";
					break;
				}
			} else {
				pc = "Bad port";
			}
			break;
		case ICMP_UNREACH_NEEDFRAG:
			if (ntohs(icmp->icmp_nextmtu) != 0) {
				(void) sprintf(buff, "Needed to fragment:"
				    " next hop MTU = %d",
				    ntohs(icmp->icmp_nextmtu));
				pc = buff;
			} else {
				pc = "Needed to fragment";
			}
			break;
		case ICMP_UNREACH_SRCFAIL:
			pc = "Source route failed";
			break;
		case ICMP_UNREACH_NET_UNKNOWN:
			pc = "Unknown network";
			break;
		case ICMP_UNREACH_HOST_UNKNOWN:
			pc = "Unknown host";
			break;
		case ICMP_UNREACH_ISOLATED:
			pc = "Source host isolated";
			break;
		case ICMP_UNREACH_NET_PROHIB:
			pc = "Net administratively prohibited";
			break;
		case ICMP_UNREACH_HOST_PROHIB:
			pc = "Host administratively prohibited";
			break;
		case ICMP_UNREACH_TOSNET:
			pc = "Net unreachable for this TOS";
			break;
		case ICMP_UNREACH_TOSHOST:
			pc = "Host unreachable for this TOS";
			break;
		case ICMP_UNREACH_FILTER_PROHIB:
			pc = "Communication administratively prohibited";
			break;
		case ICMP_UNREACH_HOST_PRECEDENCE:
			pc = "Host precedence violation";
			break;
		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
			pc = "Precedence cutoff in effect";
			break;
		default:
			break;
		}
		break;
	case ICMP_SOURCEQUENCH:
		pt = "Packet lost, slow down";
		break;
	case ICMP_REDIRECT:
		pt = "Redirect";
		switch (icmp->icmp_code) {
		case ICMP_REDIRECT_NET:
			pc = "for network";
			break;
		case ICMP_REDIRECT_HOST:
			pc = "for host";
			break;
		case ICMP_REDIRECT_TOSNET:
			pc = "for tos and net";
			break;
		case ICMP_REDIRECT_TOSHOST:
			pc = "for tos and host";
			break;
		default:
			break;
		}
		(void) sprintf(buff, "%s %s to %s",
			pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst),
			addrtoname(AF_INET, &icmp->icmp_gwaddr));
		pc = buff;
		break;
	case ICMP_ECHO:
		pt = "Echo request";
		(void) sprintf(buff, "ID: %d Sequence number: %d",
		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
		pc = buff;
		break;
	case ICMP_ROUTERADVERT:

#define	icmp_num_addrs	icmp_hun.ih_rtradv.irt_num_addrs
#define	icmp_wpa	icmp_hun.ih_rtradv.irt_wpa
#define	icmp_lifetime	icmp_hun.ih_rtradv.irt_lifetime

		pt = "Router advertisement";
		(void) sprintf(buff, "Lifetime %ds [%d]:",
		    ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs);
		if (icmp->icmp_wpa == 2) {
			struct icmp_ra_addr *ra;
			char ra_buf[MAXHOSTNAMELEN + 32];
			char ra_ext_buf[50];
			struct in_addr sin;
			int icmp_ra_len;
			int i;

			/* Cannot trust anything from the network... */
			num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8,
			    icmp->icmp_num_addrs);

			ra = (struct icmp_ra_addr *)icmp->icmp_data;
			for (i = 0; i < num_rtr_addrs; i++) {
				sin.s_addr = ra->addr;
				(void) snprintf(ra_buf, sizeof (ra_buf),
				    " {%s %u}",
				    addrtoname(AF_INET, &sin),
				    ntohl(ra->preference));
				if (strlcat(buff, ra_buf, sizeof (buff)) >=
					sizeof (buff)) {
					buff[sizeof (buff) -
					    strlen("<Too Long>)")] = '\0';
					(void) strlcat(buff, "<Too Long>",
						sizeof (buff));
					break;
				}
				ra++;
			}

			icmp_ra_len = ICMP_MINLEN + num_rtr_addrs *
			    sizeof (struct icmp_ra_addr);
			if (ilen > icmp_ra_len) {
				int curr_len = ilen - icmp_ra_len;
				int ocurr_len;
				exthdr_t *exthdr = (exthdr_t *)ra;

				extbuff[0] = '\0';

				while (curr_len > 0) {
				    /* Append Mobile-IP description */
				    (void) snprintf(ra_ext_buf,
					sizeof (ra_ext_buf), ", %s",
					get_mip_adv_desc(exthdr->type));
				    (void) strlcat(extbuff, ra_ext_buf,
					sizeof (extbuff));

				    /* Special case for padding */
				    if (exthdr->type ==
					ICMP_ADV_MSG_PADDING_EXT) {

					curr_len--;
					exthdr = (exthdr_t *)
						((char *)exthdr + 1);
					continue;
				    }

				    /* else normal extension */
				    ocurr_len = curr_len;
				    curr_len -= sizeof (*exthdr) +
							exthdr->length;
				    /* detect bad length */
				    if (ocurr_len < curr_len)
						break;
				    exthdr = (exthdr_t *)
						((char *)exthdr +
						sizeof (*exthdr) +
						exthdr->length);
				}
				px = extbuff;
			}
			pc = buff;
		}
		break;
	case ICMP_ROUTERSOLICIT:
		pt = "Router solicitation";
		break;
	case ICMP_TIMXCEED:
		pt = "Time exceeded";
		switch (icmp->icmp_code) {
		case ICMP_TIMXCEED_INTRANS:
			pc = "in transit";
			break;
		case ICMP_TIMXCEED_REASS:
			pc = "in reassembly";
			break;
		default:
			break;
		}
		break;
	case ICMP_PARAMPROB:
		pt = "IP parameter problem";
		switch (icmp->icmp_code) {
		case ICMP_PARAMPROB_OPTABSENT:
			pc = "Required option missing";
			break;
		case ICMP_PARAMPROB_BADLENGTH:
			pc = "Bad length";
			break;
		case 0: /* Should this be the default? */
			(void) sprintf(buff, "Problem at octet %d\n",
			    icmp->icmp_pptr);
			pc = buff;
		default:
			break;
		}
		break;
	case ICMP_TSTAMP:
		pt = "Timestamp request";
		break;
	case ICMP_TSTAMPREPLY:
		pt = "Timestamp reply";
		break;
	case ICMP_IREQ:
		pt = "Information request";
		break;
	case ICMP_IREQREPLY:
		pt = "Information reply";
		break;
	case ICMP_MASKREQ:
		pt = "Address mask request";
		break;
	case ICMP_MASKREPLY:
		pt = "Address mask reply";
		(void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask));
		pc = buff;
		break;
	default:
		break;
	}

	if (flags & F_SUM) {
		line = get_sum_line();
		if (*pc) {
			if (*px) {
				(void) sprintf(line, "ICMP %s (%s)%s",
				    pt, pc, px);
			} else {
				(void) sprintf(line, "ICMP %s (%s)", pt, pc);
			}
		} else {
			(void) sprintf(line, "ICMP %s", pt);
		}
	}

	if (flags & F_DTAIL) {
		show_header("ICMP:  ", "ICMP Header", ilen);
		show_space();
		(void) sprintf(get_line(0, 0), "Type = %d (%s)",
		    icmp->icmp_type, pt);
		if (*pc) {
			(void) sprintf(get_line(0, 0), "Code = %d (%s)",
			    icmp->icmp_code, pc);
		} else {
			(void) sprintf(get_line(0, 0), "Code = %d",
			    icmp->icmp_code);
		}
		(void) sprintf(get_line(0, 0), "Checksum = %x",
		    ntohs(icmp->icmp_cksum));

		if (icmp->icmp_type == ICMP_UNREACH ||
		    icmp->icmp_type == ICMP_REDIRECT) {
			if (ilen > 28) {
				show_space();
				(void) sprintf(get_line(0, 0),
				    "[ subject header follows ]");
				show_space();
				prot_nest_prefix = "ICMP:";
				(void) interpret_ip(flags,
				    (struct ip *)icmp->icmp_data, 28);
				prot_nest_prefix = "";
			}
		} else if (icmp->icmp_type == ICMP_PARAMPROB) {
			if (ilen > 28) {
				show_space();
				(void) sprintf(get_line(0, 0),
				    "[ subject header follows ]");
				show_space();
				prot_nest_prefix = "ICMP:";
				(void) interpret_ip(flags,
				    (struct ip *)icmp->icmp_data, 28);
				prot_nest_prefix = "";
			}
		} else if (icmp->icmp_type == ICMP_ROUTERADVERT) {
			if (icmp->icmp_wpa == 2) {
				int icmp_ra_len;

				show_space();
				icmp_ra_len = ICMP_MINLEN +
				    num_rtr_addrs *
					sizeof (struct icmp_ra_addr);
				prot_nest_prefix = "";
				if (ilen > icmp_ra_len) {
					interpret_icmp_mip_ext(
					    (uchar_t *)icmp + icmp_ra_len,
					    ilen - icmp_ra_len);
				}
			}
		}
		show_space();
	}
}