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