Remove "text2pcap-scanner.obj" and "tools\lemon\lemon.obj" when a "nmake
[obnox/wireshark/wip.git] / packet-bgp.c
1 /* packet-bgp.c
2  * Routines for BGP packet dissection.
3  * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
4  *
5  * $Id: packet-bgp.c,v 1.48 2001/11/03 21:25:12 guy Exp $
6  *
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC1965 Autonomous System Confederations for BGP
10  * RFC1997 BGP Communities Attribute
11  * RFC2796 BGP Route Reflection An alternative to full mesh IBGP
12  * RFC2842 Capabilities Advertisement with BGP-4
13  * RFC2858 Multiprotocol Extensions for BGP-4
14  * RFC2918 Route Refresh Capability for BGP-4
15  * Draft Ramahandra on Extended Communities Extentions
16  *
17  * TODO:
18  * Destination Preference Attribute for BGP (work in progress)
19  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
20  *
21  * Ethereal - Network traffic analyzer
22  * By Gerald Combs <gerald@ethereal.com>
23  * Copyright 1998 Gerald Combs
24  *
25  * This program is free software; you can redistribute it and/or
26  * modify it under the terms of the GNU General Public License
27  * as published by the Free Software Foundation; either version 2
28  * of the License, or (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program; if not, write to the Free Software
37  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
38  */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #ifdef HAVE_SYS_TYPES_H
48 # include <sys/types.h>
49 #endif
50
51 #ifdef HAVE_NETINET_IN_H
52 # include <netinet/in.h>
53 #endif
54
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
57 #endif
58
59 #include <string.h>
60 #include <glib.h>
61
62 #ifdef NEED_SNPRINTF_H
63 # include "snprintf.h"
64 #endif
65
66 #include "packet.h"
67 #include "packet-bgp.h"
68 #include "packet-ipv6.h"
69 #include "afn.h"
70
71 static const value_string bgptypevals[] = {
72     { BGP_OPEN, "OPEN Message" },
73     { BGP_UPDATE, "UPDATE Message" },
74     { BGP_NOTIFICATION, "NOTIFICATION Message" },
75     { BGP_KEEPALIVE, "KEEPALIVE Message" },
76     { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
77     { BGP_ROUTE_REFRESH_CISCO, "Cisco ROUTE-REFRESH Message" },
78     { 0, NULL },
79 };
80
81 static const value_string bgpnotify_major[] = {
82     { 1, "Message Header Error" },
83     { 2, "OPEN Message Error" },
84     { 3, "UPDATE Message Error" },
85     { 4, "Hold Timer Expired" },
86     { 5, "Finite State Machine Error" },
87     { 6, "Cease" },
88     { 0, NULL },
89 };
90
91 static const value_string bgpnotify_minor_1[] = {
92     { 1, "Connection Not Synchronized" },
93     { 2, "Bad Message Length" },
94     { 3, "Bad Message Type" },
95     { 0, NULL },
96 };
97
98 static const value_string bgpnotify_minor_2[] = {
99     { 1, "Unsupported Version Number" },
100     { 2, "Bad Peer AS" },
101     { 3, "Bad BGP Identifier" },
102     { 4, "Unsupported Optional Parameter" },
103     { 5, "Authentication Failure" },
104     { 6, "Unacceptable Hold Time" },
105     { 7, "Unsupported Capability" },
106     { 0, NULL },
107 };
108
109 static const value_string bgpnotify_minor_3[] = {
110     { 1, "Malformed Attribute List" },
111     { 2, "Unrecognized Well-known Attribute" },
112     { 3, "Missing Well-known Attribute" },
113     { 4, "Attribute Flags Error" },
114     { 5, "Attribute Length Error" },
115     { 6, "Invalid ORIGIN Attribute" },
116     { 7, "AS Routing Loop" },
117     { 8, "Invalid NEXT_HOP Attribute" },
118     { 9, "Optional Attribute Error" },
119     { 10, "Invalid Network Field" },
120     { 11, "Malformed AS_PATH" },
121     { 0, NULL },
122 };
123
124 static const value_string *bgpnotify_minor[] = {
125     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
126 };
127
128 static const value_string bgpattr_origin[] = {
129     { 0, "IGP" },
130     { 1, "EGP" },
131     { 2, "INCOMPLETE" },
132     { 0, NULL },
133 };
134
135 static const value_string as_segment_type[] = {
136     { 1, "AS_SET" },
137     { 2, "AS_SEQUENCE" },
138 /* RFC1965 has the wrong values, corrected in  */
139 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
140     { 4, "AS_CONFED_SET" },
141     { 3, "AS_CONFED_SEQUENCE" },
142     { 0, NULL },
143 };
144
145 static const value_string bgpattr_type[] = {
146     { BGPTYPE_ORIGIN, "ORIGIN" },
147     { BGPTYPE_AS_PATH, "AS_PATH" },
148     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
149     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
150     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
151     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
152     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
153     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
154     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
155     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
156     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
157     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
158     { BGPTYPE_EXTENDED_COMMUNITY, "EXTENDED_COMMUNITIES" },
159     { 0, NULL },
160 };
161
162 /* Beware : See also MAX_SIZE_OF_EXT_COM_NAMES */
163 static const value_string bgpext_com_type[] = {
164     { BGP_EXT_COM_RT_0, "Route Target" },
165     { BGP_EXT_COM_RT_1, "Route Target" },
166     { BGP_EXT_COM_RO_0, "Route Origin" },
167     { BGP_EXT_COM_RO_1, "Route Origin" },
168     { BGP_EXT_COM_LINKBAND, "Link Bandwidth" },
169     { BGP_EXT_COM_VPN_ORIGIN, "OSPF Domain" },
170     { BGP_EXT_COM_OSPF_RTYPE, "OSPF Route Type" },
171     { BGP_EXT_COM_OSPF_RID, "OSPF Router ID" },
172     { 0, NULL },
173 };
174
175 static const value_string bgpext_ospf_rtype[] = {
176   { BGP_OSPF_RTYPE_RTR, "Router" },  
177   { BGP_OSPF_RTYPE_NET, "Network" },  
178   { BGP_OSPF_RTYPE_SUM, "Summary" },  
179   { BGP_OSPF_RTYPE_EXT, "External" },  
180   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
181   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },  
182   { 0, NULL },
183 };
184
185
186 /* MUST be resized if a longer named extended community is added */
187 #define MAX_SIZE_OF_EXT_COM_NAMES       20
188
189 /* Subsequent address family identifier, RFC2858 */
190 static const value_string bgpattr_nlri_safi[] = {
191     { 0, "Reserved" },
192     { SAFNUM_UNICAST, "Unicast" },
193     { SAFNUM_MULCAST, "Multicast" },
194     { SAFNUM_UNIMULC, "Unicast+Multicast" },
195     { SAFNUM_MPLS_LABEL, "MPLS Labeled Prefix"},
196     { SAFNUM_LBVPNIP, "Labeled VPN-IPv4" },        /* draft-rosen-rfc2547bis-03 */
197     { 0, NULL },
198 };
199
200 /* ORF Type, draft-ietf-idr-route-filter-04.txt */
201 static const value_string orf_type_vals[] = {
202     { 2,        "Communities ORF-Type" },
203     { 3,        "Extended Communities ORF-Type" },
204     { 0,        NULL },
205 };
206
207 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
208 static const value_string orf_send_recv_vals[] = {
209     { 1,        "Receive" },
210     { 2,        "Send" },
211     { 3,        "Both" },
212     { 0,        NULL },
213 };
214
215 /* Maximal size of an IP address string */
216 #define MAX_SIZE_OF_IP_ADDR_STRING      16
217
218 static int proto_bgp = -1;
219 static int hf_bgp_type = -1;
220
221 static gint ett_bgp = -1;
222 static gint ett_bgp_unfeas = -1;
223 static gint ett_bgp_attrs = -1;
224 static gint ett_bgp_attr = -1;
225 static gint ett_bgp_attr_flags = -1;
226 static gint ett_bgp_mp_nhna = -1;
227 static gint ett_bgp_mp_reach_nlri = -1;
228 static gint ett_bgp_mp_unreach_nlri = -1;
229 static gint ett_bgp_mp_snpa = -1;
230 static gint ett_bgp_nlri = -1;
231 static gint ett_bgp_open = -1;
232 static gint ett_bgp_update = -1;
233 static gint ett_bgp_notification = -1;
234 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
235 static gint ett_bgp_as_paths = -1;
236 static gint ett_bgp_communities = -1;
237 static gint ett_bgp_cluster_list = -1;  /* cluster list tree          */
238 static gint ett_bgp_options = -1;       /* optional parameters tree   */
239 static gint ett_bgp_option = -1;        /* an optional parameter tree */
240 static gint ett_bgp_extended_communities = -1 ; /* extended communities list tree */
241 /*
242  * Decode an IPv4 prefix.
243  */
244 static int
245 decode_prefix4(tvbuff_t *tvb, gint offset, char *buf, int buflen)
246 {
247     guint8 addr[4];   /* IP address                         */
248     int    plen;      /* prefix length                      */
249     int    length;    /* number of octets needed for prefix */
250
251     /* snarf length */
252     plen = tvb_get_guint8(tvb, offset);
253     if (plen < 0 || 32 < plen)
254         return -1;
255     length = (plen + 7) / 8;
256
257     /* snarf prefix */
258     memset(addr, 0, sizeof(addr));
259     tvb_memcpy(tvb, addr, offset + 1, length);
260     if (plen % 8)
261         addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
262
263     /* hand back a formatted string */
264     snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
265     return(1 + length);
266 }
267
268 /*
269  * Decode an IPv6 prefix.
270  */
271 static int
272 decode_prefix6(tvbuff_t *tvb, gint offset, char *buf, int buflen)
273 {
274     struct e_in6_addr addr;     /* IPv6 address                       */
275     int               plen;     /* prefix length                      */
276     int               length;   /* number of octets needed for prefix */
277
278     /* snarf length */
279     plen = tvb_get_guint8(tvb, offset);
280     if (plen < 0 || 128 < plen)
281         return -1;
282     length = (plen + 7) / 8;
283
284     /* snarf prefix */
285     memset(&addr, 0, sizeof(addr));
286     tvb_memcpy(tvb, (guint8 *)&addr, offset + 1, length);
287     if (plen % 8)
288         addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
289
290     /* hand back a formatted string */
291     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
292     return(1 + length);
293 }
294
295 /*
296  * Decode an MPLS label stack
297  */
298 static int
299 decode_MPLS_stack(tvbuff_t *tvb, gint offset, char *buf, int buflen)
300 {
301     guint32     label_entry;    /* an MPLS label enrty (label + COS field + stack bit   */
302     gint        index;          /* index for the label stack                            */
303
304     index = offset ;
305     label_entry = 0x000000 ;
306
307     buf[0] = '\0' ;
308
309     while ((label_entry && 0x000001) == 0) {
310
311         label_entry = tvb_get_ntoh24(tvb, index) ;
312         snprintf(buf, buflen,"%s%u%s", buf, (label_entry >> 4), ((label_entry && 0x000001) == 0) ? "," : " (bottom)");
313         index += 3 ;
314     }
315
316     return((index - offset) / 3);
317 }
318
319 /*
320  * Decode a multiprotocol address
321  */
322
323 static int
324 mp_addr_to_str (guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
325 {
326     int                 length;                         /* length of the address in byte */
327     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
328     guint16             rd_type;                        /* Route Distinguisher type     */
329     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
330
331     length = 0 ;
332     switch (afi) {
333         case AFNUM_INET:
334                 switch (safi) {
335                         case SAFNUM_UNICAST:
336                         case SAFNUM_MULCAST:
337                         case SAFNUM_UNIMULC:
338                                 length = 4 ;
339                                 tvb_memcpy(tvb, ip4addr, offset, 4);
340                                 snprintf(buf, buflen, "%s", ip_to_str(ip4addr));
341                                 break;
342                         case SAFNUM_LBVPNIP:
343                                 rd_type=tvb_get_ntohs(tvb,offset) ;
344                                 switch (rd_type) {
345                                         case FORMAT_AS2_LOC:
346                                                 length = 12;
347                                                 tvb_memcpy(tvb, ip4addr, offset + 8, 4);
348                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
349                                                                 tvb_get_ntohs(tvb, offset + 2),
350                                                                 tvb_get_ntohl(tvb, offset + 4),
351                                                                 ip_to_str(ip4addr));
352                                                 break;
353                                         case FORMAT_IP_LOC:
354                                                 length = 12;
355                                                 tvb_memcpy(tvb, ip4addr, offset + 2, 4);   /* IP part of the RD            */
356                                                 tvb_memcpy(tvb, ip4addr2, offset +6, 4);   /* IP address of the VPN-IPv4   */
357                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
358                                                                 ip_to_str(ip4addr),
359                                                                 tvb_get_ntohs(tvb, offset + 6),
360                                                                 ip_to_str(ip4addr2));
361                                                 break ;
362                                         default:
363                                                 length = 0 ;
364                                                 snprintf(buf, buflen, "Unknown labeled VPN-IPv4 address format");
365                                                 break;
366                                 }
367                                 break;
368                         default:
369                                 length = 0 ;
370                                 snprintf(buf, buflen, "Unknown SAFI value for AFI %u", afi);
371                                 break;
372                 }
373                 break;
374         case AFNUM_INET6:
375                 length = 16 ;
376                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8,offset, sizeof(ip6addr));
377                 snprintf(buf, buflen, "%s", ip6_to_str(&ip6addr));
378                 break;
379         default:
380                 length = 0 ;
381                 snprintf(buf, buflen, "Unknown AFI value");
382                 break;
383     }
384     return(length) ;
385 }
386
387 /*
388  * Decode a multiprotocol prefix
389  */
390 static int
391 decode_prefix_MP(guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
392 {
393     int                 length;                         /* length of the prefix in byte */
394     int                 plen;                           /* length of the prefix in bit  */
395     int                 labnum;                         /* number of labels             */
396     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
397     guint16             rd_type;                        /* Route Distinguisher type     */
398     char                lab_stk[256];                   /* label stack                  */
399
400     length = 0 ;
401
402     switch (afi) {
403         case AFNUM_INET:
404                 switch (safi) {
405                         case SAFNUM_UNICAST:
406                         case SAFNUM_MULCAST:
407                         case SAFNUM_UNIMULC:
408                                 length = decode_prefix4(tvb, offset, buf, buflen) - 1 ;
409                                 break;
410                         case SAFNUM_LBVPNIP:
411                                 plen =  tvb_get_guint8(tvb,offset) ;
412
413                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
414
415                                 offset += (1 + labnum * 3);
416                                 plen -= (labnum * 3*8);
417
418                                 rd_type=tvb_get_ntohs(tvb,offset) ;
419                                 plen -= 8*8;
420
421                                 switch (rd_type) {
422                                         case FORMAT_AS2_LOC: /* Code borrowed from the decode_prefix4 function */
423                                                 if (plen < 0 || 32 < plen) {
424                                                         length = 0 ;
425                                                         break ;
426                                                 }
427
428                                                 length = (plen + 7) / 8;
429                                                 memset(ip4addr, 0, sizeof(ip4addr));
430                                                 tvb_memcpy(tvb, ip4addr, offset + 8, length);
431                                                 if (plen % 8)
432                                                         ip4addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
433
434                                                 snprintf(buf,buflen, "Label Stack=%s RD=%u:%u, IP=%s/%d",
435                                                         lab_stk,
436                                                         tvb_get_ntohs(tvb, offset + 2),
437                                                         tvb_get_ntohl(tvb, offset + 4),
438                                                         ip_to_str(ip4addr),
439                                                         plen);
440                                                 length += (labnum * 3 + 8) ;
441                                                 break ;
442                                         case FORMAT_IP_LOC: /* Code borrowed from the decode_prefix4 function */
443                                                 tvb_memcpy(tvb, ip4addr, offset + 2, 4);
444
445                                                 if (plen < 0 || 32 < plen) {
446                                                         length = 0 ;
447                                                         break ;
448                                                 }
449
450                                                 length = (plen + 7) / 8;
451                                                 memset(ip4addr2, 0, sizeof(ip4addr2));
452                                                 tvb_memcpy(tvb, ip4addr2, offset + 8, length);
453                                                 if (plen % 8)
454                                                         ip4addr2[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
455
456                                                 snprintf(buf,buflen, "Label Stack=%s RD=%s:%u, IP=%s/%d",
457                                                         lab_stk,
458                                                         ip_to_str(ip4addr),
459                                                         tvb_get_ntohs(tvb, offset + 6),
460                                                         ip_to_str(ip4addr2),
461                                                         plen);
462                                                 length += (labnum * 3 + 8) ;
463                                                 break ;
464                                         default:
465                                                 length = 0 ;
466                                                 snprintf(buf,buflen, "Unkown labeled VPN-IPv4 address format");
467                                                 break;
468                                 }
469                                 break;
470                 default:
471                         length = 0 ;
472                         snprintf(buf,buflen, "Unkown SAFI value for AFI %u", afi);
473                         break;
474                 }
475                 break;
476         case AFNUM_INET6:
477                  length = decode_prefix6(tvb, offset, buf, buflen) - 1 ;
478                  break;
479         default:
480                 length = 0 ;
481                 snprintf(buf,buflen, "Unkown AFI value");
482                 break;
483     }
484     return(1 + length) ;
485 }
486
487 /*
488  * Dissect a BGP OPEN message.
489  */
490 static void
491 dissect_bgp_open(tvbuff_t *tvb, int offset, proto_tree *tree)
492 {
493     struct bgp_open bgpo;      /* BGP OPEN message      */
494     int             hlen;      /* message length        */
495     u_int           i;         /* tmp                   */
496     int             ptype;     /* parameter type        */
497     int             plen;      /* parameter length      */
498     int             ctype;     /* capability type       */
499     int             clen;      /* capability length     */
500     int             cend;      /* capabilities end      */
501     int             ostart;    /* options start         */
502     int             oend;      /* options end           */
503     int             p;         /* tvb offset counter    */
504     proto_item      *ti;       /* tree item             */
505     proto_tree      *subtree;  /* subtree for options   */
506     proto_tree      *subtree1; /* subtree for an option */
507     proto_tree      *subtree2; /* subtree for an option */
508     proto_tree      *subtree3; /* subtree for an option */
509     guint8          orfnum;    /* number of ORFs */
510     guint8          orftype;        /* ORF Type */
511     guint8          orfsendrecv;    /* ORF Send/Receive */
512
513     /* snarf OPEN message */
514     tvb_memcpy(tvb, bgpo.bgpo_marker, offset, BGP_MIN_OPEN_MSG_SIZE);
515     hlen = ntohs(bgpo.bgpo_len);
516
517     proto_tree_add_text(tree, tvb,
518         offset + offsetof(struct bgp_open, bgpo_version), 1,
519         "Version: %u", bgpo.bgpo_version);
520     proto_tree_add_text(tree, tvb,
521         offset + offsetof(struct bgp_open, bgpo_myas), 2,
522         "My AS: %u", ntohs(bgpo.bgpo_myas));
523     proto_tree_add_text(tree, tvb,
524         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
525         "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
526     proto_tree_add_text(tree, tvb,
527         offset + offsetof(struct bgp_open, bgpo_id), 4,
528         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
529     proto_tree_add_text(tree, tvb,
530         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
531         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
532         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
533
534     /* optional parameters */
535     if (bgpo.bgpo_optlen > 0) {
536         /* add a subtree and setup some offsets */
537         ostart = offset + BGP_MIN_OPEN_MSG_SIZE;
538         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
539              "Optional parameters");
540         subtree = proto_item_add_subtree(ti, ett_bgp_options);
541         p = offset + ostart;
542         oend = p + bgpo.bgpo_optlen;
543
544         /* step through all of the optional parameters */
545         while (p < oend) {
546
547             /* grab the type and length */
548             ptype = tvb_get_guint8(tvb, p++);
549             plen = tvb_get_guint8(tvb, p++);
550
551             /* check the type */
552             switch (ptype) {
553             case BGP_OPTION_AUTHENTICATION:
554                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
555                     "Authentication information (%u %s)", plen,
556                     (plen == 1) ? "byte" : "bytes");
557                 break;
558             case BGP_OPTION_CAPABILITY:
559                 /* grab the capability code */
560                 cend = p - 1 + plen;
561                 ctype = tvb_get_guint8(tvb, p++);
562                 clen = tvb_get_guint8(tvb, p++);
563                 ti = proto_tree_add_text(subtree, tvb, p - 4,
564                      2 + plen, "Capabilities Advertisement (%u bytes)",
565                      2 + plen);
566                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
567                 proto_tree_add_text(subtree1, tvb, p - 4,
568                      1, "Parameter type: Capabilities (2)");
569                 proto_tree_add_text(subtree1, tvb, p - 3,
570                      1, "Parameter length: %u %s", plen,
571                      (plen == 1) ? "byte" : "bytes");
572                 p -= 2;
573
574                 /* step through all of the capabilities */
575                 while (p < cend) {
576                     ctype = tvb_get_guint8(tvb, p++);
577                     clen = tvb_get_guint8(tvb, p++);
578
579                     /* check the capability type */
580                     switch (ctype) {
581                     case BGP_CAPABILITY_RESERVED:
582                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
583                              2 + clen, "Reserved capability (%u %s)", 2 + clen,
584                              (clen == 1) ? "byte" : "bytes");
585                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
586                         proto_tree_add_text(subtree2, tvb, p - 2,
587                              1, "Capability code: Reserved (0)");
588                         proto_tree_add_text(subtree2, tvb, p - 1,
589                              1, "Capability length: %u %s", clen,
590                              (clen == 1) ? "byte" : "bytes");
591                         if (clen != 0) {
592                             proto_tree_add_text(subtree2, tvb, p,
593                                  clen, "Capability value: Unknown");
594                         }
595                         p += clen;
596                         break;
597                     case BGP_CAPABILITY_MULTIPROTOCOL:
598                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
599                              2 + clen,
600                              "Multiprotocol extensions capability (%u %s)",
601                              2 + clen, (clen == 1) ? "byte" : "bytes");
602                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
603                         proto_tree_add_text(subtree2, tvb, p - 2,
604                              1, "Capability code: Multiprotocol extensions (%d)",
605                              ctype);
606                         if (clen != 4) {
607                             proto_tree_add_text(subtree2, tvb, p - 1,
608                                  1, "Capability length: Invalid");
609                             proto_tree_add_text(subtree2, tvb, p,
610                                  clen, "Capability value: Unknown");
611                         }
612                         else {
613                             proto_tree_add_text(subtree2, tvb, p - 1,
614                                  1, "Capability length: %u %s", clen,
615                                  (clen == 1) ? "byte" : "bytes");
616                             ti = proto_tree_add_text(subtree2, tvb, p,
617                                  clen, "Capability value");
618                             subtree3 = proto_item_add_subtree(ti,
619                                        ett_bgp_option);
620                             /* AFI */
621                             i = tvb_get_ntohs(tvb, p);
622                             proto_tree_add_text(subtree3, tvb, p,
623                                  2, "Address family identifier: %s (%u)",
624                                  val_to_str(i, afn_vals, "Unknown"), i);
625                             p += 2;
626                             /* Reserved */
627                             proto_tree_add_text(subtree3, tvb, p,
628                                  1, "Reserved: 1 byte");
629                             p++;
630                             /* SAFI */
631                             i = tvb_get_guint8(tvb, p);
632                             proto_tree_add_text(subtree3, tvb, p,
633                                  1, "Subsequent address family identifier: %s (%u)",
634                                  val_to_str(i, bgpattr_nlri_safi,
635                                     i >= 128 ? "Vendor specific" : "Unknown"), i);
636                             p++;
637                         }
638                         break;
639                     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
640                     case BGP_CAPABILITY_ROUTE_REFRESH:
641                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
642                              2 + clen, "Route refresh capability (%u %s)", 2 + clen,
643                              (clen == 1) ? "byte" : "bytes");
644                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
645                         proto_tree_add_text(subtree2, tvb, p - 2,
646                              1, "Capability code: Route refresh (%d)", ctype);
647                         if (clen != 0) {
648                             proto_tree_add_text(subtree2, tvb, p,
649                                  clen, "Capability value: Invalid");
650                         }
651                         else {
652                             proto_tree_add_text(subtree2, tvb, p - 1,
653                                  1, "Capability length: %u %s", clen,
654                                  (clen == 1) ? "byte" : "bytes");
655                         }
656                         p += clen;
657                         break;
658                     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
659                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
660                              2 + clen,
661                              "Cooperative route filtering capability (%u %s)",
662                              2 + clen, (clen == 1) ? "byte" : "bytes");
663                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
664                         proto_tree_add_text(subtree2, tvb, p - 2,
665                              1, "Capability code: Cooperative route filtering (%d)",
666                              ctype);
667                         proto_tree_add_text(subtree2, tvb, p - 1,
668                              1, "Capability length: %u %s", clen,
669                              (clen == 1) ? "byte" : "bytes");
670                         ti = proto_tree_add_text(subtree2, tvb, p,
671                              clen, "Capability value");
672                         subtree3 = proto_item_add_subtree(ti, ett_bgp_option);
673                         /* AFI */
674                         i = tvb_get_ntohs(tvb, p);
675                         proto_tree_add_text(subtree3, tvb, p,
676                              2, "Address family identifier: %s (%u)",
677                              val_to_str(i, afn_vals, "Unknown"), i);
678                         p += 2;
679                         /* Reserved */
680                         proto_tree_add_text(subtree3, tvb, p, 
681                              1, "Reserved: 1 byte");
682                         p++;
683                         /* SAFI */
684                         i = tvb_get_guint8(tvb, p);
685                         proto_tree_add_text(subtree3, tvb, p,
686                              1, "Subsequent address family identifier: %s (%u)",
687                              val_to_str(i, bgpattr_nlri_safi,
688                              i >= 128 ? "Vendor specific" : "Unknown"), i);
689                         p++;
690                         /* Number of ORFs */
691                         orfnum = tvb_get_guint8(tvb, p);
692                         proto_tree_add_text(subtree3, tvb, p,
693                                             1, "Number of ORFs: %u", orfnum);
694                         p++;
695                         for (i=0; i<orfnum; i++) {
696                             /* ORF Type */
697                             orftype = tvb_get_guint8(tvb, p);
698                             proto_tree_add_text(subtree3, tvb, p,
699                                 1, "ORF Type: %s (%u)",
700                                 val_to_str(orftype, orf_type_vals,"Unknown"),
701                                 orftype);
702                             p++;
703                             /* Send/Receive */
704                             orfsendrecv = tvb_get_guint8(tvb, p);
705                             proto_tree_add_text(subtree3, tvb, p,
706                                 1, "Send/Receive: %s (%u)",
707                                 val_to_str(orfsendrecv, orf_send_recv_vals, 
708                                 "Uknown"), orfsendrecv);
709                             p++;
710                         }
711                         break;
712                     /* unknown capability */
713                     default:
714                         ti = proto_tree_add_text(subtree, tvb, p - 2,
715                              2 + clen, "Unknown capability (%u %s)", 2 + clen,
716                              (clen == 1) ? "byte" : "bytes");
717                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
718                         proto_tree_add_text(subtree2, tvb, p - 2,
719                              1, "Capability code: %s (%d)",
720                              ctype >= 128 ? "Private use" : "Unknown", ctype);
721                         proto_tree_add_text(subtree2, tvb, p - 1,
722                              1, "Capability length: %u %s", clen,
723                              (clen == 1) ? "byte" : "bytes");
724                         if (clen != 0) {
725                             proto_tree_add_text(subtree2, tvb, p,
726                                  clen, "Capability value: Unknown");
727                         }
728                         p += clen;
729                         break;
730                     }
731                 }
732                 break;
733             default:
734                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
735                     "Unknown optional parameter");
736                 break;
737             }
738         }
739     }
740 }
741
742 /*
743  * Dissect a BGP UPDATE message.
744  */
745 static void
746 dissect_bgp_update(tvbuff_t *tvb, int offset, proto_tree *tree)
747  {
748     struct bgp_attr bgpa;                       /* path attributes          */
749     int             hlen;                       /* message length           */
750     gint            o;                          /* packet offset            */
751     gint            q;                          /* tmp                      */
752     gint            end;                        /* message end              */
753     gint            ext_com;                    /* EXTENDED COMMUNITY type  */
754     int             len;                        /* tmp                      */
755     int             advance;                    /* tmp                      */
756     proto_item      *ti;                        /* tree item                */
757     proto_tree      *subtree;                   /* subtree for attributes   */
758     proto_tree      *subtree2;                  /* subtree for attributes   */
759     proto_tree      *subtree3;                  /* subtree for attributes   */
760     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
761     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
762     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
763     proto_tree      *community_tree;            /* subtree for a community  */
764     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
765     int             i, j;                       /* tmp                      */
766     guint8          length;                     /* AS_PATH length           */
767     guint8          type;                       /* AS_PATH type             */
768     char            *as_path_str = NULL;        /* AS_PATH string           */
769     char            *communities_str = NULL;    /* COMMUNITIES string       */
770     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
771     char            *ext_com_str = NULL;        /* EXTENDED COMMUNITY list  */
772     char            junk_buf[256];              /* tmp                      */
773     guint8          ipaddr[4];                  /* IPv4 address             */
774
775     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
776     o = offset + BGP_HEADER_SIZE;
777
778     /* check for withdrawals */
779     len = tvb_get_ntohs(tvb, o);
780     proto_tree_add_text(tree, tvb, o, 2,
781         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
782     o += 2;
783
784     /* parse unfeasible prefixes */
785     if (len > 0) {
786         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
787         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
788
789         /* parse each prefixes */
790         end = o + len;
791         while (o < end) {
792             i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
793             proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
794             o += i;
795         }
796     }
797     else {
798         o += len;
799     }
800     /* check for advertisements */
801     len = tvb_get_ntohs(tvb, o);
802     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
803             len, (len == 1) ? "byte" : "bytes");
804
805     /* path attributes */
806     if (len > 0) {
807         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
808         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
809         i = 2;
810         while (i < len) {
811             int alen, aoff;
812             char *msg;
813             guint16 af;
814             guint8 saf;
815             int off, snpa;
816             int nexthop_len;
817
818             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
819             /* check for the Extended Length bit */
820             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
821                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
822                 aoff = sizeof(bgpa) + 2;
823             } else {
824                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
825                 aoff = sizeof(bgpa) + 1;
826             }
827
828             /* This is kind of ugly - similar code appears twice, but it
829                helps browsing attrs.                                      */
830             /* the first switch prints things in the title of the subtree */
831             switch (bgpa.bgpa_type) {
832             case BGPTYPE_ORIGIN:
833                 if (alen != 1)
834                     goto default_attribute_top;
835                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
836                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
837                         "%s: %s (%u %s)",
838                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
839                         msg, alen + aoff, (alen + aoff == 1) ? "byte" :
840                         "bytes");
841                 break;
842             case BGPTYPE_AS_PATH:
843                 /* (o + i + 3) =
844                    (o + current attribute + 3 bytes to first tuple) */
845                 end = o + alen + i + 3;
846                 q = o + i + 3;
847                 /* must be freed by second switch!                         */
848                 /* "alen * 6" (5 digits + space) should be a good estimate
849                    of how long the AS path string could be                 */
850                 as_path_str = malloc((alen + 1) * 6);
851                 if (as_path_str == NULL) break;
852                 as_path_str[0] = '\0';
853
854                 /* snarf each AS path */
855                 while (q < end) {
856                     type = tvb_get_guint8(tvb, q++);
857                     if (type == AS_SET) {
858                         snprintf(as_path_str, 2, "{");
859                     }
860                     else if (type == AS_CONFED_SET) {
861                         snprintf(as_path_str, 2, "[");
862                     }
863                     else if (type == AS_CONFED_SEQUENCE) {
864                         snprintf(as_path_str, 2, "(");
865                     }
866                     length = tvb_get_guint8(tvb, q++);
867
868                     /* snarf each value in path */
869                     for (j = 0; j < length; j++) {
870                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
871                                 (type == AS_SET || type == AS_CONFED_SET)
872                                 ? ", " : " ");
873                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
874                         q += 2;
875                     }
876
877                     /* cleanup end of string */
878                     if (type == AS_SET) {
879                         as_path_str[strlen(as_path_str) - 2] = '}';
880                     }
881                     else if (type == AS_CONFED_SET) {
882                         as_path_str[strlen(as_path_str) - 2] = ']';
883                     }
884                     else if (type == AS_CONFED_SEQUENCE) {
885                         as_path_str[strlen(as_path_str) - 1] = ')';
886                     }
887                     else {
888                         as_path_str[strlen(as_path_str) - 1] = '\0';
889                     }
890                 }
891
892                 /* check for empty AS_PATH */
893                 if (alen == 0)
894                     strncpy(as_path_str, "empty", 6);
895
896                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
897                         "%s: %s (%u %s)",
898                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
899                         as_path_str, alen + aoff,
900                         (alen + aoff == 1) ? "byte" : "bytes");
901                 break;
902             case BGPTYPE_NEXT_HOP:
903                 if (alen != 4)
904                     goto default_attribute_top;
905                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
906                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
907                         "%s: %s (%u %s)",
908                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
909                         ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
910                         ? "byte" : "bytes");
911                 break;
912             case BGPTYPE_MULTI_EXIT_DISC:
913                 if (alen != 4)
914                     goto default_attribute_top;
915                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
916                         "%s: %u (%u %s)",
917                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
918                         tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
919                         (alen + aoff == 1) ? "byte" : "bytes");
920                 break;
921             case BGPTYPE_LOCAL_PREF:
922                 if (alen != 4)
923                     goto default_attribute_top;
924                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
925                         "%s: %u (%u %s)",
926                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
927                         tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
928                         (alen + aoff == 1) ? "byte" : "bytes");
929                 break;
930             case BGPTYPE_ATOMIC_AGGREGATE:
931                 if (alen != 0)
932                     goto default_attribute_top;
933                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
934                         "%s (%u %s)",
935                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
936                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
937                 break;
938             case BGPTYPE_AGGREGATOR:
939                 if (alen != 6)
940                     goto default_attribute_top;
941                 tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
942                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
943                         "%s: AS: %u origin: %s (%u %s)",
944                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
945                         tvb_get_ntohs(tvb, o + i + aoff),
946                         ip_to_str(ipaddr), alen + aoff,
947                         (alen + aoff == 1) ? "byte" : "bytes");
948                 break;
949             case BGPTYPE_COMMUNITIES:
950                 if (alen % 4 != 0)
951                     goto default_attribute_top;
952
953                 /* (o + i + 3) =
954                    (o + current attribute + 3 bytes to first tuple) */
955                 end = o + alen + i + 3;
956                 q = o + i + 3;
957                 /* must be freed by second switch!                          */
958                 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
959                    a good estimate of how long the communities string could
960                    be                                                       */
961                 communities_str = malloc((alen + 1) * 12);
962                 if (communities_str == NULL) break;
963                 communities_str[0] = '\0';
964                 memset(junk_buf, 0, sizeof(junk_buf));
965
966                 /* snarf each community */
967                 while (q < end) {
968                     /* check for well-known communities */
969                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
970                         strncpy(junk_buf, "NO_EXPORT ", 10);
971                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
972                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
973                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
974                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
975                     else {
976                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
977                                 tvb_get_ntohs(tvb, q),
978                                 tvb_get_ntohs(tvb, q + 2));
979                     }
980                     q += 4;
981
982                     strncat(communities_str, junk_buf, sizeof(junk_buf));
983                 }
984                 /* cleanup end of string */
985                 communities_str[strlen(communities_str) - 1] = '\0';
986
987                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
988                         "%s: %s (%u %s)",
989                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
990                         communities_str, alen + aoff,
991                         (alen + aoff == 1) ? "byte" : "bytes");
992                 break;
993             case BGPTYPE_ORIGINATOR_ID:
994                 if (alen != 4)
995                     goto default_attribute_top;
996                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
997                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
998                         "%s: %s (%u %s)",
999                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1000                         ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
1001                         ? "byte" : "bytes");
1002                 break;
1003             case BGPTYPE_CLUSTER_LIST:
1004                 if (alen % 4 != 0)
1005                     goto default_attribute_top;
1006
1007                 /* (o + i + 3) =
1008                    (o + current attribute + 3 bytes to first tuple) */
1009                 end = o + alen + i + 3;
1010                 q = o + i + 3;
1011                 /* must be freed by second switch!                          */
1012                 /* "alen * 16" (12 digits, 3 dots + space ) should be
1013                    a good estimate of how long the cluster_list string could
1014                    be                                                       */
1015                 cluster_list_str = malloc((alen + 1) * 16);
1016                 if (cluster_list_str == NULL) break;
1017                 cluster_list_str[0] = '\0';
1018                 memset(junk_buf, 0, sizeof(junk_buf));
1019
1020                 /* snarf each cluster list */
1021                 tvb_memcpy(tvb, ipaddr, q, 4);
1022                 while (q < end) {
1023                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
1024                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
1025                     q += 4;
1026                 }
1027                 /* cleanup end of string */
1028                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
1029
1030                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1031                         "%s: %s (%u %s)",
1032                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1033                         cluster_list_str, alen + aoff,
1034                         (alen + aoff == 1) ? "byte" : "bytes");
1035                 break;
1036             case BGPTYPE_EXTENDED_COMMUNITY:
1037                 if (alen %8 != 0)
1038                     goto default_attribute_top;
1039                 q = o + i + aoff ;
1040                 end = o + i + aoff + alen ;
1041                 ext_com_str = malloc((alen / 8)*MAX_SIZE_OF_EXT_COM_NAMES) ;
1042                 if (ext_com_str == NULL) break ;
1043                 ext_com_str[0] = '\0' ;
1044                 while (q < end) {
1045                         ext_com = tvb_get_ntohs(tvb,q) ;
1046                         snprintf(junk_buf, sizeof(junk_buf), "%s", val_to_str(ext_com,bgpext_com_type,"Unknown"));
1047                         strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1048                         q = q + 8 ;
1049                         if (q<end) strncat(ext_com_str,",",1);
1050                 }
1051                 ti = proto_tree_add_text(subtree,tvb,o+i,alen+aoff,
1052                         "%s : %s (%u %s)",
1053                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1054                         ext_com_str,
1055                         alen,
1056                         (alen ==1 ) ? "byte" : "bytes");
1057                 free(ext_com_str) ;
1058                 break;
1059
1060             default:
1061             default_attribute_top:
1062                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1063                         "%s (%u %s)",
1064                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1065                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
1066             } /* end of first switch */
1067             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1068
1069             /* figure out flags */
1070             junk_buf[0] = '\0';
1071             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1072                  strncat(junk_buf, "Optional, ", 10);
1073             }
1074             else {
1075                  strncat(junk_buf, "Well-known, ", 12);
1076             }
1077             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1078                  strncat(junk_buf, "Transitive, ", 12);
1079             }
1080             else {
1081                  strncat(junk_buf, "Non-transitive, ", 16);
1082             }
1083             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1084                  strncat(junk_buf, "Partial, ", 9);
1085             }
1086             else {
1087                  strncat(junk_buf, "Complete, ", 10);
1088             }
1089             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1090                  strncat(junk_buf, "Extended Length, ", 17);
1091             }
1092             /* stomp last ", " */
1093             j = strlen(junk_buf);
1094             junk_buf[j - 2] = '\0';
1095             ti = proto_tree_add_text(subtree2, tvb,
1096                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1097                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
1098             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1099
1100             /* add flag bitfield subtrees */
1101             proto_tree_add_text(subtree3, tvb,
1102                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1103                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1104                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1105             proto_tree_add_text(subtree3, tvb,
1106                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1107                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1108                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1109                         "Non-transitive"));
1110             proto_tree_add_text(subtree3, tvb,
1111                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1112                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1113                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1114             proto_tree_add_text(subtree3, tvb,
1115                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1116                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1117                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1118                         "Regular length"));
1119
1120             proto_tree_add_text(subtree2, tvb,
1121                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1122                     "Type code: %s (%u)",
1123                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1124                     bgpa.bgpa_type);
1125
1126             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1127                     aoff - sizeof(bgpa), "Length: %d %s", alen,
1128                     (alen == 1) ? "byte" : "bytes");
1129
1130             /* the second switch prints things in the actual subtree of each
1131                attribute                                                     */
1132             switch (bgpa.bgpa_type) {
1133             case BGPTYPE_ORIGIN:
1134                 if (alen != 1) {
1135                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1136                             "Origin (invalid): %u %s", alen,
1137                              (alen == 1) ? "byte" : "bytes");
1138                 } else {
1139                     msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1140                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1141                             "Origin: %s (%u)", msg, tvb_get_guint8(tvb, o + i + aoff));
1142                 }
1143                 break;
1144             case BGPTYPE_AS_PATH:
1145                 /* check for empty AS_PATH */
1146                 if (alen == 0) {
1147                     free(as_path_str);
1148                     break;
1149                 }
1150
1151                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1152                         "AS path: %s", as_path_str);
1153                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1154
1155                 /* (o + i + 3) =
1156                    (o + current attribute + 3 bytes to first tuple) */
1157                 end = o + alen + i + 3;
1158                 q = o + i + 3;
1159
1160                 /* snarf each AS path tuple, we have to step through each one
1161                    again to make a separate subtree so we can't just reuse
1162                    as_path_str from above */
1163                 while (q < end) {
1164                     as_path_str[0] = '\0';
1165                     type = tvb_get_guint8(tvb, q++);
1166                     if (type == AS_SET) {
1167                         snprintf(as_path_str, 2, "{");
1168                     }
1169                     else if (type == AS_CONFED_SET) {
1170                         snprintf(as_path_str, 2, "[");
1171                     }
1172                     else if (type == AS_CONFED_SEQUENCE) {
1173                         snprintf(as_path_str, 2, "(");
1174                     }
1175                     length = tvb_get_guint8(tvb, q++);
1176
1177                     /* snarf each value in path, we're just going to reuse
1178                        as_path_str since we already have it malloced       */
1179                     for (j = 0; j < length; j++) {
1180                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
1181                                 (type == AS_SET || type == AS_CONFED_SET)
1182                                 ? ", " : " ");
1183                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1184                         q += 2;
1185                     }
1186
1187                     /* cleanup end of string */
1188                     if (type == AS_SET) {
1189                         as_path_str[strlen(as_path_str) - 2] = '}';
1190                     }
1191                     else if (type == AS_CONFED_SET) {
1192                         as_path_str[strlen(as_path_str) - 2] = ']';
1193                     }
1194                     else if (type == AS_CONFED_SEQUENCE) {
1195                         as_path_str[strlen(as_path_str) - 1] = ')';
1196                     }
1197                     else {
1198                         as_path_str[strlen(as_path_str) - 1] = '\0';
1199                     }
1200
1201                     /* length here means number of ASs, ie length * 2 bytes */
1202                     ti = proto_tree_add_text(as_paths_tree, tvb,
1203                             q - length * 2 - 2,
1204                             length * 2 + 2, "AS path segment: %s", as_path_str);
1205                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1206                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 2,
1207                             1, "Path segment type: %s (%u)",
1208                             val_to_str(type, as_segment_type, "Unknown"), type);
1209                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 1,
1210                             1, "Path segment length: %u %s", length,
1211                             (length == 1) ? "AS" : "ASs");
1212
1213                     /* backup and reprint path segment value(s) only */
1214                     q -= 2 * length;
1215                     as_path_str[0] = '\0';
1216                     for (j = 0; j < length; j++) {
1217                         snprintf(junk_buf, sizeof(junk_buf), "%u ", tvb_get_ntohs(tvb, q));
1218                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1219                         q += 2;
1220                     }
1221                     as_path_str[strlen(as_path_str) - 1] = '\0';
1222
1223                     proto_tree_add_text(as_path_tree, tvb, q - length * 2,
1224                             length * 2, "Path segment value: %s", as_path_str);
1225                 }
1226
1227                 free(as_path_str);
1228                 break;
1229             case BGPTYPE_NEXT_HOP:
1230                 if (alen != 4) {
1231                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1232                             "Next hop (invalid): %u %s", alen,
1233                             (alen == 1) ? "byte" : "bytes");
1234                 } else {
1235                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1236                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1237                             "Next hop: %s", ip_to_str(ipaddr));
1238                 }
1239                 break;
1240             case BGPTYPE_MULTI_EXIT_DISC:
1241                 if (alen != 4) {
1242                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1243                             "Multiple exit discriminator (invalid): %u %s",
1244                             alen, (alen == 1) ? "byte" : "bytes");
1245                 } else {
1246                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1247                             "Multiple exit discriminator: %u",
1248                             tvb_get_ntohl(tvb, o + i + aoff));
1249                 }
1250                 break;
1251             case BGPTYPE_LOCAL_PREF:
1252                 if (alen != 4) {
1253                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1254                             "Local preference (invalid): %u %s", alen,
1255                              (alen == 1) ? "byte" : "bytes");
1256                 } else {
1257                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1258                             "Local preference: %u", tvb_get_ntohl(tvb, o + i + aoff));
1259                 }
1260                 break;
1261             case BGPTYPE_ATOMIC_AGGREGATE:
1262                 if (alen != 0) {
1263                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1264                             "Atomic aggregate (invalid): %u %s", alen,
1265                             (alen == 1) ? "byte" : "bytes");
1266                 }
1267                 break;
1268             case BGPTYPE_AGGREGATOR:
1269                 if (alen != 6) {
1270                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1271                             "Aggregator (invalid): %u %s", alen,
1272                             (alen == 1) ? "byte" : "bytes");
1273                 } else {
1274                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1275                             "Aggregator AS: %u", tvb_get_ntohs(tvb, o + i + aoff));
1276                     tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
1277                     proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 4,
1278                             "Aggregator origin: %s",
1279                             ip_to_str(ipaddr));
1280                 }
1281                 break;
1282             case BGPTYPE_COMMUNITIES:
1283                 if (alen % 4 != 0) {
1284                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1285                             "Communities (invalid): %u %s", alen,
1286                             (alen == 1) ? "byte" : "bytes");
1287                     free(communities_str);
1288                     break;
1289                 }
1290
1291                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1292                         "Communities: %s", communities_str);
1293                 communities_tree = proto_item_add_subtree(ti,
1294                         ett_bgp_communities);
1295
1296                 /* (o + i + 3) =
1297                    (o + current attribute + 3 bytes to first tuple) */
1298                 end = o + alen + i + 3;
1299                 q = o + i + 3;
1300
1301                 /* snarf each community */
1302                 while (q < end) {
1303                     /* check for reserved values */
1304                     if (tvb_get_ntohs(tvb, q) == FOURHEX0 || tvb_get_ntohs(tvb, q) == FOURHEXF) {
1305                         /* check for well-known communities */
1306                         if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
1307                             proto_tree_add_text(communities_tree, tvb,
1308                                    q - 3 + aoff, 4,
1309                                    "Community: NO_EXPORT (0x%x)", tvb_get_ntohl(tvb, q));
1310                         else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1311                             proto_tree_add_text(communities_tree, tvb,
1312                                    q - 3 + aoff, 4,
1313                                    "Community: NO_ADVERTISE (0x%x)", pntohl(q));
1314                         else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1315                             proto_tree_add_text(communities_tree, tvb,
1316                                     q - 3 + aoff, 4,
1317                                     "Community: NO_EXPORT_SUBCONFED (0x%x)",
1318                                     tvb_get_ntohl(tvb, q));
1319                         else
1320                             proto_tree_add_text(communities_tree, tvb,
1321                                     q - 3 + aoff, 4,
1322                                     "Community (reserved): 0x%x", tvb_get_ntohl(tvb, q));
1323                     }
1324                     else {
1325
1326                         ti = proto_tree_add_text(communities_tree, tvb,
1327                                 q - 3 + aoff, 4, "Community: %u:%u",
1328                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1329                         community_tree = proto_item_add_subtree(ti,
1330                             ett_bgp_communities);
1331                         proto_tree_add_text(community_tree, tvb, q - 3 + aoff,
1332                                 2, "Community AS: %u", tvb_get_ntohs(tvb, q));
1333                         proto_tree_add_text(community_tree, tvb, q - 1 + aoff,
1334                                 2, "Community value: %u", tvb_get_ntohs(tvb, q + 2));
1335                     }
1336
1337                     q += 4;
1338                 }
1339
1340                 free(communities_str);
1341                 break;
1342             case BGPTYPE_ORIGINATOR_ID:
1343                 if (alen != 4) {
1344                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1345                             "Originator identifier (invalid): %u %s", alen,
1346                             (alen == 1) ? "byte" : "bytes");
1347                 } else {
1348                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1349                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1350                             "Originator identifier: %s",
1351                             ip_to_str(ipaddr));
1352                 }
1353                 break;
1354            case BGPTYPE_MP_REACH_NLRI:
1355                 /*
1356                  * RFC 2545 specifies that there may be more than one
1357                  * address in the MP_REACH_NLRI attribute in section
1358                  * 3, "Constructing the Next Hop field".
1359                  *
1360                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1361                  * 2858 obsoletes RFC 2283, which says you can do that,
1362                  * but that doesn't mean we shouldn't dissect packets
1363                  * that conform to RFC 2283 but not RFC 2858, as some
1364                  * device on the network might implement the 2283-style
1365                  * BGP extensions rather than RFC 2858-style extensions.
1366                  */
1367                 af = tvb_get_ntohs(tvb, o + i + aoff);
1368                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1369                     "Address family: %s (%u)",
1370                     val_to_str(af, afn_vals, "Unknown"), af);
1371                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1372                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1373                     "Subsequent address family identifier: %s (%u)",
1374                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1375                     saf);
1376                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1377                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1378                         "Next hop network address (%d %s)",
1379                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1380                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1381                 j = 0;
1382                 while (j < nexthop_len) {
1383                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1384                         junk_buf, sizeof(junk_buf)) ;
1385                     if (j + advance > nexthop_len)
1386                             break;
1387                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1388                         advance, "Next hop: %s (%u)", junk_buf, advance);
1389                     j += advance;
1390                 }
1391                 alen -= nexthop_len + 4;
1392                 aoff += nexthop_len + 4 ;
1393
1394                 off = 0;
1395                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1396                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1397                         "Subnetwork points of attachment: %u", snpa);
1398                 off++;
1399                 if (snpa) {
1400                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1401                         for (/*nothing*/; snpa > 0; snpa--) {
1402                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1403                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1404                                 off++;
1405                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1406                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1407                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1408                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1409                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1410                         }
1411                 }
1412                 alen -= off;
1413                 aoff += off;
1414
1415                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1416                         "Network layer reachability information (%u %s)",
1417                         alen, (alen == 1) ? "byte" : "bytes");
1418                 if (alen)  {
1419                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1420
1421                         while (alen > 0) {
1422                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1423                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1424                                 alen -= advance;
1425                                 aoff += advance;
1426                         }
1427                 }
1428                 break;
1429            case BGPTYPE_MP_UNREACH_NLRI:
1430                 af = tvb_get_ntohs(tvb, o + i + aoff);
1431                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1432                     "Address family: %s (%u)",
1433                     val_to_str(af, afn_vals, "Unknown"), af);
1434                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1435                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1436                     "Subsequent address family identifier: %s (%u)",
1437                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1438                     saf);
1439                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1440                         alen - 3, "Withdrawn routes (%u %s)", alen - 3,
1441                         (alen - 3 == 1) ? "byte" : "bytes");
1442
1443                 alen -= 3;
1444                 aoff += 3;
1445                 if (alen > 0) {
1446                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
1447
1448                         while (alen > 0) {
1449                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1450
1451                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1452                                 alen -= advance;
1453                                 aoff += advance;
1454                         }
1455                 }
1456                 break;
1457             case BGPTYPE_CLUSTER_LIST:
1458                 if (alen % 4 != 0) {
1459                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1460                             "Cluster list (invalid): %u %s", alen,
1461                             (alen == 1) ? "byte" : "bytes");
1462                     free(cluster_list_str);
1463                     break;
1464                 }
1465
1466                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1467                         "Cluster list: %s", cluster_list_str);
1468                 cluster_list_tree = proto_item_add_subtree(ti,
1469                         ett_bgp_cluster_list);
1470
1471                 /* (p + i + 3) =
1472                    (p + current attribute + 3 bytes to first tuple) */
1473                 end = o + alen + i + 3;
1474                 q = o + i + 3;
1475
1476                 /* snarf each cluster identifier */
1477                 while (q < end) {
1478                     tvb_memcpy(tvb, ipaddr, q, 4);
1479                     ti = proto_tree_add_text(cluster_list_tree, tvb,
1480                             q - 3 + aoff, 4, "Cluster identifier: %s",
1481                             ip_to_str(ipaddr));
1482
1483                     q += 4;
1484                 }
1485
1486                 free(cluster_list_str);
1487                 break;
1488                 case BGPTYPE_EXTENDED_COMMUNITY:
1489                 if (alen %8 != 0) {
1490                         proto_tree_add_text(subtree3, tvb, o + i + aoff, alen, "Extended community (invalid) : %u %s", alen,
1491                                 (alen == 1) ? "byte" : "bytes") ;
1492                 } else {
1493                         q = o + i + aoff ;
1494                         end = o + i + aoff + alen ;
1495                         ext_com_str = malloc(MAX_SIZE_OF_EXT_COM_NAMES+MAX_SIZE_OF_IP_ADDR_STRING*2+1) ;
1496                         if (ext_com_str == NULL) break ;
1497                         ti = proto_tree_add_text(subtree2,tvb,q,alen, "Carried Extended communities");
1498                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1499
1500                         while (q < end) {
1501                           ext_com_str[0] = '\0' ;
1502                           ext_com = tvb_get_ntohs(tvb,q) ;
1503                           snprintf(junk_buf, sizeof(junk_buf), "%s", val_to_str(ext_com,bgpext_com_type,"Unknown"));
1504                           strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1505                           switch (ext_com) {
1506                           case BGP_EXT_COM_RT_0:
1507                           case BGP_EXT_COM_RO_0:
1508                             snprintf(junk_buf, sizeof(junk_buf), ": %u%s%d",tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
1509                             break ;
1510                           case BGP_EXT_COM_RT_1:
1511                           case BGP_EXT_COM_RO_1:
1512                             tvb_memcpy(tvb,ipaddr,q+2,4);
1513                             snprintf(junk_buf, sizeof(junk_buf), ": %s%s%u",ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
1514                             break;
1515                           case BGP_EXT_COM_VPN_ORIGIN:
1516                           case BGP_EXT_COM_OSPF_RID:
1517                             tvb_memcpy(tvb,ipaddr,q+2,4);
1518                             snprintf(junk_buf, sizeof(junk_buf), ": %s",ip_to_str(ipaddr));
1519                             break;
1520                           case BGP_EXT_COM_OSPF_RTYPE: 
1521                             tvb_memcpy(tvb,ipaddr,q+2,4);
1522                             snprintf(junk_buf, sizeof(junk_buf), ": Area:%s %s",ip_to_str(ipaddr),val_to_str(tvb_get_guint8(tvb,q+6),bgpext_ospf_rtype,"Unknown"));
1523                                 /* print OSPF Metric type if selected */
1524                                 /* always print E2 even if not external route -- receiving router should ignore */
1525                             if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) { 
1526                               strcat(junk_buf," E2");
1527                             } else if (tvb_get_guint8(tvb,q+6)==(BGP_OSPF_RTYPE_EXT ||BGP_OSPF_RTYPE_NSSA ) ) {
1528                               strcat(junk_buf, " E1");
1529                             }
1530                             break;
1531                           case BGP_EXT_COM_LINKBAND:
1532                             tvb_memcpy(tvb,ipaddr,q+2,4); /* need to check on IEEE format on all platforms */
1533                             snprintf(junk_buf, sizeof(junk_buf), ": %f bytes per second",(double)*ipaddr);
1534                             break;
1535                           default:
1536                             snprintf(junk_buf, sizeof(junk_buf), " ");
1537                             break ;
1538                           }
1539                           strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1540                           proto_tree_add_text(subtree3,tvb,q,8, "%s",ext_com_str);
1541                           q = q + 8 ;
1542                         }
1543                         free(ext_com_str) ;
1544                 }
1545                 break;
1546             default:
1547                 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1548                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1549                         "bytes");
1550                 break;
1551             } /* end of second switch */
1552
1553             i += alen + aoff;
1554         }
1555
1556         o += 2 + len;
1557
1558         /* NLRI */
1559         len = offset + hlen - o;
1560
1561         /* parse prefixes */
1562         if (len > 0) {
1563            ti = proto_tree_add_text(tree, tvb, o, len,
1564                    "Network layer reachability information: %u %s", len,
1565                    (len == 1) ? "byte" : "bytes");
1566             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1567             end = o + len;
1568             while (o < end) {
1569                 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1570                 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1571                 o += i;
1572             }
1573         }
1574     }
1575 }
1576
1577 /*
1578  * Dissect a BGP NOTIFICATION message.
1579  */
1580 static void
1581 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
1582 {
1583     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1584     int                     hlen;   /* message length           */
1585     char                    *p;     /* string pointer           */
1586
1587     /* snarf message */
1588     tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
1589     hlen = ntohs(bgpn.bgpn_len);
1590
1591     /* print error code */
1592     proto_tree_add_text(tree, tvb,
1593         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1594         "Error code: %s (%u)",
1595         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1596         bgpn.bgpn_major);
1597
1598     /* print error subcode */
1599     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1600      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1601         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1602             "Unknown");
1603     } else if (bgpn.bgpn_minor == 0)
1604         p = "Unspecified";
1605     else
1606         p = "Unknown";
1607     proto_tree_add_text(tree, tvb,
1608         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1609         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1610
1611     /* only print if there is optional data */
1612     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1613         proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1614             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1615     }
1616 }
1617
1618 /*
1619  * Dissect a BGP ROUTE-REFRESH message.
1620  */
1621 static void
1622 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
1623 {
1624     u_int        i;    /* tmp            */
1625
1626     /* AFI */
1627     i = tvb_get_ntohs(tvb, offset + BGP_HEADER_SIZE);
1628     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 2, 
1629                         "Address family identifier: %s (%u)",
1630                         val_to_str(i, afn_vals, "Unknown"), i);
1631     offset += 2;
1632     /* Reserved */
1633     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 1, 
1634                         "Reserved: 1 byte");
1635     offset++;
1636     /* SAFI */
1637     i = tvb_get_guint8(tvb, offset + BGP_HEADER_SIZE);
1638     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 1, 
1639                         "Subsequent address family identifier: %s (%u)",
1640                         val_to_str(i, bgpattr_nlri_safi,
1641                         i >= 128 ? "Vendor specific" : "Unknown"),
1642                         i);
1643 }
1644
1645 /*
1646  * Dissect a BGP packet.
1647  */
1648 static void
1649 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1650 {
1651     proto_item    *ti;           /* tree item                        */
1652     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1653     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1654     int           l, i;          /* tmp                              */
1655     int           found;         /* number of BGP messages in packet */
1656     static u_char marker[] = {   /* BGP message marker               */
1657         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1658         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1659     };
1660     struct bgp    bgp;           /* BGP header                       */
1661     int           hlen;          /* BGP header length                */
1662     char          *typ;          /* BGP message type                 */
1663
1664     if (check_col(pinfo->fd, COL_PROTOCOL))
1665         col_set_str(pinfo->fd, COL_PROTOCOL, "BGP");
1666     if (check_col(pinfo->fd, COL_INFO))
1667         col_clear(pinfo->fd, COL_INFO);
1668
1669     l = tvb_length(tvb);
1670     i = 0;
1671     found = -1;
1672     /* run through the TCP packet looking for BGP headers         */
1673     /* this is done twice, but this way each message type can be 
1674        printed in the COL_INFO field                              */
1675     while (i + BGP_HEADER_SIZE <= l) {
1676         tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1677
1678         /* look for bgp header */
1679         if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1680             i++;
1681             continue;
1682         }
1683
1684         found++;
1685         hlen = ntohs(bgp.bgp_len);
1686         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1687
1688         if (check_col(pinfo->fd, COL_INFO)) {
1689             if (found == 0)
1690                 col_add_fstr(pinfo->fd, COL_INFO, "%s", typ);
1691             else
1692                 col_append_fstr(pinfo->fd, COL_INFO, ", %s", typ);
1693         }
1694
1695         i += hlen;
1696     }
1697
1698     if (tree) {
1699         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0,
1700                                  l, FALSE);
1701         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1702
1703         i = 0;
1704         /* now, run through the TCP packet again, this time dissect */
1705         /* each message that we find */
1706         while (i + BGP_HEADER_SIZE <= l) {
1707             tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1708
1709             /* look for bgp header */
1710             if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1711                 i++;
1712                 continue;
1713             }
1714
1715             hlen = ntohs(bgp.bgp_len);
1716             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1717             if (l < hlen) {
1718                 ti = proto_tree_add_text(bgp_tree, tvb, i,
1719                      l, "%s (truncated)", typ);
1720             } else {
1721                 ti = proto_tree_add_text(bgp_tree, tvb, i, hlen,
1722                             "%s", typ);
1723             }
1724             /* add a different tree for each message type */
1725             switch (bgp.bgp_type) {
1726             case BGP_OPEN:
1727                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1728                 break;
1729             case BGP_UPDATE:
1730                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1731                 break;
1732             case BGP_NOTIFICATION:
1733                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1734                 break;
1735             case BGP_KEEPALIVE:
1736                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1737                 break;
1738             case BGP_ROUTE_REFRESH_CISCO:
1739             case BGP_ROUTE_REFRESH:
1740                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
1741                 break;
1742             default:
1743                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1744                 break;
1745             }
1746
1747             proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
1748                 "Marker: 16 bytes");
1749
1750             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1751                 proto_tree_add_text(bgp1_tree, tvb,
1752                     i + offsetof(struct bgp, bgp_len), 2,
1753                     "Length (invalid): %u %s", hlen,
1754                     (hlen == 1) ? "byte" : "bytes");
1755             } else {
1756                 proto_tree_add_text(bgp1_tree, tvb,
1757                     i + offsetof(struct bgp, bgp_len), 2,
1758                     "Length: %u %s", hlen,
1759                     (hlen == 1) ? "byte" : "bytes");
1760             }
1761
1762             proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
1763                                        i + offsetof(struct bgp, bgp_type), 1,
1764                                        bgp.bgp_type,
1765                                        "Type: %s (%u)", typ, bgp.bgp_type);
1766
1767             switch (bgp.bgp_type) {
1768             case BGP_OPEN:
1769                 dissect_bgp_open(tvb, i, bgp1_tree);
1770                 break;
1771             case BGP_UPDATE:
1772                 dissect_bgp_update(tvb, i, bgp1_tree);
1773                 break;
1774             case BGP_NOTIFICATION:
1775                 dissect_bgp_notification(tvb, i, bgp1_tree);
1776                 break;
1777             case BGP_KEEPALIVE:
1778                 /* no data in KEEPALIVE messages */
1779                 break;
1780             case BGP_ROUTE_REFRESH_CISCO:
1781             case BGP_ROUTE_REFRESH:
1782                 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
1783                 break;
1784             default:
1785                 break;
1786             }
1787
1788             i += hlen;
1789         }
1790     }
1791 }
1792
1793 /*
1794  * Register ourselves.
1795  */
1796 void
1797 proto_register_bgp(void)
1798 {
1799
1800     static hf_register_info hf[] = {
1801       { &hf_bgp_type,
1802         { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1803           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
1804     };
1805
1806     static gint *ett[] = {
1807       &ett_bgp,
1808       &ett_bgp_unfeas,
1809       &ett_bgp_attrs,
1810       &ett_bgp_attr,
1811       &ett_bgp_attr_flags,
1812       &ett_bgp_mp_nhna,
1813       &ett_bgp_mp_reach_nlri,
1814       &ett_bgp_mp_unreach_nlri,
1815       &ett_bgp_mp_snpa,
1816       &ett_bgp_nlri,
1817       &ett_bgp_open,
1818       &ett_bgp_update,
1819       &ett_bgp_notification,
1820       &ett_bgp_route_refresh,
1821       &ett_bgp_as_paths,
1822       &ett_bgp_communities,
1823       &ett_bgp_cluster_list,
1824       &ett_bgp_options,
1825       &ett_bgp_option,
1826       &ett_bgp_extended_communities
1827     };
1828
1829     proto_bgp = proto_register_protocol("Border Gateway Protocol",
1830                                         "BGP", "bgp");
1831     proto_register_field_array(proto_bgp, hf, array_length(hf));
1832     proto_register_subtree_array(ett, array_length(ett));
1833 }
1834
1835 void
1836 proto_reg_handoff_bgp(void)
1837 {
1838     dissector_add("tcp.port", BGP_TCP_PORT, dissect_bgp, proto_bgp);
1839 }