Updates from Ed Warnicke.
[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.12 2000/12/14 08:20:29 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 #include "packet-ip.h"
49 #include "ppptypes.h"
50 #include "packet-ppp.h"
51
52 static gint proto_mpls = -1;
53
54 static gint ett_mpls = -1;
55
56 /* Special labels in MPLS */
57 enum {
58     IP4_EXPLICIT_NULL = 0,
59     ROUTER_ALERT,
60     IP6_EXPLICIT_NULL,
61     IMPLICIT_NULL,
62
63     MAX_RESERVED = 15
64 };
65
66 static const value_string special_labels[] = {
67     {IP4_EXPLICIT_NULL, "IPv4 Explicit-Null"},
68     {ROUTER_ALERT, "Router Alert"},
69     {IP6_EXPLICIT_NULL, "IPv6 Explicit-Null"},
70     {IMPLICIT_NULL, "Implicit-Null"},
71     {0, NULL }
72 };
73
74 /* MPLS filter values */
75 enum mpls_filter_keys {
76
77     /* Is the packet MPLS-encapsulated? */
78 /*    MPLSF_PACKET,*/
79
80     /* MPLS encap properties */
81     MPLSF_LABEL,
82     MPLSF_EXP,
83     MPLSF_BOTTOM_OF_STACK,
84     MPLSF_TTL,
85
86     MPLSF_MAX
87 };
88
89 static int mpls_filter[MPLSF_MAX];
90 static hf_register_info mplsf_info[] = {
91
92 /*    {&mpls_filter[MPLSF_PACKET], 
93      {"MPLS Label Switched Packet", "mpls", FT_UINT8, BASE_NONE, NULL, 0x0, 
94       "" }},*/
95
96     {&mpls_filter[MPLSF_LABEL], 
97      {"MPLS Label", "mpls.label", FT_UINT32, BASE_DEC, VALS(special_labels), 0x0, 
98       "" }},
99
100     {&mpls_filter[MPLSF_EXP], 
101      {"MPLS Experimental Bits", "mpls.exp", FT_UINT8, BASE_DEC, NULL, 0x0, 
102       "" }},
103
104     {&mpls_filter[MPLSF_BOTTOM_OF_STACK], 
105      {"MPLS Bottom Of Label Stack", "mpls.bottom", FT_UINT8, BASE_DEC, NULL, 0x0, 
106       "" }},
107
108     {&mpls_filter[MPLSF_TTL], 
109      {"MPLS TTL", "mpls.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, 
110       "" }},
111 };
112
113 static dissector_handle_t ip_handle;
114
115 /*
116  * Given a 4-byte MPLS label starting at "start", decode this.
117  * Return the label in "label", EXP bits in "exp",
118  * bottom_of_stack in "bos", and TTL in "ttl"
119  */
120 void decode_mpls_label(const unsigned char *start,  
121                        guint32 *label, guint8 *exp,
122                        guint8 *bos, guint8 *ttl)
123 {
124     *label = (start[0] << 12) + (start[1] << 4) + ((start[2] >> 4) & 0xff);
125     *exp = (start[2] >> 1) & 0x7;
126     *bos = (start[2] & 0x1);
127     *ttl = start[3];
128 }
129
130 static void
131 dissect_mpls(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
132 {
133     guint32 label;
134     guint8 exp;
135     guint8 bos;
136     guint8 ttl;
137
138     proto_tree  *mpls_tree;
139     proto_item  *ti;
140
141     OLD_CHECK_DISPLAY_AS_DATA(proto_mpls, pd, offset, fd, tree);
142
143     if (check_col(fd, COL_PROTOCOL)) {
144         col_set_str(fd,COL_PROTOCOL, "MPLS");
145     }
146     
147     if (check_col(fd,COL_INFO)) {
148         col_add_fstr(fd,COL_INFO,"MPLS Label Switched Packet");
149     }
150
151     /* Start Decoding Here. */
152     while (1) {
153         if (!BYTES_ARE_IN_FRAME(offset, 4)) {
154             old_dissect_data(pd, offset, fd, tree);
155             return;
156         }
157
158         decode_mpls_label(pd+offset, &label, &exp, &bos, &ttl);
159
160         if (tree) {
161
162             ti = proto_tree_add_item(tree, proto_mpls, NullTVB, offset, 4, FALSE);
163             mpls_tree = proto_item_add_subtree(ti, ett_mpls);
164
165             if (label <= MAX_RESERVED)
166                 proto_tree_add_uint_format(mpls_tree, mpls_filter[MPLSF_LABEL], NullTVB,
167                                     offset, 3, label, "Label: %d (%s)", 
168                                     label, val_to_str(label, special_labels, 
169                                                       "Reserved - Unknown"));
170             else
171                 proto_tree_add_uint(mpls_tree, mpls_filter[MPLSF_LABEL], NullTVB,
172                                     offset, 3, label);
173
174             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_EXP], NullTVB, 
175                                 offset+2,1, exp);
176             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_BOTTOM_OF_STACK], NullTVB, 
177                                 offset+2,1, bos);
178             proto_tree_add_uint(mpls_tree,mpls_filter[MPLSF_TTL], NullTVB, 
179                                 offset+3,1, ttl);
180         }
181         offset += 4;
182         if (bos) break;
183     }
184     old_call_dissector(ip_handle, pd, offset, fd, tree);
185 }
186
187 void
188 proto_register_mpls(void)
189 {
190         static gint *ett[] = {
191                 &ett_mpls,
192         };
193
194         proto_mpls = proto_register_protocol("MultiProtocol Label Switching Header", "mpls");
195         proto_register_field_array(proto_mpls, mplsf_info, array_length(mplsf_info));
196         proto_register_subtree_array(ett, array_length(ett));
197 }
198
199 void
200 proto_reg_handoff_mpls(void)
201 {
202         old_dissector_add("ethertype", ETHERTYPE_MPLS, dissect_mpls);
203         old_dissector_add("ppp.protocol", PPP_MPLS_UNI, dissect_mpls);
204
205         /*
206          * Get a handle for the IP dissector.
207          */
208         ip_handle = find_dissector("ip");
209 }