Tvbuffify the IP, ICMP, TCP, UDP, OSI CLNP, OSI COTP, OSI CLTP, and OSI
[obnox/wireshark/wip.git] / packet-mpls.c
1 /* packet-mpls.c
2  * Routines for MPLS data packet disassembly
3  * 
4  * (c) Copyright Ashok Narayanan <ashokn@cisco.com>
5  *
6  * $Id: packet-mpls.c,v 1.10 2000/11/18 10:38:24 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 /*
29  * NOTES
30  *
31  * This module defines routines to handle Ethernet-encapsulated MPLS IP packets.
32  * It should implement all the functionality in <draft-ietf-mpls-label-encaps-07.txt>
33  * Multicast MPLS support is not tested yet
34  */
35
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #ifdef HAVE_SYS_TYPES_H
42 # include <sys/types.h>
43 #endif
44
45 #include <glib.h>
46 #include "etypes.h"
47 #include "packet.h"
48
49 static gint proto_mpls = -1;
50
51 static gint ett_mpls = -1;
52
53 /* Special labels in MPLS */
54 enum {
55     IP4_EXPLICIT_NULL = 0,
56     ROUTER_ALERT,
57     IP6_EXPLICIT_NULL,
58     IMPLICIT_NULL,
59
60     MAX_RESERVED = 15
61 };
62
63 static const value_string special_labels[] = {
64     {IP4_EXPLICIT_NULL, "IPv4 Explicit-Null"},
65     {ROUTER_ALERT, "Router Alert"},
66     {IP6_EXPLICIT_NULL, "IPv6 Explicit-Null"},
67     {IMPLICIT_NULL, "Implicit-Null"},
68     {0, NULL }
69 };
70
71 /* MPLS filter values */
72 enum mpls_filter_keys {
73
74     /* Is the packet MPLS-encapsulated? */
75 /*    MPLSF_PACKET,*/
76
77     /* MPLS encap properties */
78     MPLSF_LABEL,
79     MPLSF_EXP,
80     MPLSF_BOTTOM_OF_STACK,
81     MPLSF_TTL,
82
83     MPLSF_MAX
84 };
85
86 static int mpls_filter[MPLSF_MAX];
87 static hf_register_info mplsf_info[] = {
88
89 /*    {&mpls_filter[MPLSF_PACKET], 
90      {"MPLS Label Switched Packet", "mpls", FT_UINT8, BASE_NONE, NULL, 0x0, 
91       "" }},*/
92
93     {&mpls_filter[MPLSF_LABEL], 
94      {"MPLS Label", "mpls.label", FT_UINT32, BASE_DEC, VALS(special_labels), 0x0, 
95       "" }},
96
97     {&mpls_filter[MPLSF_EXP], 
98      {"MPLS Experimental Bits", "mpls.exp", FT_UINT8, BASE_DEC, NULL, 0x0, 
99       "" }},
100
101     {&mpls_filter[MPLSF_BOTTOM_OF_STACK], 
102      {"MPLS Bottom Of Label Stack", "mpls.bottom", FT_UINT8, BASE_DEC, NULL, 0x0, 
103       "" }},
104
105     {&mpls_filter[MPLSF_TTL], 
106      {"MPLS TTL", "mpls.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, 
107       "" }},
108 };
109
110 static dissector_handle_t ip_handle;
111
112 /*
113  * Given a 4-byte MPLS label starting at "start", decode this.
114  * Return the label in "label", EXP bits in "exp",
115  * bottom_of_stack in "bos", and TTL in "ttl"
116  */
117 void decode_mpls_label(const unsigned char *start,  
118                        guint32 *label, guint8 *exp,
119                        guint8 *bos, guint8 *ttl)
120 {
121     *label = (start[0] << 12) + (start[1] << 4) + ((start[2] >> 4) & 0xff);
122     *exp = (start[2] >> 1) & 0x7;
123     *bos = (start[2] & 0x1);
124     *ttl = start[3];
125 }
126
127 static void
128 dissect_mpls(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
129 {
130     guint32 label;
131     guint8 exp;
132     guint8 bos;
133     guint8 ttl;
134
135     proto_tree  *mpls_tree;
136     proto_item  *ti;
137
138     OLD_CHECK_DISPLAY_AS_DATA(proto_mpls, pd, offset, fd, tree);
139
140     if (check_col(fd, COL_PROTOCOL)) {
141         col_add_str(fd,COL_PROTOCOL, "MPLS");
142     }
143     
144     if (check_col(fd,COL_INFO)) {
145         col_add_fstr(fd,COL_INFO,"MPLS Label Switched Packet");
146     }
147
148     /* Start Decoding Here. */
149     while (1) {
150         if (!BYTES_ARE_IN_FRAME(offset, 4)) {
151             old_dissect_data(pd, offset, fd, tree);
152             return;
153         }
154
155         decode_mpls_label(pd+offset, &label, &exp, &bos, &ttl);
156
157         if (tree) {
158
159             ti = proto_tree_add_item(tree, proto_mpls, NullTVB, offset, 4, FALSE);
160             mpls_tree = proto_item_add_subtree(ti, ett_mpls);
161
162             if (label <= MAX_RESERVED)
163                 proto_tree_add_uint_format(mpls_tree, mpls_filter[MPLSF_LABEL], NullTVB,
164                                     offset, 3, label, "Label: %d (%s)", 
165                                     label, val_to_str(label, special_labels, 
166                                                       "Reserved - Unknown"));
167             else
168                 proto_tree_add_uint(mpls_tree, mpls_filter[MPLSF_LABEL], NullTVB,
169                                     offset, 3, label);
170
171             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_EXP], NullTVB, 
172                                 offset+2,1, exp);
173             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_BOTTOM_OF_STACK], NullTVB, 
174                                 offset+2,1, bos);
175             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_TTL], NullTVB, 
176                                 offset+3,1, ttl);
177         }
178         offset += 4;
179         if (bos) break;
180     }
181     old_call_dissector(ip_handle, pd, offset, fd, tree);
182 }
183
184 void
185 proto_register_mpls(void)
186 {
187         static gint *ett[] = {
188                 &ett_mpls,
189         };
190
191         proto_mpls = proto_register_protocol("MultiProtocol Label Switching Header", "mpls");
192         proto_register_field_array(proto_mpls, mplsf_info, array_length(mplsf_info));
193         proto_register_subtree_array(ett, array_length(ett));
194 }
195
196 void
197 proto_reg_handoff_mpls(void)
198 {
199         old_dissector_add("ethertype", ETHERTYPE_MPLS, dissect_mpls);
200
201         /*
202          * Get a handle for the IP dissector.
203          */
204         ip_handle = find_dissector("ip");
205 }