xref: /freebsd/contrib/tcpdump/print-geonet.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
1 /*
2  * Copyright (c) 2013 The TCPDUMP project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that: (1) source code
6  * distributions retain the above copyright notice and this paragraph
7  * in its entirety, and (2) distributions including binary code include
8  * the above copyright notice and this paragraph in its entirety in
9  * the documentation or other materials provided with the distribution.
10  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13  * FOR A PARTICULAR PURPOSE.
14  *
15  * Original code by Ola Martin Lykkja (ola.lykkja@q-free.com)
16  */
17 
18 #define NETDISSECT_REWORKED
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <tcpdump-stdinc.h>
24 
25 #include "interface.h"
26 #include "extract.h"
27 #include "addrtoname.h"
28 
29 
30 /*
31    ETSI TS 102 636-5-1 V1.1.1 (2011-02)
32    Intelligent Transport Systems (ITS); Vehicular Communications; GeoNetworking;
33    Part 5: Transport Protocols; Sub-part 1: Basic Transport Protocol
34 
35    ETSI TS 102 636-4-1 V1.1.1 (2011-06)
36    Intelligent Transport Systems (ITS); Vehicular communications; GeoNetworking;
37    Part 4: Geographical addressing and forwarding for point-to-point and point-to-multipoint communications;
38    Sub-part 1: Media-Independent Functionality
39 */
40 
41 #define GEONET_ADDR_LEN 8
42 
43 static const struct tok msg_type_values[] = {
44 	{   0, "CAM" },
45 	{   1, "DENM" },
46 	{ 101, "TPEGM" },
47 	{ 102, "TSPDM" },
48 	{ 103, "VPM" },
49 	{ 104, "SRM" },
50 	{ 105, "SLAM" },
51 	{ 106, "ecoCAM" },
52 	{ 107, "ITM" },
53 	{ 150, "SA" },
54 	{   0, NULL }
55 };
56 
57 static void
58 print_btp_body(netdissect_options *ndo,
59                const u_char *bp)
60 {
61 	int version;
62 	int msg_type;
63 	const char *msg_type_str;
64 
65 	/* Assuming ItsDpuHeader */
66 	version = bp[0];
67 	msg_type = bp[1];
68 	msg_type_str = tok2str(msg_type_values, "unknown (%u)", msg_type);
69 
70 	ND_PRINT((ndo, "; ItsPduHeader v:%d t:%d-%s", version, msg_type, msg_type_str));
71 }
72 
73 static void
74 print_btp(netdissect_options *ndo,
75           const u_char *bp)
76 {
77 	uint16_t dest = EXTRACT_16BITS(bp+0);
78 	uint16_t src = EXTRACT_16BITS(bp+2);
79 	ND_PRINT((ndo, "; BTP Dst:%u Src:%u", dest, src));
80 }
81 
82 static int
83 print_long_pos_vector(netdissect_options *ndo,
84                       const u_char *bp)
85 {
86 	uint32_t lat, lon;
87 
88 	ND_PRINT((ndo, "GN_ADDR:%s ", linkaddr_string (ndo, bp, 0, GEONET_ADDR_LEN)));
89 
90 	if (!ND_TTEST2(*(bp+12), 8))
91 		return (-1);
92 	lat = EXTRACT_32BITS(bp+12);
93 	ND_PRINT((ndo, "lat:%d ", lat));
94 	lon = EXTRACT_32BITS(bp+16);
95 	ND_PRINT((ndo, "lon:%d", lon));
96 	return (0);
97 }
98 
99 
100 /*
101  * This is the top level routine of the printer.  'p' points
102  * to the geonet header of the packet.
103  */
104 void
105 geonet_print(netdissect_options *ndo, const u_char *eth, const u_char *bp, u_int length)
106 {
107 	int version;
108 	int next_hdr;
109 	int hdr_type;
110 	int hdr_subtype;
111 	uint16_t payload_length;
112 	int hop_limit;
113 	const char *next_hdr_txt = "Unknown";
114 	const char *hdr_type_txt = "Unknown";
115 	int hdr_size = -1;
116 
117 	ND_PRINT((ndo, "GeoNet src:%s; ", etheraddr_string(ndo, eth+6)));
118 
119 	/* Process Common Header */
120 	if (length < 36)
121 		goto malformed;
122 
123 	ND_TCHECK2(*bp, 7);
124 	version = bp[0] >> 4;
125 	next_hdr = bp[0] & 0x0f;
126 	hdr_type = bp[1] >> 4;
127 	hdr_subtype = bp[1] & 0x0f;
128 	payload_length = EXTRACT_16BITS(bp+4);
129 	hop_limit = bp[7];
130 
131 	switch (next_hdr) {
132 		case 0: next_hdr_txt = "Any"; break;
133 		case 1: next_hdr_txt = "BTP-A"; break;
134 		case 2: next_hdr_txt = "BTP-B"; break;
135 		case 3: next_hdr_txt = "IPv6"; break;
136 	}
137 
138 	switch (hdr_type) {
139 		case 0: hdr_type_txt = "Any"; break;
140 		case 1: hdr_type_txt = "Beacon"; break;
141 		case 2: hdr_type_txt = "GeoUnicast"; break;
142 		case 3: switch (hdr_subtype) {
143 				case 0: hdr_type_txt = "GeoAnycastCircle"; break;
144 				case 1: hdr_type_txt = "GeoAnycastRect"; break;
145 				case 2: hdr_type_txt = "GeoAnycastElipse"; break;
146 			}
147 			break;
148 		case 4: switch (hdr_subtype) {
149 				case 0: hdr_type_txt = "GeoBroadcastCircle"; break;
150 				case 1: hdr_type_txt = "GeoBroadcastRect"; break;
151 				case 2: hdr_type_txt = "GeoBroadcastElipse"; break;
152 			}
153 			break;
154 		case 5: switch (hdr_subtype) {
155 				case 0: hdr_type_txt = "TopoScopeBcast-SH"; break;
156 				case 1: hdr_type_txt = "TopoScopeBcast-MH"; break;
157 			}
158 			break;
159 		case 6: switch (hdr_subtype) {
160 				case 0: hdr_type_txt = "LocService-Request"; break;
161 				case 1: hdr_type_txt = "LocService-Reply"; break;
162 			}
163 			break;
164 	}
165 
166 	ND_PRINT((ndo, "v:%d ", version));
167 	ND_PRINT((ndo, "NH:%d-%s ", next_hdr, next_hdr_txt));
168 	ND_PRINT((ndo, "HT:%d-%d-%s ", hdr_type, hdr_subtype, hdr_type_txt));
169 	ND_PRINT((ndo, "HopLim:%d ", hop_limit));
170 	ND_PRINT((ndo, "Payload:%d ", payload_length));
171 	if (print_long_pos_vector(ndo, bp + 8) == -1)
172 		goto trunc;
173 
174 	/* Skip Common Header */
175 	length -= 36;
176 	bp += 36;
177 
178 	/* Process Extended Headers */
179 	switch (hdr_type) {
180 		case 0: /* Any */
181 			hdr_size = 0;
182 			break;
183 		case 1: /* Beacon */
184 			hdr_size = 0;
185 			break;
186 		case 2: /* GeoUnicast */
187 			break;
188 		case 3: switch (hdr_subtype) {
189 				case 0: /* GeoAnycastCircle */
190 					break;
191 				case 1: /* GeoAnycastRect */
192 					break;
193 				case 2: /* GeoAnycastElipse */
194 					break;
195 			}
196 			break;
197 		case 4: switch (hdr_subtype) {
198 				case 0: /* GeoBroadcastCircle */
199 					break;
200 				case 1: /* GeoBroadcastRect */
201 					break;
202 				case 2: /* GeoBroadcastElipse */
203 					break;
204 			}
205 			break;
206 		case 5: switch (hdr_subtype) {
207 				case 0: /* TopoScopeBcast-SH */
208 					hdr_size = 0;
209 					break;
210 				case 1: /* TopoScopeBcast-MH */
211 					hdr_size = 68 - 36;
212 					break;
213 			}
214 			break;
215 		case 6: switch (hdr_subtype) {
216 				case 0: /* LocService-Request */
217 					break;
218 				case 1: /* LocService-Reply */
219 					break;
220 			}
221 			break;
222 	}
223 
224 	/* Skip Extended headers */
225 	if (hdr_size >= 0) {
226 		if (length < (u_int)hdr_size)
227 			goto malformed;
228 		ND_TCHECK2(*bp, hdr_size);
229 		length -= hdr_size;
230 		bp += hdr_size;
231 		switch (next_hdr) {
232 			case 0: /* Any */
233 				break;
234 			case 1:
235 			case 2: /* BTP A/B */
236 				if (length < 4)
237 					goto malformed;
238 				ND_TCHECK2(*bp, 4);
239 				print_btp(ndo, bp);
240 				length -= 4;
241 				bp += 4;
242 				if (length >= 2) {
243 					/*
244 					 * XXX - did print_btp_body()
245 					 * return if length < 2
246 					 * because this is optional,
247 					 * or was that just not
248 					 * reporting genuine errors?
249 					 */
250 					ND_TCHECK2(*bp, 2);
251 					print_btp_body(ndo, bp);
252 				}
253 				break;
254 			case 3: /* IPv6 */
255 				break;
256 		}
257 	}
258 
259 	/* Print user data part */
260 	if (ndo->ndo_vflag)
261 		ND_DEFAULTPRINT(bp, length);
262 	return;
263 
264 malformed:
265 	ND_PRINT((ndo, " Malformed (small) "));
266 	/* XXX - print the remaining data as hex? */
267 	return;
268 
269 trunc:
270 	ND_PRINT((ndo, "[|geonet]"));
271 }
272 
273 
274 /*
275  * Local Variables:
276  * c-style: whitesmith
277  * c-basic-offset: 8
278  * End:
279  */
280