decd20987f020f37dc7a70599c813f29d630601b
[obnox/wireshark/wip.git] / epan / dissectors / packet-mpls.c
1 /* packet-mpls.c
2  * Routines for MPLS data packet disassembly
3  * RFC 3032
4  *
5  * (c) Copyright Ashok Narayanan <ashokn@cisco.com>
6  *
7  * $Id$
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
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 #include <glib.h>
42 #include <epan/packet.h>
43 #include "ppptypes.h"
44 #include "etypes.h"
45 #include "prefs.h"
46 #include "packet-ppp.h"
47
48 static gint proto_mpls = -1;
49
50 static gint ett_mpls = -1;
51 static gint ett_mpls_control = -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 int hf_mpls_control_control = -1;
88 static int hf_mpls_control_res = -1;
89
90 static hf_register_info mplsf_info[] = {
91
92 /*    {&mpls_filter[MPLSF_PACKET],
93      {"MPLS Label Switched Packet", "mpls", FT_UINT8, BASE_DEC, NULL, 0x0,
94       "", HFILL }},*/
95
96     {&mpls_filter[MPLSF_LABEL],
97      {"MPLS Label", "mpls.label", FT_UINT32, BASE_DEC, VALS(special_labels), 0x0,
98       "", HFILL }},
99
100     {&mpls_filter[MPLSF_EXP],
101      {"MPLS Experimental Bits", "mpls.exp", FT_UINT8, BASE_DEC, NULL, 0x0,
102       "", HFILL }},
103
104     {&mpls_filter[MPLSF_BOTTOM_OF_STACK],
105      {"MPLS Bottom Of Label Stack", "mpls.bottom", FT_UINT8, BASE_DEC, NULL, 0x0,
106       "", HFILL }},
107
108     {&mpls_filter[MPLSF_TTL],
109      {"MPLS TTL", "mpls.ttl", FT_UINT8, BASE_DEC, NULL, 0x0,
110       "", HFILL }},
111
112     {&hf_mpls_control_control,
113      {"MPLS Control Channel", "mpls.cw.control", FT_UINT8, BASE_DEC, NULL, 0xF0,
114       "First nibble", HFILL }},
115
116     {&hf_mpls_control_res,
117      {"Reserved", "mpls.cw.res", FT_UINT16, BASE_HEX, NULL, 0xFFF, 
118       "Reserved", HFILL }},
119 };
120
121 static dissector_handle_t ipv4_handle;
122 static dissector_handle_t ipv6_handle;
123 static dissector_handle_t eth_handle;
124 static dissector_handle_t data_handle;
125 static dissector_table_t ppp_subdissector_table;
126
127 /*
128  * Given a 4-byte MPLS label starting at offset "offset", in tvbuff "tvb",
129  * decode it.
130  * Return the label in "label", EXP bits in "exp",
131  * bottom_of_stack in "bos", and TTL in "ttl"
132  */
133 void decode_mpls_label(tvbuff_t *tvb, int offset,
134                        guint32 *label, guint8 *exp,
135                        guint8 *bos, guint8 *ttl)
136 {
137     guint8 octet0 = tvb_get_guint8(tvb, offset+0);
138     guint8 octet1 = tvb_get_guint8(tvb, offset+1);
139     guint8 octet2 = tvb_get_guint8(tvb, offset+2);
140
141     *label = (octet0 << 12) + (octet1 << 4) + ((octet2 >> 4) & 0xff);
142     *exp = (octet2 >> 1) & 0x7;
143     *bos = (octet2 & 0x1);
144     *ttl = tvb_get_guint8(tvb, offset+3);
145 }
146
147 static void
148 dissect_mpls_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
149 {
150     proto_tree  *mpls_control_tree = NULL;
151     proto_item  *ti;
152     tvbuff_t    *next_tvb;
153     guint8      ctrl;
154     guint16     res, ppp_proto;
155
156     if (tvb_reported_length_remaining(tvb, 0) < 4){
157         if(tree)
158             proto_tree_add_text(tree, tvb, 0, -1, "Error processing Message");
159         return;
160     }
161     ctrl = (tvb_get_guint8(tvb, 0) & 0xF0) >> 4;
162     res = tvb_get_ntohs(tvb, 0) & 0x0FFF;
163     ppp_proto = tvb_get_ntohs(tvb, 2);
164     if (tree) {
165         ti = proto_tree_add_text(tree, tvb, 0, 4, "MPLS PW Control Channel Header");
166         mpls_control_tree = proto_item_add_subtree(ti, ett_mpls_control);
167         if(mpls_control_tree == NULL) return;
168
169         proto_tree_add_uint_format(mpls_control_tree, hf_mpls_control_control, tvb, 0, 1,
170             ctrl, "Control Channel: 0x%1x", ctrl);
171         proto_tree_add_uint_format(mpls_control_tree, hf_mpls_control_res, tvb, 0, 2,
172             res, "Reserved: 0x%03x", res);
173         proto_tree_add_text(mpls_control_tree, tvb, 2, 2,
174             "PPP DLL Protocol Number: %s (0x%04X)", 
175                 val_to_str(ppp_proto, ppp_vals, "Unknown"), ppp_proto);
176     }
177     next_tvb = tvb_new_subset(tvb, 4, -1, -1);
178     if (!dissector_try_port(ppp_subdissector_table, ppp_proto, 
179         next_tvb, pinfo, tree)) {
180             call_dissector(data_handle, next_tvb, pinfo, tree);
181     }
182
183
184 }
185
186 static void
187 dissect_mpls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
188 {
189     int offset = 0;
190     guint32 label;
191     guint8 exp;
192     guint8 bos;
193     guint8 ttl;
194     guint8 ipvers;
195
196     proto_tree  *mpls_tree;
197     proto_item  *ti;
198     tvbuff_t *next_tvb;
199
200     if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
201         col_set_str(pinfo->cinfo,COL_PROTOCOL, "MPLS");
202     }
203
204     if (check_col(pinfo->cinfo,COL_INFO)) {
205         col_add_fstr(pinfo->cinfo,COL_INFO,"MPLS Label Switched Packet");
206     }
207
208     /* Start Decoding Here. */
209     while (tvb_reported_length_remaining(tvb, offset) > 0) {
210         decode_mpls_label(tvb, offset, &label, &exp, &bos, &ttl);
211
212         if (tree) {
213
214             ti = proto_tree_add_item(tree, proto_mpls, tvb, offset, 4, FALSE);
215             mpls_tree = proto_item_add_subtree(ti, ett_mpls);
216
217             proto_item_append_text(ti, ", Label: %u", label);
218             if (label <= MAX_RESERVED){
219                 proto_tree_add_uint_format(mpls_tree, mpls_filter[MPLSF_LABEL], tvb,
220                                     offset, 3, label, "MPLS Label: %u (%s)",
221                                     label, val_to_str(label, special_labels,
222                                                       "Reserved - Unknown"));
223                 proto_item_append_text(ti, " (%s)", val_to_str(label, special_labels,
224                                         "Reserved - Unknown"));
225             } else {
226                 proto_tree_add_uint_format(mpls_tree, mpls_filter[MPLSF_LABEL], tvb,
227                                     offset, 3, label, "MPLS Label: %u", label);
228             }
229
230             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_EXP], tvb,
231                                 offset+2,1, exp);
232             proto_item_append_text(ti, ", Exp: %u", exp);
233
234             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_BOTTOM_OF_STACK], tvb,
235                                 offset+2,1, bos);
236             proto_item_append_text(ti, ", S: %u", bos);
237
238             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_TTL], tvb,
239                                 offset+3,1, ttl);
240             proto_item_append_text(ti, ", TTL: %u", ttl);
241         }
242         offset += 4;
243         if (bos) break;
244     }
245     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
246
247     ipvers = (tvb_get_guint8(tvb, offset) >> 4) & 0x0F;
248     if (ipvers == 6) {
249       call_dissector(ipv6_handle, next_tvb, pinfo, tree);
250     } else if (ipvers == 4) {
251       call_dissector(ipv4_handle, next_tvb, pinfo, tree);
252     } else if (ipvers == 1) {
253       dissect_mpls_control(next_tvb, pinfo, tree);
254     } else {
255       call_dissector(eth_handle, next_tvb, pinfo, tree);
256     }
257 }
258
259 void
260 proto_register_mpls(void)
261 {
262         static gint *ett[] = {
263                 &ett_mpls,
264                 &ett_mpls_control,
265         };
266
267         proto_mpls = proto_register_protocol("MultiProtocol Label Switching Header",
268             "MPLS", "mpls");
269         proto_register_field_array(proto_mpls, mplsf_info, array_length(mplsf_info));
270         proto_register_subtree_array(ett, array_length(ett));
271 }
272
273 void
274 proto_reg_handoff_mpls(void)
275 {
276         dissector_handle_t mpls_handle;
277
278         /*
279          * Get a handle for the IPv4 and IPv6 dissectors and PPP protocol dissector table.
280          */
281         ipv4_handle = find_dissector("ip");
282         ipv6_handle = find_dissector("ipv6");
283         eth_handle = find_dissector("eth");
284         data_handle = find_dissector("data");
285         ppp_subdissector_table = find_dissector_table("ppp.protocol");
286
287
288         mpls_handle = create_dissector_handle(dissect_mpls, proto_mpls);
289         dissector_add("ethertype", ETHERTYPE_MPLS, mpls_handle);
290         dissector_add("ethertype", ETHERTYPE_MPLS_MULTI, mpls_handle);
291         dissector_add("ppp.protocol", PPP_MPLS_UNI, mpls_handle);
292         dissector_add("ppp.protocol", PPP_MPLS_MULTI, mpls_handle);
293         dissector_add("chdlctype", ETHERTYPE_MPLS, mpls_handle);
294         dissector_add("chdlctype", ETHERTYPE_MPLS_MULTI, mpls_handle);
295         dissector_add("gre.proto", ETHERTYPE_MPLS, mpls_handle);
296         dissector_add("gre.proto", ETHERTYPE_MPLS_MULTI, mpls_handle);
297 }