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