1 /* 2 * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Lawrence Berkeley Laboratory, 11 * Berkeley, CA. The name of the University may not be used to 12 * endorse or promote products derived from this software without 13 * specific prior written permission. 14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 * 18 * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU). 19 */ 20 21 #include <sys/cdefs.h> 22 #ifndef lint 23 __RCSID("$NetBSD: print-egp.c,v 1.6 2017/02/05 04:05:05 spz Exp $"); 24 #endif 25 26 /* \summary: Exterior Gateway Protocol (EGP) printer */ 27 28 #ifdef HAVE_CONFIG_H 29 #include "config.h" 30 #endif 31 32 #include <netdissect-stdinc.h> 33 34 #include "netdissect.h" 35 #include "addrtoname.h" 36 #include "extract.h" 37 38 struct egp_packet { 39 uint8_t egp_version; 40 #define EGP_VERSION 2 41 uint8_t egp_type; 42 #define EGPT_ACQUIRE 3 43 #define EGPT_REACH 5 44 #define EGPT_POLL 2 45 #define EGPT_UPDATE 1 46 #define EGPT_ERROR 8 47 uint8_t egp_code; 48 #define EGPC_REQUEST 0 49 #define EGPC_CONFIRM 1 50 #define EGPC_REFUSE 2 51 #define EGPC_CEASE 3 52 #define EGPC_CEASEACK 4 53 #define EGPC_HELLO 0 54 #define EGPC_HEARDU 1 55 uint8_t egp_status; 56 #define EGPS_UNSPEC 0 57 #define EGPS_ACTIVE 1 58 #define EGPS_PASSIVE 2 59 #define EGPS_NORES 3 60 #define EGPS_ADMIN 4 61 #define EGPS_GODOWN 5 62 #define EGPS_PARAM 6 63 #define EGPS_PROTO 7 64 #define EGPS_INDET 0 65 #define EGPS_UP 1 66 #define EGPS_DOWN 2 67 #define EGPS_UNSOL 0x80 68 uint16_t egp_checksum; 69 uint16_t egp_as; 70 uint16_t egp_sequence; 71 union { 72 uint16_t egpu_hello; 73 uint8_t egpu_gws[2]; 74 uint16_t egpu_reason; 75 #define EGPR_UNSPEC 0 76 #define EGPR_BADHEAD 1 77 #define EGPR_BADDATA 2 78 #define EGPR_NOREACH 3 79 #define EGPR_XSPOLL 4 80 #define EGPR_NORESP 5 81 #define EGPR_UVERSION 6 82 } egp_handg; 83 #define egp_hello egp_handg.egpu_hello 84 #define egp_intgw egp_handg.egpu_gws[0] 85 #define egp_extgw egp_handg.egpu_gws[1] 86 #define egp_reason egp_handg.egpu_reason 87 union { 88 uint16_t egpu_poll; 89 uint32_t egpu_sourcenet; 90 } egp_pands; 91 #define egp_poll egp_pands.egpu_poll 92 #define egp_sourcenet egp_pands.egpu_sourcenet 93 }; 94 95 static const char *egp_acquire_codes[] = { 96 "request", 97 "confirm", 98 "refuse", 99 "cease", 100 "cease_ack" 101 }; 102 103 static const char *egp_acquire_status[] = { 104 "unspecified", 105 "active_mode", 106 "passive_mode", 107 "insufficient_resources", 108 "administratively_prohibited", 109 "going_down", 110 "parameter_violation", 111 "protocol_violation" 112 }; 113 114 static const char *egp_reach_codes[] = { 115 "hello", 116 "i-h-u" 117 }; 118 119 static const char *egp_status_updown[] = { 120 "indeterminate", 121 "up", 122 "down" 123 }; 124 125 static const char *egp_reasons[] = { 126 "unspecified", 127 "bad_EGP_header_format", 128 "bad_EGP_data_field_format", 129 "reachability_info_unavailable", 130 "excessive_polling_rate", 131 "no_response", 132 "unsupported_version" 133 }; 134 135 static void 136 egpnrprint(netdissect_options *ndo, 137 register const struct egp_packet *egp, u_int length) 138 { 139 register const uint8_t *cp; 140 uint32_t addr; 141 register uint32_t net; 142 register u_int netlen; 143 int gateways, distances, networks; 144 int t_gateways; 145 const char *comma; 146 147 addr = egp->egp_sourcenet; 148 if (IN_CLASSA(addr)) { 149 net = addr & IN_CLASSA_NET; 150 netlen = 1; 151 } else if (IN_CLASSB(addr)) { 152 net = addr & IN_CLASSB_NET; 153 netlen = 2; 154 } else if (IN_CLASSC(addr)) { 155 net = addr & IN_CLASSC_NET; 156 netlen = 3; 157 } else { 158 net = 0; 159 netlen = 0; 160 } 161 cp = (const uint8_t *)(egp + 1); 162 length -= sizeof(*egp); 163 164 t_gateways = egp->egp_intgw + egp->egp_extgw; 165 for (gateways = 0; gateways < t_gateways; ++gateways) { 166 /* Pickup host part of gateway address */ 167 addr = 0; 168 if (length < 4 - netlen) 169 goto trunc; 170 ND_TCHECK2(cp[0], 4 - netlen); 171 switch (netlen) { 172 173 case 1: 174 addr = *cp++; 175 /* fall through */ 176 case 2: 177 addr = (addr << 8) | *cp++; 178 /* fall through */ 179 case 3: 180 addr = (addr << 8) | *cp++; 181 } 182 addr |= net; 183 length -= 4 - netlen; 184 if (length < 1) 185 goto trunc; 186 ND_TCHECK2(cp[0], 1); 187 distances = *cp++; 188 length--; 189 ND_PRINT((ndo, " %s %s ", 190 gateways < (int)egp->egp_intgw ? "int" : "ext", 191 ipaddr_string(ndo, &addr))); 192 193 comma = ""; 194 ND_PRINT((ndo, "(")); 195 while (--distances >= 0) { 196 if (length < 2) 197 goto trunc; 198 ND_TCHECK2(cp[0], 2); 199 ND_PRINT((ndo, "%sd%d:", comma, (int)*cp++)); 200 comma = ", "; 201 networks = *cp++; 202 length -= 2; 203 while (--networks >= 0) { 204 /* Pickup network number */ 205 if (length < 1) 206 goto trunc; 207 ND_TCHECK2(cp[0], 1); 208 addr = (uint32_t)*cp++ << 24; 209 length--; 210 if (IN_CLASSB(addr)) { 211 if (length < 1) 212 goto trunc; 213 ND_TCHECK2(cp[0], 1); 214 addr |= (uint32_t)*cp++ << 16; 215 length--; 216 } else if (!IN_CLASSA(addr)) { 217 if (length < 2) 218 goto trunc; 219 ND_TCHECK2(cp[0], 2); 220 addr |= (uint32_t)*cp++ << 16; 221 addr |= (uint32_t)*cp++ << 8; 222 length -= 2; 223 } 224 ND_PRINT((ndo, " %s", ipaddr_string(ndo, &addr))); 225 } 226 } 227 ND_PRINT((ndo, ")")); 228 } 229 return; 230 trunc: 231 ND_PRINT((ndo, "[|]")); 232 } 233 234 void 235 egp_print(netdissect_options *ndo, 236 register const uint8_t *bp, register u_int length) 237 { 238 register const struct egp_packet *egp; 239 register int status; 240 register int code; 241 register int type; 242 243 egp = (const struct egp_packet *)bp; 244 if (length < sizeof(*egp) || !ND_TTEST(*egp)) { 245 ND_PRINT((ndo, "[|egp]")); 246 return; 247 } 248 249 if (!ndo->ndo_vflag) { 250 ND_PRINT((ndo, "EGPv%u, AS %u, seq %u, length %u", 251 egp->egp_version, 252 EXTRACT_16BITS(&egp->egp_as), 253 EXTRACT_16BITS(&egp->egp_sequence), 254 length)); 255 return; 256 } else 257 ND_PRINT((ndo, "EGPv%u, length %u", 258 egp->egp_version, 259 length)); 260 261 if (egp->egp_version != EGP_VERSION) { 262 ND_PRINT((ndo, "[version %d]", egp->egp_version)); 263 return; 264 } 265 266 type = egp->egp_type; 267 code = egp->egp_code; 268 status = egp->egp_status; 269 270 switch (type) { 271 case EGPT_ACQUIRE: 272 ND_PRINT((ndo, " acquire")); 273 switch (code) { 274 case EGPC_REQUEST: 275 case EGPC_CONFIRM: 276 ND_PRINT((ndo, " %s", egp_acquire_codes[code])); 277 switch (status) { 278 case EGPS_UNSPEC: 279 case EGPS_ACTIVE: 280 case EGPS_PASSIVE: 281 ND_PRINT((ndo, " %s", egp_acquire_status[status])); 282 break; 283 284 default: 285 ND_PRINT((ndo, " [status %d]", status)); 286 break; 287 } 288 ND_PRINT((ndo, " hello:%d poll:%d", 289 EXTRACT_16BITS(&egp->egp_hello), 290 EXTRACT_16BITS(&egp->egp_poll))); 291 break; 292 293 case EGPC_REFUSE: 294 case EGPC_CEASE: 295 case EGPC_CEASEACK: 296 ND_PRINT((ndo, " %s", egp_acquire_codes[code])); 297 switch (status ) { 298 case EGPS_UNSPEC: 299 case EGPS_NORES: 300 case EGPS_ADMIN: 301 case EGPS_GODOWN: 302 case EGPS_PARAM: 303 case EGPS_PROTO: 304 ND_PRINT((ndo, " %s", egp_acquire_status[status])); 305 break; 306 307 default: 308 ND_PRINT((ndo, "[status %d]", status)); 309 break; 310 } 311 break; 312 313 default: 314 ND_PRINT((ndo, "[code %d]", code)); 315 break; 316 } 317 break; 318 319 case EGPT_REACH: 320 switch (code) { 321 322 case EGPC_HELLO: 323 case EGPC_HEARDU: 324 ND_PRINT((ndo, " %s", egp_reach_codes[code])); 325 if (status <= EGPS_DOWN) 326 ND_PRINT((ndo, " state:%s", egp_status_updown[status])); 327 else 328 ND_PRINT((ndo, " [status %d]", status)); 329 break; 330 331 default: 332 ND_PRINT((ndo, "[reach code %d]", code)); 333 break; 334 } 335 break; 336 337 case EGPT_POLL: 338 ND_PRINT((ndo, " poll")); 339 if (egp->egp_status <= EGPS_DOWN) 340 ND_PRINT((ndo, " state:%s", egp_status_updown[status])); 341 else 342 ND_PRINT((ndo, " [status %d]", status)); 343 ND_PRINT((ndo, " net:%s", ipaddr_string(ndo, &egp->egp_sourcenet))); 344 break; 345 346 case EGPT_UPDATE: 347 ND_PRINT((ndo, " update")); 348 if (status & EGPS_UNSOL) { 349 status &= ~EGPS_UNSOL; 350 ND_PRINT((ndo, " unsolicited")); 351 } 352 if (status <= EGPS_DOWN) 353 ND_PRINT((ndo, " state:%s", egp_status_updown[status])); 354 else 355 ND_PRINT((ndo, " [status %d]", status)); 356 ND_PRINT((ndo, " %s int %d ext %d", 357 ipaddr_string(ndo, &egp->egp_sourcenet), 358 egp->egp_intgw, 359 egp->egp_extgw)); 360 if (ndo->ndo_vflag) 361 egpnrprint(ndo, egp, length); 362 break; 363 364 case EGPT_ERROR: 365 ND_PRINT((ndo, " error")); 366 if (status <= EGPS_DOWN) 367 ND_PRINT((ndo, " state:%s", egp_status_updown[status])); 368 else 369 ND_PRINT((ndo, " [status %d]", status)); 370 371 if (EXTRACT_16BITS(&egp->egp_reason) <= EGPR_UVERSION) 372 ND_PRINT((ndo, " %s", egp_reasons[EXTRACT_16BITS(&egp->egp_reason)])); 373 else 374 ND_PRINT((ndo, " [reason %d]", EXTRACT_16BITS(&egp->egp_reason))); 375 break; 376 377 default: 378 ND_PRINT((ndo, "[type %d]", type)); 379 break; 380 } 381 } 382