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