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 /* \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 #define ND_LONGJMP_FROM_TCHECK 27 #include "netdissect.h" 28 #include "extract.h" 29 #include "addrtoname.h" 30 31 32 /* 33 ETSI TS 102 636-5-1 V1.1.1 (2011-02) 34 Intelligent Transport Systems (ITS); Vehicular Communications; GeoNetworking; 35 Part 5: Transport Protocols; Sub-part 1: Basic Transport Protocol 36 37 ETSI TS 102 636-4-1 V1.1.1 (2011-06) 38 Intelligent Transport Systems (ITS); Vehicular communications; GeoNetworking; 39 Part 4: Geographical addressing and forwarding for point-to-point and point-to-multipoint communications; 40 Sub-part 1: Media-Independent Functionality 41 */ 42 43 #define GEONET_ADDR_LEN 8 44 45 static const struct tok msg_type_values[] = { 46 { 0, "CAM" }, 47 { 1, "DENM" }, 48 { 101, "TPEGM" }, 49 { 102, "TSPDM" }, 50 { 103, "VPM" }, 51 { 104, "SRM" }, 52 { 105, "SLAM" }, 53 { 106, "ecoCAM" }, 54 { 107, "ITM" }, 55 { 150, "SA" }, 56 { 0, NULL } 57 }; 58 59 static void 60 print_btp_body(netdissect_options *ndo, 61 const u_char *bp) 62 { 63 u_int msg_type; 64 65 /* Assuming ItsPduHeader */ 66 ND_PRINT("; ItsPduHeader v:%u", GET_U_1(bp)); 67 68 msg_type = GET_U_1(bp + 1); 69 ND_PRINT(" t:%u-%s", msg_type, 70 tok2str(msg_type_values, "unknown (%u)", msg_type)); 71 } 72 73 /* EN 302 636-5-1 V2.2.1 Section 7.2: BTP-A header */ 74 static void 75 print_btp(netdissect_options *ndo, 76 const u_char *bp) 77 { 78 ND_PRINT("; BTP Dst:%u", GET_BE_U_2(bp + 0)); 79 ND_PRINT(" Src:%u", GET_BE_U_2(bp + 2)); 80 } 81 82 static void 83 print_long_pos_vector(netdissect_options *ndo, 84 const u_char *bp) 85 { 86 ND_PRINT("GN_ADDR:%s ", GET_LINKADDR_STRING(bp, LINKADDR_OTHER, GEONET_ADDR_LEN)); 87 ND_PRINT("lat:%u ", GET_BE_U_4(bp + 12)); 88 ND_PRINT("lon:%u", GET_BE_U_4(bp + 16)); 89 } 90 91 92 /* 93 * This is the top level routine of the printer. 'p' points 94 * to the geonet header of the packet. 95 */ 96 void 97 geonet_print(netdissect_options *ndo, const u_char *bp, u_int length, 98 const struct lladdr_info *src) 99 { 100 u_int version; 101 u_int next_hdr; 102 u_int hdr_type; 103 u_int hdr_subtype; 104 uint16_t payload_length; 105 u_int hop_limit; 106 const char *next_hdr_txt = "Unknown"; 107 const char *hdr_type_txt = "Unknown"; 108 int hdr_size = -1; 109 110 ndo->ndo_protocol = "geonet"; 111 ND_PRINT("GeoNet "); 112 if (src != NULL) 113 ND_PRINT("src:%s", (src->addr_string)(ndo, src->addr)); 114 ND_PRINT("; "); 115 116 /* Process Common Header */ 117 if (length < 36) { 118 ND_PRINT(" (common header length %u < 36)", length); 119 goto invalid; 120 } 121 122 version = GET_U_1(bp) >> 4; 123 next_hdr = GET_U_1(bp) & 0x0f; 124 hdr_type = GET_U_1(bp + 1) >> 4; 125 hdr_subtype = GET_U_1(bp + 1) & 0x0f; 126 payload_length = GET_BE_U_2(bp + 4); 127 hop_limit = GET_U_1(bp + 7); 128 129 switch (next_hdr) { 130 case 0: next_hdr_txt = "Any"; break; 131 case 1: next_hdr_txt = "BTP-A"; break; 132 case 2: next_hdr_txt = "BTP-B"; break; 133 case 3: next_hdr_txt = "IPv6"; break; 134 } 135 136 switch (hdr_type) { 137 case 0: hdr_type_txt = "Any"; break; 138 case 1: hdr_type_txt = "Beacon"; break; 139 case 2: hdr_type_txt = "GeoUnicast"; break; 140 case 3: switch (hdr_subtype) { 141 case 0: hdr_type_txt = "GeoAnycastCircle"; break; 142 case 1: hdr_type_txt = "GeoAnycastRect"; break; 143 case 2: hdr_type_txt = "GeoAnycastElipse"; break; 144 } 145 break; 146 case 4: switch (hdr_subtype) { 147 case 0: hdr_type_txt = "GeoBroadcastCircle"; break; 148 case 1: hdr_type_txt = "GeoBroadcastRect"; break; 149 case 2: hdr_type_txt = "GeoBroadcastElipse"; break; 150 } 151 break; 152 case 5: switch (hdr_subtype) { 153 case 0: hdr_type_txt = "TopoScopeBcast-SH"; break; 154 case 1: hdr_type_txt = "TopoScopeBcast-MH"; break; 155 } 156 break; 157 case 6: switch (hdr_subtype) { 158 case 0: hdr_type_txt = "LocService-Request"; break; 159 case 1: hdr_type_txt = "LocService-Reply"; break; 160 } 161 break; 162 } 163 164 ND_PRINT("v:%u ", version); 165 ND_PRINT("NH:%u-%s ", next_hdr, next_hdr_txt); 166 ND_PRINT("HT:%u-%u-%s ", hdr_type, hdr_subtype, hdr_type_txt); 167 ND_PRINT("HopLim:%u ", hop_limit); 168 ND_PRINT("Payload:%u ", payload_length); 169 print_long_pos_vector(ndo, bp + 8); 170 171 /* Skip Common Header */ 172 ND_TCHECK_LEN(bp, 36); 173 length -= 36; 174 bp += 36; 175 176 /* Process Extended Headers */ 177 switch (hdr_type) { 178 case 0: /* Any */ 179 hdr_size = 0; 180 break; 181 case 1: /* Beacon */ 182 hdr_size = 0; 183 break; 184 case 2: /* GeoUnicast */ 185 break; 186 case 3: switch (hdr_subtype) { 187 case 0: /* GeoAnycastCircle */ 188 break; 189 case 1: /* GeoAnycastRect */ 190 break; 191 case 2: /* GeoAnycastElipse */ 192 break; 193 } 194 break; 195 case 4: switch (hdr_subtype) { 196 case 0: /* GeoBroadcastCircle */ 197 break; 198 case 1: /* GeoBroadcastRect */ 199 break; 200 case 2: /* GeoBroadcastElipse */ 201 break; 202 } 203 break; 204 case 5: switch (hdr_subtype) { 205 case 0: /* TopoScopeBcast-SH */ 206 hdr_size = 0; 207 break; 208 case 1: /* TopoScopeBcast-MH */ 209 hdr_size = 68 - 36; 210 break; 211 } 212 break; 213 case 6: switch (hdr_subtype) { 214 case 0: /* LocService-Request */ 215 break; 216 case 1: /* LocService-Reply */ 217 break; 218 } 219 break; 220 } 221 222 /* Skip Extended headers */ 223 if (hdr_size >= 0) { 224 if (length < (u_int)hdr_size) { 225 ND_PRINT(" (header size %d > %u)", hdr_size, length); 226 goto invalid; 227 } 228 ND_TCHECK_LEN(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 ND_PRINT(" (BTP length %u < 4)", length); 238 goto invalid; 239 } 240 print_btp(ndo, bp); 241 length -= 4; 242 bp += 4; 243 if (length >= 2) { 244 /* 245 * XXX - did print_btp_body() 246 * return if length < 2 247 * because this is optional, 248 * or was that just not 249 * reporting genuine errors? 250 */ 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 invalid: 265 nd_print_invalid(ndo); 266 /* XXX - print the remaining data as hex? */ 267 } 268