print-802_15_4.c revision 313537
1/*
2 * Copyright (c) 2009
3 * 	Siemens AG, All rights reserved.
4 * 	Dmitry Eremin-Solenikov (dbaryshkov@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
36static 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
47static int
48extract_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
90u_int
91ieee802_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