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