1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <stdio.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/ethernet.h>
31#include <sys/vlan.h>
32#include <net/trill.h>
33
34#include <snoop.h>
35
36int
37interpret_trill(int flags, struct ether_header **e, char *data, int *alen)
38{
39	trill_header_t *trillhdr;
40	struct ether_header *inner_ethhdr;
41	struct ether_vlan_header *inner_ethvlanhdr;
42	uint16_t ethertype;
43	int dlen = *alen;
44	size_t optslen;
45	size_t trillhdrlen;
46
47	if (dlen < sizeof (trill_header_t)) {
48		(void) snprintf(get_sum_line(), MAXLINE,
49		    "TRILL (short packet)");
50		return (0);
51	}
52
53	trillhdr = (trill_header_t *)data;
54	optslen = GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t);
55
56	if (flags & F_DTAIL) {
57		show_header("TRILL: ", "TRILL Data Frame", dlen);
58		show_space();
59
60		(void) snprintf(get_line(0, 0), get_line_remain(),
61		    "Egress nickname = %d",
62		    ntohs(trillhdr->th_egressnick));
63		(void) snprintf(get_line(0, 0), get_line_remain(),
64		    "Ingress nickname = %d",
65		    ntohs(trillhdr->th_ingressnick));
66		(void) snprintf(get_line(0, 0), get_line_remain(),
67		    "Hop count = %d", trillhdr->th_hopcount);
68		(void) snprintf(get_line(0, 0), get_line_remain(),
69		    "Multi-destination = %d", trillhdr->th_multidest);
70		(void) snprintf(get_line(0, 0), get_line_remain(),
71		    "Options Len = %d bytes", optslen);
72		show_trailer();
73	}
74
75	trillhdrlen = sizeof (trill_header_t) + optslen;
76
77	if (dlen < trillhdrlen) {
78		(void) snprintf(get_sum_line(), MAXLINE,
79		    "TRILL (options truncated)");
80		return (0);
81	}
82
83	dlen -= trillhdrlen;
84
85	if (dlen < sizeof (struct ether_header)) {
86		(void) snprintf(get_sum_line(), MAXLINE,
87		    "TRILL (missing required inner MAC)");
88		return (0);
89	}
90
91	inner_ethhdr = (struct ether_header *)(data + trillhdrlen);
92	if (inner_ethhdr->ether_type != htons(ETHERTYPE_VLAN)) {
93		(void) snprintf(get_sum_line(), MAXLINE,
94		    "TRILL (inner VLAN missing; ethertype %X)",
95		    ntohs(inner_ethhdr->ether_type));
96		return (0);
97	}
98
99	inner_ethvlanhdr = (struct ether_vlan_header *)inner_ethhdr;
100	ethertype = ntohs(inner_ethvlanhdr->ether_type);
101
102	if (flags & F_SUM) {
103		(void) snprintf(get_sum_line(), MAXLINE,
104		    "TRILL D:%d S:%d HC:%d M:%d O:%d L:%d VLAN:%d %s",
105		    ntohs(trillhdr->th_egressnick),
106		    ntohs(trillhdr->th_ingressnick),
107		    trillhdr->th_hopcount,
108		    trillhdr->th_multidest,
109		    optslen,
110		    dlen, VLAN_ID(inner_ethvlanhdr->ether_tci),
111		    print_ethertype(ethertype));
112	}
113
114	*alen = dlen;
115	*e = inner_ethhdr;
116	return (ethertype);
117}
118