10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms are permitted 60f74e101Schristos * provided that the above copyright notice and this paragraph are 70f74e101Schristos * duplicated in all such forms and that any documentation, 80f74e101Schristos * advertising materials, and other materials related to such 90f74e101Schristos * distribution and use acknowledge that the software was developed 100f74e101Schristos * by the University of California, Lawrence Berkeley Laboratory, 110f74e101Schristos * Berkeley, CA. The name of the University may not be used to 120f74e101Schristos * endorse or promote products derived from this software without 130f74e101Schristos * specific prior written permission. 140f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 150f74e101Schristos * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 160f74e101Schristos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 170f74e101Schristos * 180f74e101Schristos * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU). 190f74e101Schristos */ 200f74e101Schristos 2111b3aaa1Schristos #include <sys/cdefs.h> 220f74e101Schristos #ifndef lint 23*26ba0b50Schristos __RCSID("$NetBSD: print-egp.c,v 1.8 2024/09/02 16:15:31 christos Exp $"); 240f74e101Schristos #endif 250f74e101Schristos 26dc860a36Sspz /* \summary: Exterior Gateway Protocol (EGP) printer */ 27dc860a36Sspz 28c74ad251Schristos /* specification: RFC 827 */ 29c74ad251Schristos 30c74ad251Schristos #include <config.h> 310f74e101Schristos 32c74ad251Schristos #include "netdissect-stdinc.h" 330f74e101Schristos 34fdccd7e4Schristos #include "netdissect.h" 350f74e101Schristos #include "addrtoname.h" 360f74e101Schristos #include "extract.h" 370f74e101Schristos 380f74e101Schristos struct egp_packet { 39c74ad251Schristos nd_uint8_t egp_version; 400f74e101Schristos #define EGP_VERSION 2 41c74ad251Schristos nd_uint8_t egp_type; 420f74e101Schristos #define EGPT_ACQUIRE 3 430f74e101Schristos #define EGPT_REACH 5 440f74e101Schristos #define EGPT_POLL 2 450f74e101Schristos #define EGPT_UPDATE 1 460f74e101Schristos #define EGPT_ERROR 8 47c74ad251Schristos nd_uint8_t egp_code; 480f74e101Schristos #define EGPC_REQUEST 0 490f74e101Schristos #define EGPC_CONFIRM 1 500f74e101Schristos #define EGPC_REFUSE 2 510f74e101Schristos #define EGPC_CEASE 3 520f74e101Schristos #define EGPC_CEASEACK 4 530f74e101Schristos #define EGPC_HELLO 0 540f74e101Schristos #define EGPC_HEARDU 1 55c74ad251Schristos nd_uint8_t egp_status; 560f74e101Schristos #define EGPS_UNSPEC 0 570f74e101Schristos #define EGPS_ACTIVE 1 580f74e101Schristos #define EGPS_PASSIVE 2 590f74e101Schristos #define EGPS_NORES 3 600f74e101Schristos #define EGPS_ADMIN 4 610f74e101Schristos #define EGPS_GODOWN 5 620f74e101Schristos #define EGPS_PARAM 6 630f74e101Schristos #define EGPS_PROTO 7 640f74e101Schristos #define EGPS_INDET 0 650f74e101Schristos #define EGPS_UP 1 660f74e101Schristos #define EGPS_DOWN 2 670f74e101Schristos #define EGPS_UNSOL 0x80 68c74ad251Schristos nd_uint16_t egp_checksum; 69c74ad251Schristos nd_uint16_t egp_as; 70c74ad251Schristos nd_uint16_t egp_sequence; 710f74e101Schristos union { 72c74ad251Schristos nd_uint16_t egpu_hello; 73c74ad251Schristos nd_uint8_t egpu_gws[2]; 74c74ad251Schristos nd_uint16_t egpu_reason; 750f74e101Schristos #define EGPR_UNSPEC 0 760f74e101Schristos #define EGPR_BADHEAD 1 770f74e101Schristos #define EGPR_BADDATA 2 780f74e101Schristos #define EGPR_NOREACH 3 790f74e101Schristos #define EGPR_XSPOLL 4 800f74e101Schristos #define EGPR_NORESP 5 810f74e101Schristos #define EGPR_UVERSION 6 820f74e101Schristos } egp_handg; 830f74e101Schristos #define egp_hello egp_handg.egpu_hello 840f74e101Schristos #define egp_intgw egp_handg.egpu_gws[0] 850f74e101Schristos #define egp_extgw egp_handg.egpu_gws[1] 860f74e101Schristos #define egp_reason egp_handg.egpu_reason 870f74e101Schristos union { 88c74ad251Schristos nd_uint16_t egpu_poll; 89c74ad251Schristos nd_ipv4 egpu_sourcenet; 900f74e101Schristos } egp_pands; 910f74e101Schristos #define egp_poll egp_pands.egpu_poll 920f74e101Schristos #define egp_sourcenet egp_pands.egpu_sourcenet 930f74e101Schristos }; 940f74e101Schristos 95b3a00663Schristos static const char *egp_acquire_codes[] = { 960f74e101Schristos "request", 970f74e101Schristos "confirm", 980f74e101Schristos "refuse", 990f74e101Schristos "cease", 1000f74e101Schristos "cease_ack" 1010f74e101Schristos }; 1020f74e101Schristos 103b3a00663Schristos static const char *egp_acquire_status[] = { 1040f74e101Schristos "unspecified", 1050f74e101Schristos "active_mode", 1060f74e101Schristos "passive_mode", 1070f74e101Schristos "insufficient_resources", 1080f74e101Schristos "administratively_prohibited", 1090f74e101Schristos "going_down", 1100f74e101Schristos "parameter_violation", 1110f74e101Schristos "protocol_violation" 1120f74e101Schristos }; 1130f74e101Schristos 114b3a00663Schristos static const char *egp_reach_codes[] = { 1150f74e101Schristos "hello", 1160f74e101Schristos "i-h-u" 1170f74e101Schristos }; 1180f74e101Schristos 119b3a00663Schristos static const char *egp_status_updown[] = { 1200f74e101Schristos "indeterminate", 1210f74e101Schristos "up", 1220f74e101Schristos "down" 1230f74e101Schristos }; 1240f74e101Schristos 125b3a00663Schristos static const char *egp_reasons[] = { 1260f74e101Schristos "unspecified", 1270f74e101Schristos "bad_EGP_header_format", 1280f74e101Schristos "bad_EGP_data_field_format", 1290f74e101Schristos "reachability_info_unavailable", 1300f74e101Schristos "excessive_polling_rate", 1310f74e101Schristos "no_response", 1320f74e101Schristos "unsupported_version" 1330f74e101Schristos }; 1340f74e101Schristos 1350f74e101Schristos static void 136c74ad251Schristos egpnr_print(netdissect_options *ndo, 137c74ad251Schristos const struct egp_packet *egp, u_int length) 1380f74e101Schristos { 139c74ad251Schristos const uint8_t *cp; 140b3a00663Schristos uint32_t addr; 141c74ad251Schristos uint32_t net; 142c74ad251Schristos u_int netlen; 143c74ad251Schristos u_int gateways, distances, networks; 144c74ad251Schristos u_int intgw, extgw, t_gateways; 1450f74e101Schristos const char *comma; 1460f74e101Schristos 147c74ad251Schristos addr = GET_IPV4_TO_NETWORK_ORDER(egp->egp_sourcenet); 1480f74e101Schristos if (IN_CLASSA(addr)) { 1490f74e101Schristos net = addr & IN_CLASSA_NET; 1500f74e101Schristos netlen = 1; 1510f74e101Schristos } else if (IN_CLASSB(addr)) { 1520f74e101Schristos net = addr & IN_CLASSB_NET; 1530f74e101Schristos netlen = 2; 1540f74e101Schristos } else if (IN_CLASSC(addr)) { 1550f74e101Schristos net = addr & IN_CLASSC_NET; 1560f74e101Schristos netlen = 3; 1570f74e101Schristos } else { 1580f74e101Schristos net = 0; 1590f74e101Schristos netlen = 0; 1600f74e101Schristos } 161fdccd7e4Schristos cp = (const uint8_t *)(egp + 1); 162dc860a36Sspz length -= sizeof(*egp); 1630f74e101Schristos 164c74ad251Schristos intgw = GET_U_1(egp->egp_intgw); 165c74ad251Schristos extgw = GET_U_1(egp->egp_extgw); 166c74ad251Schristos t_gateways = intgw + extgw; 1670f74e101Schristos for (gateways = 0; gateways < t_gateways; ++gateways) { 1680f74e101Schristos /* Pickup host part of gateway address */ 1690f74e101Schristos addr = 0; 170dc860a36Sspz if (length < 4 - netlen) 171dc860a36Sspz goto trunc; 172c74ad251Schristos ND_TCHECK_LEN(cp, 4 - netlen); 1730f74e101Schristos switch (netlen) { 1740f74e101Schristos 1750f74e101Schristos case 1: 176c74ad251Schristos addr = GET_U_1(cp); 177c74ad251Schristos cp++; 1780f74e101Schristos /* fall through */ 1790f74e101Schristos case 2: 180c74ad251Schristos addr = (addr << 8) | GET_U_1(cp); 181c74ad251Schristos cp++; 1820f74e101Schristos /* fall through */ 1830f74e101Schristos case 3: 184c74ad251Schristos addr = (addr << 8) | GET_U_1(cp); 185c74ad251Schristos cp++; 186c74ad251Schristos break; 1870f74e101Schristos } 1880f74e101Schristos addr |= net; 189dc860a36Sspz length -= 4 - netlen; 190dc860a36Sspz if (length < 1) 191dc860a36Sspz goto trunc; 192c74ad251Schristos distances = GET_U_1(cp); 193c74ad251Schristos cp++; 194dc860a36Sspz length--; 195c74ad251Schristos ND_PRINT(" %s %s ", 196c74ad251Schristos gateways < intgw ? "int" : "ext", 197c74ad251Schristos ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */ 1980f74e101Schristos 1990f74e101Schristos comma = ""; 200c74ad251Schristos ND_PRINT("("); 201c74ad251Schristos while (distances != 0) { 202dc860a36Sspz if (length < 2) 203dc860a36Sspz goto trunc; 204c74ad251Schristos ND_PRINT("%sd%u:", comma, GET_U_1(cp)); 205c74ad251Schristos cp++; 2060f74e101Schristos comma = ", "; 207c74ad251Schristos networks = GET_U_1(cp); 208c74ad251Schristos cp++; 209dc860a36Sspz length -= 2; 210c74ad251Schristos while (networks != 0) { 2110f74e101Schristos /* Pickup network number */ 212dc860a36Sspz if (length < 1) 213dc860a36Sspz goto trunc; 214c74ad251Schristos addr = ((uint32_t) GET_U_1(cp)) << 24; 215c74ad251Schristos cp++; 216dc860a36Sspz length--; 2170f74e101Schristos if (IN_CLASSB(addr)) { 218dc860a36Sspz if (length < 1) 219dc860a36Sspz goto trunc; 220c74ad251Schristos addr |= ((uint32_t) GET_U_1(cp)) << 16; 221c74ad251Schristos cp++; 222dc860a36Sspz length--; 2230f74e101Schristos } else if (!IN_CLASSA(addr)) { 224dc860a36Sspz if (length < 2) 225dc860a36Sspz goto trunc; 226c74ad251Schristos addr |= ((uint32_t) GET_U_1(cp)) << 16; 227c74ad251Schristos cp++; 228c74ad251Schristos addr |= ((uint32_t) GET_U_1(cp)) << 8; 229c74ad251Schristos cp++; 230dc860a36Sspz length -= 2; 2310f74e101Schristos } 232c74ad251Schristos ND_PRINT(" %s", ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */ 233c74ad251Schristos networks--; 2340f74e101Schristos } 235c74ad251Schristos distances--; 2360f74e101Schristos } 237c74ad251Schristos ND_PRINT(")"); 2380f74e101Schristos } 2390f74e101Schristos return; 2400f74e101Schristos trunc: 241c74ad251Schristos nd_print_trunc(ndo); 2420f74e101Schristos } 2430f74e101Schristos 2440f74e101Schristos void 245b3a00663Schristos egp_print(netdissect_options *ndo, 246c74ad251Schristos const uint8_t *bp, u_int length) 2470f74e101Schristos { 248c74ad251Schristos const struct egp_packet *egp; 249c74ad251Schristos u_int version; 250c74ad251Schristos u_int type; 251c74ad251Schristos u_int code; 252c74ad251Schristos u_int status; 2530f74e101Schristos 254c74ad251Schristos ndo->ndo_protocol = "egp"; 255fdccd7e4Schristos egp = (const struct egp_packet *)bp; 256c74ad251Schristos if (length < sizeof(*egp) || !ND_TTEST_SIZE(egp)) { 257c74ad251Schristos nd_print_trunc(ndo); 2580f74e101Schristos return; 2590f74e101Schristos } 2600f74e101Schristos 261c74ad251Schristos version = GET_U_1(egp->egp_version); 262b3a00663Schristos if (!ndo->ndo_vflag) { 263c74ad251Schristos ND_PRINT("EGPv%u, AS %u, seq %u, length %u", 264c74ad251Schristos version, 265c74ad251Schristos GET_BE_U_2(egp->egp_as), 266c74ad251Schristos GET_BE_U_2(egp->egp_sequence), 267c74ad251Schristos length); 2680f74e101Schristos return; 2690f74e101Schristos } else 270c74ad251Schristos ND_PRINT("EGPv%u, length %u", 271c74ad251Schristos version, 272c74ad251Schristos length); 2730f74e101Schristos 274c74ad251Schristos if (version != EGP_VERSION) { 275c74ad251Schristos ND_PRINT("[version %u]", version); 2760f74e101Schristos return; 2770f74e101Schristos } 2780f74e101Schristos 279c74ad251Schristos type = GET_U_1(egp->egp_type); 280c74ad251Schristos code = GET_U_1(egp->egp_code); 281c74ad251Schristos status = GET_U_1(egp->egp_status); 2820f74e101Schristos 2830f74e101Schristos switch (type) { 2840f74e101Schristos case EGPT_ACQUIRE: 285c74ad251Schristos ND_PRINT(" acquire"); 2860f74e101Schristos switch (code) { 2870f74e101Schristos case EGPC_REQUEST: 2880f74e101Schristos case EGPC_CONFIRM: 289c74ad251Schristos ND_PRINT(" %s", egp_acquire_codes[code]); 2900f74e101Schristos switch (status) { 2910f74e101Schristos case EGPS_UNSPEC: 2920f74e101Schristos case EGPS_ACTIVE: 2930f74e101Schristos case EGPS_PASSIVE: 294c74ad251Schristos ND_PRINT(" %s", egp_acquire_status[status]); 2950f74e101Schristos break; 2960f74e101Schristos 2970f74e101Schristos default: 298c74ad251Schristos ND_PRINT(" [status %u]", status); 2990f74e101Schristos break; 3000f74e101Schristos } 301c74ad251Schristos ND_PRINT(" hello:%u poll:%u", 302c74ad251Schristos GET_BE_U_2(egp->egp_hello), 303c74ad251Schristos GET_BE_U_2(egp->egp_poll)); 3040f74e101Schristos break; 3050f74e101Schristos 3060f74e101Schristos case EGPC_REFUSE: 3070f74e101Schristos case EGPC_CEASE: 3080f74e101Schristos case EGPC_CEASEACK: 309c74ad251Schristos ND_PRINT(" %s", egp_acquire_codes[code]); 3100f74e101Schristos switch (status ) { 3110f74e101Schristos case EGPS_UNSPEC: 3120f74e101Schristos case EGPS_NORES: 3130f74e101Schristos case EGPS_ADMIN: 3140f74e101Schristos case EGPS_GODOWN: 3150f74e101Schristos case EGPS_PARAM: 3160f74e101Schristos case EGPS_PROTO: 317c74ad251Schristos ND_PRINT(" %s", egp_acquire_status[status]); 3180f74e101Schristos break; 3190f74e101Schristos 3200f74e101Schristos default: 321c74ad251Schristos ND_PRINT("[status %u]", status); 3220f74e101Schristos break; 3230f74e101Schristos } 3240f74e101Schristos break; 3250f74e101Schristos 3260f74e101Schristos default: 327c74ad251Schristos ND_PRINT("[code %u]", code); 3280f74e101Schristos break; 3290f74e101Schristos } 3300f74e101Schristos break; 3310f74e101Schristos 3320f74e101Schristos case EGPT_REACH: 3330f74e101Schristos switch (code) { 3340f74e101Schristos 3350f74e101Schristos case EGPC_HELLO: 3360f74e101Schristos case EGPC_HEARDU: 337c74ad251Schristos ND_PRINT(" %s", egp_reach_codes[code]); 3380f74e101Schristos if (status <= EGPS_DOWN) 339c74ad251Schristos ND_PRINT(" state:%s", egp_status_updown[status]); 3400f74e101Schristos else 341c74ad251Schristos ND_PRINT(" [status %u]", status); 3420f74e101Schristos break; 3430f74e101Schristos 3440f74e101Schristos default: 345c74ad251Schristos ND_PRINT("[reach code %u]", code); 3460f74e101Schristos break; 3470f74e101Schristos } 3480f74e101Schristos break; 3490f74e101Schristos 3500f74e101Schristos case EGPT_POLL: 351c74ad251Schristos ND_PRINT(" poll"); 352c74ad251Schristos if (status <= EGPS_DOWN) 353c74ad251Schristos ND_PRINT(" state:%s", egp_status_updown[status]); 3540f74e101Schristos else 355c74ad251Schristos ND_PRINT(" [status %u]", status); 356c74ad251Schristos ND_PRINT(" net:%s", GET_IPADDR_STRING(egp->egp_sourcenet)); 3570f74e101Schristos break; 3580f74e101Schristos 3590f74e101Schristos case EGPT_UPDATE: 360c74ad251Schristos ND_PRINT(" update"); 3610f74e101Schristos if (status & EGPS_UNSOL) { 3620f74e101Schristos status &= ~EGPS_UNSOL; 363c74ad251Schristos ND_PRINT(" unsolicited"); 3640f74e101Schristos } 3650f74e101Schristos if (status <= EGPS_DOWN) 366c74ad251Schristos ND_PRINT(" state:%s", egp_status_updown[status]); 3670f74e101Schristos else 368c74ad251Schristos ND_PRINT(" [status %u]", status); 369c74ad251Schristos ND_PRINT(" %s int %u ext %u", 370c74ad251Schristos GET_IPADDR_STRING(egp->egp_sourcenet), 371c74ad251Schristos GET_U_1(egp->egp_intgw), 372c74ad251Schristos GET_U_1(egp->egp_extgw)); 373b3a00663Schristos if (ndo->ndo_vflag) 374c74ad251Schristos egpnr_print(ndo, egp, length); 3750f74e101Schristos break; 3760f74e101Schristos 3770f74e101Schristos case EGPT_ERROR: 378c74ad251Schristos ND_PRINT(" error"); 3790f74e101Schristos if (status <= EGPS_DOWN) 380c74ad251Schristos ND_PRINT(" state:%s", egp_status_updown[status]); 3810f74e101Schristos else 382c74ad251Schristos ND_PRINT(" [status %u]", status); 3830f74e101Schristos 384c74ad251Schristos if (GET_BE_U_2(egp->egp_reason) <= EGPR_UVERSION) 385c74ad251Schristos ND_PRINT(" %s", 386c74ad251Schristos egp_reasons[GET_BE_U_2(egp->egp_reason)]); 3870f74e101Schristos else 388c74ad251Schristos ND_PRINT(" [reason %u]", GET_BE_U_2(egp->egp_reason)); 3890f74e101Schristos break; 3900f74e101Schristos 3910f74e101Schristos default: 392c74ad251Schristos ND_PRINT("[type %u]", type); 3930f74e101Schristos break; 3940f74e101Schristos } 3950f74e101Schristos } 396