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