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.38 2006-02-11 22:13:24 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
230        if (!vflag) {
231            printf("EGPv%u, AS %u, seq %u, length %u",
232                   egp->egp_version,
233                   EXTRACT_16BITS(&egp->egp_as),
234                   EXTRACT_16BITS(&egp->egp_sequence),
235                   length);
236            return;
237        } else
238            printf("EGPv%u, length %u",
239                   egp->egp_version,
240                   length);
241
242	if (egp->egp_version != EGP_VERSION) {
243		printf("[version %d]", egp->egp_version);
244		return;
245	}
246
247	type = egp->egp_type;
248	code = egp->egp_code;
249	status = egp->egp_status;
250
251	switch (type) {
252	case EGPT_ACQUIRE:
253		printf(" acquire");
254		switch (code) {
255		case EGPC_REQUEST:
256		case EGPC_CONFIRM:
257			printf(" %s", egp_acquire_codes[code]);
258			switch (status) {
259			case EGPS_UNSPEC:
260			case EGPS_ACTIVE:
261			case EGPS_PASSIVE:
262				printf(" %s", egp_acquire_status[status]);
263				break;
264
265			default:
266				printf(" [status %d]", status);
267				break;
268			}
269			printf(" hello:%d poll:%d",
270			       EXTRACT_16BITS(&egp->egp_hello),
271			       EXTRACT_16BITS(&egp->egp_poll));
272			break;
273
274		case EGPC_REFUSE:
275		case EGPC_CEASE:
276		case EGPC_CEASEACK:
277			printf(" %s", egp_acquire_codes[code]);
278			switch (status ) {
279			case EGPS_UNSPEC:
280			case EGPS_NORES:
281			case EGPS_ADMIN:
282			case EGPS_GODOWN:
283			case EGPS_PARAM:
284			case EGPS_PROTO:
285				printf(" %s", egp_acquire_status[status]);
286				break;
287
288			default:
289				printf("[status %d]", status);
290				break;
291			}
292			break;
293
294		default:
295			printf("[code %d]", code);
296			break;
297		}
298		break;
299
300	case EGPT_REACH:
301		switch (code) {
302
303		case EGPC_HELLO:
304		case EGPC_HEARDU:
305			printf(" %s", egp_reach_codes[code]);
306			if (status <= EGPS_DOWN)
307				printf(" state:%s", egp_status_updown[status]);
308			else
309				printf(" [status %d]", status);
310			break;
311
312		default:
313			printf("[reach code %d]", code);
314			break;
315		}
316		break;
317
318	case EGPT_POLL:
319		printf(" poll");
320		if (egp->egp_status <= EGPS_DOWN)
321			printf(" state:%s", egp_status_updown[status]);
322		else
323			printf(" [status %d]", status);
324		printf(" net:%s", ipaddr_string(&egp->egp_sourcenet));
325		break;
326
327	case EGPT_UPDATE:
328		printf(" update");
329		if (status & EGPS_UNSOL) {
330			status &= ~EGPS_UNSOL;
331			printf(" unsolicited");
332		}
333		if (status <= EGPS_DOWN)
334			printf(" state:%s", egp_status_updown[status]);
335		else
336			printf(" [status %d]", status);
337		printf(" %s int %d ext %d",
338		       ipaddr_string(&egp->egp_sourcenet),
339		       egp->egp_intgw,
340		       egp->egp_extgw);
341		if (vflag)
342			egpnrprint(egp);
343		break;
344
345	case EGPT_ERROR:
346		printf(" error");
347		if (status <= EGPS_DOWN)
348			printf(" state:%s", egp_status_updown[status]);
349		else
350			printf(" [status %d]", status);
351
352		if (EXTRACT_16BITS(&egp->egp_reason) <= EGPR_UVERSION)
353			printf(" %s", egp_reasons[EXTRACT_16BITS(&egp->egp_reason)]);
354		else
355			printf(" [reason %d]", EXTRACT_16BITS(&egp->egp_reason));
356		break;
357
358	default:
359		printf("[type %d]", type);
360		break;
361	}
362}
363