xref: /netbsd-src/external/bsd/tcpdump/dist/print-802_15_4.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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 #include <sys/cdefs.h>
24 #ifndef lint
25 __RCSID("$NetBSD: print-802_15_4.c,v 1.4 2017/09/08 14:01:12 christos Exp $");
26 #endif
27 
28 /* \summary: IEEE 802.15.4 printer */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include <netdissect-stdinc.h>
35 
36 #include "netdissect.h"
37 #include "addrtoname.h"
38 
39 #include "extract.h"
40 
41 static const char *ftypes[] = {
42 	"Beacon",			/* 0 */
43 	"Data",				/* 1 */
44 	"ACK",				/* 2 */
45 	"Command",			/* 3 */
46 	"Reserved (0x4)",		/* 4 */
47 	"Reserved (0x5)",		/* 5 */
48 	"Reserved (0x6)",		/* 6 */
49 	"Reserved (0x7)",		/* 7 */
50 };
51 
52 /*
53  * Frame Control subfields.
54  */
55 #define FC_FRAME_TYPE(fc)		((fc) & 0x7)
56 #define FC_SECURITY_ENABLED		0x0008
57 #define FC_FRAME_PENDING		0x0010
58 #define FC_ACK_REQUEST			0x0020
59 #define FC_PAN_ID_COMPRESSION		0x0040
60 #define FC_DEST_ADDRESSING_MODE(fc)	(((fc) >> 10) & 0x3)
61 #define FC_FRAME_VERSION(fc)		(((fc) >> 12) & 0x3)
62 #define FC_SRC_ADDRESSING_MODE(fc)	(((fc) >> 14) & 0x3)
63 
64 #define FC_ADDRESSING_MODE_NONE		0x00
65 #define FC_ADDRESSING_MODE_RESERVED	0x01
66 #define FC_ADDRESSING_MODE_SHORT	0x02
67 #define FC_ADDRESSING_MODE_LONG		0x03
68 
69 u_int
70 ieee802_15_4_if_print(netdissect_options *ndo,
71                       const struct pcap_pkthdr *h, const u_char *p)
72 {
73 	u_int caplen = h->caplen;
74 	u_int hdrlen;
75 	uint16_t fc;
76 	uint8_t seq;
77 	uint16_t panid = 0;
78 
79 	if (caplen < 3) {
80 		ND_PRINT((ndo, "[|802.15.4]"));
81 		return caplen;
82 	}
83 	hdrlen = 3;
84 
85 	fc = EXTRACT_LE_16BITS(p);
86 	seq = EXTRACT_LE_8BITS(p + 2);
87 
88 	p += 3;
89 	caplen -= 3;
90 
91 	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]));
92 	if (ndo->ndo_vflag)
93 		ND_PRINT((ndo,"seq %02x ", seq));
94 
95 	/*
96 	 * Destination address and PAN ID, if present.
97 	 */
98 	switch (FC_DEST_ADDRESSING_MODE(fc)) {
99 	case FC_ADDRESSING_MODE_NONE:
100 		if (fc & FC_PAN_ID_COMPRESSION) {
101 			/*
102 			 * PAN ID compression; this requires that both
103 			 * the source and destination addresses be present,
104 			 * but the destination address is missing.
105 			 */
106 			ND_PRINT((ndo, "[|802.15.4]"));
107 			return hdrlen;
108 		}
109 		if (ndo->ndo_vflag)
110 			ND_PRINT((ndo,"none "));
111 		break;
112 	case FC_ADDRESSING_MODE_RESERVED:
113 		if (ndo->ndo_vflag)
114 			ND_PRINT((ndo,"reserved destination addressing mode"));
115 		return hdrlen;
116 	case FC_ADDRESSING_MODE_SHORT:
117 		if (caplen < 2) {
118 			ND_PRINT((ndo, "[|802.15.4]"));
119 			return hdrlen;
120 		}
121 		panid = EXTRACT_LE_16BITS(p);
122 		p += 2;
123 		caplen -= 2;
124 		hdrlen += 2;
125 		if (caplen < 2) {
126 			ND_PRINT((ndo, "[|802.15.4]"));
127 			return hdrlen;
128 		}
129 		if (ndo->ndo_vflag)
130 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
131 		p += 2;
132 		caplen -= 2;
133 		hdrlen += 2;
134 		break;
135 	case FC_ADDRESSING_MODE_LONG:
136 		if (caplen < 2) {
137 			ND_PRINT((ndo, "[|802.15.4]"));
138 			return hdrlen;
139 		}
140 		panid = EXTRACT_LE_16BITS(p);
141 		p += 2;
142 		caplen -= 2;
143 		hdrlen += 2;
144 		if (caplen < 8) {
145 			ND_PRINT((ndo, "[|802.15.4]"));
146 			return hdrlen;
147 		}
148 		if (ndo->ndo_vflag)
149 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
150 		p += 8;
151 		caplen -= 8;
152 		hdrlen += 8;
153 		break;
154 	}
155 	if (ndo->ndo_vflag)
156 		ND_PRINT((ndo,"< "));
157 
158 	/*
159 	 * Source address and PAN ID, if present.
160 	 */
161 	switch (FC_SRC_ADDRESSING_MODE(fc)) {
162 	case FC_ADDRESSING_MODE_NONE:
163 		if (ndo->ndo_vflag)
164 			ND_PRINT((ndo,"none "));
165 		break;
166 	case FC_ADDRESSING_MODE_RESERVED:
167 		if (ndo->ndo_vflag)
168 			ND_PRINT((ndo,"reserved source addressing mode"));
169 		return 0;
170 	case FC_ADDRESSING_MODE_SHORT:
171 		if (!(fc & FC_PAN_ID_COMPRESSION)) {
172 			/*
173 			 * The source PAN ID is not compressed out, so
174 			 * fetch it.  (Otherwise, we'll use the destination
175 			 * PAN ID, fetched above.)
176 			 */
177 			if (caplen < 2) {
178 				ND_PRINT((ndo, "[|802.15.4]"));
179 				return hdrlen;
180 			}
181 			panid = EXTRACT_LE_16BITS(p);
182 			p += 2;
183 			caplen -= 2;
184 			hdrlen += 2;
185 		}
186 		if (caplen < 2) {
187 			ND_PRINT((ndo, "[|802.15.4]"));
188 			return hdrlen;
189 		}
190 		if (ndo->ndo_vflag)
191 			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
192 		p += 2;
193 		caplen -= 2;
194 		hdrlen += 2;
195 		break;
196 	case FC_ADDRESSING_MODE_LONG:
197 		if (!(fc & FC_PAN_ID_COMPRESSION)) {
198 			/*
199 			 * The source PAN ID is not compressed out, so
200 			 * fetch it.  (Otherwise, we'll use the destination
201 			 * PAN ID, fetched above.)
202 			 */
203 			if (caplen < 2) {
204 				ND_PRINT((ndo, "[|802.15.4]"));
205 				return hdrlen;
206 			}
207 			panid = EXTRACT_LE_16BITS(p);
208 			p += 2;
209 			caplen -= 2;
210 			hdrlen += 2;
211 		}
212 		if (caplen < 8) {
213 			ND_PRINT((ndo, "[|802.15.4]"));
214 			return hdrlen;
215 		}
216 		if (ndo->ndo_vflag)
217 			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
218 		p += 8;
219 		caplen -= 8;
220 		hdrlen += 8;
221 		break;
222 	}
223 
224 	if (!ndo->ndo_suppress_default_print)
225 		ND_DEFAULTPRINT(p, caplen);
226 
227 	return hdrlen;
228 }
229