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