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