]> The Tcpdump Group git mirrors - tcpdump/blob - print-medsa.c
Use INT32_MIN to check for the smallest possible 32-bit signed value.
[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 "ether.h"
32 #include "ethertype.h"
33 #include "addrtoname.h"
34 #include "extract.h"
35
36 static const char tstr[] = "[|MEDSA]";
37
38 /*
39 * Marvell Extended Distributed Switch Archiecture.
40 *
41 * A Marvell propriatary header used for passing packets to/from
42 * specific ports of a switch. There is no open specification of this
43 * header, but is documented in the Marvell Switch data sheets. For
44 * background, see:
45 *
46 * https://lwn.net/Articles/302333/
47 */
48 struct medsa_pkthdr {
49 u_char bytes[6];
50 u_short ether_type;
51 };
52
53 /* Bytes 0 and 1 are reserved and should contain 0 */
54 #define TAG(medsa) (medsa->bytes[2] >> 6)
55 #define TAG_TO_CPU 0
56 #define TAG_FROM_CPU 1
57 #define TAG_FORWARD 3
58 #define SRC_TAG(medsa) ((medsa->bytes[2] >> 5) & 0x01)
59 #define SRC_DEV(medsa) (medsa->bytes[2] & 0x1f)
60 #define SRC_PORT(medsa) ((medsa->bytes[3] >> 3) & 0x01f)
61 #define TRUNK(medsa) ((medsa->bytes[3] >> 2) & 0x01)
62 #define CODE(medsa) ((medsa->bytes[3] & 0x06) | \
63 ((medsa->bytes[4] >> 4) & 0x01))
64 #define CODE_BDPU 0
65 #define CODE_IGMP_MLD 2
66 #define CODE_ARP_MIRROR 4
67 #define CFI(medsa) (medsa->bytes[3] & 0x01)
68 #define PRI(medsa) (medsa->bytes[4] >> 5)
69 #define VID(medsa) (((u_short)(medsa->bytes[4] & 0xf) << 8 | \
70 medsa->bytes[5]))
71
72 static const struct tok tag_values[] = {
73 { TAG_TO_CPU, "To_CPU" },
74 { TAG_FROM_CPU, "From_CPU" },
75 { TAG_FORWARD, "Forward" },
76 { 0, NULL },
77 };
78
79 static const struct tok code_values[] = {
80 { CODE_BDPU, "BDPU" },
81 { CODE_IGMP_MLD, "IGMP/MLD" },
82 { CODE_ARP_MIRROR, "APR_Mirror" },
83 { 0, NULL },
84 };
85
86 static void
87 medsa_print_full(netdissect_options *ndo,
88 const struct medsa_pkthdr *medsa,
89 u_int caplen)
90 {
91 u_char tag = TAG(medsa);
92
93 ND_PRINT((ndo, "%s",
94 tok2str(tag_values, "Unknown (%u)", tag)));
95
96 switch (tag) {
97 case TAG_TO_CPU:
98 ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un"));
99 ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d",
100 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa)));
101
102 ND_PRINT((ndo, ", %s",
103 tok2str(code_values, "Unknown (%u)", CODE(medsa))));
104 if (CFI(medsa))
105 ND_PRINT((ndo, ", CFI"));
106
107 ND_PRINT((ndo, ", pri %d: ", PRI(medsa)));
108 break;
109 case TAG_FROM_CPU:
110 ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un"));
111 ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d",
112 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa)));
113
114 if (CFI(medsa))
115 ND_PRINT((ndo, ", CFI"));
116
117 ND_PRINT((ndo, ", pri %d: ", PRI(medsa)));
118 break;
119 case TAG_FORWARD:
120 ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un"));
121 if (TRUNK(medsa))
122 ND_PRINT((ndo, ", dev.trunk:vlan %d.%d:%d",
123 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa)));
124 else
125 ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d",
126 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa)));
127
128 if (CFI(medsa))
129 ND_PRINT((ndo, ", CFI"));
130
131 ND_PRINT((ndo, ", pri %d: ", PRI(medsa)));
132 break;
133 default:
134 ND_DEFAULTPRINT((const u_char *)medsa, caplen);
135 return;
136 }
137 }
138
139 void
140 medsa_print(netdissect_options *ndo,
141 const u_char *bp, u_int length, u_int caplen)
142 {
143 register const struct ether_header *ep;
144 const struct medsa_pkthdr *medsa;
145 struct lladdr_info src, dst;
146 u_short ether_type;
147
148 medsa = (const struct medsa_pkthdr *)bp;
149 ep = (const struct ether_header *)(bp - sizeof(*ep));
150 ND_TCHECK(*medsa);
151
152 if (!ndo->ndo_eflag)
153 ND_PRINT((ndo, "MEDSA %d.%d:%d: ",
154 SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa)));
155 else
156 medsa_print_full(ndo, medsa, caplen);
157
158 bp += 8;
159 length -= 8;
160 caplen -= 8;
161
162 src.addr = ESRC(ep);
163 src.addr_string = etheraddr_string;
164 dst.addr = EDST(ep);
165 dst.addr_string = etheraddr_string;
166 ether_type = EXTRACT_16BITS(&medsa->ether_type);
167 if (ether_type <= ETHERMTU) {
168 /* Try to print the LLC-layer header & higher layers */
169 if (llc_print(ndo, bp, length, caplen, &src, &dst) < 0) {
170 /* packet type not known, print raw packet */
171 if (!ndo->ndo_suppress_default_print)
172 ND_DEFAULTPRINT(bp, caplen);
173 }
174 } else {
175 if (ndo->ndo_eflag)
176 ND_PRINT((ndo, "ethertype %s (0x%04x) ",
177 tok2str(ethertype_values, "Unknown",
178 ether_type),
179 ether_type));
180
181 if (ethertype_print(ndo, ether_type, bp, length, caplen, &src, &dst) == 0) {
182 /* ether_type not known, print raw packet */
183 if (!ndo->ndo_eflag)
184 ND_PRINT((ndo, "ethertype %s (0x%04x) ",
185 tok2str(ethertype_values, "Unknown",
186 ether_type),
187 ether_type));
188
189 if (!ndo->ndo_suppress_default_print)
190 ND_DEFAULTPRINT(bp, caplen);
191 }
192 }
193 return;
194 trunc:
195 ND_PRINT((ndo, "%s", tstr));
196 }
197
198 /*
199 * Local Variables:
200 * c-style: bsd
201 * End:
202 */
203