Turn off -x
[metze/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.74 2003/01/31 08:09:24 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  * 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  * draft-ietf-idr-as4bytes-06
19  * draft-ietf-idr-dynamic-cap-03
20  *
21  * TODO:
22  * Destination Preference Attribute for BGP (work in progress)
23  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
24  *
25  * Ethereal - Network traffic analyzer
26  * By Gerald Combs <gerald@ethereal.com>
27  * Copyright 1998 Gerald Combs
28  *
29  * This program is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU General Public License
31  * as published by the Free Software Foundation; either version 2
32  * of the License, or (at your option) any later version.
33  *
34  * This program is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37  * GNU General Public License for more details.
38  *
39  * You should have received a copy of the GNU General Public License
40  * along with this program; if not, write to the Free Software
41  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
42  */
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #include <stdio.h>
49 #include <stdlib.h>
50
51 #include <string.h>
52 #include <glib.h>
53
54 #ifdef NEED_SNPRINTF_H
55 # include "snprintf.h"
56 #endif
57
58 #include <epan/packet.h>
59 #include "packet-bgp.h"
60 #include "packet-ipv6.h"
61 #include "afn.h"
62 #include "prefs.h"
63
64 static const value_string bgptypevals[] = {
65     { BGP_OPEN, "OPEN Message" },
66     { BGP_UPDATE, "UPDATE Message" },
67     { BGP_NOTIFICATION, "NOTIFICATION Message" },
68     { BGP_KEEPALIVE, "KEEPALIVE Message" },
69     { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
70     { BGP_CAPABILITY, "CAPABILITY Message" },
71     { BGP_ROUTE_REFRESH_CISCO, "Cisco ROUTE-REFRESH Message" },
72     { 0, NULL },
73 };
74
75 static const value_string bgpnotify_major[] = {
76     { 1, "Message Header Error" },
77     { 2, "OPEN Message Error" },
78     { 3, "UPDATE Message Error" },
79     { 4, "Hold Timer Expired" },
80     { 5, "Finite State Machine Error" },
81     { 6, "Cease" },
82     { 7, "CAPABILITY Message Error" },
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_7[] = {
120     { 1, "Invalid Action Value" },
121     { 2, "Invalid Capability Length" },
122     { 3, "Malformed Capability Value" },
123     { 4, "Unsopported Capability Code" },
124     { 0, NULL },
125 };
126
127 static const value_string *bgpnotify_minor[] = {
128     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
129 };
130
131 static const value_string bgpattr_origin[] = {
132     { 0, "IGP" },
133     { 1, "EGP" },
134     { 2, "INCOMPLETE" },
135     { 0, NULL },
136 };
137
138 static const value_string as_segment_type[] = {
139     { 1, "AS_SET" },
140     { 2, "AS_SEQUENCE" },
141 /* RFC1965 has the wrong values, corrected in  */
142 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
143     { 4, "AS_CONFED_SET" },
144     { 3, "AS_CONFED_SEQUENCE" },
145     { 0, NULL },
146 };
147
148 static const value_string bgpattr_type[] = {
149     { BGPTYPE_ORIGIN, "ORIGIN" },
150     { BGPTYPE_AS_PATH, "AS_PATH" },
151     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
152     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
153     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
154     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
155     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
156     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
157     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
158     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
159     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
160     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
161     { BGPTYPE_EXTENDED_COMMUNITY, "EXTENDED_COMMUNITIES" },
162     { BGPTYPE_NEW_AS_PATH, "NEW_AS_PATH" },
163     { BGPTYPE_NEW_AGGREGATOR, "NEW_AGGREGATOR" },
164     { 0, NULL },
165 };
166
167 /* Beware : See also MAX_SIZE_OF_EXT_COM_NAMES */
168 static const value_string bgpext_com_type[] = {
169     { BGP_EXT_COM_RT_0, "Route Target" },
170     { BGP_EXT_COM_RT_1, "Route Target" },
171     { BGP_EXT_COM_RO_0, "Route Origin" },
172     { BGP_EXT_COM_RO_1, "Route Origin" },
173     { BGP_EXT_COM_LINKBAND, "Link Bandwidth" },
174     { BGP_EXT_COM_VPN_ORIGIN, "OSPF Domain" },
175     { BGP_EXT_COM_OSPF_RTYPE, "OSPF Route Type" },
176     { BGP_EXT_COM_OSPF_RID, "OSPF Router ID" },
177     { BGP_EXT_COM_L2INFO, "Layer 2 Information" },
178     { 0, NULL },
179 };
180
181 static const value_string bgp_l2vpn_encaps[] = {
182     { 0,                      "Reserved"},
183     { 1,                      "Frame Relay"},
184     { 2,                      "ATM AAL5 VCC transport"},
185     { 3,                      "ATM transparent cell transport"},
186     { 4,                      "Ethernet VLAN"},
187     { 5,                      "Ethernet"},
188     { 6,                      "Cisco-HDLC"},
189     { 7,                      "PPP"},
190     { 8,                      "CEM"},
191     { 9,                      "ATM VCC cell transport"},
192     { 10,                     "ATM VPC cell transport"},
193     { 11,                     "MPLS"},
194     { 12,                     "VPLS"},
195     { 64,                     "IP-interworking"},
196     { 0, NULL},
197 };
198
199 static const value_string bgpext_ospf_rtype[] = {
200   { BGP_OSPF_RTYPE_RTR, "Router" },
201   { BGP_OSPF_RTYPE_NET, "Network" },
202   { BGP_OSPF_RTYPE_SUM, "Summary" },
203   { BGP_OSPF_RTYPE_EXT, "External" },
204   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
205   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
206   { 0, NULL },
207 };
208
209
210 /* MUST be resized if a longer named extended community is added */
211 #define MAX_SIZE_OF_EXT_COM_NAMES       20
212
213 /* Subsequent address family identifier, RFC2858 */
214 static const value_string bgpattr_nlri_safi[] = {
215     { 0, "Reserved" },
216     { SAFNUM_UNICAST, "Unicast" },
217     { SAFNUM_MULCAST, "Multicast" },
218     { SAFNUM_UNIMULC, "Unicast+Multicast" },
219     { SAFNUM_MPLS_LABEL, "Labeled Unicast"},
220     { SAFNUM_LAB_VPNUNICAST, "Labeled VPN Unicast" },        /* draft-rosen-rfc2547bis-03 */
221     { SAFNUM_LAB_VPNMULCAST, "Labeled VPN Multicast" },
222     { SAFNUM_LAB_VPNUNIMULC, "Labeled VPN Unicast+Multicast" },
223     { 0, NULL },
224 };
225
226 /* ORF Type, draft-ietf-idr-route-filter-04.txt */
227 static const value_string orf_type_vals[] = {
228     { 2,        "Communities ORF-Type" },
229     { 3,        "Extended Communities ORF-Type" },
230     { 128,      "Cisco PrefixList ORF-Type" },
231     { 129,      "Cisco CommunityList ORF-Type" },
232     { 130,      "Cisco Extended CommunityList ORF-Type" },
233     { 131,      "Cisco AsPathList ORF-Type" },
234     { 0,        NULL },
235 };
236
237 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
238 static const value_string orf_send_recv_vals[] = {
239     { 1,        "Receive" },
240     { 2,        "Send" },
241     { 3,        "Both" },
242     { 0,        NULL },
243 };
244
245 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
246 static const value_string orf_when_vals[] = {
247     { 1,        "Immediate" },
248     { 2,        "Defer" },
249     { 0,        NULL },
250 };
251
252 static const value_string orf_entry_action_vals[] = {
253     { 0,        "Add" },
254     { 0x40,     "Remove" },
255     { 0x80,     "RemoveAll" },
256     { 0,        NULL },
257 };
258
259 static const value_string orf_entry_match_vals[] = {
260     { 0,        "Permit" },
261     { 0x20,     "Deny" },
262     { 0,        NULL },
263 };
264
265 static const value_string capability_vals[] = {
266     { BGP_CAPABILITY_RESERVED, "Reserved capability" },
267     { BGP_CAPABILITY_MULTIPROTOCOL, "Multiprotocol extensions capability" },
268     { BGP_CAPABILITY_ROUTE_REFRESH, "Route refresh capability" },
269     { BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING, "Cooperative route filtering capability" },
270     { BGP_CAPABILITY_GRACEFUL_RESTART, "Graceful Restart capability" },
271     { BGP_CAPABILITY_4_OCTET_AS_NUMBER, "Support for 4-octet AS number capability" },
272     { BGP_CAPABILITY_DYNAMIC_CAPABILITY, "Support for Dynamic capability" },
273     { BGP_CAPABILITY_ROUTE_REFRESH_CISCO, "Route refresh capability" },
274     { BGP_CAPABILITY_ORF_CISCO, "Cooperative route filtering capability" },
275 };
276
277 /* Capability Message action code */
278 static const value_string bgpcap_action[] = {
279     { 0, "advertising a capability" },
280     { 1, "removing a capability" },
281     { 0, NULL },
282 };
283
284
285 /* Maximal size of an IP address string */
286 #define MAX_SIZE_OF_IP_ADDR_STRING      16
287
288 static int proto_bgp = -1;
289 static int hf_bgp_type = -1;
290
291 static gint ett_bgp = -1;
292 static gint ett_bgp_unfeas = -1;
293 static gint ett_bgp_attrs = -1;
294 static gint ett_bgp_attr = -1;
295 static gint ett_bgp_attr_flags = -1;
296 static gint ett_bgp_mp_nhna = -1;
297 static gint ett_bgp_mp_reach_nlri = -1;
298 static gint ett_bgp_mp_unreach_nlri = -1;
299 static gint ett_bgp_mp_snpa = -1;
300 static gint ett_bgp_nlri = -1;
301 static gint ett_bgp_open = -1;
302 static gint ett_bgp_update = -1;
303 static gint ett_bgp_notification = -1;
304 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
305 static gint ett_bgp_capability = -1;
306 static gint ett_bgp_as_paths = -1;
307 static gint ett_bgp_communities = -1;
308 static gint ett_bgp_cluster_list = -1;  /* cluster list tree          */
309 static gint ett_bgp_options = -1;       /* optional parameters tree   */
310 static gint ett_bgp_option = -1;        /* an optional parameter tree */
311 static gint ett_bgp_extended_communities = -1 ; /* extended communities list tree */
312 static gint ett_bgp_orf = -1;           /* orf (outbound route filter) tree */
313 static gint ett_bgp_orf_entry = -1;             /* orf entry tree */
314
315 /* desegmentation */
316 static gboolean bgp_desegment = TRUE;
317
318 static gint bgp_asn_len = 0;
319
320 /*
321  * Decode an IPv4 prefix.
322  */
323 static int
324 decode_prefix4(tvbuff_t *tvb, gint offset, char *buf, int buflen)
325 {
326     guint8 addr[4];   /* IP address                         */
327     guint8 plen;      /* prefix length                      */
328     int    length;    /* number of octets needed for prefix */
329
330     /* snarf length */
331     plen = tvb_get_guint8(tvb, offset);
332     if (plen > 32)
333         return -1;
334     length = (plen + 7) / 8;
335
336     /* snarf prefix */
337     memset(addr, 0, sizeof(addr));
338     tvb_memcpy(tvb, addr, offset + 1, length);
339     if (plen % 8)
340         addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
341
342     /* hand back a formatted string */
343     snprintf(buf, buflen, "%s/%u", ip_to_str(addr), plen);
344     return(1 + length);
345 }
346
347 /*
348  * Decode an IPv6 prefix.
349  */
350 static int
351 decode_prefix6(tvbuff_t *tvb, gint offset, char *buf, int buflen)
352 {
353     struct e_in6_addr addr;     /* IPv6 address                       */
354     int               plen;     /* prefix length                      */
355     int               length;   /* number of octets needed for prefix */
356
357     /* snarf length */
358     plen = tvb_get_guint8(tvb, offset);
359     if (plen < 0 || 128 < plen)
360         return -1;
361     length = (plen + 7) / 8;
362
363     /* snarf prefix */
364     memset(&addr, 0, sizeof(addr));
365     tvb_memcpy(tvb, (guint8 *)&addr, offset + 1, length);
366     if (plen % 8)
367         addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
368
369     /* hand back a formatted string */
370     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
371     return(1 + length);
372 }
373
374
375
376 /*
377  * Decode an MPLS label stack
378  */
379 static int
380 decode_MPLS_stack(tvbuff_t *tvb, gint offset, char *buf, size_t buflen)
381 {
382     guint32     label_entry;    /* an MPLS label enrty (label + COS field + stack bit   */
383     gint        index;          /* index for the label stack                            */
384     char        junk_buf[256];  /* tmp                                                  */
385
386     index = offset ;
387     label_entry = 0x000000 ;
388
389     buf[0] = '\0' ;
390
391     while ((label_entry & 0x000001) == 0) {
392
393         label_entry = tvb_get_ntoh24(tvb, index) ;
394
395         /* withdrawn routes may contain 0 or 0x800000 in the first label */
396         if((index-offset)==0&&(label_entry==0||label_entry==0x800000)) {
397             snprintf(buf, buflen, "0 (withdrawn)");
398             return (1);
399         }
400
401         snprintf(junk_buf, sizeof(junk_buf),"%u%s", (label_entry >> 4), ((label_entry & 0x000001) == 0) ? "," : " (bottom)");
402         if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
403             strcat(buf, junk_buf);
404         index += 3 ;
405
406         if ((label_entry & 0x000001) == 0) {
407             /* real MPLS multi-label stack in BGP? - maybe later; for now, it must be a bogus packet */
408             strcpy(junk_buf, " (BOGUS: Bottom of Stack NOT set!)");
409             if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
410                 strcat(buf, junk_buf);
411             break;
412         }
413     }
414
415     return((index - offset) / 3);
416 }
417
418 /*
419  * Decode a multiprotocol address
420  */
421
422 static int
423 mp_addr_to_str (guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
424 {
425     int                 length;                         /* length of the address in byte */
426     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
427     guint16             rd_type;                        /* Route Distinguisher type     */
428     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
429
430     length = 0 ;
431     switch (afi) {
432         case AFNUM_INET:
433                 switch (safi) {
434                         case SAFNUM_UNICAST:
435                         case SAFNUM_MULCAST:
436                         case SAFNUM_UNIMULC:
437                         case SAFNUM_MPLS_LABEL:
438                                 length = 4 ;
439                                 tvb_memcpy(tvb, ip4addr, offset, sizeof(ip4addr));
440                                 snprintf(buf, buflen, "%s", ip_to_str(ip4addr));
441                                 break;
442                         case SAFNUM_LAB_VPNUNICAST:
443                         case SAFNUM_LAB_VPNMULCAST:
444                         case SAFNUM_LAB_VPNUNIMULC:
445                                 rd_type=tvb_get_ntohs(tvb,offset) ;
446                                 switch (rd_type) {
447                                         case FORMAT_AS2_LOC:
448                                                 length = 8 + sizeof(ip4addr);
449                                                 tvb_memcpy(tvb, ip4addr, offset + 8, sizeof(ip4addr));   /* Next Hop */
450                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
451                                                                 tvb_get_ntohs(tvb, offset + 2),
452                                                                 tvb_get_ntohl(tvb, offset + 4),
453                                                                 ip_to_str(ip4addr));
454                                                 break;
455                                         case FORMAT_IP_LOC:
456                                                 length = 8 + sizeof(ip4addr);
457                                                 tvb_memcpy(tvb, ip4addr, offset + 2, sizeof(ip4addr));   /* IP part of the RD            */
458                                                 tvb_memcpy(tvb, ip4addr2, offset + 8, sizeof(ip4addr));  /* Next Hop   */
459                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
460                                                                 ip_to_str(ip4addr),
461                                                                 tvb_get_ntohs(tvb, offset + 6),
462                                                                 ip_to_str(ip4addr2));
463                                                 break ;
464                                         default:
465                                                 length = 0 ;
466                                                 snprintf(buf, buflen, "Unknown (0x%04x)labeled VPN address format",rd_type);
467                                                 break;
468                                 }
469                                 break;
470                         default:
471                             length = 0 ;
472                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
473                             break;
474                 }
475                 break;
476         case AFNUM_INET6:
477                 switch (safi) {
478                         case SAFNUM_UNICAST:
479                         case SAFNUM_MULCAST:
480                         case SAFNUM_UNIMULC:
481                             length = 16 ;
482                             tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8,offset, 16);
483                             snprintf(buf, buflen, "%s", ip6_to_str(&ip6addr));
484                             break;
485                         case SAFNUM_LAB_VPNUNICAST:
486                         case SAFNUM_LAB_VPNMULCAST:
487                         case SAFNUM_LAB_VPNUNIMULC:
488                                 rd_type=tvb_get_ntohs(tvb,offset) ;
489                                 switch (rd_type) {
490                                         case FORMAT_AS2_LOC:
491                                                 length = 8 + 16;
492                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, 16); /* Next Hop */
493                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
494                                                                 tvb_get_ntohs(tvb, offset + 2),
495                                                                 tvb_get_ntohl(tvb, offset + 4),
496                                                                 ip6_to_str(&ip6addr));
497                                                 break;
498                                         case FORMAT_IP_LOC:
499                                                 length = 8 + 16;
500                                                 tvb_memcpy(tvb, ip4addr, offset + 2, sizeof(ip4addr));   /* IP part of the RD            */
501                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, 16); /* Next Hop */
502                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
503                                                                 ip_to_str(ip4addr),
504                                                                 tvb_get_ntohs(tvb, offset + 6),
505                                                                 ip6_to_str(&ip6addr));
506                                                 break ;
507                                         default:
508                                                 length = 0 ;
509                                                 snprintf(buf, buflen, "Unknown (0x%04x)labeled VPN address format",rd_type);
510                                                 break;
511                                 }
512                                 break;
513                         default:
514                             length = 0 ;
515                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
516                             break;
517                 }
518                 break;
519        case AFNUM_L2VPN:
520                 switch (safi) {
521                         case SAFNUM_LAB_VPNUNICAST: /* only labeles prefixes do make sense */
522                         case SAFNUM_LAB_VPNMULCAST:
523                         case SAFNUM_LAB_VPNUNIMULC:
524                             length = 4; /* the next-hop is simply an ipv4 addr */
525                             tvb_memcpy(tvb, ip4addr, offset + 0, 4);
526                             snprintf(buf, buflen, "IP=%s",
527                                      ip_to_str(ip4addr));
528                             break;
529                         default:
530                             length = 0 ;
531                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
532                             break;
533                 }
534                 break;
535         default:
536                 length = 0 ;
537                 snprintf(buf, buflen, "Unknown AFI (%u) value", afi);
538                 break;
539     }
540     return(length) ;
541 }
542
543 /*
544  * Decode a multiprotocol prefix
545  */
546 static int
547 decode_prefix_MP(guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
548 {
549     int                 length;                         /* length of the prefix in byte */
550     guint8              plen;                           /* length of the prefix in bit  */
551     int                 labnum;                         /* number of labels             */
552     int                 ce_id,labblk_off;
553     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
554     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
555     guint16             rd_type;                        /* Route Distinguisher type     */
556     char                lab_stk[256];                   /* label stack                  */
557
558     length = 0 ;
559
560     switch (afi) {
561         case AFNUM_INET:
562                 switch (safi) {
563                         case SAFNUM_UNICAST:
564                         case SAFNUM_MULCAST:
565                         case SAFNUM_UNIMULC:
566                                 length = decode_prefix4(tvb, offset, buf, buflen) - 1 ;
567                                 break;
568                         case SAFNUM_MPLS_LABEL:
569                                 plen =  tvb_get_guint8(tvb,offset) ;
570                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
571
572                                 offset += (1 + labnum * 3);
573                                 plen -= (labnum * 3*8);
574                                 if (plen > 32) {
575                                         length = 0 ;
576                                         break ;
577                                 }
578
579                                 length = (plen + 7) / 8;
580                                 memset(ip4addr, 0, sizeof(ip4addr));
581                                 tvb_memcpy(tvb, ip4addr, offset, length);
582                                 if (plen % 8)
583                                         ip4addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
584
585                                 snprintf(buf,buflen, "Label Stack=%s IP=%s/%d",
586                                          lab_stk,
587                                          ip_to_str(ip4addr),
588                                          plen);
589                                 length += (labnum*3) ;
590                                 break;
591
592                         case SAFNUM_LAB_VPNUNICAST:
593                         case SAFNUM_LAB_VPNMULCAST:
594                         case SAFNUM_LAB_VPNUNIMULC:
595                                 plen =  tvb_get_guint8(tvb,offset) ;
596
597                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
598
599                                 offset += (1 + labnum * 3);
600                                 plen -= (labnum * 3*8);
601
602                                 rd_type=tvb_get_ntohs(tvb,offset) ;
603                                 plen -= 8*8;
604
605                                 switch (rd_type) {
606                                         case FORMAT_AS2_LOC: /* Code borrowed from the decode_prefix4 function */
607                                                 if (plen > 32) {
608                                                         length = 0 ;
609                                                         break ;
610                                                 }
611
612                                                 length = (plen + 7) / 8;
613                                                 memset(ip4addr, 0, sizeof(ip4addr));
614                                                 tvb_memcpy(tvb, ip4addr, offset + 8, length);
615                                                 if (plen % 8)
616                                                         ip4addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
617
618                                                 snprintf(buf,buflen, "Label Stack=%s RD=%u:%u, IP=%s/%d",
619                                                         lab_stk,
620                                                         tvb_get_ntohs(tvb, offset + 2),
621                                                         tvb_get_ntohl(tvb, offset + 4),
622                                                         ip_to_str(ip4addr),
623                                                         plen);
624                                                 length += (labnum * 3 + 8) ;
625                                                 break ;
626                                         case FORMAT_IP_LOC: /* Code borrowed from the decode_prefix4 function */
627                                                 tvb_memcpy(tvb, ip4addr, offset + 2, 4);
628
629                                                 if (plen > 32) {
630                                                         length = 0 ;
631                                                         break ;
632                                                 }
633
634                                                 length = (plen + 7) / 8;
635                                                 memset(ip4addr2, 0, sizeof(ip4addr2));
636                                                 tvb_memcpy(tvb, ip4addr2, offset + 8, length);
637                                                 if (plen % 8)
638                                                         ip4addr2[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
639
640                                                 snprintf(buf,buflen, "Label Stack=%s RD=%s:%u, IP=%s/%d",
641                                                         lab_stk,
642                                                         ip_to_str(ip4addr),
643                                                         tvb_get_ntohs(tvb, offset + 6),
644                                                         ip_to_str(ip4addr2),
645                                                         plen);
646                                                 length += (labnum * 3 + 8) ;
647                                                 break ;
648                                         default:
649                                                 length = 0 ;
650                                                 snprintf(buf,buflen, "Unknown labeled VPN address format");
651                                                 break;
652                                 }
653                                 break;
654                 default:
655                         length = 0 ;
656                         snprintf(buf,buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
657                         break;
658                 }
659                 break;
660         case AFNUM_INET6:
661                 switch (safi) {
662                         case SAFNUM_UNICAST:
663                         case SAFNUM_MULCAST:
664                         case SAFNUM_UNIMULC:
665                             length = decode_prefix6(tvb, offset, buf, buflen) - 1 ;
666                             break;
667
668                         case SAFNUM_LAB_VPNUNICAST:
669                         case SAFNUM_LAB_VPNMULCAST:
670                         case SAFNUM_LAB_VPNUNIMULC:
671                                 plen =  tvb_get_guint8(tvb,offset) ;
672
673                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
674
675                                 offset += (1 + labnum * 3);
676                                 plen -= (labnum * 3*8);
677
678                                 rd_type=tvb_get_ntohs(tvb,offset) ;
679                                 plen -= 8*8;
680
681                                 switch (rd_type) {
682                                         case FORMAT_AS2_LOC:
683                                                 if (plen > 128) {
684                                                         length = 0 ;
685                                                         break ;
686                                                 }
687
688                                                 length = (plen + 7) / 8;
689                                                 memset(ip6addr.u6_addr.u6_addr8, 0, 16);
690                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, length);
691                                                 if (plen % 8)
692                                                         ip6addr.u6_addr.u6_addr8[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
693
694                                                 snprintf(buf,buflen, "Label Stack=%s RD=%u:%u, IP=%s/%d",
695                                                         lab_stk,
696                                                         tvb_get_ntohs(tvb, offset + 2),
697                                                         tvb_get_ntohl(tvb, offset + 4),
698                                                         ip6_to_str(&ip6addr),
699                                                         plen);
700                                                 length += (labnum * 3 + 8) ;
701                                                 break ;
702                                         case FORMAT_IP_LOC: 
703                                                 tvb_memcpy(tvb, ip4addr, offset + 2, sizeof(ip4addr));
704
705                                                 if (plen > 128) {
706                                                         length = 0 ;
707                                                         break ;
708                                                 }
709
710                                                 length = (plen + 7) / 8;
711                                                 memset(ip6addr.u6_addr.u6_addr8, 0, 16);
712                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, length);
713                                                 if (plen % 8)
714                                                         ip6addr.u6_addr.u6_addr8[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
715
716                                                 snprintf(buf,buflen, "Label Stack=%s RD=%s:%u, IP=%s/%d",
717                                                         lab_stk,
718                                                         ip_to_str(ip4addr),
719                                                         tvb_get_ntohs(tvb, offset + 6),
720                                                         ip6_to_str(&ip6addr),
721                                                         plen);
722                                                 length += (labnum * 3 + 8) ;
723                                                 break ;
724                                         default:
725                                                 length = 0 ;
726                                                 snprintf(buf,buflen, "Unknown labeled VPN address format");
727                                                 break;
728                                 }
729                                 break;
730
731
732                 default:
733                         length = 0 ;
734                         snprintf(buf,buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
735                         break;
736                 }
737                 break;
738        case AFNUM_L2VPN:
739                 switch (safi) {
740                         case SAFNUM_LAB_VPNUNICAST:
741                         case SAFNUM_LAB_VPNMULCAST:
742                         case SAFNUM_LAB_VPNUNIMULC:
743                                 plen =  tvb_get_ntohs(tvb,offset);
744                                 rd_type=tvb_get_ntohs(tvb,offset+2);
745                                 ce_id=tvb_get_ntohs(tvb,offset+10);
746                                 labblk_off=tvb_get_ntohs(tvb,offset+12);
747                                 labnum = decode_MPLS_stack(tvb, offset + 14, lab_stk, sizeof(lab_stk));
748
749                                 switch (rd_type) {
750                                         case FORMAT_AS2_LOC:
751                                                 tvb_memcpy(tvb, ip4addr, offset + 6, 4);
752                                                 snprintf(buf,buflen, "RD: %u:%s, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
753                                                          tvb_get_ntohs(tvb, offset + 4),
754                                                          ip_to_str(ip4addr),
755                                                          ce_id,
756                                                          labblk_off,
757                                                          lab_stk);
758                                                 break ;
759                                         case FORMAT_IP_LOC:
760                                                 tvb_memcpy(tvb, ip4addr, offset + 4, 4);
761                                                 snprintf(buf,buflen, "RD: %s:%u, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
762                                                          ip_to_str(ip4addr),
763                                                          tvb_get_ntohs(tvb, offset + 8),
764                                                          ce_id,
765                                                          labblk_off,
766                                                          lab_stk);
767                                                 break ;
768                                         default:
769                                                 length = 0 ;
770                                                 snprintf(buf,buflen, "Unknown labeled VPN address format");
771                                                 break;
772                                 }
773                             /* FIXME there are subTLVs left to decode ... for now lets omit them */
774                             length=plen+1; /* should be 2 but length+1 is returned at the end */
775                             break;
776                 default:
777                         length = 0 ;
778                         snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
779                         break;
780                 }
781                 break;
782         default:
783                 length = 0 ;
784                 snprintf(buf,buflen, "Unknown AFI (%u) value", afi);
785                 break;
786     }
787     return(1 + length) ;
788 }
789
790 /*
791  * Dissect a BGP capability.
792  */
793 static void
794 dissect_bgp_capability_item(tvbuff_t *tvb, int *p, proto_tree *tree, int ctype, int clen)
795 {
796     proto_tree *subtree;
797     proto_item *ti;
798     guint8 orfnum;       /* number of ORFs */
799     guint8 orftype;      /* ORF Type */
800     guint8 orfsendrecv;  /* ORF Send/Receive */
801     int    tclen;        /* capability length */
802     int    i;
803
804     /* check the capability type */
805     switch (ctype) {
806     case BGP_CAPABILITY_RESERVED:
807         proto_tree_add_text(tree, tvb, *p - 2, 1,
808              "Capability code: %s (%d)", val_to_str(ctype,
809              capability_vals, "Unknown capability"), ctype);
810         proto_tree_add_text(tree, tvb, *p - 1,
811              1, "Capability length: %u %s", clen,
812              (clen == 1) ? "byte" : "bytes");
813         if (clen != 0) {
814             proto_tree_add_text(tree, tvb, *p,
815                  clen, "Capability value: Unknown");
816         }
817         *p += clen;
818         break;
819     case BGP_CAPABILITY_MULTIPROTOCOL:
820         proto_tree_add_text(tree, tvb, *p - 2, 1,
821              "Capability code: %s (%d)", val_to_str(ctype,
822              capability_vals, "Unknown capability"), ctype);
823         if (clen != 4) {
824             proto_tree_add_text(tree, tvb, *p - 1,
825                  1, "Capability length: Invalid");
826             proto_tree_add_text(tree, tvb, *p,
827                  clen, "Capability value: Unknown");
828         }
829         else {
830             proto_tree_add_text(tree, tvb, *p - 1,
831                  1, "Capability length: %u %s", clen,
832                  (clen == 1) ? "byte" : "bytes");
833             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
834             subtree = proto_item_add_subtree(ti, ett_bgp_option);
835             /* AFI */
836             i = tvb_get_ntohs(tvb, *p);
837             proto_tree_add_text(subtree, tvb, *p,
838                  2, "Address family identifier: %s (%u)",
839                  val_to_str(i, afn_vals, "Unknown"), i);
840             *p += 2;
841             /* Reserved */
842             proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
843             (*p)++;
844             /* SAFI */
845             i = tvb_get_guint8(tvb, *p);
846             proto_tree_add_text(subtree, tvb, *p,
847                  1, "Subsequent address family identifier: %s (%u)",
848                  val_to_str(i, bgpattr_nlri_safi,
849                  i >= 128 ? "Vendor specific" : "Unknown"), i);
850             (*p)++;
851         }
852         break;
853     case BGP_CAPABILITY_GRACEFUL_RESTART:
854         proto_tree_add_text(tree, tvb, *p - 2, 1,
855              "Capability code: %s (%d)", val_to_str(ctype,
856              capability_vals, "Unknown capability"), ctype);
857         if (clen < 6) {
858             proto_tree_add_text(tree, tvb, *p,
859                  clen, "Capability value: Invalid");
860         }
861         else {
862             proto_tree_add_text(tree, tvb, *p - 1,
863                  1, "Capability length: %u %s", clen,
864                  (clen == 1) ? "byte" : "bytes");
865             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
866             subtree = proto_item_add_subtree(ti, ett_bgp_option);
867             /* Timers */
868             i = tvb_get_ntohs(tvb, *p);
869             proto_tree_add_text(subtree, tvb, *p,
870                  2, "Restart Flags: [%s], Restart Time %us",
871                  (i&0x8000) ? "R" : "none", i&0xfff);
872             *p += 2;
873             tclen = clen - 2;
874             /*
875              * what follows is alist of AFI/SAFI/flag triplets
876              * read it until the TLV ends
877              */
878             while (tclen >=4) {
879                 /* AFI */
880                 i = tvb_get_ntohs(tvb, *p);
881                 proto_tree_add_text(subtree, tvb, *p,
882                      2, "Address family identifier: %s (%u)",
883                      val_to_str(i, afn_vals, "Unknown"), i);
884                 *p += 2;
885                 /* SAFI */
886                 i = tvb_get_guint8(tvb, *p);
887                 proto_tree_add_text(subtree, tvb, *p,
888                      1, "Subsequent address family identifier: %s (%u)",
889                      val_to_str(i, bgpattr_nlri_safi,
890                      i >= 128 ? "Vendor specific" : "Unknown"), i);
891                 (*p)++;
892                 /* flags */
893                 i = tvb_get_guint8(tvb, *p);
894                 proto_tree_add_text(subtree, tvb, *p, 1,
895                      "Preserve forwarding state: %s",
896                      (i&0x80) ? "yes" : "no");
897                 (*p)++;
898                 tclen-=4;
899             }
900         }
901         *p += clen;
902         break;
903     case BGP_CAPABILITY_4_OCTET_AS_NUMBER:
904         proto_tree_add_text(tree, tvb, *p - 2, 1,
905              "Capability code: %s (%d)", val_to_str(ctype,
906              capability_vals, "Unknown capability"), ctype);
907         if (clen != 4) {
908             proto_tree_add_text(tree, tvb, *p,
909                  clen, "Capability value: Invalid");
910         }
911         else {
912             proto_tree_add_text(tree, tvb, *p - 1,
913                  1, "Capability length: %u %s", clen,
914                  (clen == 1) ? "byte" : "bytes");
915             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
916             subtree = proto_item_add_subtree(ti, ett_bgp_option);
917             proto_tree_add_text(subtree, tvb, *p, 4,
918                  "AS number: %d", tvb_get_ntohl(tvb, *p));
919         }
920         *p += clen;
921         break;
922     case BGP_CAPABILITY_DYNAMIC_CAPABILITY:
923         proto_tree_add_text(tree, tvb, *p - 2, 1,
924              "Capability code: %s (%d)", val_to_str(ctype,
925              capability_vals, "Unknown capability"), ctype);
926         proto_tree_add_text(tree, tvb, *p - 1, 1,
927              "Capability length: %u %s", clen,
928              (clen == 1) ? "byte" : "bytes");
929         if (clen > 0) {
930             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
931             subtree = proto_item_add_subtree(ti, ett_bgp_option);
932             for (i = 0; (int)i <= clen; i++) {
933                 proto_tree_add_text(subtree, tvb, *p, 1,
934                      "Capability code: %s (%d)", val_to_str(ctype,
935                      capability_vals, "Unknown capability"),
936                      tvb_get_guint8(tvb, *p));
937                 (*p)++;
938             }
939         }
940         break;
941     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
942     case BGP_CAPABILITY_ROUTE_REFRESH:
943         proto_tree_add_text(tree, tvb, *p - 2, 1,
944              "Capability code: %s (%d)", val_to_str(ctype,
945              capability_vals, "Unknown capability"), ctype);
946         if (clen != 0) {
947             proto_tree_add_text(tree, tvb, *p,
948                  clen, "Capability value: Invalid");
949         }
950         else {
951             proto_tree_add_text(tree, tvb, *p - 1,
952                  1, "Capability length: %u %s", clen,
953                  (clen == 1) ? "byte" : "bytes");
954         }
955         *p += clen;
956         break;
957     case BGP_CAPABILITY_ORF_CISCO:
958     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
959         proto_tree_add_text(tree, tvb, *p - 2, 1,
960              "Capability code: %s (%d)", val_to_str(ctype,
961              capability_vals, "Unknown capability"), ctype);
962         proto_tree_add_text(tree, tvb, *p - 1,
963              1, "Capability length: %u %s", clen,
964              (clen == 1) ? "byte" : "bytes");
965         ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
966         subtree = proto_item_add_subtree(ti, ett_bgp_option);
967         /* AFI */
968         i = tvb_get_ntohs(tvb, *p);
969         proto_tree_add_text(subtree, tvb, *p,
970              2, "Address family identifier: %s (%u)",
971              val_to_str(i, afn_vals, "Unknown"), i);
972         *p += 2;
973         /* Reserved */
974         proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
975         (*p)++;
976         /* SAFI */
977         i = tvb_get_guint8(tvb, *p);
978         proto_tree_add_text(subtree, tvb, *p,
979              1, "Subsequent address family identifier: %s (%u)",
980              val_to_str(i, bgpattr_nlri_safi,
981              i >= 128 ? "Vendor specific" : "Unknown"), i);
982         (*p)++;
983         /* Number of ORFs */
984         orfnum = tvb_get_guint8(tvb, *p);
985         proto_tree_add_text(subtree, tvb, *p, 1, "Number of ORFs: %u", orfnum);
986         (*p)++;
987         for (i=0; i<orfnum; i++) {
988             /* ORF Type */
989             orftype = tvb_get_guint8(tvb, *p);
990             proto_tree_add_text(subtree, tvb, *p, 1, "ORF Type: %s (%u)",
991                  val_to_str(orftype, orf_type_vals,"Unknown"), orftype);
992             (*p)++;
993             /* Send/Receive */
994             orfsendrecv = tvb_get_guint8(tvb, *p);
995             proto_tree_add_text(subtree, tvb, *p,
996                  1, "Send/Receive: %s (%u)",
997                  val_to_str(orfsendrecv, orf_send_recv_vals,
998                  "Uknown"), orfsendrecv);
999             (*p)++;
1000         }
1001         break;
1002         /* unknown capability */
1003     default:
1004         proto_tree_add_text(tree, tvb, *p - 2, 1,
1005              "Capability code: %s (%d)", val_to_str(ctype,
1006              capability_vals, "Unknown capability"), ctype);
1007         proto_tree_add_text(tree, tvb, *p - 2,
1008              1, "Capability code: %s (%d)",
1009              ctype >= 128 ? "Private use" : "Unknown", ctype);
1010         proto_tree_add_text(tree, tvb, *p - 1,
1011              1, "Capability length: %u %s", clen,
1012              (clen == 1) ? "byte" : "bytes");
1013         if (clen != 0) {
1014             proto_tree_add_text(tree, tvb, *p,
1015                  clen, "Capability value: Unknown");
1016         }
1017         *p += clen;
1018         break;
1019     }
1020 }
1021
1022
1023 /*
1024  * Dissect a BGP OPEN message.
1025  */
1026 static const value_string community_vals[] = {
1027         { BGP_COMM_NO_EXPORT,           "NO_EXPORT" },
1028         { BGP_COMM_NO_ADVERTISE,        "NO_ADVERTISE" },
1029         { BGP_COMM_NO_EXPORT_SUBCONFED, "NO_EXPORT_SUBCONFED" },
1030         { 0,                            NULL }
1031 };
1032
1033 static void
1034 dissect_bgp_open(tvbuff_t *tvb, int offset, proto_tree *tree)
1035 {
1036     struct bgp_open bgpo;      /* BGP OPEN message      */
1037     int             hlen;      /* message length        */
1038     int             ptype;     /* parameter type        */
1039     int             plen;      /* parameter length      */
1040     int             ctype;     /* capability type       */
1041     int             clen;      /* capability length     */
1042     int             cend;      /* capabilities end      */
1043     int             ostart;    /* options start         */
1044     int             oend;      /* options end           */
1045     int             p;         /* tvb offset counter    */
1046     proto_item      *ti;       /* tree item             */
1047     proto_tree      *subtree;  /* subtree for options   */
1048     proto_tree      *subtree1; /* subtree for an option */
1049     proto_tree      *subtree2; /* subtree for an option */
1050
1051     /* snarf OPEN message */
1052     tvb_memcpy(tvb, bgpo.bgpo_marker, offset, BGP_MIN_OPEN_MSG_SIZE);
1053     hlen = g_ntohs(bgpo.bgpo_len);
1054
1055     proto_tree_add_text(tree, tvb,
1056         offset + offsetof(struct bgp_open, bgpo_version), 1,
1057         "Version: %u", bgpo.bgpo_version);
1058     proto_tree_add_text(tree, tvb,
1059         offset + offsetof(struct bgp_open, bgpo_myas), 2,
1060         "My AS: %u", g_ntohs(bgpo.bgpo_myas));
1061     proto_tree_add_text(tree, tvb,
1062         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
1063         "Hold time: %u", g_ntohs(bgpo.bgpo_holdtime));
1064     proto_tree_add_text(tree, tvb,
1065         offset + offsetof(struct bgp_open, bgpo_id), 4,
1066         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
1067     proto_tree_add_text(tree, tvb,
1068         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
1069         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
1070         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
1071
1072     /* optional parameters */
1073     if (bgpo.bgpo_optlen > 0) {
1074         /* add a subtree and setup some offsets */
1075         ostart = offset + BGP_MIN_OPEN_MSG_SIZE;
1076         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
1077              "Optional parameters");
1078         subtree = proto_item_add_subtree(ti, ett_bgp_options);
1079         p = offset + ostart;
1080         oend = p + bgpo.bgpo_optlen;
1081
1082         /* step through all of the optional parameters */
1083         while (p < oend) {
1084
1085             /* grab the type and length */
1086             ptype = tvb_get_guint8(tvb, p++);
1087             plen = tvb_get_guint8(tvb, p++);
1088
1089             /* check the type */
1090             switch (ptype) {
1091             case BGP_OPTION_AUTHENTICATION:
1092                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1093                     "Authentication information (%u %s)", plen,
1094                     (plen == 1) ? "byte" : "bytes");
1095                 break;
1096             case BGP_OPTION_CAPABILITY:
1097                 /* grab the capability code */
1098                 cend = p - 1 + plen;
1099                 ctype = tvb_get_guint8(tvb, p++);
1100                 clen = tvb_get_guint8(tvb, p++);
1101                 ti = proto_tree_add_text(subtree, tvb, p - 4,
1102                      2 + plen, "Capabilities Advertisement (%u bytes)",
1103                      2 + plen);
1104                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
1105                 proto_tree_add_text(subtree1, tvb, p - 4,
1106                      1, "Parameter type: Capabilities (2)");
1107                 proto_tree_add_text(subtree1, tvb, p - 3,
1108                      1, "Parameter length: %u %s", plen,
1109                      (plen == 1) ? "byte" : "bytes");
1110                 p -= 2;
1111
1112                 /* step through all of the capabilities */
1113                 while (p < cend) {
1114                     ctype = tvb_get_guint8(tvb, p++);
1115                     clen = tvb_get_guint8(tvb, p++);
1116
1117                     ti = proto_tree_add_text(subtree1, tvb, p - 2,
1118                          2 + clen, "%s (%u %s)", val_to_str(ctype,
1119                          capability_vals, "Unknown capability"),
1120                          2 + clen, (clen == 1) ? "byte" : "bytes");
1121                     subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
1122                     dissect_bgp_capability_item(tvb, &p,
1123                            subtree2, ctype, clen);
1124                 }
1125                 break;
1126             default:
1127                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1128                     "Unknown optional parameter");
1129                 break;
1130             }
1131         }
1132     }
1133 }
1134
1135 /*
1136  * Dissect a BGP UPDATE message.
1137  */
1138 static void
1139 dissect_bgp_update(tvbuff_t *tvb, int offset, proto_tree *tree)
1140 {
1141     struct bgp_attr bgpa;                       /* path attributes          */
1142     guint16         hlen;                       /* message length           */
1143     gint            o;                          /* packet offset            */
1144     gint            q;                          /* tmp                      */
1145     gint            end;                        /* message end              */
1146     guint16         ext_com;                    /* EXTENDED COMMUNITY type  */
1147     guint16         len;                        /* tmp                      */
1148     int             advance;                    /* tmp                      */
1149     proto_item      *ti;                        /* tree item                */
1150     proto_tree      *subtree;                   /* subtree for attributes   */
1151     proto_tree      *subtree2;                  /* subtree for attributes   */
1152     proto_tree      *subtree3;                  /* subtree for attributes   */
1153     proto_tree      *subtree4;                  /* subtree for attributes   */
1154     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
1155     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
1156     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
1157     proto_tree      *community_tree;            /* subtree for a community  */
1158     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
1159     int             i, j;                       /* tmp                      */
1160     guint8          length;                     /* AS_PATH length           */
1161     guint8          type;                       /* AS_PATH type             */
1162     char            *as_path_str = NULL;        /* AS_PATH string           */
1163     char            *communities_str = NULL;    /* COMMUNITIES string       */
1164     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
1165     char            junk_buf[256];              /* tmp                      */
1166     int             junk_buf_len;               /* tmp len                  */
1167     guint8          ipaddr[4];                  /* IPv4 address             */
1168
1169     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
1170     o = offset + BGP_HEADER_SIZE;
1171
1172     /* check for withdrawals */
1173     len = tvb_get_ntohs(tvb, o);
1174     proto_tree_add_text(tree, tvb, o, 2,
1175         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
1176     o += 2;
1177
1178     /* parse unfeasible prefixes */
1179     if (len > 0) {
1180         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
1181         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
1182
1183         /* parse each prefixes */
1184         end = o + len;
1185         while (o < end) {
1186             i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1187             if (i < 0 || 32 < i) {
1188                 proto_tree_add_text (tree, tvb, o, len, 
1189                     "Invalid withdrawn route prefix length: %u", 
1190                         tvb_get_guint8(tvb, o) );
1191                 return;
1192             }
1193
1194             proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1195             o += i;
1196         }
1197     }
1198
1199     /* check for advertisements */
1200     len = tvb_get_ntohs(tvb, o);
1201     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
1202             len, (len == 1) ? "byte" : "bytes");
1203
1204     /* path attributes */
1205     if (len > 0) {
1206         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
1207         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
1208         i = 2;
1209         while (i < len) {
1210             char    *msg;
1211             int     off;
1212             gint    k;
1213             guint16 alen, tlen, aoff; 
1214             guint16 af;
1215             guint8  saf, snpa;
1216             guint8  nexthop_len;
1217             guint8  asn_len = 0;
1218
1219             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
1220             /* check for the Extended Length bit */
1221             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1222                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
1223                 aoff = sizeof(bgpa) + 2;
1224             } else {
1225                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
1226                 aoff = sizeof(bgpa) + 1;
1227             }
1228             tlen = alen;
1229
1230             /* This is kind of ugly - similar code appears twice, but it
1231                helps browsing attrs.                                      */
1232             /* the first switch prints things in the title of the subtree */
1233             switch (bgpa.bgpa_type) {
1234             case BGPTYPE_ORIGIN:
1235                 if (tlen != 1)
1236                     goto default_attribute_top;
1237                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1238                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1239                         "%s: %s (%u %s)",
1240                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1241                         msg, tlen + aoff, (tlen + aoff == 1) ? "byte" :
1242                         "bytes");
1243                 break;
1244             case BGPTYPE_AS_PATH:
1245             case BGPTYPE_NEW_AS_PATH:
1246                 /* (o + i + aoff) =
1247                    (o + current attribute + aoff bytes to first tuple) */
1248                 q = o + i + aoff;
1249                 end = q + tlen;
1250                 /* must be freed by second switch!                         */
1251                 /* "tlen * 11" (10 digits + space) should be a good estimate
1252                    of how long the AS path string could be                 */
1253                 as_path_str = malloc((tlen + 1) * 11);
1254                 if (as_path_str == NULL) break;
1255                 as_path_str[0] = '\0';
1256
1257                 /* estimate the length of the AS number */
1258                 if (bgpa.bgpa_type == BGPTYPE_NEW_AS_PATH) 
1259                     asn_len = 4;
1260                 else {
1261                     if (bgp_asn_len == 0) {
1262                         k = q;
1263                         while (k < end) {
1264                             k++;
1265                             length = tvb_get_guint8(tvb, k++);
1266                             k += length * 2;
1267                         }
1268                         asn_len = (k == end) ? 2 : 4;
1269                     }
1270                     else {
1271                         asn_len = bgp_asn_len;
1272                     }
1273                 }
1274
1275                 /* snarf each AS path */
1276                 while (q < end) {
1277                     type = tvb_get_guint8(tvb, q++);
1278                     if (strlen(as_path_str) != 0 &&
1279                         as_path_str[strlen(as_path_str) - 1] != ' ')
1280                         strcat(as_path_str, " ");
1281                     if (type == AS_SET) {
1282                         strcat(as_path_str, "{");
1283                     }
1284                     else if (type == AS_CONFED_SET) {
1285                         strcat(as_path_str, "[");
1286                     }
1287                     else if (type == AS_CONFED_SEQUENCE) {
1288                         strcat(as_path_str, "(");
1289                     }
1290                     length = tvb_get_guint8(tvb, q++);
1291
1292                     /* snarf each value in path */
1293                     for (j = 0; j < length; j++) {
1294                         snprintf(junk_buf, sizeof(junk_buf), "%u%s",
1295                                 (asn_len == 2) ?
1296                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1297                                 (type == AS_SET || type == AS_CONFED_SET) ?
1298                                 ", " : " ");
1299                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1300                         q += asn_len;
1301                     }
1302
1303                     /* cleanup end of string */
1304                     if (type == AS_SET) {
1305                         as_path_str[strlen(as_path_str) - 2] = '}';
1306                         as_path_str[strlen(as_path_str) - 1] = '\0';
1307                     }
1308                     else if (type == AS_CONFED_SET) {
1309                         as_path_str[strlen(as_path_str) - 2] = ']';
1310                         as_path_str[strlen(as_path_str) - 1] = '\0';
1311                     }
1312                     else if (type == AS_CONFED_SEQUENCE) {
1313                         as_path_str[strlen(as_path_str) - 1] = ')';
1314                     }
1315                     else {
1316                         as_path_str[strlen(as_path_str) - 1] = '\0';
1317                     }
1318                 }
1319
1320                 /* check for empty AS_PATH */
1321                 if (tlen == 0)
1322                     strncpy(as_path_str, "empty", 6);
1323
1324                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1325                         "%s: %s (%u %s)",
1326                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1327                         as_path_str, tlen + aoff,
1328                         (tlen + aoff == 1) ? "byte" : "bytes");
1329                 break;
1330             case BGPTYPE_NEXT_HOP:
1331                 if (tlen != 4)
1332                     goto default_attribute_top;
1333                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1334                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1335                         "%s: %s (%u %s)",
1336                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1337                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1338                         ? "byte" : "bytes");
1339                 break;
1340             case BGPTYPE_MULTI_EXIT_DISC:
1341                 if (tlen != 4)
1342                     goto default_attribute_top;
1343                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1344                         "%s: %u (%u %s)",
1345                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1346                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1347                         (tlen + aoff == 1) ? "byte" : "bytes");
1348                 break;
1349             case BGPTYPE_LOCAL_PREF:
1350                 if (tlen != 4)
1351                     goto default_attribute_top;
1352                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1353                         "%s: %u (%u %s)",
1354                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1355                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1356                         (tlen + aoff == 1) ? "byte" : "bytes");
1357                 break;
1358             case BGPTYPE_ATOMIC_AGGREGATE:
1359                 if (tlen != 0)
1360                     goto default_attribute_top;
1361                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1362                         "%s (%u %s)",
1363                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1364                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1365                 break;
1366             case BGPTYPE_AGGREGATOR:
1367                 if (tlen != 6 && tlen != 8)
1368                     goto default_attribute_top;
1369             case BGPTYPE_NEW_AGGREGATOR:
1370                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
1371                     goto default_attribute_top;
1372                 asn_len = tlen - 4;
1373                 tvb_memcpy(tvb, ipaddr, o + i + aoff + asn_len, 4);
1374                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1375                         "%s: AS: %u origin: %s (%u %s)",
1376                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1377                         (asn_len == 2) ? tvb_get_ntohs(tvb, o + i + aoff) :
1378                         tvb_get_ntohl(tvb, o + i + aoff),
1379                         ip_to_str(ipaddr), tlen + aoff,
1380                         (tlen + aoff == 1) ? "byte" : "bytes");
1381                 break;
1382             case BGPTYPE_COMMUNITIES:
1383                 if (tlen % 4 != 0)
1384                     goto default_attribute_top;
1385
1386                 /* (o + i + aoff) =
1387                    (o + current attribute + aoff bytes to first tuple) */
1388                 q = o + i + aoff;
1389                 end = q + tlen;
1390                 /* must be freed by second switch!                          */
1391                 /* "tlen * 12" (5 digits, a :, 5 digits + space ) should be
1392                    a good estimate of how long the communities string could
1393                    be                                                       */
1394                 communities_str = malloc((tlen + 1) * 12);
1395                 if (communities_str == NULL) break;
1396                 communities_str[0] = '\0';
1397                 memset(junk_buf, 0, sizeof(junk_buf));
1398
1399                 /* snarf each community */
1400                 while (q < end) {
1401                     /* check for well-known communities */
1402                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
1403                         strncpy(junk_buf, "NO_EXPORT ", 10);
1404                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1405                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
1406                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1407                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
1408                     else {
1409                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
1410                                 tvb_get_ntohs(tvb, q),
1411                                 tvb_get_ntohs(tvb, q + 2));
1412                     }
1413                     q += 4;
1414
1415                     strncat(communities_str, junk_buf, sizeof(junk_buf));
1416                 }
1417                 /* cleanup end of string */
1418                 communities_str[strlen(communities_str) - 1] = '\0';
1419
1420                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1421                         "%s: %s (%u %s)",
1422                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1423                         communities_str, tlen + aoff,
1424                         (tlen + aoff == 1) ? "byte" : "bytes");
1425                 break;
1426             case BGPTYPE_ORIGINATOR_ID:
1427                 if (tlen != 4)
1428                     goto default_attribute_top;
1429                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1430                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1431                         "%s: %s (%u %s)",
1432                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1433                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1434                         ? "byte" : "bytes");
1435                 break;
1436             case BGPTYPE_CLUSTER_LIST:
1437                 if (tlen % 4 != 0)
1438                     goto default_attribute_top;
1439
1440                 /* (o + i + aoff) =
1441                    (o + current attribute + aoff bytes to first tuple) */
1442                 q = o + i + aoff;
1443                 end = q + tlen;
1444                 /* must be freed by second switch!                          */
1445                 /* "tlen * 16" (12 digits, 3 dots + space ) should be
1446                    a good estimate of how long the cluster_list string could
1447                    be                                                       */
1448                 cluster_list_str = malloc((tlen + 1) * 16);
1449                 if (cluster_list_str == NULL) break;
1450                 cluster_list_str[0] = '\0';
1451                 memset(junk_buf, 0, sizeof(junk_buf));
1452
1453                 /* snarf each cluster list */
1454                 tvb_memcpy(tvb, ipaddr, q, 4);
1455                 while (q < end) {
1456                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
1457                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
1458                     q += 4;
1459                 }
1460                 /* cleanup end of string */
1461                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
1462
1463                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1464                         "%s: %s (%u %s)",
1465                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1466                         cluster_list_str, tlen + aoff,
1467                         (tlen + aoff == 1) ? "byte" : "bytes");
1468                 break;
1469             case BGPTYPE_EXTENDED_COMMUNITY:
1470                 if (tlen %8 != 0)
1471                     break;
1472                 ti = proto_tree_add_text(subtree,tvb,o+i,tlen+aoff,
1473                         "%s: (%u %s)",
1474                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1475                         tlen + aoff,
1476                         (tlen + aoff == 1) ? "byte" : "bytes");
1477                 break;
1478
1479             default:
1480             default_attribute_top:
1481                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1482                         "%s (%u %s)",
1483                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1484                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1485             } /* end of first switch */
1486             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1487
1488             /* figure out flags */
1489             junk_buf[0] = '\0';
1490             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1491                  strncat(junk_buf, "Optional, ", 10);
1492             }
1493             else {
1494                  strncat(junk_buf, "Well-known, ", 12);
1495             }
1496             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1497                  strncat(junk_buf, "Transitive, ", 12);
1498             }
1499             else {
1500                  strncat(junk_buf, "Non-transitive, ", 16);
1501             }
1502             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1503                  strncat(junk_buf, "Partial, ", 9);
1504             }
1505             else {
1506                  strncat(junk_buf, "Complete, ", 10);
1507             }
1508             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1509                  strncat(junk_buf, "Extended Length, ", 17);
1510             }
1511             /* stomp last ", " */
1512             j = strlen(junk_buf);
1513             junk_buf[j - 2] = '\0';
1514             ti = proto_tree_add_text(subtree2, tvb,
1515                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1516                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
1517             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1518
1519             /* add flag bitfield subtrees */
1520             proto_tree_add_text(subtree3, tvb,
1521                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1522                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1523                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1524             proto_tree_add_text(subtree3, tvb,
1525                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1526                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1527                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1528                         "Non-transitive"));
1529             proto_tree_add_text(subtree3, tvb,
1530                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1531                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1532                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1533             proto_tree_add_text(subtree3, tvb,
1534                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1535                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1536                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1537                         "Regular length"));
1538
1539             proto_tree_add_text(subtree2, tvb,
1540                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1541                     "Type code: %s (%u)",
1542                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1543                     bgpa.bgpa_type);
1544
1545             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1546                     aoff - sizeof(bgpa), "Length: %d %s", tlen,
1547                     (tlen == 1) ? "byte" : "bytes");
1548
1549             /* the second switch prints things in the actual subtree of each
1550                attribute                                                     */
1551             switch (bgpa.bgpa_type) {
1552             case BGPTYPE_ORIGIN:
1553                 if (tlen != 1) {
1554                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1555                             "Origin (invalid): %u %s", tlen,
1556                              (tlen == 1) ? "byte" : "bytes");
1557                 } else {
1558                     msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1559                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1560                             "Origin: %s (%u)", msg, tvb_get_guint8(tvb, o + i + aoff));
1561                 }
1562                 break;
1563             case BGPTYPE_AS_PATH:
1564             case BGPTYPE_NEW_AS_PATH:
1565                 /* check for empty AS_PATH */
1566                 if (tlen == 0) {
1567                     free(as_path_str);
1568                     break;
1569                 }
1570
1571                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1572                         "AS path: %s", as_path_str);
1573                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1574
1575                 /* (o + i + aoff) =
1576                    (o + current attribute + aoff bytes to first tuple) */
1577                 q = o + i + aoff;
1578                 end = q + tlen;
1579
1580                 /* snarf each AS path tuple, we have to step through each one
1581                    again to make a separate subtree so we can't just reuse
1582                    as_path_str from above */
1583                 while (q < end) {
1584                     as_path_str[0] = '\0';
1585                     type = tvb_get_guint8(tvb, q++);
1586                     if (type == AS_SET) {
1587                         snprintf(as_path_str, 2, "{");
1588                     }
1589                     else if (type == AS_CONFED_SET) {
1590                         snprintf(as_path_str, 2, "[");
1591                     }
1592                     else if (type == AS_CONFED_SEQUENCE) {
1593                         snprintf(as_path_str, 2, "(");
1594                     }
1595                     length = tvb_get_guint8(tvb, q++);
1596
1597                     /* snarf each value in path, we're just going to reuse
1598                        as_path_str since we already have it malloced       */
1599                     for (j = 0; j < length; j++) {
1600                         snprintf(junk_buf, sizeof(junk_buf), "%u%s",
1601                                 (asn_len == 2) ? 
1602                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1603                                 (type == AS_SET || type == AS_CONFED_SET) ? ", " : " ");
1604                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1605                         q += asn_len;
1606                     }
1607
1608                     /* cleanup end of string */
1609                     if (type == AS_SET) {
1610                         as_path_str[strlen(as_path_str) - 2] = '}';
1611                     }
1612                     else if (type == AS_CONFED_SET) {
1613                         as_path_str[strlen(as_path_str) - 2] = ']';
1614                     }
1615                     else if (type == AS_CONFED_SEQUENCE) {
1616                         as_path_str[strlen(as_path_str) - 1] = ')';
1617                     }
1618                     else {
1619                         as_path_str[strlen(as_path_str) - 1] = '\0';
1620                     }
1621
1622                     /* length here means number of ASs, ie length * 2 bytes */
1623                     ti = proto_tree_add_text(as_paths_tree, tvb,
1624                             q - length * asn_len - 2,
1625                             length * asn_len + 2, "AS path segment: %s", as_path_str);
1626                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1627                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 2,
1628                             1, "Path segment type: %s (%u)",
1629                             val_to_str(type, as_segment_type, "Unknown"), type);
1630                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 1,
1631                             1, "Path segment length: %u %s", length,
1632                             (length == 1) ? "AS" : "ASs");
1633
1634                     /* backup and reprint path segment value(s) only */
1635                     q -= asn_len * length;
1636                     as_path_str[0] = '\0';
1637                     for (j = 0; j < length; j++) {
1638                         snprintf(junk_buf, sizeof(junk_buf), "%u ",
1639                                 (asn_len == 2) ? 
1640                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q));
1641                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1642                         q += asn_len;
1643                     }
1644                     as_path_str[strlen(as_path_str) - 1] = '\0';
1645
1646                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len,
1647                             length * asn_len, "Path segment value: %s", as_path_str);
1648                 }
1649
1650                 free(as_path_str);
1651                 break;
1652             case BGPTYPE_NEXT_HOP:
1653                 if (tlen != 4) {
1654                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1655                             "Next hop (invalid): %u %s", tlen,
1656                             (tlen == 1) ? "byte" : "bytes");
1657                 } else {
1658                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1659                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1660                             "Next hop: %s", ip_to_str(ipaddr));
1661                 }
1662                 break;
1663             case BGPTYPE_MULTI_EXIT_DISC:
1664                 if (tlen != 4) {
1665                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1666                             "Multiple exit discriminator (invalid): %u %s",
1667                             tlen, (tlen == 1) ? "byte" : "bytes");
1668                 } else {
1669                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1670                             "Multiple exit discriminator: %u",
1671                             tvb_get_ntohl(tvb, o + i + aoff));
1672                 }
1673                 break;
1674             case BGPTYPE_LOCAL_PREF:
1675                 if (tlen != 4) {
1676                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1677                             "Local preference (invalid): %u %s", tlen,
1678                              (tlen == 1) ? "byte" : "bytes");
1679                 } else {
1680                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1681                             "Local preference: %u", tvb_get_ntohl(tvb, o + i + aoff));
1682                 }
1683                 break;
1684             case BGPTYPE_ATOMIC_AGGREGATE:
1685                 if (tlen != 0) {
1686                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1687                             "Atomic aggregate (invalid): %u %s", tlen,
1688                             (tlen == 1) ? "byte" : "bytes");
1689                 }
1690                 break;
1691             case BGPTYPE_AGGREGATOR:
1692                 if (tlen != 6 && tlen != 8) {
1693                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1694                             "Aggregator (invalid): %u %s", tlen,
1695                             (tlen == 1) ? "byte" : "bytes");
1696                     break;
1697                 }
1698             case BGPTYPE_NEW_AGGREGATOR:
1699                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
1700                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1701                             "Aggregator (invalid): %u %s", tlen,
1702                             (tlen == 1) ? "byte" : "bytes");
1703                 else {
1704                     asn_len = tlen - 4;
1705                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1706                             "Aggregator AS: %u", asn_len == 2 ?
1707                             tvb_get_ntohs(tvb, o + i + aoff) :
1708                             tvb_get_ntohl(tvb, o + i + aoff));
1709                     tvb_memcpy(tvb, ipaddr, o + i + aoff + asn_len, 4);
1710                     proto_tree_add_text(subtree2, tvb, o + i + aoff + asn_len,
1711                             4, "Aggregator origin: %s", ip_to_str(ipaddr));
1712                 }
1713                 break;
1714             case BGPTYPE_COMMUNITIES:
1715                 if (tlen % 4 != 0) {
1716                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1717                             "Communities (invalid): %u %s", tlen,
1718                             (tlen == 1) ? "byte" : "bytes");
1719                     free(communities_str);
1720                     break;
1721                 }
1722
1723                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1724                         "Communities: %s", communities_str);
1725                 communities_tree = proto_item_add_subtree(ti,
1726                         ett_bgp_communities);
1727
1728                 /* (o + i + aoff) =
1729                    (o + current attribute + aoff bytes to first tuple) */
1730                 q = o + i + aoff;
1731                 end = q + tlen;
1732
1733                 /* snarf each community */
1734                 while (q < end) {
1735                     /* check for reserved values */
1736                     guint32 community = tvb_get_ntohl(tvb, q);
1737                     if ((community & 0xFFFF0000) == FOURHEX0 ||
1738                          (community & 0xFFFF0000) == FOURHEXF) {
1739                         proto_tree_add_text(communities_tree, tvb,
1740                                q - 3 + aoff, 4,
1741                                "Community: %s (0x%08x)",
1742                                val_to_str(community, community_vals, "(reserved)"),
1743                                community);
1744                     }
1745                     else {
1746                         ti = proto_tree_add_text(communities_tree, tvb,
1747                                 q - 3 + aoff, 4, "Community: %u:%u",
1748                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1749                         community_tree = proto_item_add_subtree(ti,
1750                             ett_bgp_communities);
1751                         proto_tree_add_text(community_tree, tvb, q - 3 + aoff,
1752                                 2, "Community AS: %u", tvb_get_ntohs(tvb, q));
1753                         proto_tree_add_text(community_tree, tvb, q - 1 + aoff,
1754                                 2, "Community value: %u", tvb_get_ntohs(tvb, q + 2));
1755                     }
1756
1757                     q += 4;
1758                 }
1759
1760                 free(communities_str);
1761                 break;
1762             case BGPTYPE_ORIGINATOR_ID:
1763                 if (tlen != 4) {
1764                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1765                             "Originator identifier (invalid): %u %s", tlen,
1766                             (tlen == 1) ? "byte" : "bytes");
1767                 } else {
1768                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1769                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1770                             "Originator identifier: %s",
1771                             ip_to_str(ipaddr));
1772                 }
1773                 break;
1774            case BGPTYPE_MP_REACH_NLRI:
1775                 /*
1776                  * RFC 2545 specifies that there may be more than one
1777                  * address in the MP_REACH_NLRI attribute in section
1778                  * 3, "Constructing the Next Hop field".
1779                  *
1780                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1781                  * 2858 obsoletes RFC 2283, which says you can do that,
1782                  * but that doesn't mean we shouldn't dissect packets
1783                  * that conform to RFC 2283 but not RFC 2858, as some
1784                  * device on the network might implement the 2283-style
1785                  * BGP extensions rather than RFC 2858-style extensions.
1786                  */
1787                 af = tvb_get_ntohs(tvb, o + i + aoff);
1788                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1789                     "Address family: %s (%u)",
1790                     val_to_str(af, afn_vals, "Unknown"), af);
1791                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1792                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1793                     "Subsequent address family identifier: %s (%u)",
1794                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1795                     saf);
1796                 if (af != AFNUM_INET && af != AFNUM_INET6 && af != AFNUM_L2VPN) {
1797                     /*
1798                      * The addresses don't contain lengths, so if we
1799                      * don't understand the address family type, we
1800                      * cannot parse the subsequent addresses as we
1801                      * don't know how long they are.
1802                      *
1803                      * XXX - we should put a protocol tree item in for
1804                      * this, as an unknown blob.
1805                      */
1806                     break;
1807                 }
1808                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1809                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1810                         "Next hop network address (%d %s)",
1811                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1812                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1813                 j = 0;
1814                 while (j < nexthop_len) {
1815                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1816                         junk_buf, sizeof(junk_buf)) ;
1817                     if (advance == 0) /* catch if this is a unknown AFI type*/
1818                             break;
1819                     if (j + advance > nexthop_len)
1820                             break;
1821                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1822                         advance, "Next hop: %s (%u)", junk_buf, advance);
1823                     j += advance;
1824                 }
1825                 tlen -= nexthop_len + 4;
1826                 aoff += nexthop_len + 4 ;
1827
1828                 off = 0;
1829                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1830                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1831                         "Subnetwork points of attachment: %u", snpa);
1832                 off++;
1833                 if (snpa) {
1834                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1835                         for (/*nothing*/; snpa > 0; snpa--) {
1836                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1837                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1838                                 off++;
1839                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1840                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1841                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1842                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1843                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1844                         }
1845                 }
1846                 tlen -= off;
1847                 aoff += off;
1848
1849                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1850                         "Network layer reachability information (%u %s)",
1851                         tlen, (tlen == 1) ? "byte" : "bytes");
1852                 if (tlen)  {
1853                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1854
1855                         while (tlen > 0) {
1856                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1857                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1858                                 tlen -= advance;
1859                                 aoff += advance;
1860                         }
1861                 }
1862                 break;
1863            case BGPTYPE_MP_UNREACH_NLRI:
1864                 af = tvb_get_ntohs(tvb, o + i + aoff);
1865                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1866                     "Address family: %s (%u)",
1867                     val_to_str(af, afn_vals, "Unknown"), af);
1868                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1869                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1870                     "Subsequent address family identifier: %s (%u)",
1871                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1872                     saf);
1873                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1874                         tlen - 3, "Withdrawn routes (%u %s)", tlen - 3,
1875                         (tlen - 3 == 1) ? "byte" : "bytes");
1876
1877                 tlen -= 3;
1878                 aoff += 3;
1879                 if (tlen > 0) {
1880                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
1881
1882                         while (tlen > 0) {
1883                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1884                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1885                                 tlen -= advance;
1886                                 aoff += advance;
1887                                 if (advance==1)  /* catch if this is a unknown AFI type*/
1888                                         break;
1889                         }
1890                 }
1891                 break;
1892             case BGPTYPE_CLUSTER_LIST:
1893                 if (tlen % 4 != 0) {
1894                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1895                             "Cluster list (invalid): %u %s", tlen,
1896                             (tlen == 1) ? "byte" : "bytes");
1897                     free(cluster_list_str);
1898                     break;
1899                 }
1900
1901                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1902                         "Cluster list: %s", cluster_list_str);
1903                 cluster_list_tree = proto_item_add_subtree(ti,
1904                         ett_bgp_cluster_list);
1905
1906                 /* (o + i + aoff) =
1907                    (o + current attribute + aoff bytes to first tuple) */
1908                 q = o + i + aoff;
1909                 end = q + tlen;
1910
1911                 /* snarf each cluster identifier */
1912                 while (q < end) {
1913                     tvb_memcpy(tvb, ipaddr, q, 4);
1914                     ti = proto_tree_add_text(cluster_list_tree, tvb,
1915                             q - 3 + aoff, 4, "Cluster identifier: %s",
1916                             ip_to_str(ipaddr));
1917
1918                     q += 4;
1919                 }
1920
1921                 free(cluster_list_str);
1922                 break;
1923                 case BGPTYPE_EXTENDED_COMMUNITY:
1924                 if (tlen %8 != 0) {
1925                         proto_tree_add_text(subtree3, tvb, o + i + aoff, tlen, "Extended community (invalid) : %u %s", tlen,
1926                                 (tlen == 1) ? "byte" : "bytes") ;
1927                 } else {
1928                         q = o + i + aoff ;
1929                         end = o + i + aoff + tlen ;
1930                         ti = proto_tree_add_text(subtree2,tvb,q,tlen, "Carried Extended communities");
1931                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1932
1933                         while (q < end) {
1934                             junk_buf_len=0;
1935                             ext_com = tvb_get_ntohs(tvb,q) ;
1936                             junk_buf_len=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf), "%s",
1937                                                   val_to_str(ext_com,bgpext_com_type,"Unknown"));
1938                             switch (ext_com) {
1939                             case BGP_EXT_COM_RT_0:
1940                             case BGP_EXT_COM_RO_0:
1941                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %u%s%d",
1942                                                        tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
1943                                 junk_buf[junk_buf_len]='\0';
1944                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1945                                 break ;
1946                             case BGP_EXT_COM_RT_1:
1947                             case BGP_EXT_COM_RO_1:
1948                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1949                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s%s%u",
1950                                                        ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
1951                                 junk_buf[junk_buf_len]='\0';
1952                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1953                                 break;
1954                             case BGP_EXT_COM_VPN_ORIGIN:
1955                             case BGP_EXT_COM_OSPF_RID:
1956                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1957                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s",
1958                                                        ip_to_str(ipaddr));
1959                                 junk_buf[junk_buf_len]='\0';
1960                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1961                                 break;
1962                             case BGP_EXT_COM_OSPF_RTYPE:
1963                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1964                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": Area:%s %s",
1965                                          ip_to_str(ipaddr),
1966                                          val_to_str(tvb_get_guint8(tvb,q+6),bgpext_ospf_rtype,"Unknown"));
1967                                 /* print OSPF Metric type if selected */
1968                                 /* always print E2 even if not external route -- receiving router should ignore */
1969                                 if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) {
1970                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E2");
1971                                 } else if (tvb_get_guint8(tvb,q+6)==(BGP_OSPF_RTYPE_EXT ||BGP_OSPF_RTYPE_NSSA ) ) {
1972                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E1");
1973                                 }
1974                                 junk_buf[junk_buf_len]='\0';
1975                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1976                                 break;
1977                             case BGP_EXT_COM_LINKBAND:
1978                                 tvb_memcpy(tvb,ipaddr,q+2,4); /* need to check on IEEE format on all platforms */
1979                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %.3f Mbps",
1980                                                        ((double)*ipaddr)*8/1000000);
1981                                 junk_buf[junk_buf_len]='\0';
1982                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1983                                 break;
1984                             case BGP_EXT_COM_L2INFO:
1985                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len,
1986                                                        ": %s, Control Flags: %s%s%s%s%s, MTU: %u %s",
1987                                                        val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"),
1988                                                        tvb_get_guint8(tvb,q+3) ? "" : "none",
1989                                                        tvb_get_ntohs(tvb,q+3)&0x08 ? "Q" : "",
1990                                                        tvb_get_ntohs(tvb,q+3)&0x04 ? "F" : "",
1991                                                        tvb_get_ntohs(tvb,q+3)&0x02 ? "C" : "",
1992                                                        tvb_get_ntohs(tvb,q+3)&0x01 ? "S" : "",
1993                                                        tvb_get_ntohs(tvb,q+4),
1994                                                        tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
1995                                 junk_buf[junk_buf_len]='\0';
1996                                 ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1997
1998                                 subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1999                                 proto_tree_add_text(subtree4,tvb,q+2,1, "Encapsulation: %s",
2000                                                          val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"));
2001                                 proto_tree_add_text(subtree4,tvb,q+3,1, "Control Flags: %s%sControl Word %s required, Sequenced delivery %s required",
2002                                                     tvb_get_ntohs(tvb,q+3)&0x08 ? "Q flag (Reserved) set" : "",
2003                                                     tvb_get_ntohs(tvb,q+3)&0x04 ? "F flag (reserved) set" : "",
2004                                                     tvb_get_ntohs(tvb,q+3)&0x02 ? "is" : "not",
2005                                                     tvb_get_ntohs(tvb,q+3)&0x01 ? "is" : "not");
2006                                 proto_tree_add_text(subtree4,tvb,q+4,2, "MTU: %u %s",
2007                                                     tvb_get_ntohs(tvb,q+4),
2008                                                     tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
2009                                 break;
2010                             default:
2011                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, " ");
2012                                 junk_buf[junk_buf_len]='\0';
2013                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2014                                 break ;
2015                             }
2016                             q = q + 8 ;
2017                         }
2018                 }
2019                 break;
2020             default:
2021                 proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2022                         "Unknown (%d %s)", tlen, (tlen == 1) ? "byte" :
2023                         "bytes");
2024                 break;
2025             } /* end of second switch */
2026
2027             i += alen + aoff;
2028         }
2029
2030         o += 2 + len;
2031
2032         /* NLRI */
2033         len = offset + hlen - o;
2034
2035         /* parse prefixes */
2036         if (len > 0) {
2037            ti = proto_tree_add_text(tree, tvb, o, len,
2038                    "Network layer reachability information: %u %s", len,
2039                    (len == 1) ? "byte" : "bytes");
2040             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
2041             end = o + len;
2042             while (o < end) {
2043                 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
2044                 if (i < 0 || 32 < i) {
2045                     proto_tree_add_text (tree, tvb, o, len, 
2046                         "Invalid NLRI prefix length: %u", 
2047                             tvb_get_guint8(tvb, o) );
2048                     return;
2049                 }
2050                 
2051                 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
2052                 o += i;
2053             }
2054         }
2055     }
2056 }
2057
2058 /*
2059  * Dissect a BGP NOTIFICATION message.
2060  */
2061 static void
2062 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
2063 {
2064     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
2065     int                     hlen;   /* message length           */
2066     char                    *p;     /* string pointer           */
2067
2068     /* snarf message */
2069     tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
2070     hlen = g_ntohs(bgpn.bgpn_len);
2071
2072     /* print error code */
2073     proto_tree_add_text(tree, tvb,
2074         offset + offsetof(struct bgp_notification, bgpn_major), 1,
2075         "Error code: %s (%u)",
2076         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
2077         bgpn.bgpn_major);
2078
2079     /* print error subcode */
2080     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
2081      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
2082         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
2083             "Unknown");
2084     } else if (bgpn.bgpn_minor == 0)
2085         p = "Unspecified";
2086     else
2087         p = "Unknown";
2088     proto_tree_add_text(tree, tvb,
2089         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
2090         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
2091
2092     /* only print if there is optional data */
2093     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
2094         proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
2095             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
2096     }
2097 }
2098
2099 /*
2100  * Dissect a BGP ROUTE-REFRESH message.
2101  */
2102 static void
2103 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
2104 {
2105     guint16         i;    /* tmp            */
2106     int             p;         /* tvb offset counter    */
2107     int             pend;       /* end of list of entries for one orf type */
2108     guint16         hlen;       /* tvb RR msg length */
2109     proto_item      *ti;       /* tree item             */
2110     proto_item      *ti1;       /* tree item             */
2111     proto_tree      *subtree;  /* tree for orf   */
2112     proto_tree      *subtree1; /* tree for orf entry */
2113     guint8          orftype;        /* ORF Type */
2114     guint8          orfwhen;        /* ORF flag: immediate, defer */
2115     guint16         orflen;         /* ORF len */
2116     guint8          entryflag;      /* ORF Entry flag: action(add,del,delall) match(permit,deny) */
2117     guint32         entryseq;       /* ORF Entry sequence number */
2118     int             entrylen;       /* ORF Entry length */
2119     guint8          pfx_ge;         /* ORF PrefixList mask lower bound */
2120     guint8          pfx_le;         /* ORF PrefixList mask upper bound */
2121     char            pfxbuf[20];     /* ORF PrefixList prefix string buffer */
2122     int             pfx_masklen;    /* ORF PRefixList prefix mask length */
2123
2124
2125 /*
2126 example 1
2127  00 1c 05       hlen=28
2128  00 01 00 01    afi,safi= ipv4-unicast
2129  02 80 00 01    defer, prefix-orf, len=1
2130     80            removeall
2131 example 2
2132  00 25 05       hlen=37
2133  00 01 00 01    afi,saif= ipv4-unicast
2134  01 80 00 0a    immediate, prefix-orf, len=10
2135     00            add
2136     00 00 00 05   seqno = 5
2137     12            ge = 18
2138     18            le = 24
2139     10 07 02      prefix = 7.2.0.0/16
2140 */
2141     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2142     p = offset + BGP_HEADER_SIZE;
2143     /* AFI */
2144     i = tvb_get_ntohs(tvb, p);
2145     proto_tree_add_text(tree, tvb, p, 2,
2146                         "Address family identifier: %s (%u)",
2147                         val_to_str(i, afn_vals, "Unknown"), i);
2148     p += 2;
2149     /* Reserved */
2150     proto_tree_add_text(tree, tvb, p, 1,
2151                         "Reserved: 1 byte");
2152     p++;
2153     /* SAFI */
2154     i = tvb_get_guint8(tvb, p);
2155     proto_tree_add_text(tree, tvb, p, 1,
2156                         "Subsequent address family identifier: %s (%u)",
2157                         val_to_str(i, bgpattr_nlri_safi,
2158                         i >= 128 ? "Vendor specific" : "Unknown"),
2159                         i);
2160     p++;
2161     if ( hlen == BGP_HEADER_SIZE + 4 )
2162         return;
2163     while (p < offset + hlen) {
2164         /* ORF type */
2165         orfwhen = tvb_get_guint8(tvb, p);
2166         orftype = tvb_get_guint8(tvb, p+1);
2167         orflen = tvb_get_ntohs(tvb, p+2);
2168         ti = proto_tree_add_text(tree, tvb, p , orflen + 4 , "ORF information (%u bytes)", orflen + 4);
2169         subtree = proto_item_add_subtree(ti, ett_bgp_orf);
2170         proto_tree_add_text(subtree, tvb, p , 1, "ORF flag: %s", val_to_str(orfwhen, orf_when_vals,"UNKNOWN"));
2171         proto_tree_add_text(subtree, tvb, p+1 , 1, "ORF type: %s", val_to_str(orftype, orf_type_vals,"UNKNOWN"));
2172         proto_tree_add_text(subtree, tvb, p+2 , 2, "ORF len: %u %s", orflen, (orflen == 1) ? "byte" : "bytes");
2173         p += 4;
2174
2175         if (orftype != BGP_ORF_PREFIX_CISCO){
2176                 proto_tree_add_text(subtree, tvb, p, orflen, "ORFEntry-Unknown (%u bytes)", orflen);
2177                 p += orflen;
2178                 continue;
2179         }
2180         pend = p + orflen;
2181         while (p < pend) {
2182                 entryflag = tvb_get_guint8(tvb, p);
2183                 if ((entryflag & BGP_ORF_ACTION) == BGP_ORF_REMOVEALL) {
2184                         ti1 = proto_tree_add_text(subtree, tvb, p, 1, "ORFEntry-PrefixList (1 byte)");
2185                         subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2186                         proto_tree_add_text(subtree1, tvb, p , 1, "RemoveAll");
2187                         p++;
2188                 } else {
2189                         entryseq = tvb_get_ntohl(tvb, p+1);
2190                         pfx_ge = tvb_get_guint8(tvb, p+5);
2191                         pfx_le = tvb_get_guint8(tvb, p+6);
2192                         /* calc len */
2193                         decode_prefix4(tvb,  p+7, pfxbuf, sizeof(pfxbuf));
2194                         pfx_masklen = tvb_get_guint8(tvb, p+7);
2195                         entrylen = 7+ 1 + (pfx_masklen+7)/8;
2196                         ti1 = proto_tree_add_text(subtree, tvb, p, entrylen, "ORFEntry-PrefixList (%u bytes)", entrylen);
2197                         subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2198                         proto_tree_add_text(subtree1, tvb, p , 1, "ACTION: %s MATCH: %s",
2199                          val_to_str(entryflag&BGP_ORF_ACTION, orf_entry_action_vals,"UNKNOWN"),
2200                          val_to_str(entryflag&BGP_ORF_MATCH, orf_entry_match_vals,"UNKNOWN"));
2201                         p++;
2202                         proto_tree_add_text(subtree1, tvb, p , 4, "Entry Sequence No: %u", entryseq);
2203                         p += 4;
2204                         proto_tree_add_text(subtree1, tvb, p , 1, "PrefixMask length lower bound: %u", pfx_ge);
2205                         p++;
2206                         proto_tree_add_text(subtree1, tvb, p , 1, "PrefixMask length upper bound: %u", pfx_le);
2207                         p++;
2208                         proto_tree_add_text(subtree1, tvb, p , 1 + (pfx_masklen+7)/8, "Prefix: %s", pfxbuf);
2209                         p+= 1 + (pfx_masklen+7)/8;
2210                 }
2211         }
2212     }
2213 }
2214
2215 /*
2216  * Dissect a BGP CAPABILITY message.
2217  */
2218 static void
2219 dissect_bgp_capability(tvbuff_t *tvb, int offset, proto_tree *tree)
2220 {
2221     proto_item *ti;
2222     proto_tree *subtree;
2223     guint8  action;
2224     int ctype;
2225     int clen;
2226     int mend;
2227
2228     mend = offset + tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2229     offset += BGP_HEADER_SIZE;
2230     /* step through all of the capabilities */
2231     while (offset < mend) {
2232         action = tvb_get_guint8(tvb, offset++);
2233         ctype  = tvb_get_guint8(tvb, offset++);
2234         clen   = tvb_get_guint8(tvb, offset++);
2235
2236         ti = proto_tree_add_text(tree, tvb, offset - 2, 2 + clen, 
2237              "%s (%u %s)", val_to_str(ctype, capability_vals,
2238              "Unknown capability"), 2 + clen, (clen == 1) ? "byte" : "bytes");
2239         subtree = proto_item_add_subtree(ti, ett_bgp_option);
2240         proto_tree_add_text(subtree, tvb, offset-2, 1, "Action: %d (%s)",
2241             action, val_to_str(action, bgpcap_action, "Invalid action value"));
2242         dissect_bgp_capability_item(tvb, &offset, subtree, ctype, clen);
2243     }
2244 }
2245
2246
2247 /*
2248  * Dissect a BGP packet.
2249  */
2250 static void
2251 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2252 {
2253     proto_item    *ti;           /* tree item                        */
2254     proto_tree    *bgp_tree;     /* BGP packet tree                  */
2255     proto_tree    *bgp1_tree;    /* BGP message tree                 */
2256     int           l, i;          /* tmp                              */
2257     int           found;         /* number of BGP messages in packet */
2258     static guchar marker[] = {   /* BGP message marker               */
2259         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2260         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2261     };
2262     guint8        bgp_marker[BGP_MARKER_SIZE];    /* Marker (should be all ones */
2263     guint16       bgp_len;                        /* Message length             */
2264     guint8        bgp_type;                       /* Message type               */
2265
2266     char          *typ;                           /* Message type (string)      */
2267
2268     if (check_col(pinfo->cinfo, COL_PROTOCOL))
2269         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BGP");
2270     if (check_col(pinfo->cinfo, COL_INFO))
2271         col_clear(pinfo->cinfo, COL_INFO);
2272
2273     l = tvb_reported_length(tvb);
2274     i = 0;
2275     found = -1;
2276     /* run through the TCP packet looking for BGP headers         */
2277     while (i + BGP_HEADER_SIZE <= l) {
2278         tvb_memcpy(tvb, bgp_marker, i, BGP_MARKER_SIZE);
2279         bgp_len = tvb_get_ntohs(tvb, i + BGP_MARKER_SIZE);
2280         bgp_type = tvb_get_guint8(tvb, i + BGP_MARKER_SIZE + 2);
2281
2282         /* look for bgp header */
2283         if (memcmp(bgp_marker, marker, sizeof(marker)) != 0) {
2284             i++;
2285             continue;
2286         }
2287
2288         found++;
2289
2290         /*
2291          * Desegmentation check.
2292          */
2293         if (bgp_desegment) {
2294             if (bgp_len > tvb_length_remaining(tvb, i) && pinfo->can_desegment) {
2295                 /*
2296                  * Not all of this packet is in the data we've been
2297                  * handed, but we can do reassembly on it.
2298                  *
2299                  * Tell the TCP dissector where the data for
2300                  * this message starts in the data it handed
2301                  * us, and how many more bytes we need, and
2302                  * return.
2303                  */
2304                 pinfo->desegment_offset = i;
2305                 pinfo->desegment_len = bgp_len - tvb_length_remaining(tvb, i);
2306                 return;
2307             }
2308         }
2309
2310         typ = val_to_str(bgp_type, bgptypevals, "Unknown Message");
2311
2312         if (check_col(pinfo->cinfo, COL_INFO)) {
2313             if (found == 0)
2314                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", typ);
2315             else
2316                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", typ);
2317         }
2318
2319         if (tree) {
2320             ti = proto_tree_add_item(tree, proto_bgp, tvb, i, bgp_len, FALSE);
2321             bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2322
2323             ti = proto_tree_add_text(bgp_tree, tvb, i, bgp_len, "%s", typ);
2324
2325             /* add a different tree for each message type */
2326             switch (bgp_type) {
2327             case BGP_OPEN:
2328                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
2329                 break;
2330             case BGP_UPDATE:
2331                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
2332                 break;
2333             case BGP_NOTIFICATION:
2334                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
2335                 break;
2336             case BGP_KEEPALIVE:
2337                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2338                 break;
2339             case BGP_ROUTE_REFRESH_CISCO:
2340             case BGP_ROUTE_REFRESH:
2341                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
2342                 break;
2343             case BGP_CAPABILITY:
2344                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_capability);
2345                 break;
2346             default:
2347                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2348                 break;
2349             }
2350
2351             proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
2352                 "Marker: 16 bytes");
2353
2354             if (bgp_len < BGP_HEADER_SIZE || bgp_len > BGP_MAX_PACKET_SIZE) {
2355                 proto_tree_add_text(bgp1_tree, tvb,
2356                     i + BGP_MARKER_SIZE, 2,
2357                     "Length (invalid): %u %s", bgp_len,
2358                     (bgp_len == 1) ? "byte" : "bytes");
2359                 return;
2360             } else {
2361                 proto_tree_add_text(bgp1_tree, tvb,
2362                     i + BGP_MARKER_SIZE, 2,
2363                     "Length: %u %s", bgp_len,
2364                     (bgp_len == 1) ? "byte" : "bytes");
2365             }
2366
2367             proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
2368                                        i + BGP_MARKER_SIZE + 2, 1,
2369                                        bgp_type,
2370                                        "Type: %s (%u)", typ, bgp_type);
2371
2372             switch (bgp_type) {
2373             case BGP_OPEN:
2374                 dissect_bgp_open(tvb, i, bgp1_tree);
2375                 break;
2376             case BGP_UPDATE:
2377                 dissect_bgp_update(tvb, i, bgp1_tree);
2378                 break;
2379             case BGP_NOTIFICATION:
2380                 dissect_bgp_notification(tvb, i, bgp1_tree);
2381                 break;
2382             case BGP_KEEPALIVE:
2383                 /* no data in KEEPALIVE messages */
2384                 break;
2385             case BGP_ROUTE_REFRESH_CISCO:
2386             case BGP_ROUTE_REFRESH:
2387                 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
2388                 break;
2389             case BGP_CAPABILITY:
2390                 dissect_bgp_capability(tvb, i, bgp1_tree);
2391                 break;
2392             default:
2393                 break;
2394             }
2395         }
2396
2397         i += bgp_len;
2398     }
2399 }
2400
2401 /*
2402  * Register ourselves.
2403  */
2404 void
2405 proto_register_bgp(void)
2406 {
2407
2408     static hf_register_info hf[] = {
2409       { &hf_bgp_type,
2410         { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
2411           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
2412     };
2413
2414     static gint *ett[] = {
2415       &ett_bgp,
2416       &ett_bgp_unfeas,
2417       &ett_bgp_attrs,
2418       &ett_bgp_attr,
2419       &ett_bgp_attr_flags,
2420       &ett_bgp_mp_nhna,
2421       &ett_bgp_mp_reach_nlri,
2422       &ett_bgp_mp_unreach_nlri,
2423       &ett_bgp_mp_snpa,
2424       &ett_bgp_nlri,
2425       &ett_bgp_open,
2426       &ett_bgp_update,
2427       &ett_bgp_notification,
2428       &ett_bgp_route_refresh,
2429       &ett_bgp_capability,
2430       &ett_bgp_as_paths,
2431       &ett_bgp_communities,
2432       &ett_bgp_cluster_list,
2433       &ett_bgp_options,
2434       &ett_bgp_option,
2435       &ett_bgp_extended_communities,
2436       &ett_bgp_orf,
2437       &ett_bgp_orf_entry
2438     };
2439     module_t *bgp_module;
2440     static enum_val_t asn_len[] = {
2441         {"Auto-detect", 0},
2442         {"2 octet", 2},
2443         {"4 octet", 4},
2444         {NULL, -1}
2445     };
2446
2447     proto_bgp = proto_register_protocol("Border Gateway Protocol",
2448                                         "BGP", "bgp");
2449     proto_register_field_array(proto_bgp, hf, array_length(hf));
2450     proto_register_subtree_array(ett, array_length(ett));
2451
2452     bgp_module = prefs_register_protocol(proto_bgp, NULL);
2453     prefs_register_bool_preference(bgp_module, "desegment",
2454       "Desegment all BGP messages spanning multiple TCP segments",
2455       "Whether the BGP dissector should desegment all messages spanning multiple TCP segments",
2456       &bgp_desegment);
2457     prefs_register_enum_preference(bgp_module, "asn_len",
2458       "Length of the AS number",
2459       "BGP dissector detect the length of the AS number in AS_PATH attributes automatically or manually (NOTE: Automatic detection is not 100% accurate)",
2460       &bgp_asn_len, asn_len, FALSE);
2461 }
2462
2463 void
2464 proto_reg_handoff_bgp(void)
2465 {
2466     dissector_handle_t bgp_handle;
2467
2468     bgp_handle = create_dissector_handle(dissect_bgp, proto_bgp);
2469     dissector_add("tcp.port", BGP_TCP_PORT, bgp_handle);
2470 }