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