Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2009
      3  * 	Siemens AG, All rights reserved.
      4  * 	Dmitry Eremin-Solenikov (dbaryshkov (at) gmail.com)
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that: (1) source code distributions
      8  * retain the above copyright notice and this paragraph in its entirety, (2)
      9  * distributions including binary code include the above copyright notice and
     10  * this paragraph in its entirety in the documentation or other materials
     11  * provided with the distribution, and (3) all advertising materials mentioning
     12  * features or use of this software display the following acknowledgement:
     13  * ``This product includes software developed by the University of California,
     14  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     15  * the University nor the names of its contributors may be used to endorse
     16  * or promote products derived from this software without specific prior
     17  * written permission.
     18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     19  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     21  */
     22 
     23 /* \summary: IEEE 802.15.4 printer */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include "config.h"
     27 #endif
     28 
     29 #include <netdissect-stdinc.h>
     30 
     31 #include "netdissect.h"
     32 #include "addrtoname.h"
     33 
     34 #include "extract.h"
     35 
     36 static const char *ftypes[] = {
     37 	"Beacon",			/* 0 */
     38 	"Data",				/* 1 */
     39 	"ACK",				/* 2 */
     40 	"Command",			/* 3 */
     41 	"Reserved",			/* 4 */
     42 	"Reserved",			/* 5 */
     43 	"Reserved",			/* 6 */
     44 	"Reserved",			/* 7 */
     45 };
     46 
     47 static int
     48 extract_header_length(uint16_t fc)
     49 {
     50 	int len = 0;
     51 
     52 	switch ((fc >> 10) & 0x3) {
     53 	case 0x00:
     54 		if (fc & (1 << 6)) /* intra-PAN with none dest addr */
     55 			return -1;
     56 		break;
     57 	case 0x01:
     58 		return -1;
     59 	case 0x02:
     60 		len += 4;
     61 		break;
     62 	case 0x03:
     63 		len += 10;
     64 		break;
     65 	}
     66 
     67 	switch ((fc >> 14) & 0x3) {
     68 	case 0x00:
     69 		break;
     70 	case 0x01:
     71 		return -1;
     72 	case 0x02:
     73 		len += 4;
     74 		break;
     75 	case 0x03:
     76 		len += 10;
     77 		break;
     78 	}
     79 
     80 	if (fc & (1 << 6)) {
     81 		if (len < 2)
     82 			return -1;
     83 		len -= 2;
     84 	}
     85 
     86 	return len;
     87 }
     88 
     89 
     90 u_int
     91 ieee802_15_4_if_print(netdissect_options *ndo,
     92                       const struct pcap_pkthdr *h, const u_char *p)
     93 {
     94 	u_int caplen = h->caplen;
     95 	int hdrlen;
     96 	uint16_t fc;
     97 	uint8_t seq;
     98 
     99 	if (caplen < 3) {
    100 		ND_PRINT((ndo, "[|802.15.4] %x", caplen));
    101 		return caplen;
    102 	}
    103 
    104 	fc = EXTRACT_LE_16BITS(p);
    105 	hdrlen = extract_header_length(fc);
    106 
    107 	seq = EXTRACT_LE_8BITS(p + 2);
    108 
    109 	p += 3;
    110 	caplen -= 3;
    111 
    112 	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
    113 	if (ndo->ndo_vflag)
    114 		ND_PRINT((ndo,"seq %02x ", seq));
    115 	if (hdrlen == -1) {
    116 		ND_PRINT((ndo,"invalid! "));
    117 		return caplen;
    118 	}
    119 
    120 
    121 	if (!ndo->ndo_vflag) {
    122 		p+= hdrlen;
    123 		caplen -= hdrlen;
    124 	} else {
    125 		uint16_t panid = 0;
    126 
    127 		switch ((fc >> 10) & 0x3) {
    128 		case 0x00:
    129 			ND_PRINT((ndo,"none "));
    130 			break;
    131 		case 0x01:
    132 			ND_PRINT((ndo,"reserved destination addressing mode"));
    133 			return 0;
    134 		case 0x02:
    135 			panid = EXTRACT_LE_16BITS(p);
    136 			p += 2;
    137 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
    138 			p += 2;
    139 			break;
    140 		case 0x03:
    141 			panid = EXTRACT_LE_16BITS(p);
    142 			p += 2;
    143 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
    144 			p += 8;
    145 			break;
    146 		}
    147 		ND_PRINT((ndo,"< "));
    148 
    149 		switch ((fc >> 14) & 0x3) {
    150 		case 0x00:
    151 			ND_PRINT((ndo,"none "));
    152 			break;
    153 		case 0x01:
    154 			ND_PRINT((ndo,"reserved source addressing mode"));
    155 			return 0;
    156 		case 0x02:
    157 			if (!(fc & (1 << 6))) {
    158 				panid = EXTRACT_LE_16BITS(p);
    159 				p += 2;
    160 			}
    161 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
    162 			p += 2;
    163 			break;
    164 		case 0x03:
    165 			if (!(fc & (1 << 6))) {
    166 				panid = EXTRACT_LE_16BITS(p);
    167 				p += 2;
    168 			}
    169                         ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
    170 			p += 8;
    171 			break;
    172 		}
    173 
    174 		caplen -= hdrlen;
    175 	}
    176 
    177 	if (!ndo->ndo_suppress_default_print)
    178 		ND_DEFAULTPRINT(p, caplen);
    179 
    180 	return 0;
    181 }
    182