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