File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / trafshow / parse_dl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:55:18 2012 UTC (12 years, 4 months ago) by misho
Branches: trafshow, MAIN
CVS tags: v5_2_3p0, v5_2_3, HEAD
trafshow

    1: /*
    2:  *	Copyright (c) 2004 Rinet Corp., Novosibirsk, Russia
    3:  *
    4:  * Redistribution and use in source forms, with and without modification,
    5:  * are permitted provided that this entire comment appears intact.
    6:  *
    7:  * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
    8:  */
    9: 
   10: #ifdef	HAVE_CONFIG_H
   11: #include <config.h>
   12: #endif
   13: 
   14: #include <sys/types.h>
   15: #include <sys/socket.h>
   16: #ifdef	linux
   17: #include <linux/if.h>
   18: #else
   19: #include <net/if.h>
   20: #endif
   21: #include <netinet/in.h>
   22: #include <netinet/in_systm.h>
   23: #include <netinet/if_ether.h>
   24: #include <netinet/ip.h>
   25: #include <string.h>
   26: #include <pcap.h>
   27: 
   28: #include "parse_dl.h"
   29: #include "parse_ip.h"
   30: #include "netstat.h"
   31: #include "ethertype.h"
   32: #include "sll.h"
   33: 
   34: #ifndef	DLT_LINUX_SLL
   35: #define	DLT_LINUX_SLL	113
   36: #endif
   37: 
   38: struct ether_dot1q_header {
   39: 	u_char dhost[ETHER_ADDR_LEN];
   40: 	u_char shost[ETHER_ADDR_LEN];
   41: 	u_int16_t encap_proto;
   42: 	u_int16_t tag;
   43: 	u_int16_t proto;
   44: };
   45: 
   46: int
   47: is_parse_dl(type)
   48: 	int type;
   49: {
   50: 	return (type == DLT_NULL ||
   51: 		type == DLT_LOOP ||
   52: 		type == DLT_EN10MB ||
   53: 		type == DLT_SLIP ||
   54: 		type == DLT_PPP_ETHER ||
   55: 		type == DLT_PPP ||
   56: 		type == DLT_RAW ||
   57: 		type == DLT_C_HDLC ||
   58: 		type == DLT_PPP_SERIAL ||
   59: 		type == DLT_LINUX_SLL);
   60: }
   61: 
   62: const char *
   63: parse_dl_name(type)
   64: 	int type;
   65: {
   66: 	switch (type) {
   67: 	case DLT_NULL:
   68: 	case DLT_LOOP:
   69: 		return "Loopback";
   70: 	case DLT_EN10MB:
   71: 		return "Ethernet";
   72: 	case DLT_SLIP:
   73: 		return "SLIP";
   74: 	case DLT_PPP_ETHER:
   75: 		return "PPP over Ethernet";
   76: 	case DLT_PPP:
   77: 		return "Async PPP";
   78: 	case DLT_RAW:
   79: 		return "raw IP";
   80: 	case DLT_C_HDLC:
   81: 		return "Cisco HDLC";
   82: 	case DLT_PPP_SERIAL:
   83: 		return "Sync PPP";
   84: 	case DLT_LINUX_SLL:
   85: 		return "Linux cooked socket";
   86: 	}
   87: 	return "Unknown";
   88: }
   89: 
   90: int
   91: parse_dl(ns, dlt, caplen, pktlen, pkt)
   92: 	NETSTAT *ns;
   93: 	int dlt, caplen, pktlen;
   94: 	const u_char *pkt;
   95: {
   96: 	const struct ether_header *ether = 0;
   97: 	const struct ip *ip = 0;
   98: 	const u_char *p = pkt;
   99: 	u_int length = pktlen;
  100: 	u_int type, hdrlen;
  101: 	u_char dsap, ssap;
  102: 
  103: 	/* sanity check */
  104: 	if (!pkt) return -1;
  105: 
  106: 	switch (dlt) {
  107: 	case DLT_NULL:
  108: 	case DLT_LOOP:
  109: 		if (caplen < 4)
  110: 			return -1;
  111: 		memcpy((u_char *)&type, p, sizeof(type));
  112: 		if (type & 0xffff0000) { /* swap bytes */
  113: 			type = (((type & 0xff) << 24) |
  114: 				((type & 0xff00) << 8) |
  115: 				((type & 0xff0000) >> 8) |
  116: 				((type >> 24) & 0xff));
  117: 		}
  118: 		if (type != AF_INET && type != AF_INET6)
  119: 			return -1;
  120: 		p += 4;
  121: 		ip = (const struct ip *)p;
  122: 		caplen -= 4;
  123: 		length -= 4;
  124: 		break;
  125: 
  126: 	case DLT_EN10MB:
  127: 		hdrlen = sizeof(struct ether_header);
  128: 		if (caplen < hdrlen)
  129: 			return -1;
  130: 		ether = (struct ether_header *)p;
  131: 		if (ns) {
  132: #ifdef	HAVE_ETHER_ADDR
  133: 			memcpy(ns->eth_src_addr,
  134: 			       &ether->ether_shost, sizeof(struct ether_addr));
  135: 			memcpy(ns->eth_dst_addr,
  136: 			       &ether->ether_dhost, sizeof(struct ether_addr));
  137: #else
  138: 			memcpy(ns->eth_src_addr,
  139: 			       ether->ether_shost, ETHER_ADDR_LEN);
  140: 			memcpy(ns->eth_dst_addr,
  141: 			       ether->ether_dhost, ETHER_ADDR_LEN);
  142: #endif
  143: 			ns->eth_type = ether->ether_type;
  144: 		}
  145: 		type = ntohs(ether->ether_type);
  146: 		if (type <= ETHERMTU) {
  147: 			/* IEEE 802.3 frame: the type is data length */
  148: 			if (caplen < hdrlen + 3)
  149: 				return -1;
  150: 
  151: 			/* extract SAP (Service Access Point) IDs */
  152: 			dsap = p[hdrlen];
  153: 			ssap = p[hdrlen + 1];
  154: 			if (ns) {
  155: 				ns->eth_dsap = dsap;
  156: 				ns->eth_ssap = ssap;
  157: 				ns->data_len = type;
  158: 			}
  159: 			type = 0; /* no type known yet */
  160: 
  161: 			hdrlen += 3;	/* skip 802.2 LLC header */
  162: 
  163: 			if (dsap == 0x06 && ssap == 0x06) {
  164: 				/* 802.3/802.2 encapsulated IP */
  165: 				type = ETHERTYPE_IP;
  166: 
  167: 			} else if (dsap == 0xAA && ssap == 0xAA) {
  168: 				if (caplen < hdrlen + 5)
  169: 					return -1;
  170: 
  171: 				/* extract encap type after 3-bytes OUI */
  172: 				type = *(u_int16_t *)(p + hdrlen + 3);
  173: 				if (ns) ns->eth_type = type;
  174: 				type = ntohs(type);
  175: 
  176: 				hdrlen += 5;	/* skip 802.2 SNAP header */
  177: 			}
  178: 		} else if (type == ETHERTYPE_8021Q) {
  179: 			hdrlen = sizeof(struct ether_dot1q_header);
  180: 			if (caplen < hdrlen)
  181: 				return -1;
  182: 			if (ns) ns->eth_tag = ((struct ether_dot1q_header *)p)->tag;
  183: 			type = ntohs(((struct ether_dot1q_header *)p)->proto);
  184: 		}
  185: 		p += hdrlen;
  186: 		if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
  187: 			ip = (const struct ip *)p;
  188: 		caplen -= hdrlen;
  189: 		length -= hdrlen;
  190: 		break;
  191: 
  192: 	case DLT_SLIP:
  193: 		if (caplen < 16)
  194: 			return -1;
  195: 		p += 16;
  196: 		ip = (const struct ip *)p;
  197: 		caplen -= 16;
  198: 		length -= 16;
  199: 		break;
  200: 
  201: 	case DLT_PPP_ETHER:
  202: 		if (caplen < 6 || p[1])
  203: 			return -1;
  204: 		p += 6;
  205: 		caplen -= 6;
  206: 		length -= 6;
  207: 		/* pass through */
  208: 
  209: 	case DLT_PPP:
  210: 		if (caplen < 4)
  211: 			return -1;
  212: 		hdrlen = 0;
  213: #ifdef SLC_BPFHDR
  214: 		if (dlt == DLT_PPP) {
  215: 			ip = (const struct ip *)(p + SLC_BPFHDR);/* skip bpf pseudo header */
  216: 			p += SLC_BPFHDRLEN; /* now pointer to link level header */
  217: 		}
  218: #endif
  219: 		/* PPP address and PPP control fields may be present (-acfc) */
  220: 		if (p[0] == 0xff && p[1] == 0x03) {
  221: 			p += 2;
  222: 			hdrlen += 2;
  223: 		}
  224: 		/* retrive the protocol type */
  225: 		if (*p & 01) {	/* compressed protocol field (pfc) */
  226: 			type = *p++;
  227: 			hdrlen++;
  228: 		} else {	/* un-compressed protocol field (-pfc) */
  229: 			type = ntohs(*(u_int16_t *)p);
  230: 			p += 2;
  231: 			hdrlen += 2;
  232: 		}
  233: 		/* check for IP or IPv6 */
  234: 		if (type != 0x21 && type != 0x57 &&
  235: 		    type != ETHERTYPE_IP && type != ETHERTYPE_IPV6)
  236: 			return -1;
  237: #ifdef SLC_BPFHDR
  238: 		if (dlt == DLT_PPP) {
  239: 			caplen -= SLC_BPFHDR;
  240: 			length -= SLC_BPFHDR;
  241: 		} else {
  242: 			ip = (const struct ip *)p;
  243: 			caplen -= hdrlen;
  244: 			length -= hdrlen;
  245: 		}
  246: #else
  247: 		ip = (const struct ip *)p;
  248: 		caplen -= hdrlen;
  249: 		length -= hdrlen;
  250: #endif
  251: 		break;
  252: 
  253: 	case DLT_RAW:
  254: 		ip = (const struct ip *)p;
  255: 		break;
  256: 
  257: 	case DLT_C_HDLC:
  258: 	case DLT_PPP_SERIAL:
  259: 		if (caplen < 4)
  260: 			return -1;
  261: 		/* check for UNICAST or BCAST */
  262: 		if (p[0] != 0x0f && p[0] != 0x8f)
  263: 			return -1;
  264: 		type = ntohs(*(u_int16_t *)&p[2]);
  265: 		if (type != ETHERTYPE_IP && type != ETHERTYPE_IPV6)
  266: 			return -1;
  267: 		p += 4;
  268: 		ip = (const struct ip *)p;
  269: 		caplen -= 4;
  270: 		length -= 4;
  271: 		break;
  272: 
  273: 	case DLT_LINUX_SLL:
  274: 		if (caplen < SLL_HDR_LEN)
  275: 			return -1;
  276: 		if (ntohs(((struct sll_header *)p)->sll_halen) == ETHER_ADDR_LEN) {
  277: 			if (ns) {
  278: 				/* the source address is in the packet header */
  279: 				memcpy(ns->eth_src_addr,
  280: 				       ((struct sll_header *)p)->sll_addr,
  281: 				       ETHER_ADDR_LEN);
  282: 				/* just a fake the destination address */
  283: 				memset(ns->eth_dst_addr, 0, ETHER_ADDR_LEN);
  284: 				type = ntohs(((struct sll_header *)p)->sll_pkttype);
  285: 				if (type != LINUX_SLL_OUTGOING) {
  286: 					if (type == LINUX_SLL_BROADCAST)
  287: 						memset(ns->eth_dst_addr, 0xff,
  288: 						       ETHER_ADDR_LEN);
  289: 					else if (type == LINUX_SLL_MULTICAST)
  290: 						ns->eth_dst_addr[0] = 1;
  291: 					else	ns->eth_dst_addr[ETHER_ADDR_LEN-1] = 1;
  292: 				}
  293: 				ns->eth_type = ((struct sll_header *)p)->sll_protocol;
  294: 			}
  295: 			/* point somewhere to avoid return after switch() */
  296: 			ether = (struct ether_header *)p;
  297: 		}
  298: 		type = ntohs(((struct sll_header *)p)->sll_protocol);
  299: 		p += SLL_HDR_LEN;
  300: 		caplen -= SLL_HDR_LEN;
  301: 		length -= SLL_HDR_LEN;
  302: 		if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
  303: 			ip = (const struct ip *)p;
  304: 		break;
  305: 
  306: 	default:
  307: 		/* Unknown or unsupported data link type */
  308: 		return -1;
  309: 	}
  310: 
  311: 	if (!ether && !ip)
  312: 		return -1;
  313: 
  314: 	if (caplen > length)
  315: 		caplen = length;
  316: 
  317: 	if (ns) {
  318: 		if (!ns->pkt_cnt) ns->pkt_cnt = 1;
  319: 		if (!ns->pkt_len) ns->pkt_len = pktlen;
  320: 		if (!ns->data_len) ns->data_len = length;
  321: 	}
  322: 
  323: 	hdrlen = (char *)p - (char *)pkt;
  324: 	if (ip && caplen >= sizeof(struct ip)) {
  325: 		int hlen = parse_ip(ns, caplen, ip);
  326: 		if (hlen > 0) hdrlen += hlen;
  327: 	}
  328: 	return hdrlen;
  329: }
  330: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>