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);
}
Beispiel #2
0
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;
}