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