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