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, ðer_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); }
static int set_general(struct sc_stream* stream, char* stream_str) { int rc = 0; uint8_t mac[6]; char* key; char* next_field = stream_str; /* General format is series of key=value pairs, separated by ",". */ while( next_field && (rc == 0) ) { char* value; char* field; field = strsep(&next_field, ","); /* Split key and value */ value = field; key = strsep(&value, "="); if( !value ) { /* Handle some key-only magic values */ if( !strcmp(key, "all") ) rc = sc_stream_all(stream); /* The following needs a strncmp because we pass the stream as * 'sniff [0,1]' */ else if( !strncmp(key, "sniff", strlen("sniff")) ) rc = sc_stream_sniff(stream, key); else if( !strcmp(key, "ip") ) rc = set_eth_type(stream, key); else if( !strcmp(key, "udp") || !strcmp(key, "tcp") ) rc = set_protocol(stream, key); else { fprintf(stderr, "%s: ERROR: No value for key %s\n", __func__, key); return -EINVAL; } } else { if( !strcmp(key, "dmac") ) { if( parse_mac(value, mac) < 0 ) { fprintf(stderr, "%s: ERROR: Failed to parse mac \"%s\"\n", __func__, key); return -EINVAL; } rc = sc_stream_eth_dhost(stream, mac); } else if( !strcmp(key, "smac") ) { if( parse_mac(value, mac) < 0 ) fprintf(stderr, "%s: ERROR: Failed to parse mac \"%s\"\n", __func__, key); return -EINVAL; rc = sc_stream_eth_shost(stream, mac); } else if( !strcmp(key, "vid") ) { rc = set_vlan_id(stream, value); } else if( !strcmp(key, "eth_type") ) { rc = set_eth_type(stream, value); } else if( !strcmp(key, "shost") ) { rc = sc_stream_ip_source_host(stream, value); } else if( !strcmp(key, "dhost") ) { rc = sc_stream_ip_dest_host(stream, value); } else if( !strcmp(key, "ip_protocol") ) { rc = set_protocol(stream, value); } else if( !strcmp(key, "sport") ) { rc = sc_stream_ip_source_port(stream, value); } else if( !strcmp(key, "dport") ) { rc = sc_stream_ip_dest_port(stream, value); } else { fprintf(stderr, "%s: ERROR: Unrecognised key \"%s\"\n", __func__, key); return -EINVAL; } } } return rc; }