198524Sfenner/*
298524Sfenner * Copyright (C) 2001 WIDE Project.  All rights reserved.
398524Sfenner *
498524Sfenner * Redistribution and use in source and binary forms, with or without
598524Sfenner * modification, are permitted provided that the following conditions
698524Sfenner * are met:
798524Sfenner * 1. Redistributions of source code must retain the above copyright
898524Sfenner *    notice, this list of conditions and the following disclaimer.
998524Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1098524Sfenner *    notice, this list of conditions and the following disclaimer in the
1198524Sfenner *    documentation and/or other materials provided with the distribution.
1298524Sfenner * 3. Neither the name of the project nor the names of its contributors
1398524Sfenner *    may be used to endorse or promote products derived from this software
1498524Sfenner *    without specific prior written permission.
1598524Sfenner *
1698524Sfenner * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1798524Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1898524Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1998524Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2098524Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2198524Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2298524Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2398524Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2498524Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2598524Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2698524Sfenner * SUCH DAMAGE.
2798524Sfenner */
2898524Sfenner
2998524Sfenner#ifndef lint
30127668Sbmsstatic const char rcsid[] _U_ =
31190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-mpls.c,v 1.14 2005-07-05 09:38:19 hannes Exp $ (LBL)";
3298524Sfenner#endif
3398524Sfenner
3498524Sfenner#ifdef HAVE_CONFIG_H
3598524Sfenner#include "config.h"
3698524Sfenner#endif
3798524Sfenner
38127668Sbms#include <tcpdump-stdinc.h>
3998524Sfenner
4098524Sfenner#include <stdio.h>
4198524Sfenner#include <stdlib.h>
4298524Sfenner#include <string.h>
4398524Sfenner
4498524Sfenner#include "addrtoname.h"
4598524Sfenner#include "interface.h"
4698524Sfenner#include "extract.h"			/* must come after interface.h */
47146773Ssam#include "mpls.h"
4898524Sfenner
4998524Sfennerstatic const char *mpls_labelname[] = {
5098524Sfenner/*0*/	"IPv4 explicit NULL", "router alert", "IPv6 explicit NULL",
5198524Sfenner	"implicit NULL", "rsvd",
5298524Sfenner/*5*/	"rsvd", "rsvd", "rsvd", "rsvd", "rsvd",
5398524Sfenner/*10*/	"rsvd", "rsvd", "rsvd", "rsvd", "rsvd",
5498524Sfenner/*15*/	"rsvd",
5598524Sfenner};
5698524Sfenner
57235530Sdelphijenum mpls_packet_type {
58235530Sdelphij	PT_UNKNOWN,
59235530Sdelphij	PT_IPV4,
60235530Sdelphij	PT_IPV6,
61235530Sdelphij	PT_OSI
62235530Sdelphij};
63235530Sdelphij
6498524Sfenner/*
6598524Sfenner * RFC3032: MPLS label stack encoding
6698524Sfenner */
6798524Sfennervoid
6898524Sfennermpls_print(const u_char *bp, u_int length)
6998524Sfenner{
7098524Sfenner	const u_char *p;
71147899Ssam	u_int32_t label_entry;
72235530Sdelphij	u_int16_t label_stack_depth = 0;
73235530Sdelphij	enum mpls_packet_type pt = PT_UNKNOWN;
7498524Sfenner
7598524Sfenner	p = bp;
7698524Sfenner	printf("MPLS");
77111726Sfenner	do {
78147899Ssam		TCHECK2(*p, sizeof(label_entry));
79147899Ssam		label_entry = EXTRACT_32BITS(p);
80147899Ssam		printf("%s(label %u",
81235530Sdelphij		       (label_stack_depth && vflag) ? "\n\t" : " ",
82235530Sdelphij       		       MPLS_LABEL(label_entry));
83235530Sdelphij		label_stack_depth++;
84111726Sfenner		if (vflag &&
85147899Ssam		    MPLS_LABEL(label_entry) < sizeof(mpls_labelname) / sizeof(mpls_labelname[0]))
86147899Ssam			printf(" (%s)", mpls_labelname[MPLS_LABEL(label_entry)]);
87147899Ssam		printf(", exp %u", MPLS_EXP(label_entry));
88147899Ssam		if (MPLS_STACK(label_entry))
89127668Sbms			printf(", [S]");
90147899Ssam		printf(", ttl %u)", MPLS_TTL(label_entry));
9198524Sfenner
92147899Ssam		p += sizeof(label_entry);
93147899Ssam	} while (!MPLS_STACK(label_entry));
9498524Sfenner
95235530Sdelphij	/*
96235530Sdelphij	 * Try to figure out the packet type.
97235530Sdelphij	 */
98147899Ssam	switch (MPLS_LABEL(label_entry)) {
99235530Sdelphij
10098524Sfenner	case 0:	/* IPv4 explicit NULL label */
101235530Sdelphij	case 3:	/* IPv4 implicit NULL label */
102235530Sdelphij		pt = PT_IPV4;
10398524Sfenner		break;
104235530Sdelphij
10598524Sfenner	case 2:	/* IPv6 explicit NULL label */
106235530Sdelphij		pt = PT_IPV6;
10798524Sfenner		break;
108235530Sdelphij
10998524Sfenner	default:
11098524Sfenner		/*
111127668Sbms		 * Generally there's no indication of protocol in MPLS label
112235530Sdelphij		 * encoding.
113235530Sdelphij		 *
114235530Sdelphij		 * However, draft-hsmit-isis-aal5mux-00.txt describes a
115235530Sdelphij		 * technique for encapsulating IS-IS and IP traffic on the
116235530Sdelphij		 * same ATM virtual circuit; you look at the first payload
117235530Sdelphij		 * byte to determine the network layer protocol, based on
118235530Sdelphij		 * the fact that
119235530Sdelphij		 *
120235530Sdelphij		 *	1) the first byte of an IP header is 0x45-0x4f
121235530Sdelphij		 *	   for IPv4 and 0x60-0x6f for IPv6;
122235530Sdelphij		 *
123235530Sdelphij		 *	2) the first byte of an OSI CLNP packet is 0x81,
124235530Sdelphij		 *	   the first byte of an OSI ES-IS packet is 0x82,
125235530Sdelphij		 *	   and the first byte of an OSI IS-IS packet is
126235530Sdelphij		 *	   0x83;
127235530Sdelphij		 *
128235530Sdelphij		 * so the network layer protocol can be inferred from the
129235530Sdelphij		 * first byte of the packet, if the protocol is one of the
130235530Sdelphij		 * ones listed above.
131235530Sdelphij		 *
132235530Sdelphij		 * Cisco sends control-plane traffic MPLS-encapsulated in
133235530Sdelphij		 * this fashion.
13498524Sfenner		 */
135235530Sdelphij		switch(*p) {
136127668Sbms
137235530Sdelphij		case 0x45:
138235530Sdelphij		case 0x46:
139235530Sdelphij		case 0x47:
140235530Sdelphij		case 0x48:
141235530Sdelphij		case 0x49:
142235530Sdelphij		case 0x4a:
143235530Sdelphij		case 0x4b:
144235530Sdelphij		case 0x4c:
145235530Sdelphij		case 0x4d:
146235530Sdelphij		case 0x4e:
147235530Sdelphij		case 0x4f:
148235530Sdelphij			pt = PT_IPV4;
149235530Sdelphij			break;
150235530Sdelphij
151235530Sdelphij		case 0x60:
152235530Sdelphij		case 0x61:
153235530Sdelphij		case 0x62:
154235530Sdelphij		case 0x63:
155235530Sdelphij		case 0x64:
156235530Sdelphij		case 0x65:
157235530Sdelphij		case 0x66:
158235530Sdelphij		case 0x67:
159235530Sdelphij		case 0x68:
160235530Sdelphij		case 0x69:
161235530Sdelphij		case 0x6a:
162235530Sdelphij		case 0x6b:
163235530Sdelphij		case 0x6c:
164235530Sdelphij		case 0x6d:
165235530Sdelphij		case 0x6e:
166235530Sdelphij		case 0x6f:
167235530Sdelphij			pt = PT_IPV6;
168235530Sdelphij			break;
169235530Sdelphij
170235530Sdelphij		case 0x81:
171235530Sdelphij		case 0x82:
172235530Sdelphij		case 0x83:
173235530Sdelphij			pt = PT_OSI;
174235530Sdelphij			break;
175235530Sdelphij
176235530Sdelphij		default:
177235530Sdelphij			/* ok bail out - we did not figure out what it is*/
178235530Sdelphij			break;
179235530Sdelphij		}
180235530Sdelphij	}
181235530Sdelphij
182235530Sdelphij	/*
183235530Sdelphij	 * Print the payload.
184235530Sdelphij	 */
185235530Sdelphij	if (pt == PT_UNKNOWN) {
186235530Sdelphij		if (!suppress_default_print)
187235530Sdelphij			default_print(p, length - (p - bp));
188235530Sdelphij		return;
189235530Sdelphij	}
190235530Sdelphij	if (vflag)
191235530Sdelphij		printf("\n\t");
192235530Sdelphij	else
193235530Sdelphij		printf(" ");
194235530Sdelphij	switch (pt) {
195235530Sdelphij
196235530Sdelphij	case PT_IPV4:
197235530Sdelphij		ip_print(gndo, p, length - (p - bp));
198235530Sdelphij		break;
199235530Sdelphij
200235530Sdelphij	case PT_IPV6:
201127668Sbms#ifdef INET6
202235530Sdelphij		ip6_print(gndo, p, length - (p - bp));
203235530Sdelphij#else
204235530Sdelphij		printf("IPv6, length: %u", length);
205127668Sbms#endif
206235530Sdelphij		break;
207235530Sdelphij
208235530Sdelphij	case PT_OSI:
209235530Sdelphij		isoclns_print(p, length - (p - bp), length - (p - bp));
210235530Sdelphij		break;
211235530Sdelphij
212235530Sdelphij	default:
213235530Sdelphij		break;
21498524Sfenner	}
215235530Sdelphij	return;
21698524Sfenner
21798524Sfennertrunc:
21898524Sfenner	printf("[|MPLS]");
21998524Sfenner}
220127668Sbms
221146773Ssam
222127668Sbms/*
223146773Ssam * Local Variables:
224146773Ssam * c-style: whitesmith
225146773Ssam * c-basic-offset: 8
226146773Ssam * End:
227127668Sbms */
228