955cdd3522fa1acda55fde0c8603083ed76930da
[obnox/wireshark/wip.git] / epan / dissectors / 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$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25 /* Supports:
26  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
27  * RFC1965 Autonomous System Confederations for BGP
28  * RFC1997 BGP Communities Attribute
29  * RFC2547 BGP/MPLS VPNs
30  * RFC2796 BGP Route Reflection An alternative to full mesh IBGP
31  * RFC2842 Capabilities Advertisement with BGP-4
32  * RFC2858 Multiprotocol Extensions for BGP-4
33  * RFC2918 Route Refresh Capability for BGP-4
34  * RFC3107 Carrying Label Information in BGP-4
35  * draft-ietf-idr-as4bytes-06
36  * draft-ietf-idr-dynamic-cap-03
37  * draft-ietf-idr-bgp-ext-communities-05
38  * draft-knoll-idr-qos-attribute-03
39  *
40  * TODO:
41  * Destination Preference Attribute for BGP (work in progress)
42  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
43  */
44
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51
52 #include <string.h>
53 #include <glib.h>
54
55 #include <epan/packet.h>
56 #include <epan/addr_and_mask.h>
57 #include "packet-bgp.h"
58 #include "packet-ipv6.h"
59 #include "packet-frame.h"
60 #include <epan/afn.h>
61 #include <epan/prefs.h>
62 #include <epan/emem.h>
63
64 /* #define MAX_STR_LEN 256 */
65
66 static const value_string bgptypevals[] = {
67     { BGP_OPEN, "OPEN Message" },
68     { BGP_UPDATE, "UPDATE Message" },
69     { BGP_NOTIFICATION, "NOTIFICATION Message" },
70     { BGP_KEEPALIVE, "KEEPALIVE Message" },
71     { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
72     { BGP_CAPABILITY, "CAPABILITY Message" },
73     { BGP_ROUTE_REFRESH_CISCO, "Cisco ROUTE-REFRESH Message" },
74     { 0, NULL }
75 };
76
77 static const value_string bgpnotify_major[] = {
78     { 1, "Message Header Error" },
79     { 2, "OPEN Message Error" },
80     { 3, "UPDATE Message Error" },
81     { 4, "Hold Timer Expired" },
82     { 5, "Finite State Machine Error" },
83     { 6, "Cease" },
84     { 7, "CAPABILITY Message Error" },
85     { 0, NULL }
86 };
87
88 static const value_string bgpnotify_minor_1[] = {
89     { 1, "Connection Not Synchronized" },
90     { 2, "Bad Message Length" },
91     { 3, "Bad Message Type" },
92     { 0, NULL }
93 };
94
95 static const value_string bgpnotify_minor_2[] = {
96     { 1, "Unsupported Version Number" },
97     { 2, "Bad Peer AS" },
98     { 3, "Bad BGP Identifier" },
99     { 4, "Unsupported Optional Parameter" },
100     { 5, "Authentication Failure" },
101     { 6, "Unacceptable Hold Time" },
102     { 7, "Unsupported Capability" },
103     { 0, NULL }
104 };
105
106 static const value_string bgpnotify_minor_3[] = {
107     { 1, "Malformed Attribute List" },
108     { 2, "Unrecognized Well-known Attribute" },
109     { 3, "Missing Well-known Attribute" },
110     { 4, "Attribute Flags Error" },
111     { 5, "Attribute Length Error" },
112     { 6, "Invalid ORIGIN Attribute" },
113     { 7, "AS Routing Loop" },
114     { 8, "Invalid NEXT_HOP Attribute" },
115     { 9, "Optional Attribute Error" },
116     { 10, "Invalid Network Field" },
117     { 11, "Malformed AS_PATH" },
118     { 0, NULL }
119 };
120
121 /* draft-ietf-idr-cease-subcode-02 */
122 static const value_string bgpnotify_minor_6[] = {
123     { 1,                        "Maximum Number of Prefixes Reached"},
124     { 2,                        "Administratively Shutdown"},
125     { 3,                        "Peer Unconfigured"},
126     { 4,                        "Administratively Reset"},
127     { 5,                        "Connection Rejected"},
128     { 6,                        "Other Configuration Change"},
129     { 7,                        "Connection Collision Resolution"},
130     { 0, NULL }
131 };
132
133 static const value_string bgpnotify_minor_7[] = {
134     { 1, "Invalid Action Value" },
135     { 2, "Invalid Capability Length" },
136     { 3, "Malformed Capability Value" },
137     { 4, "Unsupported Capability Code" },
138     { 0, NULL }
139 };
140
141 static const value_string *bgpnotify_minor[] = {
142     NULL,
143     bgpnotify_minor_1, /* open */
144     bgpnotify_minor_2, /* update */
145     bgpnotify_minor_3, /* notification */
146     NULL,              /* hold-timer expired */
147     NULL,              /* FSM error */
148     bgpnotify_minor_6, /* cease */
149     bgpnotify_minor_7  /* capability */
150 };
151
152 static const value_string bgpattr_origin[] = {
153     { 0, "IGP" },
154     { 1, "EGP" },
155     { 2, "INCOMPLETE" },
156     { 0, NULL }
157 };
158
159 static const value_string as_segment_type[] = {
160     { 1, "AS_SET" },
161     { 2, "AS_SEQUENCE" },
162 /* RFC1965 has the wrong values, corrected in  */
163 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
164     { 4, "AS_CONFED_SET" },
165     { 3, "AS_CONFED_SEQUENCE" },
166     { 0, NULL }
167 };
168
169 static const value_string bgpattr_type[] = {
170     { BGPTYPE_ORIGIN, "ORIGIN" },
171     { BGPTYPE_AS_PATH, "AS_PATH" },
172     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
173     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
174     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
175     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
176     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
177     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
178     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
179     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
180     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
181     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
182     { BGPTYPE_EXTENDED_COMMUNITY, "EXTENDED_COMMUNITIES" },
183     { BGPTYPE_NEW_AS_PATH, "NEW_AS_PATH" },
184     { BGPTYPE_NEW_AGGREGATOR, "NEW_AGGREGATOR" },
185     { BGPTYPE_SAFI_SPECIFIC_ATTR, "SAFI_SPECIFIC_ATTRIBUTE" },
186     { 0, NULL }
187 };
188
189 static const value_string bgpext_com8_type[] = {
190     { BGP_EXT_COM_QOS_MARK_T, "QoS Marking - transitive" },
191     { BGP_EXT_COM_QOS_MARK_NT, "QoS Marking - non-transitive" },
192     { BGP_EXT_COM_COS_CAP_T, "CoS Capability - transitive" },
193     { 0, NULL }
194 };
195
196 static const value_string bgpext_com_type[] = {
197     { BGP_EXT_COM_RT_0, "Route Target" },
198     { BGP_EXT_COM_RT_1, "Route Target" },
199     { BGP_EXT_COM_RT_2, "Route Target" },
200     { BGP_EXT_COM_RO_0, "Route Origin" },
201     { BGP_EXT_COM_RO_1, "Route Origin" },
202     { BGP_EXT_COM_RO_2, "Route Origin" },
203     { BGP_EXT_COM_LINKBAND, "Link Bandwidth" },
204     { BGP_EXT_COM_VPN_ORIGIN, "OSPF Domain" },
205     { BGP_EXT_COM_OSPF_RTYPE, "OSPF Route Type" },
206     { BGP_EXT_COM_OSPF_RID, "OSPF Router ID" },
207     { BGP_EXT_COM_L2INFO, "Layer 2 Information" },
208     { 0, NULL }
209 };
210
211 static const value_string qos_tech_type[] = {
212     { QOS_TECH_TYPE_DSCP, "DiffServ enabled IP (DSCP encoding)" },
213     { QOS_TECH_TYPE_802_1q, "Ethernet using 802.1q priority tag" },
214     { QOS_TECH_TYPE_E_LSP, "MPLS using E-LSP" },
215     { QOS_TECH_TYPE_VC, "Virtual Channel (VC) encoding" },
216     { QOS_TECH_TYPE_GMPLS_TIME, "GMPLS - time slot encoding" },
217     { QOS_TECH_TYPE_GMPLS_LAMBDA, "GMPLS - lambda encoding" },
218     { QOS_TECH_TYPE_GMPLS_FIBRE, "GMPLS - fibre encoding" },
219     { 0, NULL }
220 };
221
222 static const value_string bgp_ssa_type[] = {
223     { BGP_SSA_L2TPv3 , "L2TPv3 Tunnel" },
224     { BGP_SSA_mGRE , "mGRE Tunnel" },
225     { BGP_SSA_IPSec , "IPSec Tunnel" },
226     { BGP_SSA_MPLS , "MPLS Tunnel" },
227     { 0, NULL }
228 };
229
230 static const value_string bgp_l2vpn_encaps[] = {
231     { 0,                      "Reserved"},
232     { 1,                      "Frame Relay"},
233     { 2,                      "ATM AAL5 VCC transport"},
234     { 3,                      "ATM transparent cell transport"},
235     { 4,                      "Ethernet VLAN"},
236     { 5,                      "Ethernet"},
237     { 6,                      "Cisco-HDLC"},
238     { 7,                      "PPP"},
239     { 8,                      "CEM"},
240     { 9,                      "ATM VCC cell transport"},
241     { 10,                     "ATM VPC cell transport"},
242     { 11,                     "MPLS"},
243     { 12,                     "VPLS"},
244     { 64,                     "IP-interworking"},
245     { 0, NULL }
246 };
247
248 static const value_string bgpext_ospf_rtype[] = {
249   { BGP_OSPF_RTYPE_RTR, "Router" },
250   { BGP_OSPF_RTYPE_NET, "Network" },
251   { BGP_OSPF_RTYPE_SUM, "Summary" },
252   { BGP_OSPF_RTYPE_EXT, "External" },
253   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
254   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
255   { 0, NULL }
256 };
257
258 /* Subsequent address family identifier, RFC2858 */
259 static const value_string bgpattr_nlri_safi[] = {
260     { 0, "Reserved" },
261     { SAFNUM_UNICAST, "Unicast" },
262     { SAFNUM_MULCAST, "Multicast" },
263     { SAFNUM_UNIMULC, "Unicast+Multicast" },
264     { SAFNUM_MPLS_LABEL, "Labeled Unicast"},
265     { SAFNUM_TUNNEL, "Tunnel"},
266     { SAFNUM_VPLS, "VPLS"},
267     { SAFNUM_LAB_VPNUNICAST, "Labeled VPN Unicast" },        /* draft-rosen-rfc2547bis-03 */
268     { SAFNUM_LAB_VPNMULCAST, "Labeled VPN Multicast" },
269     { SAFNUM_LAB_VPNUNIMULC, "Labeled VPN Unicast+Multicast" },
270     { 0, NULL }
271 };
272
273 /* ORF Type, draft-ietf-idr-route-filter-04.txt */
274 static const value_string orf_type_vals[] = {
275     { 2,        "Communities ORF-Type" },
276     { 3,        "Extended Communities ORF-Type" },
277     { 128,      "Cisco PrefixList ORF-Type" },
278     { 129,      "Cisco CommunityList ORF-Type" },
279     { 130,      "Cisco Extended CommunityList ORF-Type" },
280     { 131,      "Cisco AsPathList ORF-Type" },
281     { 0,        NULL }
282 };
283
284 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
285 static const value_string orf_send_recv_vals[] = {
286     { 1,        "Receive" },
287     { 2,        "Send" },
288     { 3,        "Both" },
289     { 0,        NULL }
290 };
291
292 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
293 static const value_string orf_when_vals[] = {
294     { 1,        "Immediate" },
295     { 2,        "Defer" },
296     { 0,        NULL }
297 };
298
299 static const value_string orf_entry_action_vals[] = {
300     { 0,        "Add" },
301     { 0x40,     "Remove" },
302     { 0x80,     "RemoveAll" },
303     { 0,        NULL }
304 };
305
306 static const value_string orf_entry_match_vals[] = {
307     { 0,        "Permit" },
308     { 0x20,     "Deny" },
309     { 0,        NULL }
310 };
311
312 static const value_string capability_vals[] = {
313     { BGP_CAPABILITY_RESERVED, "Reserved capability" },
314     { BGP_CAPABILITY_MULTIPROTOCOL, "Multiprotocol extensions capability" },
315     { BGP_CAPABILITY_ROUTE_REFRESH, "Route refresh capability" },
316     { BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING, "Cooperative route filtering capability" },
317     { BGP_CAPABILITY_GRACEFUL_RESTART, "Graceful Restart capability" },
318     { BGP_CAPABILITY_4_OCTET_AS_NUMBER, "Support for 4-octet AS number capability" },
319     { BGP_CAPABILITY_DYNAMIC_CAPABILITY, "Support for Dynamic capability" },
320     { BGP_CAPABILITY_ROUTE_REFRESH_CISCO, "Route refresh capability" },
321     { BGP_CAPABILITY_ORF_CISCO, "Cooperative route filtering capability" },
322     { 0, NULL }
323 };
324
325 /* Capability Message action code */
326 static const value_string bgpcap_action[] = {
327     { 0, "advertising a capability" },
328     { 1, "removing a capability" },
329     { 0, NULL }
330 };
331
332
333 /* Maximal size of an IP address string */
334 #define MAX_SIZE_OF_IP_ADDR_STRING      16
335
336 static int proto_bgp = -1;
337 static int hf_bgp_type = -1;
338 static int hf_bgp_next_hop = -1;
339 static int hf_bgp_as_path = -1;
340 static int hf_bgp_cluster_identifier = -1;
341 static int hf_bgp_community_as = -1;
342 static int hf_bgp_community_value = -1;
343 static int hf_bgp_origin = -1;
344 static int hf_bgp_cluster_list = -1;
345 static int hf_bgp_originator_id = -1;
346 static int hf_bgp_ssa_t = -1;
347 static int hf_bgp_ssa_type = -1;
348 static int hf_bgp_ssa_len = -1;
349 static int hf_bgp_ssa_value = -1;
350 static int hf_bgp_ssa_l2tpv3_pref = -1;
351 static int hf_bgp_ssa_l2tpv3_s = -1;
352 static int hf_bgp_ssa_l2tpv3_unused = -1;
353 static int hf_bgp_ssa_l2tpv3_cookie_len = -1;
354 static int hf_bgp_ssa_l2tpv3_session_id = -1;
355 static int hf_bgp_ssa_l2tpv3_cookie = -1;
356 static int hf_bgp_local_pref = -1;
357 static int hf_bgp_multi_exit_disc = -1;
358 static int hf_bgp_aggregator_as = -1;
359 static int hf_bgp_aggregator_origin = -1;
360 static int hf_bgp_mp_reach_nlri_ipv4_prefix = -1;
361 static int hf_bgp_mp_unreach_nlri_ipv4_prefix = -1;
362 static int hf_bgp_mp_nlri_tnl_id = -1;
363 static int hf_bgp_withdrawn_prefix = -1;
364 static int hf_bgp_nlri_prefix = -1;
365
366 static gint ett_bgp = -1;
367 static gint ett_bgp_prefix = -1;
368 static gint ett_bgp_unfeas = -1;
369 static gint ett_bgp_attrs = -1;
370 static gint ett_bgp_attr = -1;
371 static gint ett_bgp_attr_flags = -1;
372 static gint ett_bgp_mp_nhna = -1;
373 static gint ett_bgp_mp_reach_nlri = -1;
374 static gint ett_bgp_mp_unreach_nlri = -1;
375 static gint ett_bgp_mp_snpa = -1;
376 static gint ett_bgp_nlri = -1;
377 static gint ett_bgp_open = -1;
378 static gint ett_bgp_update = -1;
379 static gint ett_bgp_notification = -1;
380 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
381 static gint ett_bgp_capability = -1;
382 static gint ett_bgp_as_paths = -1;
383 static gint ett_bgp_as_path_segments = -1;
384 static gint ett_bgp_communities = -1;
385 static gint ett_bgp_cluster_list = -1;  /* cluster list tree          */
386 static gint ett_bgp_options = -1;       /* optional parameters tree   */
387 static gint ett_bgp_option = -1;        /* an optional parameter tree */
388 static gint ett_bgp_extended_communities = -1; /* extended communities list tree */
389 static gint ett_bgp_ext_com_flags = -1; /* extended communities flags tree */
390 static gint ett_bgp_ssa = -1;           /* safi specific attribute */
391 static gint ett_bgp_ssa_subtree = -1;   /* safi specific attribute Subtrees */
392 static gint ett_bgp_orf = -1;           /* orf (outbound route filter) tree */
393 static gint ett_bgp_orf_entry = -1;             /* orf entry tree */
394
395 /* desegmentation */
396 static gboolean bgp_desegment = TRUE;
397
398 static gint bgp_asn_len = 0;
399
400 /*
401  * Decode an IPv4 prefix.
402  */
403 static int
404 decode_prefix4(proto_tree *tree, int hf_addr, tvbuff_t *tvb, gint offset,
405     guint16 tlen, const char *tag)
406 {
407     proto_item *ti;
408     proto_tree *prefix_tree;
409     union {
410        guint8 addr_bytes[4];
411        guint32 addr;
412     } ip_addr;        /* IP address                         */
413     guint8 plen;      /* prefix length                      */
414     int    length;    /* number of octets needed for prefix */
415
416     /* snarf length and prefix */
417     plen = tvb_get_guint8(tvb, offset);
418     length = ipv4_addr_and_mask(tvb, offset + 1, ip_addr.addr_bytes, plen);
419     if (length < 0) {
420         proto_tree_add_text(tree, tvb, offset, 1, "%s length %u invalid (> 32)",
421             tag, plen);
422         return -1;
423     }
424
425     /* put prefix into protocol tree */
426     ti = proto_tree_add_text(tree, tvb, offset,
427             tlen != 0 ? tlen : 1 + length, "%s/%u",
428         ip_to_str(ip_addr.addr_bytes), plen);
429     prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
430     proto_tree_add_text(prefix_tree, tvb, offset, 1, "%s prefix length: %u",
431         tag, plen);
432     if (hf_addr != -1) {
433         proto_tree_add_ipv4(prefix_tree, hf_addr, tvb, offset + 1, length,
434             ip_addr.addr);
435     } else {
436         proto_tree_add_text(prefix_tree, tvb, offset + 1, length,
437             "%s prefix: %s", tag, ip_to_str(ip_addr.addr_bytes));
438     }
439     return(1 + length);
440 }
441
442 /*
443  * Decode an IPv6 prefix.
444  */
445 static int
446 decode_prefix6(proto_tree *tree, int hf_addr, tvbuff_t *tvb, gint offset,
447     guint16 tlen, const char *tag)
448 {
449     proto_item        *ti;
450     proto_tree        *prefix_tree;
451     struct e_in6_addr addr;     /* IPv6 address                       */
452     int               plen;     /* prefix length                      */
453     int               length;   /* number of octets needed for prefix */
454
455     /* snarf length and prefix */
456     plen = tvb_get_guint8(tvb, offset);
457     length = ipv6_addr_and_mask(tvb, offset + 1, &addr, plen);
458     if (length < 0) {
459         proto_tree_add_text(tree, tvb, offset, 1, "%s length %u invalid",
460             tag, plen);
461         return -1;
462     }
463
464     /* put prefix into protocol tree */
465     ti = proto_tree_add_text(tree, tvb, offset,
466             tlen != 0 ? tlen : 1 + length, "%s/%u",
467             ip6_to_str(&addr), plen);
468     prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
469     proto_tree_add_text(prefix_tree, tvb, offset, 1, "%s prefix length: %u",
470         tag, plen);
471     if (hf_addr != -1) {
472         proto_tree_add_ipv6(prefix_tree, hf_addr, tvb, offset + 1, length,
473             addr.bytes);
474     } else {
475         proto_tree_add_text(prefix_tree, tvb, offset + 1, length,
476             "%s prefix: %s", tag, ip6_to_str(&addr));
477     }
478     return(1 + length);
479 }
480
481
482
483 /*
484  * Decode an MPLS label stack
485  * XXX - We should change *buf to **buf, use ep_alloc() and drop the buflen
486  * argument.
487  */
488 static guint
489 decode_MPLS_stack(tvbuff_t *tvb, gint offset, emem_strbuf_t *stack_strbuf)
490 {
491     guint32     label_entry;    /* an MPLS label enrty (label + COS field + stack bit   */
492     gint        indx;          /* index for the label stack */
493
494     indx = offset ;
495     label_entry = 0x000000 ;
496
497     ep_strbuf_truncate(stack_strbuf, 0);
498
499     while ((label_entry & 0x000001) == 0) {
500
501         label_entry = tvb_get_ntoh24(tvb, indx) ;
502
503         /* withdrawn routes may contain 0 or 0x800000 in the first label */
504         if((indx-offset)==0&&(label_entry==0||label_entry==0x800000)) {
505             ep_strbuf_append(stack_strbuf, "0 (withdrawn)");
506             return (1);
507         }
508
509         ep_strbuf_append_printf(stack_strbuf, "%u%s", label_entry >> 4,
510                 ((label_entry & 0x000001) == 0) ? "," : " (bottom)");
511
512         indx += 3 ;
513
514         if ((label_entry & 0x000001) == 0) {
515             /* real MPLS multi-label stack in BGP? - maybe later; for now, it must be a bogus packet */
516             ep_strbuf_append(stack_strbuf, " (BOGUS: Bottom of Stack NOT set!)");
517             break;
518         }
519     }
520
521     return((indx - offset) / 3);
522 }
523
524 /*
525  * Decode a multiprotocol address
526  */
527
528 static int
529 mp_addr_to_str (guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, emem_strbuf_t *strbuf)
530 {
531     int                 length;                         /* length of the address in byte */
532     guint32             ip4addr,ip4addr2;               /* IPv4 address                 */
533     guint16             rd_type;                        /* Route Distinguisher type     */
534     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
535
536     length = 0 ;
537     switch (afi) {
538         case AFNUM_INET:
539                 switch (safi) {
540                         case SAFNUM_UNICAST:
541                         case SAFNUM_MULCAST:
542                         case SAFNUM_UNIMULC:
543                         case SAFNUM_MPLS_LABEL:
544                         case SAFNUM_TUNNEL:
545                                 length = 4 ;
546                                 ip4addr = tvb_get_ipv4(tvb, offset);
547                                 ep_strbuf_append(strbuf, ip_to_str((guint8 *)&ip4addr));
548                                 break;
549                         case SAFNUM_LAB_VPNUNICAST:
550                         case SAFNUM_LAB_VPNMULCAST:
551                         case SAFNUM_LAB_VPNUNIMULC:
552                                 rd_type=tvb_get_ntohs(tvb,offset) ;
553                                 switch (rd_type) {
554                                         case FORMAT_AS2_LOC:
555                                                 length = 8 + sizeof(ip4addr);
556                                                 ip4addr = tvb_get_ipv4(tvb, offset + 8);   /* Next Hop */
557                                                 ep_strbuf_printf(strbuf, "Empty Label Stack RD=%u:%u IPv4=%s",
558                                                                 tvb_get_ntohs(tvb, offset + 2),
559                                                                 tvb_get_ntohl(tvb, offset + 4),
560                                                                 ip_to_str((guint8 *)&ip4addr));
561                                                 break;
562                                         case FORMAT_IP_LOC:
563                                                 length = 8 + sizeof(ip4addr);
564                                                 ip4addr = tvb_get_ipv4(tvb, offset + 2);   /* IP part of the RD            */
565                                                 ip4addr2 = tvb_get_ipv4(tvb, offset + 8);  /* Next Hop   */
566                                                 ep_strbuf_printf(strbuf, "Empty Label Stack RD=%s:%u IPv4=%s",
567                                                                 ip_to_str((guint8 *)&ip4addr),
568                                                                 tvb_get_ntohs(tvb, offset + 6),
569                                                                 ip_to_str((guint8 *)&ip4addr2));
570                                                 break ;
571                                         default:
572                                                 length = 0 ;
573                                                 ep_strbuf_printf(strbuf, "Unknown (0x%04x) labeled VPN IPv4 address format",rd_type);
574                                                 break;
575                                 }
576                                 break;
577                         default:
578                             length = 0 ;
579                             ep_strbuf_printf(strbuf, "Unknown SAFI (%u) for AFI %u", safi, afi);
580                             break;
581                 }
582                 break;
583         case AFNUM_INET6:
584                 switch (safi) {
585                         case SAFNUM_UNICAST:
586                         case SAFNUM_MULCAST:
587                         case SAFNUM_UNIMULC:
588                         case SAFNUM_MPLS_LABEL:
589                         case SAFNUM_TUNNEL:
590                             length = 16 ;
591                             tvb_get_ipv6(tvb, offset, &ip6addr);
592                             ep_strbuf_printf(strbuf, "%s", ip6_to_str(&ip6addr));
593                             break;
594                         case SAFNUM_LAB_VPNUNICAST:
595                         case SAFNUM_LAB_VPNMULCAST:
596                         case SAFNUM_LAB_VPNUNIMULC:
597                                 rd_type=tvb_get_ntohs(tvb,offset) ;
598                                 switch (rd_type) {
599                                         case FORMAT_AS2_LOC:
600                                                 length = 8 + 16;
601                                                 tvb_get_ipv6(tvb, offset + 8, &ip6addr); /* Next Hop */
602                                                 ep_strbuf_printf(strbuf, "Empty Label Stack RD=%u:%u IPv6=%s",
603                                                                 tvb_get_ntohs(tvb, offset + 2),
604                                                                 tvb_get_ntohl(tvb, offset + 4),
605                                                                 ip6_to_str(&ip6addr));
606                                                 break;
607                                         case FORMAT_IP_LOC:
608                                                 length = 8 + 16;
609                                                 ip4addr = tvb_get_ipv4(tvb, offset + 2);   /* IP part of the RD            */
610                                                 tvb_get_ipv6(tvb, offset + 8, &ip6addr); /* Next Hop */
611                                                 ep_strbuf_printf(strbuf, "Empty Label Stack RD=%s:%u IPv6=%s",
612                                                                 ip_to_str((guint8 *)&ip4addr),
613                                                                 tvb_get_ntohs(tvb, offset + 6),
614                                                                 ip6_to_str(&ip6addr));
615                                                 break ;
616                                         default:
617                                                 length = 0 ;
618                                                 ep_strbuf_printf(strbuf, "Unknown (0x%04x) labeled VPN IPv6 address format",rd_type);
619                                                 break;
620                                 }
621                                 break;
622                         default:
623                             length = 0 ;
624                             ep_strbuf_printf(strbuf, "Unknown SAFI (%u) for AFI %u", safi, afi);
625                             break;
626                 }
627                 break;
628        case AFNUM_L2VPN:
629        case AFNUM_L2VPN_OLD:
630                 switch (safi) {
631                         case SAFNUM_LAB_VPNUNICAST: /* only labeles prefixes do make sense */
632                         case SAFNUM_LAB_VPNMULCAST:
633                         case SAFNUM_LAB_VPNUNIMULC:
634                         case SAFNUM_VPLS:
635                             length = 4; /* the next-hop is simply an ipv4 addr */
636                             ip4addr = tvb_get_ipv4(tvb, offset + 0);
637                             ep_strbuf_printf(strbuf, "IPv4=%s",
638                                      ip_to_str((guint8 *)&ip4addr));
639                             break;
640                         default:
641                             length = 0 ;
642                             ep_strbuf_printf(strbuf, "Unknown SAFI (%u) for AFI %u", safi, afi);
643                             break;
644                 }
645                 break;
646         default:
647                 length = 0 ;
648                 ep_strbuf_printf(strbuf, "Unknown AFI (%u) value", afi);
649                 break;
650     }
651     return(length) ;
652 }
653
654 /*
655  * Decode a multiprotocol prefix
656  */
657 static int
658 decode_prefix_MP(proto_tree *tree, int hf_addr4, int hf_addr6,
659     guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, const char *tag)
660 {
661     int                 start_offset = offset;
662     proto_item          *ti;
663     proto_tree          *prefix_tree;
664     int                 total_length;       /* length of the entire item */
665     int                 length;             /* length of the prefix address, in bytes */
666     guint               plen;               /* length of the prefix address, in bits */
667     guint               labnum;             /* number of labels             */
668     guint16             tnl_id;             /* Tunnel Identifier */
669     int                 ce_id,labblk_off,labblk_size;
670     union {
671        guint8 addr_bytes[4];
672        guint32 addr;
673     } ip4addr, ip4addr2;                    /* IPv4 address                 */
674     struct e_in6_addr   ip6addr;            /* IPv6 address                 */
675     guint16             rd_type;            /* Route Distinguisher type     */
676     emem_strbuf_t      *stack_strbuf;       /* label stack                  */
677
678     switch (afi) {
679
680     case AFNUM_INET:
681         switch (safi) {
682
683         case SAFNUM_UNICAST:
684         case SAFNUM_MULCAST:
685         case SAFNUM_UNIMULC:
686             total_length = decode_prefix4(tree, hf_addr4, tvb, offset, 0, tag);
687             if (total_length < 0)
688                 return -1;
689             break;
690
691         case SAFNUM_MPLS_LABEL:
692             plen =  tvb_get_guint8(tvb, offset);
693             stack_strbuf = ep_strbuf_new_label(NULL);
694             labnum = decode_MPLS_stack(tvb, offset + 1, stack_strbuf);
695
696             offset += (1 + labnum * 3);
697             if (plen <= (labnum * 3*8)) {
698                 proto_tree_add_text(tree, tvb, start_offset, 1,
699                         "%s Labeled IPv4 prefix length %u invalid",
700                         tag, plen);
701                 return -1;
702             }
703             plen -= (labnum * 3*8);
704             length = ipv4_addr_and_mask(tvb, offset, ip4addr.addr_bytes, plen);
705             if (length < 0) {
706                 proto_tree_add_text(tree, tvb, start_offset, 1,
707                         "%s Labeled IPv4 prefix length %u invalid",
708                         tag, plen + (labnum * 3*8));
709                 return -1;
710             }
711
712             ti = proto_tree_add_text(tree, tvb, start_offset,
713                     (offset + length) - start_offset,
714                     "Label Stack=%s IPv4=%s/%u",
715                     stack_strbuf->str, ip_to_str(ip4addr.addr_bytes), plen);
716             prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
717             proto_tree_add_text(prefix_tree, tvb, start_offset, 1, "%s Prefix length: %u",
718                 tag, plen + labnum * 3 * 8);
719             proto_tree_add_text(prefix_tree, tvb, start_offset + 1, 3 * labnum, "%s Label Stack: %s",
720                 tag, stack_strbuf->str);
721             if (hf_addr4 != -1) {
722                 proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb, offset,
723                         length, ip4addr.addr);
724             } else {
725                 proto_tree_add_text(prefix_tree, tvb, offset, length,
726                         "%s IPv4 prefix: %s",
727                         tag, ip_to_str(ip4addr.addr_bytes));
728             }
729             total_length = (1 + labnum*3) + length;
730             break;
731
732         case SAFNUM_TUNNEL:
733             plen =  tvb_get_guint8(tvb, offset);
734             if (plen <= 16){
735                 proto_tree_add_text(tree, tvb, start_offset, 1,
736                         "%s Tunnel IPv4 prefix length %u invalid",
737                         tag, plen);
738                 return -1;
739             }
740             tnl_id = tvb_get_ntohs(tvb, offset + 1);
741             offset += 3; /* Length + Tunnel Id */
742             plen -= 16; /* 2-octet Identifier */
743             length = ipv4_addr_and_mask(tvb, offset, ip4addr.addr_bytes, plen);
744             if (length < 0) {
745                 proto_tree_add_text(tree, tvb, start_offset, 1,
746                         "%s Tunnel IPv4 prefix length %u invalid",
747                         tag, plen + 16);
748                 return -1;
749             }
750             ti = proto_tree_add_text(tree, tvb, start_offset,
751                         (offset + length) - start_offset,
752                         "Tunnel Identifier=0x%x IPv4=%s/%u",
753                         tnl_id, ip_to_str(ip4addr.addr_bytes), plen);
754             prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
755
756             proto_tree_add_text(prefix_tree, tvb, start_offset, 1, "%s Prefix length: %u",
757                 tag, plen + 16);
758             proto_tree_add_item(prefix_tree, hf_bgp_mp_nlri_tnl_id, tvb,
759                                 start_offset + 1, 2, FALSE);
760             if (hf_addr4 != -1) {
761                 proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb, offset,
762                                 length, ip4addr.addr);
763             } else {
764                 proto_tree_add_text(prefix_tree, tvb, offset, length,
765                         "%s IPv4 prefix: %s",
766                         tag, ip_to_str(ip4addr.addr_bytes));
767             }
768             total_length = 1 + 2 + length; /* length field + Tunnel Id + IPv4 len */
769             break;
770
771         case SAFNUM_LAB_VPNUNICAST:
772         case SAFNUM_LAB_VPNMULCAST:
773         case SAFNUM_LAB_VPNUNIMULC:
774             plen =  tvb_get_guint8(tvb, offset);
775             stack_strbuf = ep_strbuf_new_label(NULL);
776             labnum = decode_MPLS_stack(tvb, offset + 1, stack_strbuf);
777
778             offset += (1 + labnum * 3);
779             if (plen <= (labnum * 3*8)) {
780                 proto_tree_add_text(tree, tvb, start_offset, 1,
781                         "%s Labeled VPN IPv4 prefix length %u invalid",
782                         tag, plen);
783                 return -1;
784             }
785             plen -= (labnum * 3*8);
786
787             rd_type = tvb_get_ntohs(tvb, offset);
788             if (plen < 8*8) {
789                 proto_tree_add_text(tree, tvb, start_offset, 1,
790                         "%s Labeled VPN IPv4 prefix length %u invalid",
791                         tag, plen + (labnum * 3*8));
792                 return -1;
793             }
794             plen -= 8*8;
795
796             switch (rd_type) {
797
798             case FORMAT_AS2_LOC: /* Code borrowed from the decode_prefix4 function */
799                 length = ipv4_addr_and_mask(tvb, offset + 8, ip4addr.addr_bytes, plen);
800                 if (length < 0) {
801                     proto_tree_add_text(tree, tvb, start_offset, 1,
802                             "%s Labeled VPN IPv4 prefix length %u invalid",
803                             tag, plen + (labnum * 3*8) + 8*8);
804                     return -1;
805                 }
806
807                 ti = proto_tree_add_text(tree, tvb, start_offset,
808                         (offset + 8 + length) - start_offset,
809                         "Label Stack=%s RD=%u:%u, IPv4=%s/%u",
810                         stack_strbuf->str,
811                         tvb_get_ntohs(tvb, offset + 2),
812                         tvb_get_ntohl(tvb, offset + 4),
813                         ip_to_str(ip4addr.addr_bytes), plen);
814                 prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
815                 proto_tree_add_text(prefix_tree, tvb, start_offset, 1, "%s Prefix length: %u",
816                         tag, plen + labnum * 3 * 8 + 8 * 8);
817                 proto_tree_add_text(prefix_tree, tvb, start_offset + 1, 3 * labnum,
818                         "%s Label Stack: %s", tag, stack_strbuf->str);
819                 proto_tree_add_text(prefix_tree, tvb, start_offset + 1 + 3 * labnum, 8,
820                         "%s Route Distinguisher: %u:%u", tag, tvb_get_ntohs(tvb, offset + 2),
821                         tvb_get_ntohl(tvb, offset + 4));
822                 if (hf_addr4 != -1) {
823                     proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb,
824                             offset + 8, length, ip4addr.addr);
825                 } else {
826                     proto_tree_add_text(prefix_tree, tvb, offset + 8,
827                             length, "%s IPv4 prefix: %s", tag,
828                             ip_to_str(ip4addr.addr_bytes));
829                 }
830                 total_length = (1 + labnum * 3 + 8) + length;
831                 break;
832
833             case FORMAT_IP_LOC: /* Code borrowed from the decode_prefix4 function */
834                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 2, 4);
835
836                 length = ipv4_addr_and_mask(tvb, offset + 8, ip4addr2.addr_bytes, plen);
837                 if (length < 0) {
838                         proto_tree_add_text(tree, tvb, start_offset, 1,
839                                 "%s Labeled VPN IPv4 prefix length %u invalid",
840                                 tag, plen + (labnum * 3*8) + 8*8);
841                         return -1;
842                 }
843
844                 ti = proto_tree_add_text(tree, tvb, start_offset,
845                         (offset + 8 + length) - start_offset,
846                         "Label Stack=%s RD=%s:%u, IPv4=%s/%u",
847                         stack_strbuf->str,
848                         ip_to_str(ip4addr.addr_bytes),
849                         tvb_get_ntohs(tvb, offset + 6),
850                         ip_to_str(ip4addr2.addr_bytes),
851                         plen);
852                 prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
853                 proto_tree_add_text(prefix_tree, tvb, start_offset, 1, "%s Prefix length: %u",
854                         tag, plen + labnum * 3 * 8 + 8 * 8);
855                 proto_tree_add_text(prefix_tree, tvb, start_offset + 1, 3 * labnum,
856                         "%s Label Stack: %s", tag, stack_strbuf->str);
857                 proto_tree_add_text(prefix_tree, tvb, start_offset + 1 + 3 * labnum, 8,
858                         "%s Route Distinguisher: %s:%u", tag, ip_to_str(ip4addr.addr_bytes),
859                         tvb_get_ntohs(tvb, offset + 6));
860                 if (hf_addr4 != -1) {
861                         proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb,
862                                 offset + 8, length, ip4addr2.addr);
863                 } else {
864                         proto_tree_add_text(prefix_tree, tvb, offset + 8,
865                                 length, "%s IPv4 prefix: %s", tag,
866                                 ip_to_str(ip4addr2.addr_bytes));
867                 }
868                 total_length = (1 + labnum * 3 + 8) + length;
869                 break;
870
871             default:
872                 proto_tree_add_text(tree, tvb, start_offset,
873                         (offset - start_offset) + 2,
874                         "Unknown labeled VPN IPv4 address format %u", rd_type);
875                 return -1;
876             }
877             break;
878
879         default:
880             proto_tree_add_text(tree, tvb, start_offset, 0,
881                     "Unknown SAFI (%u) for AFI %u", safi, afi);
882             return -1;
883         }
884         break;
885
886     case AFNUM_INET6:
887         switch (safi) {
888
889         case SAFNUM_UNICAST:
890         case SAFNUM_MULCAST:
891         case SAFNUM_UNIMULC:
892             total_length = decode_prefix6(tree, hf_addr6, tvb, offset, 0, tag);
893             if (total_length < 0)
894                 return -1;
895             break;
896
897         case SAFNUM_MPLS_LABEL:
898             plen =  tvb_get_guint8(tvb, offset);
899             stack_strbuf = ep_strbuf_new_label(NULL);
900             labnum = decode_MPLS_stack(tvb, offset + 1, stack_strbuf);
901
902             offset += (1 + labnum * 3);
903             if (plen <= (labnum * 3*8)) {
904                 proto_tree_add_text(tree, tvb, start_offset, 1,
905                         "%s Labeled IPv6 prefix length %u invalid", tag, plen);
906                 return -1;
907             }
908             plen -= (labnum * 3*8);
909
910             length = ipv6_addr_and_mask(tvb, offset, &ip6addr, plen);
911             if (length < 0) {
912                 proto_tree_add_text(tree, tvb, start_offset, 1,
913                         "%s Labeled IPv6 prefix length %u invalid",
914                         tag, plen  + (labnum * 3*8));
915                 return -1;
916             }
917
918             ti = proto_tree_add_text(tree, tvb, start_offset,
919                  (offset + length) - start_offset,
920                  "Label Stack=%s, IPv6=%s/%u",
921                  stack_strbuf->str,
922                  ip6_to_str(&ip6addr), plen);
923             total_length = (1 + labnum * 3) + length;
924             break;
925
926         case SAFNUM_TUNNEL:
927             plen =  tvb_get_guint8(tvb, offset);
928             if (plen <= 16){
929                 proto_tree_add_text(tree, tvb, start_offset, 1,
930                         "%s Tunnel IPv6 prefix length %u invalid",
931                         tag, plen);
932                 return -1;
933             }
934             tnl_id = tvb_get_ntohs(tvb, offset + 1);
935             offset += 3; /* Length + Tunnel Id */
936             plen -= 16; /* 2-octet Identifier */
937             length = ipv6_addr_and_mask(tvb, offset, &ip6addr, plen);
938             if (length < 0) {
939                 proto_tree_add_text(tree, tvb, start_offset, 1,
940                         "%s Tunnel IPv6 prefix length %u invalid",
941                         tag, plen + 16);
942                 return -1;
943             }
944             ti = proto_tree_add_text(tree, tvb, start_offset,
945                         (offset + length) - start_offset,
946                         "Tunnel Identifier=0x%x IPv6=%s/%u",
947                         tnl_id, ip6_to_str(&ip6addr), plen);
948             total_length = (1 + 2) + length; /* length field + Tunnel Id + IPv4 len */
949             break;
950
951         case SAFNUM_LAB_VPNUNICAST:
952         case SAFNUM_LAB_VPNMULCAST:
953         case SAFNUM_LAB_VPNUNIMULC:
954             plen =  tvb_get_guint8(tvb, offset);
955             stack_strbuf = ep_strbuf_new_label(NULL);
956             labnum = decode_MPLS_stack(tvb, offset + 1, stack_strbuf);
957
958             offset += (1 + labnum * 3);
959             if (plen <= (labnum * 3*8)) {
960                 proto_tree_add_text(tree, tvb, start_offset, 1,
961                         "%s Labeled VPN IPv6 prefix length %u invalid", tag, plen);
962                 return -1;
963             }
964             plen -= (labnum * 3*8);
965
966             rd_type = tvb_get_ntohs(tvb,offset);
967             if (plen < 8*8) {
968                 proto_tree_add_text(tree, tvb, start_offset, 1,
969                         "%s Labeled VPN IPv6 prefix length %u invalid",
970                         tag, plen + (labnum * 3*8));
971                 return -1;
972             }
973             plen -= 8*8;
974
975             switch (rd_type) {
976
977             case FORMAT_AS2_LOC:
978                 length = ipv6_addr_and_mask(tvb, offset + 8, &ip6addr, plen);
979                 if (length < 0) {
980                     proto_tree_add_text(tree, tvb, start_offset, 1,
981                             "%s Labeled VPN IPv6 prefix length %u invalid",
982                             tag, plen + (labnum * 3*8) + 8*8);
983                     return -1;
984                 }
985
986                 ti = proto_tree_add_text(tree, tvb, start_offset,
987                         (offset + 8 + length) - start_offset,
988                         "Label Stack=%s RD=%u:%u, IPv6=%s/%u",
989                         stack_strbuf->str,
990                         tvb_get_ntohs(tvb, offset + 2),
991                         tvb_get_ntohl(tvb, offset + 4),
992                         ip6_to_str(&ip6addr), plen);
993                 total_length = (1 + labnum * 3 + 8) + length;
994                 break;
995
996             case FORMAT_IP_LOC:
997                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 2, 4);
998
999                 length = ipv6_addr_and_mask(tvb, offset + 8, &ip6addr, plen);
1000                 if (length < 0) {
1001                     proto_tree_add_text(tree, tvb, start_offset, 1,
1002                             "%s Labeled VPN IPv6 prefix length %u invalid",
1003                             tag, plen + (labnum * 3*8) + 8*8);
1004                     return -1;
1005                 }
1006
1007                 ti = proto_tree_add_text(tree, tvb, start_offset,
1008                         (offset + 8 + length) - start_offset,
1009                         "Label Stack=%s RD=%s:%u, IPv6=%s/%u",
1010                         stack_strbuf->str,
1011                         ip_to_str(ip4addr.addr_bytes),
1012                         tvb_get_ntohs(tvb, offset + 6),
1013                         ip6_to_str(&ip6addr), plen);
1014                 total_length = (1 + labnum * 3 + 8) + length;
1015                 break;
1016
1017             default:
1018                 proto_tree_add_text(tree, tvb, start_offset, 0,
1019                         "Unknown labeled VPN IPv6 address format %u", rd_type);
1020                 return -1;
1021             }
1022             break;
1023
1024         default:
1025             proto_tree_add_text(tree, tvb, start_offset, 0,
1026                     "Unknown SAFI (%u) for AFI %u", safi, afi);
1027             return -1;
1028         }
1029         break;
1030
1031     case AFNUM_L2VPN:
1032     case AFNUM_L2VPN_OLD:
1033         switch (safi) {
1034
1035         case SAFNUM_LAB_VPNUNICAST:
1036         case SAFNUM_LAB_VPNMULCAST:
1037         case SAFNUM_LAB_VPNUNIMULC:
1038         case SAFNUM_VPLS:
1039             plen =  tvb_get_ntohs(tvb,offset);
1040             rd_type=tvb_get_ntohs(tvb,offset+2);
1041             ce_id=tvb_get_ntohs(tvb,offset+10);
1042             labblk_off=tvb_get_ntohs(tvb,offset+12);
1043             labblk_size=tvb_get_ntohs(tvb,offset+14);
1044             stack_strbuf = ep_strbuf_new_label(NULL);
1045             labnum = decode_MPLS_stack(tvb, offset + 16, stack_strbuf);
1046
1047             switch (rd_type) {
1048
1049             case FORMAT_AS2_LOC:
1050                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 6, 4);
1051                 proto_tree_add_text(tree, tvb, start_offset,
1052                         (offset + plen + 1) - start_offset,
1053                         "RD: %u:%s, CE-ID: %u, Label-Block Offset: %u, "
1054                         "Label-Block Size: %u Label Base %s",
1055                         tvb_get_ntohs(tvb, offset + 4),
1056                         ip_to_str(ip4addr.addr_bytes),
1057                         ce_id,
1058                         labblk_off,
1059                         labblk_size,
1060                         stack_strbuf->str);
1061                 break;
1062
1063             case FORMAT_IP_LOC:
1064                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 4, 4);
1065                 proto_tree_add_text(tree, tvb, offset,
1066                         (offset + plen + 1) - start_offset,
1067                         "RD: %s:%u, CE-ID: %u, Label-Block Offset: %u, "
1068                         "Label-Block Size: %u, Label Base %s",
1069                         ip_to_str(ip4addr.addr_bytes),
1070                         tvb_get_ntohs(tvb, offset + 8),
1071                         ce_id,
1072                         labblk_off,
1073                         labblk_size,
1074                         stack_strbuf->str);
1075                 break;
1076
1077             default:
1078                 proto_tree_add_text(tree, tvb, start_offset,
1079                         (offset - start_offset) + 2,
1080                         "Unknown labeled VPN address format %u", rd_type);
1081                 return -1;
1082             }
1083             /* FIXME there are subTLVs left to decode ... for now lets omit them */
1084             total_length = plen+2;
1085             break;
1086
1087         default:
1088             proto_tree_add_text(tree, tvb, start_offset, 0,
1089                     "Unknown SAFI (%u) for AFI %u", safi, afi);
1090             return -1;
1091         }
1092         break;
1093
1094     default:
1095         proto_tree_add_text(tree, tvb, start_offset, 0,
1096                 "Unknown AFI (%u) value", afi);
1097         return -1;
1098     }
1099     return(total_length);
1100 }
1101
1102 /*
1103  * Dissect a BGP capability.
1104  */
1105 static void
1106 dissect_bgp_capability_item(tvbuff_t *tvb, int *p, proto_tree *tree, int ctype, int clen)
1107 {
1108     proto_tree *subtree;
1109     proto_item *ti;
1110     guint8 orfnum;       /* number of ORFs */
1111     guint8 orftype;      /* ORF Type */
1112     guint8 orfsendrecv;  /* ORF Send/Receive */
1113     int    tclen;        /* capability length */
1114     int    i;
1115
1116     /* check the capability type */
1117     switch (ctype) {
1118     case BGP_CAPABILITY_RESERVED:
1119         proto_tree_add_text(tree, tvb, *p - 2, 1,
1120              "Capability code: %s (%d)", val_to_str(ctype,
1121              capability_vals, "Unknown capability"), ctype);
1122         proto_tree_add_text(tree, tvb, *p - 1,
1123              1, "Capability length: %u byte%s", clen,
1124              plurality(clen, "", "s"));
1125         if (clen != 0) {
1126             proto_tree_add_text(tree, tvb, *p,
1127                  clen, "Capability value: Unknown");
1128         }
1129         *p += clen;
1130         break;
1131     case BGP_CAPABILITY_MULTIPROTOCOL:
1132         proto_tree_add_text(tree, tvb, *p - 2, 1,
1133              "Capability code: %s (%d)", val_to_str(ctype,
1134              capability_vals, "Unknown capability"), ctype);
1135         if (clen != 4) {
1136             proto_tree_add_text(tree, tvb, *p - 1,
1137                  1, "Capability length: Invalid");
1138             proto_tree_add_text(tree, tvb, *p,
1139                  clen, "Capability value: Unknown");
1140         }
1141         else {
1142             proto_tree_add_text(tree, tvb, *p - 1,
1143                  1, "Capability length: %u byte%s", clen,
1144                  plurality(clen, "", "s"));
1145             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1146             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1147             /* AFI */
1148             i = tvb_get_ntohs(tvb, *p);
1149             proto_tree_add_text(subtree, tvb, *p,
1150                  2, "Address family identifier: %s (%u)",
1151                  val_to_str(i, afn_vals, "Unknown"), i);
1152             *p += 2;
1153             /* Reserved */
1154             proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
1155             (*p)++;
1156             /* SAFI */
1157             i = tvb_get_guint8(tvb, *p);
1158             proto_tree_add_text(subtree, tvb, *p,
1159                  1, "Subsequent address family identifier: %s (%u)",
1160                  val_to_str(i, bgpattr_nlri_safi,
1161                  i >= 128 ? "Vendor specific" : "Unknown"), i);
1162             (*p)++;
1163         }
1164         break;
1165     case BGP_CAPABILITY_GRACEFUL_RESTART:
1166         proto_tree_add_text(tree, tvb, *p - 2, 1,
1167              "Capability code: %s (%d)", val_to_str(ctype,
1168              capability_vals, "Unknown capability"), ctype);
1169         if (clen < 6) {
1170             proto_tree_add_text(tree, tvb, *p,
1171                  clen, "Capability value: Invalid");
1172             *p += clen;
1173         }
1174         else {
1175             proto_tree_add_text(tree, tvb, *p - 1,
1176                  1, "Capability length: %u byte%s", clen,
1177                  plurality(clen, "", "s"));
1178             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1179             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1180             /* Timers */
1181             i = tvb_get_ntohs(tvb, *p);
1182             proto_tree_add_text(subtree, tvb, *p,
1183                  2, "Restart Flags: [%s], Restart Time %us",
1184                  (i&0x8000) ? "R" : "none", i&0xfff);
1185             *p += 2;
1186             tclen = clen - 2;
1187             /*
1188              * what follows is alist of AFI/SAFI/flag triplets
1189              * read it until the TLV ends
1190              */
1191             while (tclen >=4) {
1192                 /* AFI */
1193                 i = tvb_get_ntohs(tvb, *p);
1194                 proto_tree_add_text(subtree, tvb, *p,
1195                      2, "Address family identifier: %s (%u)",
1196                      val_to_str(i, afn_vals, "Unknown"), i);
1197                 *p += 2;
1198                 /* SAFI */
1199                 i = tvb_get_guint8(tvb, *p);
1200                 proto_tree_add_text(subtree, tvb, *p,
1201                      1, "Subsequent address family identifier: %s (%u)",
1202                      val_to_str(i, bgpattr_nlri_safi,
1203                      i >= 128 ? "Vendor specific" : "Unknown"), i);
1204                 (*p)++;
1205                 /* flags */
1206                 i = tvb_get_guint8(tvb, *p);
1207                 proto_tree_add_text(subtree, tvb, *p, 1,
1208                      "Preserve forwarding state: %s",
1209                      (i&0x80) ? "yes" : "no");
1210                 (*p)++;
1211                 tclen-=4;
1212             }
1213         }
1214         break;
1215     case BGP_CAPABILITY_4_OCTET_AS_NUMBER:
1216         proto_tree_add_text(tree, tvb, *p - 2, 1,
1217              "Capability code: %s (%d)", val_to_str(ctype,
1218              capability_vals, "Unknown capability"), ctype);
1219         if (clen != 4) {
1220             proto_tree_add_text(tree, tvb, *p,
1221                  clen, "Capability value: Invalid");
1222         }
1223         else {
1224             proto_tree_add_text(tree, tvb, *p - 1,
1225                  1, "Capability length: %u byte%s", clen,
1226                  plurality(clen, "", "s"));
1227             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1228             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1229             proto_tree_add_text(subtree, tvb, *p, 4,
1230                  "AS number: %d", tvb_get_ntohl(tvb, *p));
1231         }
1232         *p += clen;
1233         break;
1234     case BGP_CAPABILITY_DYNAMIC_CAPABILITY:
1235         proto_tree_add_text(tree, tvb, *p - 2, 1,
1236              "Capability code: %s (%d)", val_to_str(ctype,
1237              capability_vals, "Unknown capability"), ctype);
1238         proto_tree_add_text(tree, tvb, *p - 1, 1,
1239              "Capability length: %u byte%s", clen,
1240              plurality(clen, "", "s"));
1241         if (clen > 0) {
1242             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1243             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1244             for (i = 0; (int)i <= clen; i++) {
1245                 proto_tree_add_text(subtree, tvb, *p, 1,
1246                      "Capability code: %s (%d)", val_to_str(ctype,
1247                      capability_vals, "Unknown capability"),
1248                      tvb_get_guint8(tvb, *p));
1249                 (*p)++;
1250             }
1251         }
1252         break;
1253     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
1254     case BGP_CAPABILITY_ROUTE_REFRESH:
1255         proto_tree_add_text(tree, tvb, *p - 2, 1,
1256              "Capability code: %s (%d)", val_to_str(ctype,
1257              capability_vals, "Unknown capability"), ctype);
1258         if (clen != 0) {
1259             proto_tree_add_text(tree, tvb, *p,
1260                  clen, "Capability value: Invalid");
1261         }
1262         else {
1263             proto_tree_add_text(tree, tvb, *p - 1,
1264                  1, "Capability length: %u byte%s", clen,
1265                  plurality(clen, "", "s"));
1266         }
1267         *p += clen;
1268         break;
1269     case BGP_CAPABILITY_ORF_CISCO:
1270     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
1271         proto_tree_add_text(tree, tvb, *p - 2, 1,
1272              "Capability code: %s (%d)", val_to_str(ctype,
1273              capability_vals, "Unknown capability"), ctype);
1274         proto_tree_add_text(tree, tvb, *p - 1,
1275              1, "Capability length: %u byte%s", clen,
1276              plurality(clen, "", "s"));
1277         ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1278         subtree = proto_item_add_subtree(ti, ett_bgp_option);
1279         /* AFI */
1280         i = tvb_get_ntohs(tvb, *p);
1281         proto_tree_add_text(subtree, tvb, *p,
1282              2, "Address family identifier: %s (%u)",
1283              val_to_str(i, afn_vals, "Unknown"), i);
1284         *p += 2;
1285         /* Reserved */
1286         proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
1287         (*p)++;
1288         /* SAFI */
1289         i = tvb_get_guint8(tvb, *p);
1290         proto_tree_add_text(subtree, tvb, *p,
1291              1, "Subsequent address family identifier: %s (%u)",
1292              val_to_str(i, bgpattr_nlri_safi,
1293              i >= 128 ? "Vendor specific" : "Unknown"), i);
1294         (*p)++;
1295         /* Number of ORFs */
1296         orfnum = tvb_get_guint8(tvb, *p);
1297         proto_tree_add_text(subtree, tvb, *p, 1, "Number of ORFs: %u", orfnum);
1298         (*p)++;
1299         for (i=0; i<orfnum; i++) {
1300             /* ORF Type */
1301             orftype = tvb_get_guint8(tvb, *p);
1302             proto_tree_add_text(subtree, tvb, *p, 1, "ORF Type: %s (%u)",
1303                  val_to_str(orftype, orf_type_vals,"Unknown"), orftype);
1304             (*p)++;
1305             /* Send/Receive */
1306             orfsendrecv = tvb_get_guint8(tvb, *p);
1307             proto_tree_add_text(subtree, tvb, *p,
1308                  1, "Send/Receive: %s (%u)",
1309                  val_to_str(orfsendrecv, orf_send_recv_vals,
1310                  "Uknown"), orfsendrecv);
1311             (*p)++;
1312         }
1313         break;
1314         /* unknown capability */
1315     default:
1316         proto_tree_add_text(tree, tvb, *p - 2, 1,
1317              "Capability code: %s (%d)", val_to_str(ctype,
1318              capability_vals, "Unknown capability"), ctype);
1319         proto_tree_add_text(tree, tvb, *p - 2,
1320              1, "Capability code: %s (%d)",
1321              ctype >= 128 ? "Private use" : "Unknown", ctype);
1322         proto_tree_add_text(tree, tvb, *p - 1,
1323              1, "Capability length: %u byte%s", clen,
1324              plurality(clen, "", "s"));
1325         if (clen != 0) {
1326             proto_tree_add_text(tree, tvb, *p,
1327                  clen, "Capability value: Unknown");
1328         }
1329         *p += clen;
1330         break;
1331     }
1332 }
1333
1334
1335 /*
1336  * Dissect a BGP OPEN message.
1337  */
1338 static const value_string community_vals[] = {
1339         { BGP_COMM_NO_EXPORT,           "NO_EXPORT" },
1340         { BGP_COMM_NO_ADVERTISE,        "NO_ADVERTISE" },
1341         { BGP_COMM_NO_EXPORT_SUBCONFED, "NO_EXPORT_SUBCONFED" },
1342         { 0,                            NULL }
1343 };
1344
1345 static void
1346 dissect_bgp_open(tvbuff_t *tvb, proto_tree *tree)
1347 {
1348     struct bgp_open bgpo;      /* BGP OPEN message      */
1349     int             hlen;      /* message length        */
1350     int             ptype;     /* parameter type        */
1351     int             plen;      /* parameter length      */
1352     int             ctype;     /* capability type       */
1353     int             clen;      /* capability length     */
1354     int             cend;      /* capabilities end      */
1355     int             ostart;    /* options start         */
1356     int             oend;      /* options end           */
1357     int             p;         /* tvb offset counter    */
1358     proto_item      *ti;       /* tree item             */
1359     proto_tree      *subtree;  /* subtree for options   */
1360     proto_tree      *subtree1; /* subtree for an option */
1361     proto_tree      *subtree2; /* subtree for an option */
1362
1363     /* snarf OPEN message */
1364     tvb_memcpy(tvb, bgpo.bgpo_marker, 0, BGP_MIN_OPEN_MSG_SIZE);
1365     hlen = g_ntohs(bgpo.bgpo_len);
1366
1367     proto_tree_add_text(tree, tvb,
1368         offsetof(struct bgp_open, bgpo_version), 1,
1369         "Version: %u", bgpo.bgpo_version);
1370     proto_tree_add_text(tree, tvb,
1371         offsetof(struct bgp_open, bgpo_myas), 2,
1372         "My AS: %u", g_ntohs(bgpo.bgpo_myas));
1373     proto_tree_add_text(tree, tvb,
1374         offsetof(struct bgp_open, bgpo_holdtime), 2,
1375         "Hold time: %u", g_ntohs(bgpo.bgpo_holdtime));
1376     proto_tree_add_text(tree, tvb,
1377         offsetof(struct bgp_open, bgpo_id), 4,
1378         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
1379     proto_tree_add_text(tree, tvb,
1380         offsetof(struct bgp_open, bgpo_optlen), 1,
1381         "Optional parameters length: %u byte%s", bgpo.bgpo_optlen,
1382         plurality(bgpo.bgpo_optlen, "", "s"));
1383
1384     /* optional parameters */
1385     if (bgpo.bgpo_optlen > 0) {
1386         /* add a subtree and setup some offsets */
1387         ostart = BGP_MIN_OPEN_MSG_SIZE;
1388         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
1389              "Optional parameters");
1390         subtree = proto_item_add_subtree(ti, ett_bgp_options);
1391         p = ostart;
1392         oend = p + bgpo.bgpo_optlen;
1393
1394         /* step through all of the optional parameters */
1395         while (p < oend) {
1396
1397             /* grab the type and length */
1398             ptype = tvb_get_guint8(tvb, p++);
1399             plen = tvb_get_guint8(tvb, p++);
1400
1401             /* check the type */
1402             switch (ptype) {
1403             case BGP_OPTION_AUTHENTICATION:
1404                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1405                     "Authentication information (%u byte%s)", plen,
1406                     plurality(plen, "", "s"));
1407                 break;
1408             case BGP_OPTION_CAPABILITY:
1409                 /* grab the capability code */
1410                 cend = p - 1 + plen;
1411                 ctype = tvb_get_guint8(tvb, p++);
1412                 clen = tvb_get_guint8(tvb, p++);
1413                 ti = proto_tree_add_text(subtree, tvb, p - 4,
1414                      2 + plen, "Capabilities Advertisement (%u bytes)",
1415                      2 + plen);
1416                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
1417                 proto_tree_add_text(subtree1, tvb, p - 4,
1418                      1, "Parameter type: Capabilities (2)");
1419                 proto_tree_add_text(subtree1, tvb, p - 3,
1420                      1, "Parameter length: %u byte%s", plen,
1421                      plurality(plen, "", "s"));
1422                 p -= 2;
1423
1424                 /* step through all of the capabilities */
1425                 while (p < cend) {
1426                     ctype = tvb_get_guint8(tvb, p++);
1427                     clen = tvb_get_guint8(tvb, p++);
1428
1429                     ti = proto_tree_add_text(subtree1, tvb, p - 2,
1430                          2 + clen, "%s (%u byte%s)", val_to_str(ctype,
1431                          capability_vals, "Unknown capability"),
1432                          2 + clen, plurality(clen, "", "s"));
1433                     subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
1434                     dissect_bgp_capability_item(tvb, &p,
1435                            subtree2, ctype, clen);
1436                 }
1437                 break;
1438             default:
1439                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1440                     "Unknown optional parameter");
1441                 break;
1442             }
1443         }
1444     }
1445 }
1446
1447 /*
1448  * Dissect a BGP UPDATE message.
1449  */
1450 static void
1451 dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
1452 {
1453     struct bgp_attr bgpa;                       /* path attributes          */
1454     guint16         hlen;                       /* message length           */
1455     gint            o;                          /* packet offset            */
1456     gint            q;                          /* tmp                      */
1457     gint            end;                        /* message end              */
1458     guint16         ext_com;                    /* EXTENDED COMMUNITY extended length type  */
1459     guint8          ext_com8;                   /* EXTENDED COMMUNITY regular type  */
1460     gboolean        is_regular_type;            /* flag for regular types   */
1461     gboolean        is_extended_type;           /* flag for extended types  */
1462     guint16         len;                        /* tmp                      */
1463     int             advance;                    /* tmp                      */
1464     proto_item      *ti;                        /* tree item                */
1465     proto_tree      *subtree;                   /* subtree for attributes   */
1466     proto_tree      *subtree2;                  /* subtree for attributes   */
1467     proto_tree      *subtree3;                  /* subtree for attributes   */
1468     proto_tree      *subtree4;                  /* subtree for attributes   */
1469     proto_tree      *subtree5;                  /* subtree for attributes   */
1470     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
1471     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
1472     proto_tree      *as_path_segment_tree;      /* subtree for AS_PATH segments */
1473     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
1474     proto_tree      *community_tree;            /* subtree for a community  */
1475     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
1476     int             i, j;                       /* tmp                      */
1477     guint8          length;                     /* AS_PATH length           */
1478     guint8          type;                       /* AS_PATH type             */
1479     guint32         as_path_item;               /* item in AS_PATH segment  */
1480     emem_strbuf_t   *as_path_emstr = NULL;      /* AS_PATH                  */
1481     emem_strbuf_t   *communities_emstr = NULL;  /* COMMUNITIES              */
1482     emem_strbuf_t   *cluster_list_emstr = NULL; /* CLUSTER_LIST             */
1483     emem_strbuf_t   *junk_emstr;                /* tmp                      */
1484     guint32         ipaddr;                     /* IPv4 address             */
1485     guint32         aggregator_as;
1486     guint16         ssa_type;                   /* SSA T + Type */
1487     guint16         ssa_len;                    /* SSA TLV Length */
1488     guint8          ssa_v3_len;                 /* SSA L2TPv3 Cookie Length */
1489     gfloat          linkband;                   /* Link bandwidth           */
1490
1491     hlen = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
1492     o = BGP_HEADER_SIZE;
1493     junk_emstr = ep_strbuf_new_label(NULL);
1494
1495     /* check for withdrawals */
1496     len = tvb_get_ntohs(tvb, o);
1497     proto_tree_add_text(tree, tvb, o, 2,
1498         "Unfeasible routes length: %u byte%s", len, plurality(len, "", "s"));
1499     o += 2;
1500
1501     /* parse unfeasible prefixes */
1502     if (len > 0) {
1503         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
1504         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
1505
1506         /* parse each prefix */
1507         end = o + len;
1508         while (o < end) {
1509             i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
1510                 "Withdrawn route");
1511             if (i < 0)
1512                 return;
1513             o += i;
1514         }
1515     }
1516
1517     /* check for advertisements */
1518     len = tvb_get_ntohs(tvb, o);
1519     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u byte%s",
1520             len, plurality(len, "", "s"));
1521
1522     /* path attributes */
1523     if (len > 0) {
1524         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
1525         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
1526         i = 2;
1527         while (i < len) {
1528             proto_item *hidden_item;
1529             const char *msg;
1530             int     off;
1531             gint    k;
1532             guint16 alen, tlen, aoff, aoff_save;
1533             guint16 af;
1534             guint8  saf, snpa;
1535             guint8  nexthop_len;
1536             guint8  asn_len = 0;
1537
1538             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
1539             /* check for the Extended Length bit */
1540             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1541                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
1542                 aoff = sizeof(bgpa) + 2;
1543             } else {
1544                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
1545                 aoff = sizeof(bgpa) + 1;
1546             }
1547             tlen = alen;
1548
1549             /* This is kind of ugly - similar code appears twice, but it
1550                helps browsing attrs.                                      */
1551             /* the first switch prints things in the title of the subtree */
1552             switch (bgpa.bgpa_type) {
1553             case BGPTYPE_ORIGIN:
1554                 if (tlen != 1)
1555                     goto default_attribute_top;
1556                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1557                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1558                         "%s: %s (%u byte%s)",
1559                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1560                         msg, tlen + aoff, plurality(tlen + aoff, "", "s"));
1561                 break;
1562             case BGPTYPE_AS_PATH:
1563             case BGPTYPE_NEW_AS_PATH:
1564                 /* (o + i + aoff) =
1565                    (o + current attribute + aoff bytes to first tuple) */
1566                 q = o + i + aoff;
1567                 end = q + tlen;
1568                 /* must be freed by second switch!                         */
1569                 /* "tlen * 11" (10 digits + space) should be a good estimate
1570                    of how long the AS path string could be                 */
1571                 if (as_path_emstr == NULL)
1572                     as_path_emstr = ep_strbuf_sized_new((tlen + 1) * 11, 0);
1573                 ep_strbuf_truncate(as_path_emstr, 0);
1574
1575                 /* estimate the length of the AS number */
1576                 if (bgpa.bgpa_type == BGPTYPE_NEW_AS_PATH)
1577                     asn_len = 4;
1578                 else {
1579                     if (bgp_asn_len == 0) {
1580                         k = q;
1581                         while (k < end) {
1582                             k++;
1583                             length = tvb_get_guint8(tvb, k++);
1584                             k += length * 2;
1585                         }
1586                         asn_len = (k == end) ? 2 : 4;
1587                     }
1588                     else {
1589                         asn_len = bgp_asn_len;
1590                     }
1591                 }
1592
1593                 /* snarf each AS path */
1594                 while (q < end) {
1595                     type = tvb_get_guint8(tvb, q++);
1596                     if (as_path_emstr->len > 1 &&
1597                         as_path_emstr->str[as_path_emstr->len - 1] != ' ')
1598                         ep_strbuf_append_c(as_path_emstr, ' ');
1599                     if (type == AS_SET) {
1600                         ep_strbuf_append_c(as_path_emstr, '{');
1601                     }
1602                     else if (type == AS_CONFED_SET) {
1603                         ep_strbuf_append_c(as_path_emstr, '[');
1604                     }
1605                     else if (type == AS_CONFED_SEQUENCE) {
1606                         ep_strbuf_append_c(as_path_emstr, '(');
1607                     }
1608                     length = tvb_get_guint8(tvb, q++);
1609
1610                     /* snarf each value in path */
1611                     for (j = 0; j < length; j++) {
1612                         ep_strbuf_append_printf(as_path_emstr, "%u%s",
1613                                 (asn_len == 2) ?
1614                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1615                                 (type == AS_SET || type == AS_CONFED_SET) ?
1616                                 ", " : " ");
1617                         q += asn_len;
1618                     }
1619
1620                     /* cleanup end of string */
1621                     if (type == AS_SET) {
1622                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 2);
1623                         ep_strbuf_append_c(as_path_emstr, '}');
1624                     }
1625                     else if (type == AS_CONFED_SET) {
1626                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 2);
1627                         ep_strbuf_append_c(as_path_emstr, ']');
1628                     }
1629                     else if (type == AS_CONFED_SEQUENCE) {
1630                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 1);
1631                         ep_strbuf_append_c(as_path_emstr, ')');
1632                     }
1633                     else {
1634                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 1);
1635                     }
1636                 }
1637
1638                 /* check for empty AS_PATH */
1639                 if (tlen == 0)
1640                     ep_strbuf_printf(as_path_emstr, "empty");
1641
1642                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1643                         "%s: %s (%u byte%s)",
1644                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1645                         as_path_emstr->str, tlen + aoff,
1646                         plurality(tlen + aoff, "", "s"));
1647                 break;
1648             case BGPTYPE_NEXT_HOP:
1649                 if (tlen != 4)
1650                     goto default_attribute_top;
1651                 ipaddr = tvb_get_ipv4(tvb, o + i + aoff);
1652                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1653                         "%s: %s (%u byte%s)",
1654                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1655                         ip_to_str((guint8 *)&ipaddr), tlen + aoff,
1656                         plurality(tlen + aoff, "", "s"));
1657                 break;
1658             case BGPTYPE_MULTI_EXIT_DISC:
1659                 if (tlen != 4)
1660                     goto default_attribute_top;
1661                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1662                         "%s: %u (%u byte%s)",
1663                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1664                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1665                         plurality(tlen + aoff, "", "s"));
1666                 break;
1667             case BGPTYPE_LOCAL_PREF:
1668                 if (tlen != 4)
1669                     goto default_attribute_top;
1670                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1671                         "%s: %u (%u byte%s)",
1672                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1673                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1674                         plurality(tlen + aoff, "", "s"));
1675                 break;
1676             case BGPTYPE_ATOMIC_AGGREGATE:
1677                 if (tlen != 0)
1678                     goto default_attribute_top;
1679                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1680                         "%s (%u byte%s)",
1681                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1682                         tlen + aoff, plurality(tlen + aoff, "", "s"));
1683                 break;
1684             case BGPTYPE_AGGREGATOR:
1685                 if (tlen != 6 && tlen != 8)
1686                     goto default_attribute_top;
1687             case BGPTYPE_NEW_AGGREGATOR:
1688                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
1689                     goto default_attribute_top;
1690                 asn_len = tlen - 4;
1691                 ipaddr = tvb_get_ipv4(tvb, o + i + aoff + asn_len);
1692                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1693                         "%s: AS: %u origin: %s (%u byte%s)",
1694                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1695                         (asn_len == 2) ? tvb_get_ntohs(tvb, o + i + aoff) :
1696                         tvb_get_ntohl(tvb, o + i + aoff),
1697                         ip_to_str((guint8 *)&ipaddr),
1698                         tlen + aoff, plurality(tlen + aoff, "", "s"));
1699                 break;
1700             case BGPTYPE_COMMUNITIES:
1701                 if (tlen % 4 != 0)
1702                     goto default_attribute_top;
1703
1704                 /* (o + i + aoff) =
1705                    (o + current attribute + aoff bytes to first tuple) */
1706                 q = o + i + aoff;
1707                 end = q + tlen;
1708                 /* must be freed by second switch!                          */
1709                 /* "tlen * 12" (5 digits, a :, 5 digits + space ) should be
1710                    a good estimate of how long the communities string could
1711                    be                                                       */
1712                 if (communities_emstr == NULL)
1713                     communities_emstr = ep_strbuf_sized_new((tlen + 1) * 12, 0);
1714                 ep_strbuf_truncate(communities_emstr, 0);
1715
1716                 /* snarf each community */
1717                 while (q < end) {
1718                     /* check for well-known communities */
1719                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
1720                         ep_strbuf_append(communities_emstr, "NO_EXPORT ");
1721                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1722                         ep_strbuf_append(communities_emstr, "NO_ADVERTISE ");
1723                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1724                         ep_strbuf_append(communities_emstr, "NO_EXPORT_SUBCONFED ");
1725                     else {
1726                         ep_strbuf_append_printf(communities_emstr, "%u:%u ",
1727                                 tvb_get_ntohs(tvb, q),
1728                                 tvb_get_ntohs(tvb, q + 2));
1729                     }
1730                     q += 4;
1731                 }
1732                 /* cleanup end of string */
1733                 ep_strbuf_truncate(communities_emstr, communities_emstr->len - 1);
1734
1735                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1736                         "%s: %s (%u byte%s)",
1737                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1738                         communities_emstr->str, tlen + aoff,
1739                         plurality(tlen + aoff, "", "s"));
1740                 break;
1741             case BGPTYPE_ORIGINATOR_ID:
1742                 if (tlen != 4)
1743                     goto default_attribute_top;
1744                 ipaddr = tvb_get_ipv4(tvb, o + i + aoff);
1745                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1746                         "%s: %s (%u byte%s)",
1747                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1748                         ip_to_str((guint8 *)&ipaddr),
1749                         tlen + aoff, plurality(tlen + aoff, "", "s"));
1750                 break;
1751             case BGPTYPE_CLUSTER_LIST:
1752                 if (tlen % 4 != 0)
1753                     goto default_attribute_top;
1754
1755                 /* (o + i + aoff) =
1756                    (o + current attribute + aoff bytes to first tuple) */
1757                 q = o + i + aoff;
1758                 end = q + tlen;
1759                 /* must be freed by second switch!                          */
1760                 /* "tlen * 16" (12 digits, 3 dots + space ) should be
1761                    a good estimate of how long the cluster_list string could
1762                    be                                                       */
1763                 if (cluster_list_emstr == NULL)
1764                     cluster_list_emstr = ep_strbuf_sized_new((tlen + 1) * 16, 0);
1765                 ep_strbuf_truncate(cluster_list_emstr, 0);
1766
1767                 /* snarf each cluster list */
1768                 while (q < end) {
1769                     ipaddr = tvb_get_ipv4(tvb, q);
1770                     ep_strbuf_append_printf(cluster_list_emstr, "%s ", ip_to_str((guint8 *)&ipaddr));
1771                     q += 4;
1772                 }
1773                 /* cleanup end of string */
1774                 ep_strbuf_truncate(cluster_list_emstr, cluster_list_emstr->len - 1);
1775
1776                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1777                         "%s: %s (%u byte%s)",
1778                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1779                         cluster_list_emstr->str, tlen + aoff,
1780                         plurality(tlen + aoff, "", "s"));
1781                 break;
1782             case BGPTYPE_EXTENDED_COMMUNITY:
1783                 if (tlen %8 != 0)
1784                     break;
1785                 ti = proto_tree_add_text(subtree,tvb,o+i,tlen+aoff,
1786                         "%s: (%u byte%s)",
1787                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1788                         tlen + aoff,
1789                         plurality(tlen + aoff, "", "s"));
1790                 break;
1791             case BGPTYPE_SAFI_SPECIFIC_ATTR:
1792                 ti = proto_tree_add_text(subtree,tvb,o+i,tlen+aoff,
1793                         "%s: (%u byte%s)",
1794                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1795                         tlen + aoff,
1796                         plurality(tlen + aoff, "", "s"));
1797                 break;
1798
1799             default:
1800             default_attribute_top:
1801                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1802                         "%s (%u byte%s)",
1803                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1804                         tlen + aoff, plurality(tlen + aoff, "", "s"));
1805             } /* end of first switch */
1806             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1807
1808             /* figure out flags */
1809             ep_strbuf_truncate(junk_emstr, 0);
1810             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1811                  ep_strbuf_append(junk_emstr, "Optional, ");
1812             }
1813             else {
1814                  ep_strbuf_append(junk_emstr, "Well-known, ");
1815             }
1816             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1817                  ep_strbuf_append(junk_emstr, "Transitive, ");
1818             }
1819             else {
1820                  ep_strbuf_append(junk_emstr, "Non-transitive, ");
1821             }
1822             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1823                  ep_strbuf_append(junk_emstr, "Partial");
1824             }
1825             else {
1826                  ep_strbuf_append(junk_emstr, "Complete");
1827             }
1828             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1829                  ep_strbuf_append(junk_emstr, ", Extended Length");
1830             }
1831             ti = proto_tree_add_text(subtree2, tvb,
1832                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1833                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_emstr->str);
1834             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1835
1836             /* add flag bitfield subtrees */
1837             proto_tree_add_text(subtree3, tvb,
1838                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1839                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1840                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1841             proto_tree_add_text(subtree3, tvb,
1842                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1843                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1844                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1845                         "Non-transitive"));
1846             proto_tree_add_text(subtree3, tvb,
1847                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1848                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1849                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1850             proto_tree_add_text(subtree3, tvb,
1851                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1852                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1853                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1854                         "Regular length"));
1855
1856             proto_tree_add_text(subtree2, tvb,
1857                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1858                     "Type code: %s (%u)",
1859                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1860                     bgpa.bgpa_type);
1861
1862             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1863                     aoff - sizeof(bgpa), "Length: %d byte%s", tlen,
1864                     plurality(tlen, "", "s"));
1865
1866             /* the second switch prints things in the actual subtree of each
1867                attribute                                                     */
1868             switch (bgpa.bgpa_type) {
1869             case BGPTYPE_ORIGIN:
1870                 if (tlen != 1) {
1871                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1872                             "Origin (invalid): %u byte%s", tlen,
1873                              plurality(tlen, "", "s"));
1874                 } else {
1875                     proto_tree_add_item(subtree2, hf_bgp_origin, tvb,
1876                             o + i + aoff, 1, FALSE);
1877                 }
1878                 break;
1879             case BGPTYPE_AS_PATH:
1880             case BGPTYPE_NEW_AS_PATH:
1881                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1882                         "AS path: %s", as_path_emstr->str);
1883                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1884
1885                 /* (o + i + aoff) =
1886                    (o + current attribute + aoff bytes to first tuple) */
1887                 q = o + i + aoff;
1888                 end = q + tlen;
1889
1890                 /* snarf each AS path tuple, we have to step through each one
1891                    again to make a separate subtree so we can't just reuse
1892                    as_path_gstr from above */
1893                 /* XXX - Can we use some g_string*() trickery instead, e.g.
1894                    g_string_erase()? */
1895                 while (q < end) {
1896                     ep_strbuf_truncate(as_path_emstr, 0);
1897                     type = tvb_get_guint8(tvb, q++);
1898                     if (type == AS_SET) {
1899                         ep_strbuf_append_c(as_path_emstr, '{');
1900                     }
1901                     else if (type == AS_CONFED_SET) {
1902                         ep_strbuf_append_c(as_path_emstr, '[');
1903                     }
1904                     else if (type == AS_CONFED_SEQUENCE) {
1905                         ep_strbuf_append_c(as_path_emstr, '(');
1906                     }
1907                     length = tvb_get_guint8(tvb, q++);
1908
1909                     /* snarf each value in path */
1910                     for (j = 0; j < length; j++) {
1911                         ep_strbuf_append_printf(as_path_emstr, "%u%s",
1912                                 (asn_len == 2) ?
1913                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1914                                 (type == AS_SET || type == AS_CONFED_SET) ? ", " : " ");
1915                         q += asn_len;
1916                     }
1917
1918                     /* cleanup end of string */
1919                     if (type == AS_SET) {
1920                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 2);
1921                         ep_strbuf_append_c(as_path_emstr, '}');
1922                     }
1923                     else if (type == AS_CONFED_SET) {
1924                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 2);
1925                         ep_strbuf_append_c(as_path_emstr, ']');
1926                     }
1927                     else if (type == AS_CONFED_SEQUENCE) {
1928                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 1);
1929                         ep_strbuf_append_c(as_path_emstr, ')');
1930                     }
1931                     else {
1932                         ep_strbuf_truncate(as_path_emstr, as_path_emstr->len - 1);
1933                     }
1934
1935                     /* length here means number of ASs, ie length * 2 bytes */
1936                     ti = proto_tree_add_text(as_paths_tree, tvb,
1937                             q - length * asn_len - 2,
1938                             length * asn_len + 2, "AS path segment: %s", as_path_emstr->str);
1939                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1940                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 2,
1941                             1, "Path segment type: %s (%u)",
1942                             val_to_str(type, as_segment_type, "Unknown"), type);
1943                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 1,
1944                             1, "Path segment length: %u AS%s", length,
1945                             plurality(length, "", "s"));
1946
1947                     /* backup and reprint path segment value(s) only */
1948                     q -= asn_len * length;
1949                     ti = proto_tree_add_text(as_path_tree, tvb, q,
1950                             length * asn_len, "Path segment value:");
1951                     as_path_segment_tree = proto_item_add_subtree(ti,
1952                             ett_bgp_as_path_segments);
1953                     for (j = 0; j < length; j++) {
1954                         as_path_item = (asn_len == 2) ?
1955                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q);
1956                         proto_item_append_text(ti, " %u", as_path_item);
1957                         hidden_item = proto_tree_add_uint(as_path_tree, hf_bgp_as_path, tvb,
1958                             q, asn_len, as_path_item);
1959                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1960                         q += asn_len;
1961                     }
1962                 }
1963
1964                 break;
1965             case BGPTYPE_NEXT_HOP:
1966                 if (tlen != 4) {
1967                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1968                             "Next hop (invalid): %u byte%s", tlen,
1969                             plurality(tlen, "", "s"));
1970                 } else {
1971                     proto_tree_add_item(subtree2, hf_bgp_next_hop, tvb,
1972                             o + i + aoff, tlen, FALSE);
1973                 }
1974                 break;
1975             case BGPTYPE_MULTI_EXIT_DISC:
1976                 if (tlen != 4) {
1977                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1978                             "Multiple exit discriminator (invalid): %u byte%s",
1979                             tlen, plurality(tlen, "", "s"));
1980                 } else {
1981                     proto_tree_add_item(subtree2, hf_bgp_multi_exit_disc, tvb,
1982                             o + i + aoff, tlen, FALSE);
1983                 }
1984                 break;
1985             case BGPTYPE_LOCAL_PREF:
1986                 if (tlen != 4) {
1987                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1988                             "Local preference (invalid): %u byte%s", tlen,
1989                              plurality(tlen, "", "s"));
1990                 } else {
1991                     proto_tree_add_item(subtree2, hf_bgp_local_pref, tvb,
1992                             o + i + aoff, tlen, FALSE);
1993                 }
1994                 break;
1995             case BGPTYPE_ATOMIC_AGGREGATE:
1996                 if (tlen != 0) {
1997                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1998                             "Atomic aggregate (invalid): %u byte%s", tlen,
1999                             plurality(tlen, "", "s"));
2000                 }
2001                 break;
2002             case BGPTYPE_AGGREGATOR:
2003                 if (tlen != 6 && tlen != 8) {
2004                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2005                             "Aggregator (invalid): %u byte%s", tlen,
2006                             plurality(tlen, "", "s"));
2007                     break;
2008                 }
2009             case BGPTYPE_NEW_AGGREGATOR:
2010                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
2011                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2012                             "Aggregator (invalid): %u byte%s", tlen,
2013                             plurality(tlen, "", "s"));
2014                 else {
2015                     asn_len = tlen - 4;
2016                     aggregator_as = (asn_len == 2) ?
2017                             tvb_get_ntohs(tvb, o + i + aoff) :
2018                             tvb_get_ntohl(tvb, o + i + aoff);
2019                     proto_tree_add_uint(subtree2, hf_bgp_aggregator_as, tvb,
2020                             o + i + aoff, asn_len, aggregator_as);
2021                     proto_tree_add_item(subtree2, hf_bgp_aggregator_origin, tvb,
2022                         o + i + aoff + asn_len, 4, FALSE);
2023                 }
2024                 break;
2025             case BGPTYPE_COMMUNITIES:
2026                 if (tlen % 4 != 0) {
2027                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2028                             "Communities (invalid): %u byte%s", tlen,
2029                             plurality(tlen, "", "s"));
2030                     break;
2031                 }
2032
2033                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2034                         "Communities: %s", communities_emstr->str);
2035                 communities_tree = proto_item_add_subtree(ti,
2036                         ett_bgp_communities);
2037
2038                 /* (o + i + aoff) =
2039                    (o + current attribute + aoff bytes to first tuple) */
2040                 q = o + i + aoff;
2041                 end = q + tlen;
2042
2043                 /* snarf each community */
2044                 while (q < end) {
2045                     /* check for reserved values */
2046                     guint32 community = tvb_get_ntohl(tvb, q);
2047                     if ((community & 0xFFFF0000) == FOURHEX0 ||
2048                          (community & 0xFFFF0000) == FOURHEXF) {
2049                         proto_tree_add_text(communities_tree, tvb,
2050                                q - 3 + aoff, 4,
2051                                "Community: %s (0x%08x)",
2052                                val_to_str(community, community_vals, "(reserved)"),
2053                                community);
2054                     }
2055                     else {
2056                         ti = proto_tree_add_text(communities_tree, tvb,
2057                                 q - 3 + aoff, 4, "Community: %u:%u",
2058                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
2059                         community_tree = proto_item_add_subtree(ti,
2060                             ett_bgp_communities);
2061                         proto_tree_add_item(community_tree, hf_bgp_community_as,
2062                             tvb, q - 3 + aoff, 2, FALSE);
2063                         proto_tree_add_item(community_tree, hf_bgp_community_value,
2064                             tvb, q - 1 + aoff, 2, FALSE);
2065                     }
2066
2067                     q += 4;
2068                 }
2069
2070                 break;
2071             case BGPTYPE_ORIGINATOR_ID:
2072                 if (tlen != 4) {
2073                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2074                             "Originator identifier (invalid): %u byte%s", tlen,
2075                             plurality(tlen, "", "s"));
2076                 } else {
2077                     proto_tree_add_item(subtree2, hf_bgp_originator_id, tvb,
2078                             o + i + aoff, tlen, FALSE);
2079                 }
2080                 break;
2081            case BGPTYPE_MP_REACH_NLRI:
2082                 /*
2083                  * RFC 2545 specifies that there may be more than one
2084                  * address in the MP_REACH_NLRI attribute in section
2085                  * 3, "Constructing the Next Hop field".
2086                  *
2087                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
2088                  * 2858 obsoletes RFC 2283, which says you can do that,
2089                  * but that doesn't mean we shouldn't dissect packets
2090                  * that conform to RFC 2283 but not RFC 2858, as some
2091                  * device on the network might implement the 2283-style
2092                  * BGP extensions rather than RFC 2858-style extensions.
2093                  */
2094                 af = tvb_get_ntohs(tvb, o + i + aoff);
2095                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
2096                     "Address family: %s (%u)",
2097                     val_to_str(af, afn_vals, "Unknown"), af);
2098                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
2099                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
2100                     "Subsequent address family identifier: %s (%u)",
2101                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
2102                     saf);
2103                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
2104                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
2105                         nexthop_len + 1,
2106                         "Next hop network address (%d byte%s)",
2107                         nexthop_len, plurality(nexthop_len, "", "s"));
2108                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
2109
2110                 /*
2111                  * The addresses don't contain lengths, so if we
2112                  * don't understand the address family type, we
2113                  * cannot parse the subsequent addresses as we
2114                  * don't know how long they are.
2115                  */
2116                 switch (af) {
2117                 default:
2118                     proto_tree_add_text(subtree3, tvb, o + i + aoff + 4,
2119                         nexthop_len, "Unknown Address Family");
2120                     break;
2121
2122                 case AFNUM_INET:
2123                 case AFNUM_INET6:
2124                 case AFNUM_L2VPN:
2125                 case AFNUM_L2VPN_OLD:
2126
2127                     j = 0;
2128                     while (j < nexthop_len) {
2129                         advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
2130                                 junk_emstr) ;
2131                         if (advance == 0) /* catch if this is a unknown AFI type*/
2132                                 break;
2133                         if (j + advance > nexthop_len)
2134                                 break;
2135                         proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
2136                                 advance, "Next hop: %s (%u)", junk_emstr->str, advance);
2137                         j += advance;
2138                     }
2139                     break;
2140                 }
2141
2142                 aoff_save = aoff;
2143                 tlen -= nexthop_len + 4;
2144                 aoff += nexthop_len + 4 ;
2145
2146                 off = 0;
2147                 snpa = tvb_get_guint8(tvb, o + i + aoff);
2148                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
2149                         "Subnetwork points of attachment: %u", snpa);
2150                 off++;
2151                 if (snpa) {
2152                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
2153                         for (/*nothing*/; snpa > 0; snpa--) {
2154                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
2155                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
2156                                 off++;
2157                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
2158                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
2159                                         "SNPA (%u byte%s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
2160                                         plurality(tvb_get_guint8(tvb, o + i + aoff + off - 1), "", "s"));
2161                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
2162                         }
2163                 }
2164                 tlen -= off;
2165                 aoff += off;
2166
2167                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2168                         "Network layer reachability information (%u byte%s)",
2169                         tlen, plurality(tlen, "", "s"));
2170                 if (tlen)  {
2171                     subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
2172                     if (af != AFNUM_INET && af != AFNUM_INET6 && af != AFNUM_L2VPN) {
2173                         proto_tree_add_text(subtree3, tvb, o + i + aoff,
2174                                 tlen, "Unknown Address Family");
2175                     } else {
2176                         while (tlen > 0) {
2177                                 advance = decode_prefix_MP(subtree3,
2178                                     hf_bgp_mp_reach_nlri_ipv4_prefix,
2179                                     -1,
2180                                     af, saf,
2181                                     tvb, o + i + aoff, "MP Reach NLRI");
2182                                 if (advance < 0)
2183                                     break;
2184                                 tlen -= advance;
2185                                 aoff += advance;
2186                         }
2187                     }
2188                 }
2189                 aoff = aoff_save;
2190                 break;
2191            case BGPTYPE_MP_UNREACH_NLRI:
2192                 af = tvb_get_ntohs(tvb, o + i + aoff);
2193                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
2194                     "Address family: %s (%u)",
2195                     val_to_str(af, afn_vals, "Unknown"), af);
2196                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
2197                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
2198                     "Subsequent address family identifier: %s (%u)",
2199                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
2200                     saf);
2201                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
2202                         tlen - 3, "Withdrawn routes (%u byte%s)", tlen - 3,
2203                         plurality(tlen - 3, "", "s"));
2204
2205                 aoff_save = aoff;
2206                 tlen -= 3;
2207                 aoff += 3;
2208                 if (tlen > 0) {
2209                     subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
2210
2211                     while (tlen > 0) {
2212                         advance = decode_prefix_MP(subtree3,
2213                                 hf_bgp_mp_unreach_nlri_ipv4_prefix,
2214                                 -1,
2215                                 af, saf,
2216                                 tvb, o + i + aoff, "MP Unreach NLRI");
2217                         if (advance < 0)
2218                             break;
2219                         tlen -= advance;
2220                         aoff += advance;
2221                     }
2222                 }
2223                 aoff = aoff_save;
2224                 break;
2225             case BGPTYPE_CLUSTER_LIST:
2226                 if (tlen % 4 != 0) {
2227                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2228                             "Cluster list (invalid): %u byte%s", tlen,
2229                             plurality(tlen, "", "s"));
2230                     break;
2231                 }
2232
2233                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2234                         "Cluster list: %s", cluster_list_emstr->str);
2235                 cluster_list_tree = proto_item_add_subtree(ti,
2236                         ett_bgp_cluster_list);
2237
2238                 /* (o + i + aoff) =
2239                    (o + current attribute + aoff bytes to first tuple) */
2240                 q = o + i + aoff;
2241                 end = q + tlen;
2242
2243                 /* snarf each cluster identifier */
2244                 while (q < end) {
2245                     proto_tree_add_item(cluster_list_tree, hf_bgp_cluster_list,
2246                             tvb, q - 3 + aoff, 4, FALSE);
2247                     q += 4;
2248                 }
2249
2250                 break;
2251             case BGPTYPE_EXTENDED_COMMUNITY:
2252                 if (tlen %8 != 0) {
2253                         proto_tree_add_text(subtree3, tvb, o + i + aoff, tlen, "Extended community (invalid) : %u byte%s", tlen,
2254                                 plurality(tlen, "", "s"));
2255                 } else {
2256                         q = o + i + aoff ;
2257                         end = o + i + aoff + tlen ;
2258                         ti = proto_tree_add_text(subtree2,tvb,q,tlen, "Carried Extended communities");
2259                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities);
2260
2261                         while (q < end) {
2262                             ext_com8 = tvb_get_guint8(tvb,q); /* handle regular types (8 bit) */
2263                             ext_com  = tvb_get_ntohs(tvb,q);  /* handle extended length types (16 bit) */
2264                             ep_strbuf_printf(junk_emstr, "%s", val_to_str(ext_com8,bgpext_com8_type,"Unknown"));
2265                             is_regular_type = FALSE;
2266                             is_extended_type = FALSE;
2267                             /* handle regular types (8 bit) */
2268                             switch (ext_com8) {
2269                             case BGP_EXT_COM_QOS_MARK_T:
2270                             case BGP_EXT_COM_QOS_MARK_NT:
2271                                 is_regular_type = TRUE;
2272                                 ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2273
2274                                 subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities);
2275                                 ti = proto_tree_add_text(subtree4, tvb, q, 1,
2276                                                     "Type: 0x%02x", tvb_get_guint8(tvb,q));
2277                                 ti = proto_tree_add_text(subtree4, tvb, q+1, 1,
2278                                                     "Flags: 0x%02x", tvb_get_guint8(tvb,q+1));
2279                                 subtree5 = proto_item_add_subtree(ti,ett_bgp_ext_com_flags);
2280                                 /* add flag bitfield */
2281                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2282                                                          0x10, 8, "Remarking", "No Remarking"));
2283                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2284                                                          0x08, 8, "Ignored marking", "No Ignored marking"));
2285                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2286                                                          0x04, 8, "Aggregation of markings", "No Aggregation of markings"));
2287
2288                                 ti = proto_tree_add_text(subtree4, tvb, q+2, 1,
2289                                                     "QoS Set Number: 0x%02x", tvb_get_guint8(tvb,q+2));
2290                                 ti = proto_tree_add_text(subtree4, tvb, q+3, 1,
2291                                                     "Technology Type: 0x%02x (%s)", tvb_get_guint8(tvb,q+3),
2292                                                          val_to_str(tvb_get_guint8(tvb,q+3),qos_tech_type,"Unknown"));
2293                                 ti = proto_tree_add_text(subtree4, tvb, q+4, 2,
2294                                                     "QoS Marking O (16 bit): %s", decode_numeric_bitfield(tvb_get_ntohs(tvb,q+4),
2295                                                          0xffff, 16, "0x%04x"));
2296                                 ti = proto_tree_add_text(subtree4, tvb, q+6, 1,
2297                                                     "QoS Marking A  (8 bit): %s (decimal %d)", decode_numeric_bitfield(tvb_get_guint8(tvb,q+6),
2298                                                          0xff, 8, "0x%02x"), tvb_get_guint8(tvb,q+6));
2299                                 ti = proto_tree_add_text(subtree4, tvb, q+7, 1,
2300                                                     "Defaults to zero: 0x%02x", tvb_get_guint8(tvb,q+7));
2301                                 break;
2302                             case BGP_EXT_COM_COS_CAP_T:
2303                                 is_regular_type = TRUE;
2304                                 ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2305
2306                                 subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities);
2307                                 ti = proto_tree_add_text(subtree4, tvb, q, 1,
2308                                                     "Type: 0x%02x", tvb_get_guint8(tvb,q));
2309                                 ti = proto_tree_add_text(subtree4, tvb, q+1, 1,
2310                                                     "Flags byte 1 : 0x%02x", tvb_get_guint8(tvb,q+1));
2311                                 subtree5 = proto_item_add_subtree(ti,ett_bgp_ext_com_flags);
2312                                 /* add flag bitfield */
2313                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2314                                                          0x80, 8, "BE class supported", "BE class NOT supported"));
2315                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2316                                                          0x40, 8, "EF class supported", "EF class NOT supported"));
2317                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2318                                                          0x20, 8, "AF class supported", "AF class NOT supported"));
2319                                 ti = proto_tree_add_text(subtree5, tvb, q+1, 1, "%s", decode_boolean_bitfield(tvb_get_guint8(tvb,q+1),
2320                                                          0x10, 8, "LE class supported", "LE class NOT supported"));
2321                                 ti = proto_tree_add_text(subtree4, tvb, q+2, 1,
2322                                                     "Flags byte 2..7 : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
2323                                                         tvb_get_guint8(tvb,q+2),tvb_get_guint8(tvb,q+3),tvb_get_guint8(tvb,q+4),
2324                                                         tvb_get_guint8(tvb,q+5),tvb_get_guint8(tvb,q+6),tvb_get_guint8(tvb,q+7));
2325                                 break;
2326                             }
2327
2328                             if (!is_regular_type) {
2329                                     ep_strbuf_append(junk_emstr, val_to_str(ext_com,bgpext_com_type,"Unknown"));
2330
2331                                     /* handle extended length types (16 bit) */
2332                                     switch (ext_com) {
2333                                     case BGP_EXT_COM_RT_0:
2334                                     case BGP_EXT_COM_RT_2:
2335                                     case BGP_EXT_COM_RO_0:
2336                                     case BGP_EXT_COM_RO_2:
2337                                         is_extended_type = TRUE;
2338                                         ep_strbuf_append_printf(junk_emstr, ": %u%s%d",
2339                                                                tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
2340                                         proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2341                                         break ;
2342                                     case BGP_EXT_COM_RT_1:
2343                                     case BGP_EXT_COM_RO_1:
2344                                         is_extended_type = TRUE;
2345                                         ipaddr = tvb_get_ipv4(tvb,q+2);
2346                                         ep_strbuf_append_printf(junk_emstr, ": %s%s%u",
2347                                                                ip_to_str((guint8 *)&ipaddr),":",tvb_get_ntohs(tvb,q+6));
2348                                         proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2349                                         break;
2350                                     case BGP_EXT_COM_VPN_ORIGIN:
2351                                     case BGP_EXT_COM_OSPF_RID:
2352                                         is_extended_type = TRUE;
2353                                         ipaddr = tvb_get_ipv4(tvb,q+2);
2354                                         ep_strbuf_append_printf(junk_emstr, ": %s", ip_to_str((guint8 *)&ipaddr));
2355                                         proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2356                                         break;
2357                                     case BGP_EXT_COM_OSPF_RTYPE:
2358                                         is_extended_type = TRUE;
2359                                         ipaddr = tvb_get_ipv4(tvb,q+2);
2360                                         ep_strbuf_append_printf(junk_emstr, ": Area: %s, Type: %s", ip_to_str((guint8 *)&ipaddr),
2361                                                  val_to_str(tvb_get_guint8(tvb,q+6),bgpext_ospf_rtype,"Unknown"));
2362                                         /* print OSPF Metric type if selected */
2363                                         /* always print E2 even if not external route -- receiving router should ignore */
2364                                         if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) {
2365                                             ep_strbuf_append(junk_emstr, " E2");
2366                                         } else if ((tvb_get_guint8(tvb,q+6)==BGP_OSPF_RTYPE_EXT) || (tvb_get_guint8(tvb,q+6)==BGP_OSPF_RTYPE_NSSA)) {
2367                                             ep_strbuf_append(junk_emstr, " E1");
2368                                         } else {
2369                                             ep_strbuf_append(junk_emstr, ", no options");
2370                                         }
2371                                         proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2372                                         break;
2373                                     case BGP_EXT_COM_LINKBAND:
2374                                         is_extended_type = TRUE;
2375                                         linkband = tvb_get_ntohieee_float(tvb,q+2);
2376                                         ep_strbuf_append_printf(junk_emstr, ": %.3f Mbps", linkband*8/1000000);
2377                                         proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2378                                         break;
2379                                     case BGP_EXT_COM_L2INFO:
2380                                         is_extended_type = TRUE;
2381                                         ep_strbuf_append_printf(junk_emstr,
2382                                                                ": %s, Control Flags: %s%s%s%s%s, MTU: %u byte%s",
2383                                                                val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"),
2384                                                                tvb_get_guint8(tvb,q+3) ? "" : "none",
2385                                                                tvb_get_ntohs(tvb,q+3)&0x08 ? "Q" : "",
2386                                                                tvb_get_ntohs(tvb,q+3)&0x04 ? "F" : "",
2387                                                                tvb_get_ntohs(tvb,q+3)&0x02 ? "C" : "",
2388                                                                tvb_get_ntohs(tvb,q+3)&0x01 ? "S" : "",
2389                                                                tvb_get_ntohs(tvb,q+4),
2390                                                                plurality(tvb_get_ntohs(tvb,q+4), "", "s"));
2391                                         ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_emstr->str);
2392
2393                                         subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities);
2394                                         proto_tree_add_text(subtree4,tvb,q+2,1, "Encapsulation: %s",
2395                                                                  val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"));
2396                                         proto_tree_add_text(subtree4,tvb,q+3,1, "Control Flags: %s%sControl Word %s required, Sequenced delivery %s required",
2397                                                             tvb_get_ntohs(tvb,q+3)&0x08 ? "Q flag (Reserved) set" : "",
2398                                                             tvb_get_ntohs(tvb,q+3)&0x04 ? "F flag (reserved) set" : "",
2399                                                             tvb_get_ntohs(tvb,q+3)&0x02 ? "is" : "not",
2400                                                             tvb_get_ntohs(tvb,q+3)&0x01 ? "is" : "not");
2401                                         proto_tree_add_text(subtree4,tvb,q+4,2, "MTU: %u byte%s",
2402                                                             tvb_get_ntohs(tvb,q+4),
2403                                                             plurality(tvb_get_ntohs(tvb,q+4), "", "s"));
2404                                         break;
2405                                     }
2406                             }
2407                             if (!is_regular_type && !is_extended_type)
2408                                 proto_tree_add_text(subtree3,tvb,q,8, "%s","Unknown");
2409                             q = q + 8;
2410                         }
2411                 }
2412                 break;
2413             case BGPTYPE_SAFI_SPECIFIC_ATTR:
2414                 q = o + i + aoff;
2415                 end = o + i + aoff + tlen ;
2416
2417                 while(q < end) {
2418                     ssa_type = tvb_get_ntohs(tvb, q) & BGP_SSA_TYPE;
2419                     ssa_len = tvb_get_ntohs(tvb, q + 2);
2420
2421                     ti = proto_tree_add_text(subtree2, tvb, q, MIN(ssa_len + 4, end - q),
2422                             "%s Information",
2423                             val_to_str(ssa_type, bgp_ssa_type, "Unknown SSA"));
2424                     subtree3 = proto_item_add_subtree(ti, ett_bgp_ssa);
2425
2426                     proto_tree_add_item(subtree3, hf_bgp_ssa_t, tvb,
2427                             q, 1, FALSE);
2428                     hidden_item = proto_tree_add_item(subtree3, hf_bgp_ssa_type, tvb,
2429                             q, 2, FALSE);
2430                     PROTO_ITEM_SET_HIDDEN(hidden_item);
2431                     proto_tree_add_text(subtree3, tvb, q, 2,
2432                             "Type: %s", val_to_str(ssa_type, bgp_ssa_type, "Unknown"));
2433                     if ((ssa_len == 0) || (q + ssa_len > end)) {
2434                         proto_tree_add_text(subtree3, tvb, q + 2, end - q - 2,
2435                                 "Invalid Length of %u", ssa_len);
2436                         break;
2437                     }
2438                     proto_tree_add_item(subtree3, hf_bgp_ssa_len, tvb,
2439                             q + 2, 2, FALSE);
2440
2441                     switch(ssa_type){
2442                     case BGP_SSA_L2TPv3:
2443                             proto_tree_add_item(subtree3, hf_bgp_ssa_l2tpv3_pref, tvb,
2444                                     q + 4, 2, FALSE);
2445
2446                             ti = proto_tree_add_text(subtree3, tvb, q + 6, 1, "Flags");
2447                             subtree4 = proto_item_add_subtree(ti, ett_bgp_ssa_subtree) ;
2448                             proto_tree_add_item(subtree4, hf_bgp_ssa_l2tpv3_s, tvb,
2449                                     q + 6, 1, FALSE);
2450                             proto_tree_add_item(subtree4, hf_bgp_ssa_l2tpv3_unused, tvb,
2451                                     q + 6, 1, FALSE);
2452
2453                             ssa_v3_len = tvb_get_guint8(tvb, q + 7);
2454                             if (ssa_v3_len + 8 == ssa_len){
2455                                 proto_tree_add_item(subtree3, hf_bgp_ssa_l2tpv3_cookie_len, tvb,
2456                                         q + 7, 1, FALSE);
2457                             } else {
2458                                 proto_tree_add_text(subtree3, tvb, q + 7, 1,
2459                                         "Invalid Cookie Length of %u", ssa_v3_len);
2460                                 break;
2461                             }
2462                             proto_tree_add_item(subtree3, hf_bgp_ssa_l2tpv3_session_id, tvb,
2463                                     q + 8, 4, FALSE);
2464                             if (ssa_v3_len)
2465                                     proto_tree_add_item(subtree3, hf_bgp_ssa_l2tpv3_cookie, tvb,
2466                                             q + 12, ssa_v3_len, FALSE);
2467                             break;
2468                     case BGP_SSA_mGRE:
2469                     case BGP_SSA_IPSec:
2470                     case BGP_SSA_MPLS:
2471                     default:
2472                             proto_tree_add_item(subtree3, hf_bgp_ssa_value, tvb,
2473                                     q + 4, ssa_len, FALSE);
2474                             break;
2475                     }
2476                     q = q + ssa_len + 4; /* 4 from type and length */
2477                 }
2478                 break;
2479
2480             default:
2481                 proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2482                         "Unknown (%u byte%s)", tlen, plurality(tlen, "", "s"));
2483                 break;
2484             } /* end of second switch */
2485
2486             i += alen + aoff;
2487         }
2488
2489         o += 2 + len;
2490
2491         /* NLRI */
2492         len = hlen - o;
2493
2494         /* parse prefixes */
2495         if (len > 0) {
2496             ti = proto_tree_add_text(tree, tvb, o, len,
2497                    "Network layer reachability information: %u byte%s", len,
2498                    plurality(len, "", "s"));
2499             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
2500             end = o + len;
2501             while (o < end) {
2502                 i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
2503                     "NLRI");
2504                 if (i < 0)
2505                     return;
2506                 o += i;
2507             }
2508         }
2509     }
2510 }
2511
2512 /*
2513  * Dissect a BGP NOTIFICATION message.
2514  */
2515 static void
2516 dissect_bgp_notification(tvbuff_t *tvb, proto_tree *tree)
2517 {
2518     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
2519     int                     hlen;   /* message length           */
2520     const char              *p;     /* string pointer           */
2521
2522     /* snarf message */
2523     tvb_memcpy(tvb, bgpn.bgpn_marker, 0, BGP_MIN_NOTIFICATION_MSG_SIZE);
2524     hlen = g_ntohs(bgpn.bgpn_len);
2525
2526     /* print error code */
2527     proto_tree_add_text(tree, tvb,
2528         offsetof(struct bgp_notification, bgpn_major), 1,
2529         "Error code: %s (%u)",
2530         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
2531         bgpn.bgpn_major);
2532
2533     /* print error subcode */
2534     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
2535      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
2536         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
2537             "Unknown");
2538     } else if (bgpn.bgpn_minor == 0)
2539         p = "Unspecified";
2540     else
2541         p = "Unknown";
2542     proto_tree_add_text(tree, tvb,
2543         offsetof(struct bgp_notification, bgpn_minor), 1,
2544         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
2545
2546     /* only print if there is optional data */
2547     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
2548         proto_tree_add_text(tree, tvb, BGP_MIN_NOTIFICATION_MSG_SIZE,
2549             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
2550     }
2551 }
2552
2553 /*
2554  * Dissect a BGP ROUTE-REFRESH message.
2555  */
2556 static void
2557 dissect_bgp_route_refresh(tvbuff_t *tvb, proto_tree *tree)
2558 {
2559     guint16         i;    /* tmp            */
2560     int             p;         /* tvb offset counter    */
2561     int             pend;       /* end of list of entries for one orf type */
2562     guint16         hlen;       /* tvb RR msg length */
2563     proto_item      *ti;       /* tree item             */
2564     proto_item      *ti1;       /* tree item             */
2565     proto_tree      *subtree;  /* tree for orf   */
2566     proto_tree      *subtree1; /* tree for orf entry */
2567     guint8          orftype;        /* ORF Type */
2568     guint8          orfwhen;        /* ORF flag: immediate, defer */
2569     guint16         orflen;         /* ORF len */
2570     guint8          entryflag;      /* ORF Entry flag: action(add,del,delall) match(permit,deny) */
2571     guint32         entryseq;       /* ORF Entry sequence number */
2572     int             entrylen;       /* ORF Entry length */
2573     guint8          pfx_ge;         /* ORF PrefixList mask lower bound */
2574     guint8          pfx_le;         /* ORF PrefixList mask upper bound */
2575     int             advance;        /* tmp                      */
2576
2577
2578 /*
2579 example 1
2580  00 1c 05       hlen=28
2581  00 01 00 01    afi,safi= ipv4-unicast
2582  02 80 00 01    defer, prefix-orf, len=1
2583     80            removeall
2584 example 2
2585  00 25 05       hlen=37
2586  00 01 00 01    afi,saif= ipv4-unicast
2587  01 80 00 0a    immediate, prefix-orf, len=10
2588     00            add
2589     00 00 00 05   seqno = 5
2590     12            ge = 18
2591     18            le = 24
2592     10 07 02      prefix = 7.2.0.0/16
2593 */
2594     hlen = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
2595     p = BGP_HEADER_SIZE;
2596     /* AFI */
2597     i = tvb_get_ntohs(tvb, p);
2598     proto_tree_add_text(tree, tvb, p, 2,
2599                         "Address family identifier: %s (%u)",
2600                         val_to_str(i, afn_vals, "Unknown"), i);
2601     p += 2;
2602     /* Reserved */
2603     proto_tree_add_text(tree, tvb, p, 1,
2604                         "Reserved: 1 byte");
2605     p++;
2606     /* SAFI */
2607     i = tvb_get_guint8(tvb, p);
2608     proto_tree_add_text(tree, tvb, p, 1,
2609                         "Subsequent address family identifier: %s (%u)",
2610                         val_to_str(i, bgpattr_nlri_safi,
2611                         i >= 128 ? "Vendor specific" : "Unknown"),
2612                         i);
2613     p++;
2614     if ( hlen == BGP_HEADER_SIZE + 4 )
2615         return;
2616     while (p < hlen) {
2617         /* ORF type */
2618         orfwhen = tvb_get_guint8(tvb, p);
2619         orftype = tvb_get_guint8(tvb, p+1);
2620         orflen = tvb_get_ntohs(tvb, p+2);
2621         ti = proto_tree_add_text(tree, tvb, p , orflen + 4 , "ORF information (%u bytes)", orflen + 4);
2622         subtree = proto_item_add_subtree(ti, ett_bgp_orf);
2623         proto_tree_add_text(subtree, tvb, p , 1, "ORF flag: %s", val_to_str(orfwhen, orf_when_vals,"UNKNOWN"));
2624         proto_tree_add_text(subtree, tvb, p+1 , 1, "ORF type: %s", val_to_str(orftype, orf_type_vals,"UNKNOWN"));
2625         proto_tree_add_text(subtree, tvb, p+2 , 2, "ORF len: %u byte%s", orflen, plurality(orflen, "", "s"));
2626         p += 4;
2627
2628         if (orftype != BGP_ORF_PREFIX_CISCO) {
2629             proto_tree_add_text(subtree, tvb, p, orflen,
2630                     "ORFEntry-Unknown (%u bytes)", orflen);
2631             p += orflen;
2632             continue;
2633         }
2634         pend = p + orflen;
2635         while (p < pend) {
2636             entryflag = tvb_get_guint8(tvb, p);
2637             if ((entryflag & BGP_ORF_ACTION) == BGP_ORF_REMOVEALL) {
2638                 ti1 = proto_tree_add_text(subtree, tvb, p, 1,
2639                         "ORFEntry-PrefixList (1 byte)");
2640                 subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2641                 proto_tree_add_text(subtree1, tvb, p , 1, "RemoveAll");
2642                 p++;
2643             } else {
2644                 ti1 = proto_tree_add_text(subtree, tvb, p, -1,
2645                         "ORFEntry-PrefixList");
2646                 subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2647                 proto_tree_add_text(subtree1, tvb, p, 1,
2648                         "ACTION: %s MATCH: %s",
2649                         val_to_str(entryflag&BGP_ORF_ACTION,
2650                             orf_entry_action_vals, "UNKNOWN"),
2651                         val_to_str(entryflag&BGP_ORF_MATCH,
2652                             orf_entry_match_vals, "UNKNOWN"));
2653                 p++;
2654                 entryseq = tvb_get_ntohl(tvb, p);
2655                 proto_tree_add_text(subtree1, tvb, p, 4,
2656                         "Entry Sequence No: %u", entryseq);
2657                 p += 4;
2658                 pfx_ge = tvb_get_guint8(tvb, p);
2659                 proto_tree_add_text(subtree1, tvb, p, 1,
2660                         "PrefixMask length lower bound: %u", pfx_ge);
2661                 p++;
2662                 pfx_le = tvb_get_guint8(tvb, p);
2663                 proto_tree_add_text(subtree1, tvb, p, 1,
2664                         "PrefixMask length upper bound: %u", pfx_le);
2665                 p++;
2666
2667                 advance = decode_prefix4(subtree1, -1, tvb, p, 0, "ORF");
2668                 if (advance < 0)
2669                         break;
2670                 entrylen = 7 + 1 + advance;
2671
2672                 proto_item_append_text(ti1, " (%u bytes)", entrylen);
2673                 proto_item_set_len(ti1, entrylen);
2674                 p += advance;
2675             }
2676         }
2677     }
2678 }
2679
2680 /*
2681  * Dissect a BGP CAPABILITY message.
2682  */
2683 static void
2684 dissect_bgp_capability(tvbuff_t *tvb, proto_tree *tree)
2685 {
2686     int offset = 0;
2687     proto_item *ti;
2688     proto_tree *subtree;
2689     guint8  action;
2690     int ctype;
2691     int clen;
2692     int mend;
2693
2694     mend = offset + tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2695     offset += BGP_HEADER_SIZE;
2696     /* step through all of the capabilities */
2697     while (offset < mend) {
2698         action = tvb_get_guint8(tvb, offset++);
2699         ctype  = tvb_get_guint8(tvb, offset++);
2700         clen   = tvb_get_guint8(tvb, offset++);
2701
2702         ti = proto_tree_add_text(tree, tvb, offset - 2, 2 + clen,
2703              "%s (%u byte%s)", val_to_str(ctype, capability_vals,
2704              "Unknown capability"), 2 + clen, plurality(clen, "", "s"));
2705         subtree = proto_item_add_subtree(ti, ett_bgp_option);
2706         proto_tree_add_text(subtree, tvb, offset-2, 1, "Action: %d (%s)",
2707             action, val_to_str(action, bgpcap_action, "Invalid action value"));
2708         dissect_bgp_capability_item(tvb, &offset, subtree, ctype, clen);
2709     }
2710 }
2711
2712 static void
2713 dissect_bgp_pdu(tvbuff_t *volatile tvb, packet_info *pinfo, proto_tree *tree,
2714     gboolean first)
2715 {
2716     guint16       bgp_len;       /* Message length             */
2717     guint8        bgp_type;      /* Message type               */
2718     const char    *typ;          /* Message type (string)      */
2719     proto_item    *ti;           /* tree item                        */
2720     proto_tree    *bgp_tree;     /* BGP packet tree                  */
2721     proto_tree    *bgp1_tree;    /* BGP message tree                 */
2722
2723     bgp_len = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
2724     bgp_type = tvb_get_guint8(tvb, BGP_MARKER_SIZE + 2);
2725     typ = val_to_str(bgp_type, bgptypevals, "Unknown message type (0x%02x)");
2726
2727     if (check_col(pinfo->cinfo, COL_INFO)) {
2728         if (first)
2729             col_add_str(pinfo->cinfo, COL_INFO, typ);
2730         else
2731             col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", typ);
2732     }
2733
2734     if (tree) {
2735         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0, -1, FALSE);
2736         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2737
2738         ti = proto_tree_add_text(bgp_tree, tvb, 0, -1, "%s", typ);
2739
2740         /* add a different tree for each message type */
2741         switch (bgp_type) {
2742         case BGP_OPEN:
2743             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
2744             break;
2745         case BGP_UPDATE:
2746             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
2747             break;
2748         case BGP_NOTIFICATION:
2749             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
2750             break;
2751         case BGP_KEEPALIVE:
2752             bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2753             break;
2754         case BGP_ROUTE_REFRESH_CISCO:
2755         case BGP_ROUTE_REFRESH:
2756             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
2757             break;
2758         case BGP_CAPABILITY:
2759             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_capability);
2760             break;
2761         default:
2762             bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2763             break;
2764         }
2765
2766         proto_tree_add_text(bgp1_tree, tvb, 0, BGP_MARKER_SIZE,
2767                             "Marker: 16 bytes");
2768
2769         if (bgp_len < BGP_HEADER_SIZE || bgp_len > BGP_MAX_PACKET_SIZE) {
2770             proto_tree_add_text(bgp1_tree, tvb, BGP_MARKER_SIZE, 2,
2771                                 "Length (invalid): %u byte%s", bgp_len,
2772                                 plurality(bgp_len, "", "s"));
2773             return;
2774         } else {
2775             proto_tree_add_text(bgp1_tree, tvb, BGP_MARKER_SIZE, 2,
2776                                 "Length: %u byte%s", bgp_len,
2777                                 plurality(bgp_len, "", "s"));
2778         }
2779
2780         proto_tree_add_uint(bgp1_tree, hf_bgp_type, tvb,
2781                                    BGP_MARKER_SIZE + 2, 1,
2782                                    bgp_type);
2783
2784         switch (bgp_type) {
2785         case BGP_OPEN:
2786             dissect_bgp_open(tvb, bgp1_tree);
2787             break;
2788         case BGP_UPDATE:
2789             dissect_bgp_update(tvb, bgp1_tree);
2790             break;
2791         case BGP_NOTIFICATION:
2792             dissect_bgp_notification(tvb, bgp1_tree);
2793             break;
2794         case BGP_KEEPALIVE:
2795             /* no data in KEEPALIVE messages */
2796             break;
2797         case BGP_ROUTE_REFRESH_CISCO:
2798         case BGP_ROUTE_REFRESH:
2799             dissect_bgp_route_refresh(tvb, bgp1_tree);
2800             break;
2801         case BGP_CAPABILITY:
2802             dissect_bgp_capability(tvb, bgp1_tree);
2803             break;
2804         default:
2805             break;
2806         }
2807     }
2808 }
2809
2810 /*
2811  * Dissect a BGP packet.
2812  */
2813 static void
2814 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2815 {
2816     volatile int  offset = 0;   /* offset into the tvbuff           */
2817     gint          reported_length_remaining;
2818     guint8        bgp_marker[BGP_MARKER_SIZE];    /* Marker (should be all ones */
2819     static guchar marker[] = {   /* BGP message marker               */
2820         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2821         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2822     };
2823     proto_item    *ti;           /* tree item                        */
2824     proto_tree    *bgp_tree;     /* BGP packet tree                  */
2825     guint16       bgp_len;       /* Message length             */
2826     int           offset_before;
2827     guint         length_remaining;
2828     guint         length;
2829     volatile gboolean first = TRUE;  /* TRUE for the first BGP message in packet */
2830     tvbuff_t *volatile next_tvb;
2831
2832     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BGP");
2833     if (check_col(pinfo->cinfo, COL_INFO))
2834         col_clear(pinfo->cinfo, COL_INFO);
2835
2836     /*
2837      * Scan through the TCP payload looking for a BGP marker.
2838      */
2839     while ((reported_length_remaining = tvb_reported_length_remaining(tvb, offset))
2840                 > 0) {
2841         /*
2842          * "reported_length_remaining" is the number of bytes of TCP payload
2843          * remaining.  If it's more than the length of a BGP marker,
2844          * we check only the number of bytes in a BGP marker.
2845          */
2846         if (reported_length_remaining > BGP_MARKER_SIZE)
2847             reported_length_remaining = BGP_MARKER_SIZE;
2848
2849         /*
2850          * OK, is there a BGP marker starting at the specified offset -
2851          * or, at least, the beginning of a BGP marker running to the end
2852          * of the TCP payload?
2853          *
2854          * This will throw an exception if the frame is short; that's what
2855          * we want.
2856          */
2857         tvb_memcpy(tvb, bgp_marker, offset, reported_length_remaining);
2858         if (memcmp(bgp_marker, marker, reported_length_remaining) == 0) {
2859             /*
2860              * Yes - stop scanning and start processing BGP packets.
2861              */
2862             break;
2863         }
2864
2865         /*
2866          * No - keep scanning through the tvbuff to try to find a marker.
2867          */
2868         offset++;
2869     }
2870
2871     /*
2872      * If we skipped any bytes, mark it as a BGP continuation.
2873      */
2874     if (offset > 0) {
2875         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0, -1, FALSE);
2876         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2877
2878         proto_tree_add_text(bgp_tree, tvb, 0, offset, "Continuation");
2879     }
2880
2881     /*
2882      * Now process the BGP packets in the TCP payload.
2883      *
2884      * XXX - perhaps "tcp_dissect_pdus()" should take a starting
2885      * offset, in which case we can replace the loop below with
2886      * a call to "tcp_dissect_pdus()".
2887      */
2888     while (tvb_reported_length_remaining(tvb, offset) > 0) {
2889         /*
2890          * This will throw an exception if we don't have any data left.
2891          * That's what we want.  (See "tcp_dissect_pdus()", which is
2892          * similar.)
2893          */
2894         length_remaining = tvb_ensure_length_remaining(tvb, offset);
2895
2896         /*
2897          * Can we do reassembly?
2898          */
2899         if (bgp_desegment && pinfo->can_desegment) {
2900             /*
2901              * Yes - would a BGP header starting at this offset be split
2902              * across segment boundaries?
2903              */
2904             if (length_remaining < BGP_HEADER_SIZE) {
2905                 /*
2906                  * Yes.  Tell the TCP dissector where the data for this
2907                  * message starts in the data it handed us, and how many
2908                  * more bytes we need, and return.
2909                  */
2910                 pinfo->desegment_offset = offset;
2911                 pinfo->desegment_len = BGP_HEADER_SIZE - length_remaining;
2912                 return;
2913             }
2914         }
2915
2916         /*
2917          * Get the length and type from the BGP header.
2918          */
2919         bgp_len = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2920         if (bgp_len < BGP_HEADER_SIZE) {
2921             /*
2922              * The BGP length doesn't include the BGP header; report that
2923              * as an error.
2924              */
2925             show_reported_bounds_error(tvb, pinfo, tree);
2926             return;
2927         }
2928
2929         /*
2930          * Can we do reassembly?
2931          */
2932         if (bgp_desegment && pinfo->can_desegment) {
2933             /*
2934              * Yes - is the PDU split across segment boundaries?
2935              */
2936             if (length_remaining < bgp_len) {
2937                 /*
2938                  * Yes.  Tell the TCP dissector where the data for this
2939                  * message starts in the data it handed us, and how many
2940                  * more bytes we need, and return.
2941                  */
2942                 pinfo->desegment_offset = offset;
2943                 pinfo->desegment_len = bgp_len - length_remaining;
2944                 return;
2945             }
2946         }
2947
2948         /*
2949          * Construct a tvbuff containing the amount of the payload we have
2950          * available.  Make its reported length the amount of data in the PDU.
2951          *
2952          * XXX - if reassembly isn't enabled. the subdissector will throw a
2953          * BoundsError exception, rather than a ReportedBoundsError exception.
2954          * We really want a tvbuff where the length is "length", the reported
2955          * length is "plen", and the "if the snapshot length were infinite"
2956          * length is the minimum of the reported length of the tvbuff handed
2957          * to us and "plen", with a new type of exception thrown if the offset
2958          * is within the reported length but beyond that third length, with
2959          * that exception getting the "Unreassembled Packet" error.
2960          */
2961         length = length_remaining;
2962         if (length > bgp_len)
2963             length = bgp_len;
2964         next_tvb = tvb_new_subset(tvb, offset, length, bgp_len);
2965
2966         /*
2967          * Dissect the PDU.
2968          *
2969          * Catch the ReportedBoundsError exception; if this particular message
2970          * happens to get a ReportedBoundsError exception, that doesn't mean
2971          * that we should stop dissecting PDUs within this frame or chunk of
2972          * reassembled data.
2973          *
2974          * If it gets a BoundsError, we can stop, as there's nothing more to
2975          * see, so we just re-throw it.
2976          */
2977         TRY {
2978             dissect_bgp_pdu(next_tvb, pinfo, tree, first);
2979         }
2980         CATCH(BoundsError) {
2981             RETHROW;
2982         }
2983         CATCH(ReportedBoundsError) {
2984             show_reported_bounds_error(tvb, pinfo, tree);
2985         }
2986         ENDTRY;
2987
2988         first = FALSE;
2989
2990         /*
2991          * Step to the next PDU.
2992          * Make sure we don't overflow.
2993          */
2994         offset_before = offset;
2995         offset += bgp_len;
2996         if (offset <= offset_before)
2997             break;
2998     }
2999 }
3000
3001 /*
3002  * Register ourselves.
3003  */
3004 void
3005 proto_register_bgp(void)
3006 {
3007
3008     static hf_register_info hf[] = {
3009       { &hf_bgp_type,
3010         { "Type", "bgp.type", FT_UINT8, BASE_DEC,
3011           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
3012       { &hf_bgp_aggregator_as,
3013         { "Aggregator AS", "bgp.aggregator_as", FT_UINT16, BASE_DEC,
3014           NULL, 0x0, NULL, HFILL}},
3015       { &hf_bgp_aggregator_origin,
3016         { "Aggregator origin", "bgp.aggregator_origin", FT_IPv4, BASE_NONE,
3017           NULL, 0x0, NULL, HFILL}},
3018       { &hf_bgp_as_path,
3019         { "AS Path", "bgp.as_path", FT_UINT16, BASE_DEC,
3020           NULL, 0x0, NULL, HFILL}},
3021       { &hf_bgp_cluster_identifier,
3022         { "Cluster identifier", "bgp.cluster_identifier", FT_IPv4, BASE_NONE,
3023           NULL, 0x0, NULL, HFILL}},
3024       { &hf_bgp_community_as,
3025         { "Community AS", "bgp.community_as", FT_UINT16, BASE_DEC,
3026           NULL, 0x0, NULL, HFILL}},
3027       { &hf_bgp_community_value,
3028         { "Community value", "bgp.community_value", FT_UINT16, BASE_DEC,
3029           NULL, 0x0, NULL, HFILL}},
3030       { &hf_bgp_local_pref,
3031         { "Local preference", "bgp.local_pref", FT_UINT32, BASE_DEC,
3032           NULL, 0x0, NULL, HFILL}},
3033       { &hf_bgp_mp_reach_nlri_ipv4_prefix,
3034         { "MP Reach NLRI IPv4 prefix", "bgp.mp_reach_nlri_ipv4_prefix", FT_IPv4, BASE_NONE,
3035           NULL, 0x0, NULL, HFILL}},
3036       { &hf_bgp_mp_unreach_nlri_ipv4_prefix,
3037         { "MP Unreach NLRI IPv4 prefix", "bgp.mp_unreach_nlri_ipv4_prefix", FT_IPv4, BASE_NONE,
3038           NULL, 0x0, NULL, HFILL}},
3039       { &hf_bgp_mp_nlri_tnl_id,
3040         { "MP Reach NLRI Tunnel Identifier", "bgp.mp_nlri_tnl_id", FT_UINT16, BASE_HEX,
3041           NULL, 0x0, NULL, HFILL}},
3042       { &hf_bgp_multi_exit_disc,
3043         { "Multiple exit discriminator", "bgp.multi_exit_disc", FT_UINT32, BASE_DEC,
3044           NULL, 0x0, NULL, HFILL}},
3045       { &hf_bgp_next_hop,
3046         { "Next hop", "bgp.next_hop", FT_IPv4, BASE_NONE,
3047           NULL, 0x0, NULL, HFILL}},
3048       { &hf_bgp_nlri_prefix,
3049         { "NLRI prefix", "bgp.nlri_prefix", FT_IPv4, BASE_NONE,
3050           NULL, 0x0, NULL, HFILL}},
3051       { &hf_bgp_origin,
3052         { "Origin", "bgp.origin", FT_UINT8, BASE_DEC,
3053           VALS(bgpattr_origin), 0x0, NULL, HFILL}},
3054       { &hf_bgp_originator_id,
3055         { "Originator identifier", "bgp.originator_id", FT_IPv4, BASE_NONE,
3056           NULL, 0x0, NULL, HFILL}},
3057       { &hf_bgp_ssa_t,
3058         { "Transitive bit", "bgp.ssa_t", FT_BOOLEAN, 8,
3059           NULL, 0x80, "SSA Transitive bit", HFILL}},
3060       { &hf_bgp_ssa_type,
3061         { "SSA Type", "bgp.ssa_type", FT_UINT16, BASE_DEC,
3062           VALS(bgp_ssa_type), 0x7FFF, NULL, HFILL}},
3063       { &hf_bgp_ssa_len,
3064         { "Length", "bgp.ssa_len", FT_UINT16, BASE_DEC,
3065           NULL, 0x0, "SSA Length", HFILL}},
3066       { &hf_bgp_ssa_value,
3067         { "Value", "bgp.ssa_value", FT_BYTES, BASE_NONE,
3068           NULL, 0x0, "SSA Value", HFILL}},
3069       { &hf_bgp_ssa_l2tpv3_pref,
3070         { "Preference", "bgp.ssa_l2tpv3_pref", FT_UINT16, BASE_DEC,
3071           NULL, 0x0, NULL, HFILL}},
3072       { &hf_bgp_ssa_l2tpv3_s,
3073         { "Sequencing bit", "bgp.ssa_l2tpv3_s", FT_BOOLEAN, 8,
3074           NULL, 0x80, "Sequencing S-bit", HFILL}},
3075       { &hf_bgp_ssa_l2tpv3_unused,
3076         { "Unused", "bgp.ssa_l2tpv3_Unused", FT_BOOLEAN, 8,
3077           NULL, 0x7F, "Unused Flags", HFILL}},
3078       { &hf_bgp_ssa_l2tpv3_cookie_len,
3079         { "Cookie Length", "bgp.ssa_l2tpv3_cookie_len", FT_UINT8, BASE_DEC,
3080           NULL, 0x0, NULL, HFILL}},
3081       { &hf_bgp_ssa_l2tpv3_session_id,
3082         { "Session ID", "bgp.ssa_l2tpv3_session_id", FT_UINT32, BASE_DEC,
3083           NULL, 0x0, NULL, HFILL}},
3084       { &hf_bgp_ssa_l2tpv3_cookie,
3085         { "Cookie", "bgp.ssa_l2tpv3_cookie", FT_BYTES, BASE_NONE,
3086           NULL, 0x0, NULL, HFILL}},
3087       { &hf_bgp_withdrawn_prefix,
3088         { "Withdrawn prefix", "bgp.withdrawn_prefix", FT_IPv4, BASE_NONE,
3089           NULL, 0x0, NULL, HFILL}},
3090       { &hf_bgp_cluster_list,
3091         { "Cluster List", "bgp.cluster_list", FT_BYTES, BASE_NONE,
3092           NULL, 0x0, NULL, HFILL}}
3093     };
3094
3095     static gint *ett[] = {
3096       &ett_bgp,
3097       &ett_bgp_prefix,
3098       &ett_bgp_unfeas,
3099       &ett_bgp_attrs,
3100       &ett_bgp_attr,
3101       &ett_bgp_attr_flags,
3102       &ett_bgp_mp_nhna,
3103       &ett_bgp_mp_reach_nlri,
3104       &ett_bgp_mp_unreach_nlri,
3105       &ett_bgp_mp_snpa,
3106       &ett_bgp_nlri,
3107       &ett_bgp_open,
3108       &ett_bgp_update,
3109       &ett_bgp_notification,
3110       &ett_bgp_route_refresh,
3111       &ett_bgp_capability,
3112       &ett_bgp_as_paths,
3113       &ett_bgp_as_path_segments,
3114       &ett_bgp_communities,
3115       &ett_bgp_cluster_list,
3116       &ett_bgp_options,
3117       &ett_bgp_option,
3118       &ett_bgp_extended_communities,
3119       &ett_bgp_ext_com_flags,
3120       &ett_bgp_ssa,
3121       &ett_bgp_ssa_subtree,
3122       &ett_bgp_orf,
3123       &ett_bgp_orf_entry
3124     };
3125     module_t *bgp_module;
3126     static enum_val_t asn_len[] = {
3127         {"auto-detect", "Auto-detect", 0},
3128         {"2", "2 octet", 2},
3129         {"4", "4 octet", 4},
3130         {NULL, NULL, -1}
3131     };
3132
3133     proto_bgp = proto_register_protocol("Border Gateway Protocol",
3134                                         "BGP", "bgp");
3135     proto_register_field_array(proto_bgp, hf, array_length(hf));
3136     proto_register_subtree_array(ett, array_length(ett));
3137
3138     bgp_module = prefs_register_protocol(proto_bgp, NULL);
3139     prefs_register_bool_preference(bgp_module, "desegment",
3140       "Reassemble BGP messages spanning multiple TCP segments",
3141       "Whether the BGP dissector should reassemble messages spanning multiple TCP segments."
3142       " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3143       &bgp_desegment);
3144     prefs_register_enum_preference(bgp_module, "asn_len",
3145       "Length of the AS number",
3146       "BGP dissector detect the length of the AS number in AS_PATH attributes automatically or manually (NOTE: Automatic detection is not 100% accurate)",
3147       &bgp_asn_len, asn_len, FALSE);
3148 }
3149
3150 void
3151 proto_reg_handoff_bgp(void)
3152 {
3153     dissector_handle_t bgp_handle;
3154
3155     bgp_handle = create_dissector_handle(dissect_bgp, proto_bgp);
3156     dissector_add("tcp.port", BGP_TCP_PORT, bgp_handle);
3157 }