]> The Tcpdump Group git mirrors - tcpdump/blob - print-medsa.c
8161012bf110147d71db7e14c850b243dd880ee1
[tcpdump] / print-medsa.c
1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /* \summary: Marvell Extended Distributed Switch Architecture (MEDSA) printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "netdissect-stdinc.h"
29
30 #include "netdissect.h"
31 #include "ethertype.h"
32 #include "addrtoname.h"
33 #include "extract.h"
34
35 static const char tstr[] = "[|MEDSA]";
36
37 /*
38 * Marvell Extended Distributed Switch Archiecture.
39 *
40 * A Marvell propriatary header used for passing packets to/from
41 * specific ports of a switch. There is no open specification of this
42 * header, but is documented in the Marvell Switch data sheets. For
43 * background, see:
44 *
45 * https://lwn.net/Articles/302333/
46 */
47 struct medsa_pkthdr {
48 nd_byte reserved[2];
49 nd_uint8_t tag_flags_dev;
50 nd_uint8_t port_trunc_codehi_cfi;
51 nd_uint8_t pri_vidhi_codelo;
52 nd_uint8_t vidlo;
53 nd_uint16_t ether_type;
54 };
55
56 /* Bytes 0 and 1 are reserved and should contain 0 */
57 #define TAG(medsa) (EXTRACT_U_1(medsa->tag_flags_dev) >> 6)
58 #define TAG_TO_CPU 0
59 #define TAG_FROM_CPU 1
60 #define TAG_FORWARD 3
61 #define SRC_TAG(medsa) ((EXTRACT_U_1(medsa->tag_flags_dev) >> 5) & 0x01)
62 #define SRC_DEV(medsa) (EXTRACT_U_1(medsa->tag_flags_dev) & 0x1f)
63 #define SRC_PORT(medsa) ((EXTRACT_U_1(medsa->port_trunc_codehi_cfi) >> 3) & 0x01f)
64 #define TRUNK(medsa) ((EXTRACT_U_1(medsa->port_trunc_codehi_cfi) >> 2) & 0x01)
65 #define CODE(medsa) ((EXTRACT_U_1(medsa->port_trunc_codehi_cfi) & 0x06) | \
66 ((EXTRACT_U_1(medsa->pri_vidhi_codelo) >> 4) & 0x01))
67 #define CODE_BDPU 0
68 #define CODE_IGMP_MLD 2
69 #define CODE_ARP_MIRROR 4
70 #define CFI(medsa) (EXTRACT_U_1(medsa->port_trunc_codehi_cfi) & 0x01)
71 #define PRI(medsa) (EXTRACT_U_1(medsa->pri_vidhi_codelo) >> 5)
72 #define VID(medsa) (((u_short)(EXTRACT_U_1(medsa->pri_vidhi_codelo) & 0xf) << 8 | \
73 EXTRACT_U_1(medsa->vidlo)))
74
75 static const struct tok tag_values[] = {
76 { TAG_TO_CPU, "To_CPU" },
77 { TAG_FROM_CPU, "From_CPU" },
78 { TAG_FORWARD, "Forward" },
79 { 0, NULL },
80 };
81
82 static const struct tok code_values[] = {
83 { CODE_BDPU, "BDPU" },
84 { CODE_IGMP_MLD, "IGMP/MLD" },
85 { CODE_ARP_MIRROR, "APR_Mirror" },
86 { 0, NULL },
87 };
88
89 static void
90 medsa_print_full(netdissect_options *ndo,
91 const struct medsa_pkthdr *medsa,
92 u_int caplen)
93 {
94 u_char tag = TAG(medsa);
95
96 ND_PRINT("%s",
97 tok2str(tag_values, "Unknown (%u)", tag));
98
99 switch (tag) {
100 case TAG_TO_CPU:
101 ND_PRINT(", %stagged", SRC_TAG(medsa) ? "" : "un");
102 ND_PRINT(", dev.port:vlan %u.%u:%u",
103 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa));
104
105 ND_PRINT(", %s",
106 tok2str(code_values, "Unknown (%u)", CODE(medsa)));
107 if (CFI(medsa))
108 ND_PRINT(", CFI");
109
110 ND_PRINT(", pri %u: ", PRI(medsa));
111 break;
112 case TAG_FROM_CPU:
113 ND_PRINT(", %stagged", SRC_TAG(medsa) ? "" : "un");
114 ND_PRINT(", dev.port:vlan %u.%u:%u",
115 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa));
116
117 if (CFI(medsa))
118 ND_PRINT(", CFI");
119
120 ND_PRINT(", pri %u: ", PRI(medsa));
121 break;
122 case TAG_FORWARD:
123 ND_PRINT(", %stagged", SRC_TAG(medsa) ? "" : "un");
124 if (TRUNK(medsa))
125 ND_PRINT(", dev.trunk:vlan %u.%u:%u",
126 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa));
127 else
128 ND_PRINT(", dev.port:vlan %u.%u:%u",
129 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa));
130
131 if (CFI(medsa))
132 ND_PRINT(", CFI");
133
134 ND_PRINT(", pri %u: ", PRI(medsa));
135 break;
136 default:
137 ND_DEFAULTPRINT((const u_char *)medsa, caplen);
138 return;
139 }
140 }
141
142 void
143 medsa_print(netdissect_options *ndo,
144 const u_char *bp, u_int length, u_int caplen,
145 const struct lladdr_info *src, const struct lladdr_info *dst)
146 {
147 const struct medsa_pkthdr *medsa;
148 u_short ether_type;
149
150 medsa = (const struct medsa_pkthdr *)bp;
151 ND_TCHECK_SIZE(medsa);
152
153 if (!ndo->ndo_eflag)
154 ND_PRINT("MEDSA %u.%u:%u: ",
155 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa));
156 else
157 medsa_print_full(ndo, medsa, caplen);
158
159 bp += 8;
160 length -= 8;
161 caplen -= 8;
162
163 ether_type = EXTRACT_BE_U_2(medsa->ether_type);
164 if (ether_type <= MAX_ETHERNET_LENGTH_VAL) {
165 /* Try to print the LLC-layer header & higher layers */
166 if (llc_print(ndo, bp, length, caplen, src, dst) < 0) {
167 /* packet type not known, print raw packet */
168 if (!ndo->ndo_suppress_default_print)
169 ND_DEFAULTPRINT(bp, caplen);
170 }
171 } else {
172 if (ndo->ndo_eflag)
173 ND_PRINT("ethertype %s (0x%04x) ",
174 tok2str(ethertype_values, "Unknown",
175 ether_type),
176 ether_type);
177 if (ethertype_print(ndo, ether_type, bp, length, caplen, src, dst) == 0) {
178 /* ether_type not known, print raw packet */
179 if (!ndo->ndo_eflag)
180 ND_PRINT("ethertype %s (0x%04x) ",
181 tok2str(ethertype_values, "Unknown",
182 ether_type),
183 ether_type);
184
185 if (!ndo->ndo_suppress_default_print)
186 ND_DEFAULTPRINT(bp, caplen);
187 }
188 }
189 return;
190 trunc:
191 ND_PRINT("%s", tstr);
192 }
193
194 /*
195 * Local Variables:
196 * c-style: bsd
197 * End:
198 */
199