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 (0x4)",		/* 4 */
     42 	"Reserved (0x5)",		/* 5 */
     43 	"Reserved (0x6)",		/* 6 */
     44 	"Reserved (0x7)",		/* 7 */
     45 };
     46 
     47 /*
     48  * Frame Control subfields.
     49  */
     50 #define FC_FRAME_TYPE(fc)		((fc) & 0x7)
     51 #define FC_SECURITY_ENABLED		0x0008
     52 #define FC_FRAME_PENDING		0x0010
     53 #define FC_ACK_REQUEST			0x0020
     54 #define FC_PAN_ID_COMPRESSION		0x0040
     55 #define FC_DEST_ADDRESSING_MODE(fc)	(((fc) >> 10) & 0x3)
     56 #define FC_FRAME_VERSION(fc)		(((fc) >> 12) & 0x3)
     57 #define FC_SRC_ADDRESSING_MODE(fc)	(((fc) >> 14) & 0x3)
     58 
     59 #define FC_ADDRESSING_MODE_NONE		0x00
     60 #define FC_ADDRESSING_MODE_RESERVED	0x01
     61 #define FC_ADDRESSING_MODE_SHORT	0x02
     62 #define FC_ADDRESSING_MODE_LONG		0x03
     63 
     64 u_int
     65 ieee802_15_4_if_print(netdissect_options *ndo,
     66                       const struct pcap_pkthdr *h, const u_char *p)
     67 {
     68 	u_int caplen = h->caplen;
     69 	u_int hdrlen;
     70 	uint16_t fc;
     71 	uint8_t seq;
     72 	uint16_t panid = 0;
     73 
     74 	if (caplen < 3) {
     75 		ND_PRINT((ndo, "[|802.15.4]"));
     76 		return caplen;
     77 	}
     78 	hdrlen = 3;
     79 
     80 	fc = EXTRACT_LE_16BITS(p);
     81 	seq = EXTRACT_LE_8BITS(p + 2);
     82 
     83 	p += 3;
     84 	caplen -= 3;
     85 
     86 	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]));
     87 	if (ndo->ndo_vflag)
     88 		ND_PRINT((ndo,"seq %02x ", seq));
     89 
     90 	/*
     91 	 * Destination address and PAN ID, if present.
     92 	 */
     93 	switch (FC_DEST_ADDRESSING_MODE(fc)) {
     94 	case FC_ADDRESSING_MODE_NONE:
     95 		if (fc & FC_PAN_ID_COMPRESSION) {
     96 			/*
     97 			 * PAN ID compression; this requires that both
     98 			 * the source and destination addresses be present,
     99 			 * but the destination address is missing.
    100 			 */
    101 			ND_PRINT((ndo, "[|802.15.4]"));
    102 			return hdrlen;
    103 		}
    104 		if (ndo->ndo_vflag)
    105 			ND_PRINT((ndo,"none "));
    106 		break;
    107 	case FC_ADDRESSING_MODE_RESERVED:
    108 		if (ndo->ndo_vflag)
    109 			ND_PRINT((ndo,"reserved destination addressing mode"));
    110 		return hdrlen;
    111 	case FC_ADDRESSING_MODE_SHORT:
    112 		if (caplen < 2) {
    113 			ND_PRINT((ndo, "[|802.15.4]"));
    114 			return hdrlen;
    115 		}
    116 		panid = EXTRACT_LE_16BITS(p);
    117 		p += 2;
    118 		caplen -= 2;
    119 		hdrlen += 2;
    120 		if (caplen < 2) {
    121 			ND_PRINT((ndo, "[|802.15.4]"));
    122 			return hdrlen;
    123 		}
    124 		if (ndo->ndo_vflag)
    125 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
    126 		p += 2;
    127 		caplen -= 2;
    128 		hdrlen += 2;
    129 		break;
    130 	case FC_ADDRESSING_MODE_LONG:
    131 		if (caplen < 2) {
    132 			ND_PRINT((ndo, "[|802.15.4]"));
    133 			return hdrlen;
    134 		}
    135 		panid = EXTRACT_LE_16BITS(p);
    136 		p += 2;
    137 		caplen -= 2;
    138 		hdrlen += 2;
    139 		if (caplen < 8) {
    140 			ND_PRINT((ndo, "[|802.15.4]"));
    141 			return hdrlen;
    142 		}
    143 		if (ndo->ndo_vflag)
    144 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
    145 		p += 8;
    146 		caplen -= 8;
    147 		hdrlen += 8;
    148 		break;
    149 	}
    150 	if (ndo->ndo_vflag)
    151 		ND_PRINT((ndo,"< "));
    152 
    153 	/*
    154 	 * Source address and PAN ID, if present.
    155 	 */
    156 	switch (FC_SRC_ADDRESSING_MODE(fc)) {
    157 	case FC_ADDRESSING_MODE_NONE:
    158 		if (ndo->ndo_vflag)
    159 			ND_PRINT((ndo,"none "));
    160 		break;
    161 	case FC_ADDRESSING_MODE_RESERVED:
    162 		if (ndo->ndo_vflag)
    163 			ND_PRINT((ndo,"reserved source addressing mode"));
    164 		return 0;
    165 	case FC_ADDRESSING_MODE_SHORT:
    166 		if (!(fc & FC_PAN_ID_COMPRESSION)) {
    167 			/*
    168 			 * The source PAN ID is not compressed out, so
    169 			 * fetch it.  (Otherwise, we'll use the destination
    170 			 * PAN ID, fetched above.)
    171 			 */
    172 			if (caplen < 2) {
    173 				ND_PRINT((ndo, "[|802.15.4]"));
    174 				return hdrlen;
    175 			}
    176 			panid = EXTRACT_LE_16BITS(p);
    177 			p += 2;
    178 			caplen -= 2;
    179 			hdrlen += 2;
    180 		}
    181 		if (caplen < 2) {
    182 			ND_PRINT((ndo, "[|802.15.4]"));
    183 			return hdrlen;
    184 		}
    185 		if (ndo->ndo_vflag)
    186 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
    187 		p += 2;
    188 		caplen -= 2;
    189 		hdrlen += 2;
    190 		break;
    191 	case FC_ADDRESSING_MODE_LONG:
    192 		if (!(fc & FC_PAN_ID_COMPRESSION)) {
    193 			/*
    194 			 * The source PAN ID is not compressed out, so
    195 			 * fetch it.  (Otherwise, we'll use the destination
    196 			 * PAN ID, fetched above.)
    197 			 */
    198 			if (caplen < 2) {
    199 				ND_PRINT((ndo, "[|802.15.4]"));
    200 				return hdrlen;
    201 			}
    202 			panid = EXTRACT_LE_16BITS(p);
    203 			p += 2;
    204 			caplen -= 2;
    205 			hdrlen += 2;
    206 		}
    207 		if (caplen < 8) {
    208 			ND_PRINT((ndo, "[|802.15.4]"));
    209 			return hdrlen;
    210 		}
    211 		if (ndo->ndo_vflag)
    212 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
    213 		p += 8;
    214 		caplen -= 8;
    215 		hdrlen += 8;
    216 		break;
    217 	}
    218 
    219 	if (!ndo->ndo_suppress_default_print)
    220 		ND_DEFAULTPRINT(p, caplen);
    221 
    222 	return hdrlen;
    223 }
    224