1235427Sdelphij/*
2235427Sdelphij * Copyright (c) 2009
3235427Sdelphij * 	Siemens AG, All rights reserved.
4235427Sdelphij * 	Dmitry Eremin-Solenikov (dbaryshkov@gmail.com)
5235427Sdelphij *
6235427Sdelphij * Redistribution and use in source and binary forms, with or without
7235427Sdelphij * modification, are permitted provided that: (1) source code distributions
8235427Sdelphij * retain the above copyright notice and this paragraph in its entirety, (2)
9235427Sdelphij * distributions including binary code include the above copyright notice and
10235427Sdelphij * this paragraph in its entirety in the documentation or other materials
11235427Sdelphij * provided with the distribution, and (3) all advertising materials mentioning
12235427Sdelphij * features or use of this software display the following acknowledgement:
13235427Sdelphij * ``This product includes software developed by the University of California,
14235427Sdelphij * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15235427Sdelphij * the University nor the names of its contributors may be used to endorse
16235427Sdelphij * or promote products derived from this software without specific prior
17235427Sdelphij * written permission.
18235427Sdelphij * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19235427Sdelphij * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20235427Sdelphij * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21235427Sdelphij */
22235427Sdelphij
23235427Sdelphij#ifdef HAVE_CONFIG_H
24235427Sdelphij#include "config.h"
25235427Sdelphij#endif
26235427Sdelphij
27235427Sdelphij#include <tcpdump-stdinc.h>
28235427Sdelphij
29235427Sdelphij#include <stdio.h>
30235427Sdelphij#include <pcap.h>
31235427Sdelphij#include <string.h>
32235427Sdelphij
33235427Sdelphij#include "interface.h"
34235427Sdelphij#include "addrtoname.h"
35235427Sdelphij
36235427Sdelphij#include "extract.h"
37235427Sdelphij
38235427Sdelphijstatic const char *ftypes[] = {
39235427Sdelphij	"Beacon",			/* 0 */
40235427Sdelphij	"Data",				/* 1 */
41235427Sdelphij	"ACK",				/* 2 */
42235427Sdelphij	"Command",			/* 3 */
43235427Sdelphij	"Reserved",			/* 4 */
44235427Sdelphij	"Reserved",			/* 5 */
45235427Sdelphij	"Reserved",			/* 6 */
46235427Sdelphij	"Reserved",			/* 7 */
47235427Sdelphij};
48235427Sdelphij
49235427Sdelphijstatic int
50235427Sdelphijextract_header_length(u_int16_t fc)
51235427Sdelphij{
52235427Sdelphij	int len = 0;
53235427Sdelphij
54235427Sdelphij	switch ((fc >> 10) & 0x3) {
55235427Sdelphij	case 0x00:
56235427Sdelphij		if (fc & (1 << 6)) /* intra-PAN with none dest addr */
57235427Sdelphij			return -1;
58235427Sdelphij		break;
59235427Sdelphij	case 0x01:
60235427Sdelphij		return -1;
61235427Sdelphij	case 0x02:
62235427Sdelphij		len += 4;
63235427Sdelphij		break;
64235427Sdelphij	case 0x03:
65235427Sdelphij		len += 10;
66235427Sdelphij		break;
67235427Sdelphij	}
68235427Sdelphij
69235427Sdelphij	switch ((fc >> 14) & 0x3) {
70235427Sdelphij	case 0x00:
71235427Sdelphij		break;
72235427Sdelphij	case 0x01:
73235427Sdelphij		return -1;
74235427Sdelphij	case 0x02:
75235427Sdelphij		len += 4;
76235427Sdelphij		break;
77235427Sdelphij	case 0x03:
78235427Sdelphij		len += 10;
79235427Sdelphij		break;
80235427Sdelphij	}
81235427Sdelphij
82235427Sdelphij	if (fc & (1 << 6)) {
83235427Sdelphij		if (len < 2)
84235427Sdelphij			return -1;
85235427Sdelphij		len -= 2;
86235427Sdelphij	}
87235427Sdelphij
88235427Sdelphij	return len;
89235427Sdelphij}
90235427Sdelphij
91235427Sdelphij
92235427Sdelphiju_int
93235427Sdelphijieee802_15_4_if_print(struct netdissect_options *ndo,
94235427Sdelphij                      const struct pcap_pkthdr *h, const u_char *p)
95235427Sdelphij{
96235427Sdelphij	u_int caplen = h->caplen;
97235427Sdelphij	int hdrlen;
98235427Sdelphij	u_int16_t fc;
99235427Sdelphij	u_int8_t seq;
100235427Sdelphij
101235427Sdelphij	if (caplen < 3) {
102235427Sdelphij		ND_PRINT((ndo, "[|802.15.4] %x", caplen));
103235427Sdelphij		return caplen;
104235427Sdelphij	}
105235427Sdelphij
106235427Sdelphij	fc = EXTRACT_LE_16BITS(p);
107235427Sdelphij	hdrlen = extract_header_length(fc);
108235427Sdelphij
109235427Sdelphij	seq = EXTRACT_LE_8BITS(p + 2);
110235427Sdelphij
111235427Sdelphij	p += 3;
112235427Sdelphij	caplen -= 3;
113235427Sdelphij
114235427Sdelphij	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
115235427Sdelphij	if (vflag)
116235427Sdelphij		ND_PRINT((ndo,"seq %02x ", seq));
117235427Sdelphij	if (hdrlen == -1) {
118235427Sdelphij		ND_PRINT((ndo,"malformed! "));
119235427Sdelphij		return caplen;
120235427Sdelphij	}
121235427Sdelphij
122235427Sdelphij
123235427Sdelphij	if (!vflag) {
124235427Sdelphij		p+= hdrlen;
125235427Sdelphij		caplen -= hdrlen;
126235427Sdelphij	} else {
127235427Sdelphij		u_int16_t panid = 0;
128235427Sdelphij
129235427Sdelphij		switch ((fc >> 10) & 0x3) {
130235427Sdelphij		case 0x00:
131235427Sdelphij			ND_PRINT((ndo,"none "));
132235427Sdelphij			break;
133235427Sdelphij		case 0x01:
134235427Sdelphij			ND_PRINT((ndo,"reserved destination addressing mode"));
135235427Sdelphij			return 0;
136235427Sdelphij		case 0x02:
137235427Sdelphij			panid = EXTRACT_LE_16BITS(p);
138235427Sdelphij			p += 2;
139235427Sdelphij			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
140235427Sdelphij			p += 2;
141235427Sdelphij			break;
142235427Sdelphij		case 0x03:
143235427Sdelphij			panid = EXTRACT_LE_16BITS(p);
144235427Sdelphij			p += 2;
145235427Sdelphij			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p)));
146235427Sdelphij			p += 8;
147235427Sdelphij			break;
148235427Sdelphij		}
149235427Sdelphij		ND_PRINT((ndo,"< ");
150235427Sdelphij
151235427Sdelphij		switch ((fc >> 14) & 0x3) {
152235427Sdelphij		case 0x00:
153235427Sdelphij			ND_PRINT((ndo,"none "));
154235427Sdelphij			break;
155235427Sdelphij		case 0x01:
156235427Sdelphij			ND_PRINT((ndo,"reserved source addressing mode"));
157235427Sdelphij			return 0;
158235427Sdelphij		case 0x02:
159235427Sdelphij			if (!(fc & (1 << 6))) {
160235427Sdelphij				panid = EXTRACT_LE_16BITS(p);
161235427Sdelphij				p += 2;
162235427Sdelphij			}
163235427Sdelphij			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
164235427Sdelphij			p += 2;
165235427Sdelphij			break;
166235427Sdelphij		case 0x03:
167235427Sdelphij			if (!(fc & (1 << 6))) {
168235427Sdelphij				panid = EXTRACT_LE_16BITS(p);
169235427Sdelphij				p += 2;
170235427Sdelphij			}
171235427Sdelphij                        ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p))));
172235427Sdelphij			p += 8;
173235427Sdelphij			break;
174235427Sdelphij		}
175235427Sdelphij
176235427Sdelphij		caplen -= hdrlen;
177235427Sdelphij	}
178235427Sdelphij
179235427Sdelphij	if (!suppress_default_print)
180235427Sdelphij		(ndo->ndo_default_print)(ndo, p, caplen);
181235427Sdelphij
182235427Sdelphij	return 0;
183235427Sdelphij}
184