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
extract_header_length(u_int16_t fc)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
ieee802_15_4_if_print(struct netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)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