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