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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <tcpdump-stdinc.h>
28 
29 #include <stdio.h>
30 #include <pcap.h>
31 #include <string.h>
32 
33 #include "interface.h"
34 #include "addrtoname.h"
35 
36 #include "extract.h"
37 
38 static const char *ftypes[] = {
39 	"Beacon",			/* 0 */
40 	"Data",				/* 1 */
41 	"ACK",				/* 2 */
42 	"Command",			/* 3 */
43 	"Reserved",			/* 4 */
44 	"Reserved",			/* 5 */
45 	"Reserved",			/* 6 */
46 	"Reserved",			/* 7 */
47 };
48 
49 static int
50 extract_header_length(u_int16_t fc)
51 {
52 	int len = 0;
53 
54 	switch ((fc >> 10) & 0x3) {
55 	case 0x00:
56 		if (fc & (1 << 6)) /* intra-PAN with none dest addr */
57 			return -1;
58 		break;
59 	case 0x01:
60 		return -1;
61 	case 0x02:
62 		len += 4;
63 		break;
64 	case 0x03:
65 		len += 10;
66 		break;
67 	}
68 
69 	switch ((fc >> 14) & 0x3) {
70 	case 0x00:
71 		break;
72 	case 0x01:
73 		return -1;
74 	case 0x02:
75 		len += 4;
76 		break;
77 	case 0x03:
78 		len += 10;
79 		break;
80 	}
81 
82 	if (fc & (1 << 6)) {
83 		if (len < 2)
84 			return -1;
85 		len -= 2;
86 	}
87 
88 	return len;
89 }
90 
91 
92 u_int
93 ieee802_15_4_if_print(struct netdissect_options *ndo,
94                       const struct pcap_pkthdr *h, const u_char *p)
95 {
96 	u_int caplen = h->caplen;
97 	int hdrlen;
98 	u_int16_t fc;
99 	u_int8_t seq;
100 
101 	if (caplen < 3) {
102 		ND_PRINT((ndo, "[|802.15.4] %x", caplen));
103 		return caplen;
104 	}
105 
106 	fc = EXTRACT_LE_16BITS(p);
107 	hdrlen = extract_header_length(fc);
108 
109 	seq = EXTRACT_LE_8BITS(p + 2);
110 
111 	p += 3;
112 	caplen -= 3;
113 
114 	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
115 	if (vflag)
116 		ND_PRINT((ndo,"seq %02x ", seq));
117 	if (hdrlen == -1) {
118 		ND_PRINT((ndo,"malformed! "));
119 		return caplen;
120 	}
121 
122 
123 	if (!vflag) {
124 		p+= hdrlen;
125 		caplen -= hdrlen;
126 	} else {
127 		u_int16_t panid = 0;
128 
129 		switch ((fc >> 10) & 0x3) {
130 		case 0x00:
131 			ND_PRINT((ndo,"none "));
132 			break;
133 		case 0x01:
134 			ND_PRINT((ndo,"reserved destination addressing mode"));
135 			return 0;
136 		case 0x02:
137 			panid = EXTRACT_LE_16BITS(p);
138 			p += 2;
139 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
140 			p += 2;
141 			break;
142 		case 0x03:
143 			panid = EXTRACT_LE_16BITS(p);
144 			p += 2;
145 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p)));
146 			p += 8;
147 			break;
148 		}
149 		ND_PRINT((ndo,"< ");
150 
151 		switch ((fc >> 14) & 0x3) {
152 		case 0x00:
153 			ND_PRINT((ndo,"none "));
154 			break;
155 		case 0x01:
156 			ND_PRINT((ndo,"reserved source addressing mode"));
157 			return 0;
158 		case 0x02:
159 			if (!(fc & (1 << 6))) {
160 				panid = EXTRACT_LE_16BITS(p);
161 				p += 2;
162 			}
163 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
164 			p += 2;
165 			break;
166 		case 0x03:
167 			if (!(fc & (1 << 6))) {
168 				panid = EXTRACT_LE_16BITS(p);
169 				p += 2;
170 			}
171                         ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p))));
172 			p += 8;
173 			break;
174 		}
175 
176 		caplen -= hdrlen;
177 	}
178 
179 	if (!suppress_default_print)
180 		(ndo->ndo_default_print)(ndo, p, caplen);
181 
182 	return 0;
183 }
184