add details for doxygen
[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.31 2004/05/15 19:54:10 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 /*
28  * NOTES
29  *
30  * This module defines routines to handle Ethernet-encapsulated MPLS IP packets.
31  * It should implement all the functionality in <draft-ietf-mpls-label-encaps-07.txt>
32  * Multicast MPLS support is not tested yet
33  */
34
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <glib.h>
41 #include <epan/packet.h>
42 #include "ppptypes.h"
43 #include "etypes.h"
44 #include "prefs.h"
45 #include "packet-ppp.h"
46
47 static gint proto_mpls = -1;
48
49 static gint ett_mpls = -1;
50 static gint ett_mpls_control = -1;
51
52 /* Special labels in MPLS */
53 enum {
54     IP4_EXPLICIT_NULL = 0,
55     ROUTER_ALERT,
56     IP6_EXPLICIT_NULL,
57     IMPLICIT_NULL,
58
59     MAX_RESERVED = 15
60 };
61
62 static const value_string special_labels[] = {
63     {IP4_EXPLICIT_NULL, "IPv4 Explicit-Null"},
64     {ROUTER_ALERT, "Router Alert"},
65     {IP6_EXPLICIT_NULL, "IPv6 Explicit-Null"},
66     {IMPLICIT_NULL, "Implicit-Null"},
67     {0, NULL }
68 };
69
70 /* MPLS filter values */
71 enum mpls_filter_keys {
72
73     /* Is the packet MPLS-encapsulated? */
74 /*    MPLSF_PACKET,*/
75
76     /* MPLS encap properties */
77     MPLSF_LABEL,
78     MPLSF_EXP,
79     MPLSF_BOTTOM_OF_STACK,
80     MPLSF_TTL,
81
82     MPLSF_MAX
83 };
84
85 static int mpls_filter[MPLSF_MAX];
86 static int hf_mpls_control_control = -1;
87 static int hf_mpls_control_res = -1;
88
89 static hf_register_info mplsf_info[] = {
90
91 /*    {&mpls_filter[MPLSF_PACKET],
92      {"MPLS Label Switched Packet", "mpls", FT_UINT8, BASE_DEC, NULL, 0x0,
93       "", HFILL }},*/
94
95     {&mpls_filter[MPLSF_LABEL],
96      {"MPLS Label", "mpls.label", FT_UINT32, BASE_DEC, VALS(special_labels), 0x0,
97       "", HFILL }},
98
99     {&mpls_filter[MPLSF_EXP],
100      {"MPLS Experimental Bits", "mpls.exp", FT_UINT8, BASE_DEC, NULL, 0x0,
101       "", HFILL }},
102
103     {&mpls_filter[MPLSF_BOTTOM_OF_STACK],
104      {"MPLS Bottom Of Label Stack", "mpls.bottom", FT_UINT8, BASE_DEC, NULL, 0x0,
105       "", HFILL }},
106
107     {&mpls_filter[MPLSF_TTL],
108      {"MPLS TTL", "mpls.ttl", FT_UINT8, BASE_DEC, NULL, 0x0,
109       "", HFILL }},
110
111     {&hf_mpls_control_control,
112      {"MPLS Control Channel", "mpls.cw.control", FT_UINT8, BASE_DEC, NULL, 0xF0,
113       "First nibble", HFILL }},
114
115     {&hf_mpls_control_res,
116      {"Reserved", "mpls.cw.res", FT_UINT16, BASE_HEX, NULL, 0xFFF, 
117       "Reserved", HFILL }},
118 };
119
120 static dissector_handle_t ipv4_handle;
121 static dissector_handle_t ipv6_handle;
122 static dissector_handle_t eth_handle;
123 static dissector_handle_t data_handle;
124 static dissector_table_t ppp_subdissector_table;
125
126 /*
127  * Given a 4-byte MPLS label starting at offset "offset", in tvbuff "tvb",
128  * decode it.
129  * Return the label in "label", EXP bits in "exp",
130  * bottom_of_stack in "bos", and TTL in "ttl"
131  */
132 void decode_mpls_label(tvbuff_t *tvb, int offset,
133                        guint32 *label, guint8 *exp,
134                        guint8 *bos, guint8 *ttl)
135 {
136     guint8 octet0 = tvb_get_guint8(tvb, offset+0);
137     guint8 octet1 = tvb_get_guint8(tvb, offset+1);
138     guint8 octet2 = tvb_get_guint8(tvb, offset+2);
139
140     *label = (octet0 << 12) + (octet1 << 4) + ((octet2 >> 4) & 0xff);
141     *exp = (octet2 >> 1) & 0x7;
142     *bos = (octet2 & 0x1);
143     *ttl = tvb_get_guint8(tvb, offset+3);
144 }
145
146 static void
147 dissect_mpls_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
148 {
149     proto_tree  *mpls_control_tree = NULL;
150     proto_item  *ti;
151     tvbuff_t    *next_tvb;
152     guint8      ctrl;
153     guint16     res, ppp_proto;
154
155     if (tvb_reported_length_remaining(tvb, 0) < 4){
156         if(tree)
157             proto_tree_add_text(tree, tvb, 0, -1, "Error processing Message");
158         return;
159     }
160     ctrl = (tvb_get_guint8(tvb, 0) & 0xF0) >> 4;
161     res = tvb_get_ntohs(tvb, 0) & 0x0FFF;
162     ppp_proto = tvb_get_ntohs(tvb, 2);
163     if (tree) {
164         ti = proto_tree_add_text(tree, tvb, 0, 4, "MPLS PW Control Channel Header");
165         mpls_control_tree = proto_item_add_subtree(ti, ett_mpls_control);
166         if(mpls_control_tree == NULL) return;
167
168         proto_tree_add_uint_format(mpls_control_tree, hf_mpls_control_control, tvb, 0, 1,
169             ctrl, "Control Channel: 0x%1x", ctrl);
170         proto_tree_add_uint_format(mpls_control_tree, hf_mpls_control_res, tvb, 0, 2,
171             res, "Reserved: 0x%03x", res);
172         proto_tree_add_text(mpls_control_tree, tvb, 2, 2,
173             "PPP DLL Protocol Number: %s (0x%04X)", 
174                 val_to_str(ppp_proto, ppp_vals, "Unknown"), ppp_proto);
175     }
176     next_tvb = tvb_new_subset(tvb, 4, -1, -1);
177     if (!dissector_try_port(ppp_subdissector_table, ppp_proto, 
178         next_tvb, pinfo, tree)) {
179             call_dissector(data_handle, next_tvb, pinfo, tree);
180     }
181
182
183 }
184
185 static void
186 dissect_mpls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
187 {
188     int offset = 0;
189     guint32 label;
190     guint8 exp;
191     guint8 bos;
192     guint8 ttl;
193     guint8 ipvers;
194
195     proto_tree  *mpls_tree;
196     proto_item  *ti;
197     tvbuff_t *next_tvb;
198
199     if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
200         col_set_str(pinfo->cinfo,COL_PROTOCOL, "MPLS");
201     }
202
203     if (check_col(pinfo->cinfo,COL_INFO)) {
204         col_add_fstr(pinfo->cinfo,COL_INFO,"MPLS Label Switched Packet");
205     }
206
207     /* Start Decoding Here. */
208     while (tvb_reported_length_remaining(tvb, offset) > 0) {
209         decode_mpls_label(tvb, offset, &label, &exp, &bos, &ttl);
210
211         if (tree) {
212
213             ti = proto_tree_add_item(tree, proto_mpls, tvb, offset, 4, FALSE);
214             mpls_tree = proto_item_add_subtree(ti, ett_mpls);
215
216             if (label <= MAX_RESERVED)
217                 proto_tree_add_uint_format(mpls_tree, mpls_filter[MPLSF_LABEL], tvb,
218                                     offset, 3, label, "Label: %u (%s)",
219                                     label, val_to_str(label, special_labels,
220                                                       "Reserved - Unknown"));
221             else
222                 proto_tree_add_uint(mpls_tree, mpls_filter[MPLSF_LABEL], tvb,
223                                     offset, 3, label);
224
225             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_EXP], tvb,
226                                 offset+2,1, exp);
227             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_BOTTOM_OF_STACK], tvb,
228                                 offset+2,1, bos);
229             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_TTL], tvb,
230                                 offset+3,1, ttl);
231         }
232         offset += 4;
233         if (bos) break;
234     }
235     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
236
237     ipvers = (tvb_get_guint8(tvb, offset) >> 4) & 0x0F;
238     if (ipvers == 6) {
239       call_dissector(ipv6_handle, next_tvb, pinfo, tree);
240     } else if (ipvers == 4) {
241       call_dissector(ipv4_handle, next_tvb, pinfo, tree);
242     } else if (ipvers == 1) {
243       dissect_mpls_control(next_tvb, pinfo, tree);
244     } else {
245       call_dissector(eth_handle, next_tvb, pinfo, tree);
246     }
247 }
248
249 void
250 proto_register_mpls(void)
251 {
252         static gint *ett[] = {
253                 &ett_mpls,
254                 &ett_mpls_control,
255         };
256
257         proto_mpls = proto_register_protocol("MultiProtocol Label Switching Header",
258             "MPLS", "mpls");
259         proto_register_field_array(proto_mpls, mplsf_info, array_length(mplsf_info));
260         proto_register_subtree_array(ett, array_length(ett));
261 }
262
263 void
264 proto_reg_handoff_mpls(void)
265 {
266         dissector_handle_t mpls_handle;
267
268         /*
269          * Get a handle for the IPv4 and IPv6 dissectors and PPP protocol dissector table.
270          */
271         ipv4_handle = find_dissector("ip");
272         ipv6_handle = find_dissector("ipv6");
273         eth_handle = find_dissector("eth");
274         data_handle = find_dissector("data");
275         ppp_subdissector_table = find_dissector_table("ppp.protocol");
276
277
278         mpls_handle = create_dissector_handle(dissect_mpls, proto_mpls);
279         dissector_add("ethertype", ETHERTYPE_MPLS, mpls_handle);
280         dissector_add("ppp.protocol", PPP_MPLS_UNI, mpls_handle);
281         dissector_add("chdlctype", ETHERTYPE_MPLS, mpls_handle);
282         dissector_add("chdlctype", ETHERTYPE_MPLS_MULTI, mpls_handle);
283         dissector_add("gre.proto", ETHERTYPE_MPLS, mpls_handle);
284 }