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