]> The Tcpdump Group git mirrors - tcpdump/blob - print-erspan.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-erspan.c
1 /* $OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch Exp $ */
2
3 /*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* \summary: Cisco ERSPAN printer */
30
31 /*
32 * Specifications: I-D draft-foschiano-erspan-03.
33 */
34
35 #include <config.h>
36
37 #include "netdissect-stdinc.h"
38
39 #define ND_LONGJMP_FROM_TCHECK
40 #include "netdissect.h"
41 #include "extract.h"
42 #include "gre.h"
43
44 /*
45 * ERSPAN Type II.
46 */
47 #define ERSPAN2_VER_SHIFT 28
48 #define ERSPAN2_VER_MASK (0xfU << ERSPAN2_VER_SHIFT)
49 #define ERSPAN2_VER (0x1U << ERSPAN2_VER_SHIFT)
50 #define ERSPAN2_VLAN_SHIFT 16
51 #define ERSPAN2_VLAN_MASK (0xfffU << ERSPAN2_VLAN_SHIFT)
52 #define ERSPAN2_COS_SHIFT 13
53 #define ERSPAN2_COS_MASK (0x7U << ERSPAN2_COS_SHIFT)
54 #define ERSPAN2_EN_SHIFT 11
55 #define ERSPAN2_EN_MASK (0x3U << ERSPAN2_EN_SHIFT)
56 #define ERSPAN2_EN_NONE (0x0U << ERSPAN2_EN_SHIFT)
57 #define ERSPAN2_EN_ISL (0x1U << ERSPAN2_EN_SHIFT)
58 #define ERSPAN2_EN_DOT1Q (0x2U << ERSPAN2_EN_SHIFT)
59 #define ERSPAN2_EN_VLAN (0x3U << ERSPAN2_EN_SHIFT)
60 #define ERSPAN2_T_SHIFT 10
61 #define ERSPAN2_T_MASK (0x1U << ERSPAN2_T_SHIFT)
62 #define ERSPAN2_SID_SHIFT 0
63 #define ERSPAN2_SID_MASK (0x3ffU << ERSPAN2_SID_SHIFT)
64
65 #define ERSPAN2_INDEX_SHIFT 0
66 #define ERSPAN2_INDEX_MASK (0xfffffU << ERSPAN2_INDEX_SHIFT)
67
68 void
69 erspan_i_ii_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int len)
70 {
71 uint32_t hdr, ver, vlan, cos, en, sid, index;
72
73 ndo->ndo_protocol = "erspan";
74 nd_print_protocol(ndo);
75
76 if (!(flags & GRE_SP)) {
77 /*
78 * ERSPAN Type I; no header, just a raw Ethernet frame.
79 */
80 ND_PRINT(" type1: ");
81 ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
82 return;
83 }
84
85 /*
86 * ERSPAN Type II.
87 */
88 ND_ICHECK_U(len, <, 4);
89 hdr = GET_BE_U_4(bp);
90 bp += 4;
91 len -= 4;
92
93 ver = hdr & ERSPAN2_VER_MASK;
94 if (ver != ERSPAN2_VER) {
95 /*
96 * Not Type II.
97 */
98 ver >>= ERSPAN2_VER_SHIFT;
99 ND_PRINT(" erspan-unknown-version-%x", ver);
100 return;
101 }
102
103 if (ndo->ndo_vflag)
104 ND_PRINT(" type2");
105
106 sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT;
107 ND_PRINT(" session %u", sid);
108
109 en = hdr & ERSPAN2_EN_MASK;
110 vlan = (hdr & ERSPAN2_VLAN_MASK) >> ERSPAN2_VLAN_SHIFT;
111 switch (en) {
112 case ERSPAN2_EN_NONE:
113 break;
114 case ERSPAN2_EN_ISL:
115 ND_PRINT(" isl %u", vlan);
116 break;
117 case ERSPAN2_EN_DOT1Q:
118 ND_PRINT(" vlan %u", vlan);
119 break;
120 case ERSPAN2_EN_VLAN:
121 ND_PRINT(" vlan payload");
122 break;
123 }
124
125 if (ndo->ndo_vflag) {
126 cos = (hdr & ERSPAN2_COS_MASK) >> ERSPAN2_COS_SHIFT;
127 ND_PRINT(" cos %u", cos);
128
129 if (hdr & ERSPAN2_T_MASK)
130 ND_PRINT(" truncated");
131 }
132
133 ND_ICHECK_U(len, <, 4);
134 hdr = GET_BE_U_4(bp);
135 bp += 4;
136 len -= 4;
137
138 if (ndo->ndo_vflag) {
139 index = (hdr & ERSPAN2_INDEX_MASK) >> ERSPAN2_INDEX_SHIFT;
140 ND_PRINT(" index %u", index);
141 }
142
143 ND_PRINT(": ");
144 ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
145 return;
146
147 invalid:
148 nd_print_invalid(ndo);
149 }
150
151 /*
152 * ERSPAN Type III.
153 */
154 #define ERSPAN3_VER_SHIFT 28
155 #define ERSPAN3_VER_MASK (0xfU << ERSPAN3_VER_SHIFT)
156 #define ERSPAN3_VER (0x2U << ERSPAN3_VER_SHIFT)
157 #define ERSPAN3_VLAN_SHIFT 16
158 #define ERSPAN3_VLAN_MASK (0xfffU << ERSPAN3_VLAN_SHIFT)
159 #define ERSPAN3_COS_SHIFT 13
160 #define ERSPAN3_COS_MASK (0x7U << ERSPAN3_COS_SHIFT)
161 #define ERSPAN3_BSO_SHIFT 11
162 #define ERSPAN3_BSO_MASK (0x3U << ERSPAN3_BSO_SHIFT)
163 #define ERSPAN3_BSO_GOOD_UNKNOWN 0x0U
164 #define ERSPAN3_BSO_BAD 0x3U
165 #define ERSPAN3_BSO_SHORT 0x1U
166 #define ERSPAN3_BSO_OVERSIZED 0x2U
167 #define ERSPAN3_T_SHIFT 10
168 #define ERSPAN3_T_MASK (0x1U << ERSPAN3_T_SHIFT)
169 #define ERSPAN3_SID_SHIFT 0
170 #define ERSPAN3_SID_MASK (0x3ffU << ERSPAN3_SID_SHIFT)
171 #define ERSPAN3_P_SHIFT 15
172 #define ERSPAN3_P_MASK (0x1U << ERSPAN3_P_SHIFT)
173 #define ERSPAN3_FT_SHIFT 10
174 #define ERSPAN3_FT_MASK (0x1fU << ERSPAN3_FT_SHIFT)
175 #define ERSPAN3_FT_ETHERNET 0
176 #define ERSPAN3_FT_IP 2
177 #define ERSPAN3_HW_ID_SHIFT 4
178 #define ERSPAN3_HW_ID_MASK (0x3fU << ERSPAN3_HW_ID_SHIFT)
179 #define ERSPAN3_D_SHIFT 3
180 #define ERSPAN3_D_MASK (0x1U << ERSPAN3_D_SHIFT)
181 #define ERSPAN3_GRA_SHIFT 1
182 #define ERSPAN3_GRA_MASK (0x3U << ERSPAN3_GRA_SHIFT)
183 #define ERSPAN3_O_SHIFT 0
184 #define ERSPAN3_O_MASK (0x1U << ERSPAN3_O_SHIFT)
185
186 static const struct tok erspan3_bso_values[] = {
187 { ERSPAN3_BSO_GOOD_UNKNOWN, "Good/unknown" },
188 { ERSPAN3_BSO_BAD, "Bad" },
189 { ERSPAN3_BSO_SHORT, "Short" },
190 { ERSPAN3_BSO_OVERSIZED, "Oversized" },
191 { 0, NULL }
192 };
193
194 static const struct tok erspan3_ft_values[] = {
195 { ERSPAN3_FT_ETHERNET, "Ethernet" },
196 { ERSPAN3_FT_IP, "IP" },
197 { 0, NULL }
198 };
199
200 void
201 erspan_iii_print(netdissect_options *ndo, const u_char *bp, u_int len)
202 {
203 uint32_t hdr, hdr2, ver, cos, sid, ft;
204
205 ndo->ndo_protocol = "erspan";
206 nd_print_protocol(ndo);
207
208 /*
209 * We do not check the GRE flags; ERSPAN Type III always
210 * has an ERSPAN header.
211 */
212 ND_ICHECK_U(len, <, 4);
213 hdr = GET_BE_U_4(bp);
214 bp += 4;
215 len -= 4;
216
217 ver = hdr & ERSPAN3_VER_MASK;
218 if (ver != ERSPAN3_VER) {
219 /*
220 * Not Type III.
221 */
222 ver >>= ERSPAN3_VER_SHIFT;
223 ND_PRINT(" erspan-unknown-version-%x", ver);
224 return;
225 }
226
227 if (ndo->ndo_vflag)
228 ND_PRINT(" type3");
229
230 sid = (hdr & ERSPAN3_SID_MASK) >> ERSPAN3_SID_SHIFT;
231 ND_PRINT(" session %u", sid);
232
233 ND_PRINT(" bso %s",
234 tok2str(erspan3_bso_values, "unknown %x",
235 (hdr & ERSPAN3_BSO_MASK) >> ERSPAN3_BSO_SHIFT));
236
237 if (ndo->ndo_vflag) {
238 cos = (hdr & ERSPAN3_COS_MASK) >> ERSPAN3_COS_SHIFT;
239 ND_PRINT(" cos %u", cos);
240
241 if (hdr & ERSPAN3_T_MASK)
242 ND_PRINT(" truncated");
243 }
244
245 /* Skip timestamp */
246 ND_ICHECK_U(len, <, 4);
247 ND_TCHECK_4(bp);
248 bp += 4;
249 len -= 4;
250
251 /* Skip SGT */
252 ND_ICHECK_U(len, <, 2);
253 ND_TCHECK_2(bp);
254 bp += 2;
255 len -= 2;
256
257 /* Additional fields */
258 ND_ICHECK_U(len, <, 2);
259 hdr2 = GET_BE_U_2(bp);
260 bp += 2;
261 len -= 2;
262
263 ft = (hdr2 & ERSPAN3_FT_MASK) >> ERSPAN3_FT_SHIFT;
264 ND_PRINT(" ft %s",
265 tok2str(erspan3_ft_values, "unknown %x", ft));
266
267
268 /* Do we have the platform-specific header? */
269 if (hdr2 & ERSPAN3_O_MASK) {
270 /* Yes. Skip it. */
271 ND_ICHECK_U(len, <, 8);
272 ND_TCHECK_8(bp);
273 bp += 8;
274 len -= 8;
275 }
276
277 ND_PRINT(": ");
278
279 switch (ft) {
280
281 case ERSPAN3_FT_ETHERNET:
282 ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
283 break;
284
285 default:
286 ND_PRINT("Frame type unknown");
287 break;
288 }
289 return;
290
291 invalid:
292 nd_print_invalid(ndo);
293 }