xref: /netbsd-src/external/bsd/tcpdump/dist/print-egp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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