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