xref: /illumos-gate/usr/src/test/os-tests/tests/mac/mac_parsing.c (revision 3d6ee46b4ddaa0ca6a00cc84d52edf88676f88ce)
1*3d6ee46bSPatrick Mooney /*
2*3d6ee46bSPatrick Mooney  * This file and its contents are supplied under the terms of the
3*3d6ee46bSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*3d6ee46bSPatrick Mooney  * You may only use this file in accordance with the terms of version
5*3d6ee46bSPatrick Mooney  * 1.0 of the CDDL.
6*3d6ee46bSPatrick Mooney  *
7*3d6ee46bSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*3d6ee46bSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*3d6ee46bSPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*3d6ee46bSPatrick Mooney  */
11*3d6ee46bSPatrick Mooney 
12*3d6ee46bSPatrick Mooney /*
13*3d6ee46bSPatrick Mooney  * Copyright 2025 Oxide Computer Compnay
14*3d6ee46bSPatrick Mooney  */
15*3d6ee46bSPatrick Mooney 
16*3d6ee46bSPatrick Mooney /*
17*3d6ee46bSPatrick Mooney  * Driver for mac ktests
18*3d6ee46bSPatrick Mooney  *
19*3d6ee46bSPatrick Mooney  * This generates input payloads for the packet-parsing tests in the mac_test
20*3d6ee46bSPatrick Mooney  * module.  Prior to calling this program, that module (`mac_test`) must be
21*3d6ee46bSPatrick Mooney  * loaded so we can execute those tests with our payloads.  Since that manual
22*3d6ee46bSPatrick Mooney  * step of loading the module is required, this test is currently omitted from
23*3d6ee46bSPatrick Mooney  * the default runfile.
24*3d6ee46bSPatrick Mooney  */
25*3d6ee46bSPatrick Mooney 
26*3d6ee46bSPatrick Mooney #include <stdio.h>
27*3d6ee46bSPatrick Mooney #include <stdlib.h>
28*3d6ee46bSPatrick Mooney #include <stdbool.h>
29*3d6ee46bSPatrick Mooney #include <unistd.h>
30*3d6ee46bSPatrick Mooney #include <fcntl.h>
31*3d6ee46bSPatrick Mooney #include <strings.h>
32*3d6ee46bSPatrick Mooney #include <spawn.h>
33*3d6ee46bSPatrick Mooney #include <wait.h>
34*3d6ee46bSPatrick Mooney #include <errno.h>
35*3d6ee46bSPatrick Mooney #include <err.h>
36*3d6ee46bSPatrick Mooney #include <sys/debug.h>
37*3d6ee46bSPatrick Mooney #include <sys/sysmacros.h>
38*3d6ee46bSPatrick Mooney 
39*3d6ee46bSPatrick Mooney #include <libnvpair.h>
40*3d6ee46bSPatrick Mooney #include <libktest.h>
41*3d6ee46bSPatrick Mooney #include <sys/ethernet.h>
42*3d6ee46bSPatrick Mooney #include <netinet/in.h>
43*3d6ee46bSPatrick Mooney #include <netinet/ip.h>
44*3d6ee46bSPatrick Mooney #include <netinet/ip6.h>
45*3d6ee46bSPatrick Mooney #include <netinet/tcp.h>
46*3d6ee46bSPatrick Mooney 
47*3d6ee46bSPatrick Mooney static ktest_hdl_t *kthdl = NULL;
48*3d6ee46bSPatrick Mooney 
49*3d6ee46bSPatrick Mooney /*
50*3d6ee46bSPatrick Mooney  * Clones of in-kernel types to specify desired results.
51*3d6ee46bSPatrick Mooney  * N.B. These must be kept in sync with those in mac_provider.h
52*3d6ee46bSPatrick Mooney  */
53*3d6ee46bSPatrick Mooney typedef enum mac_ether_offload_flags {
54*3d6ee46bSPatrick Mooney 	MEOI_L2INFO_SET		= 1 << 0,
55*3d6ee46bSPatrick Mooney 	MEOI_L3INFO_SET		= 1 << 1,
56*3d6ee46bSPatrick Mooney 	MEOI_L4INFO_SET		= 1 << 2,
57*3d6ee46bSPatrick Mooney 	MEOI_VLAN_TAGGED	= 1 << 3,
58*3d6ee46bSPatrick Mooney 	MEOI_L3_FRAGMENT	= 1 << 4
59*3d6ee46bSPatrick Mooney } mac_ether_offload_flags_t;
60*3d6ee46bSPatrick Mooney 
61*3d6ee46bSPatrick Mooney typedef struct mac_ether_offload_info {
62*3d6ee46bSPatrick Mooney 	mac_ether_offload_flags_t	meoi_flags;	/* What's valid? */
63*3d6ee46bSPatrick Mooney 	size_t		meoi_len;	/* Total message length */
64*3d6ee46bSPatrick Mooney 	uint8_t		meoi_l2hlen;	/* How long is the Ethernet header? */
65*3d6ee46bSPatrick Mooney 	uint16_t	meoi_l3proto;	/* What's the Ethertype */
66*3d6ee46bSPatrick Mooney 	uint16_t	meoi_l3hlen;	/* How long is the header? */
67*3d6ee46bSPatrick Mooney 	uint8_t		meoi_l4proto;	/* What is the payload type? */
68*3d6ee46bSPatrick Mooney 	uint8_t		meoi_l4hlen;	/* How long is the L4 header */
69*3d6ee46bSPatrick Mooney } mac_ether_offload_info_t;
70*3d6ee46bSPatrick Mooney 
71*3d6ee46bSPatrick Mooney 
72*3d6ee46bSPatrick Mooney typedef struct test_pkt {
73*3d6ee46bSPatrick Mooney 	size_t tp_sz;
74*3d6ee46bSPatrick Mooney 	uint8_t *tp_bytes;
75*3d6ee46bSPatrick Mooney } test_pkt_t;
76*3d6ee46bSPatrick Mooney 
77*3d6ee46bSPatrick Mooney static test_pkt_t *
tp_alloc(void)78*3d6ee46bSPatrick Mooney tp_alloc(void)
79*3d6ee46bSPatrick Mooney {
80*3d6ee46bSPatrick Mooney 	void *buf = calloc(1, sizeof (test_pkt_t));
81*3d6ee46bSPatrick Mooney 	VERIFY(buf != NULL);
82*3d6ee46bSPatrick Mooney 	return (buf);
83*3d6ee46bSPatrick Mooney }
84*3d6ee46bSPatrick Mooney 
85*3d6ee46bSPatrick Mooney static void
tp_free(test_pkt_t * tp)86*3d6ee46bSPatrick Mooney tp_free(test_pkt_t *tp)
87*3d6ee46bSPatrick Mooney {
88*3d6ee46bSPatrick Mooney 	if (tp->tp_bytes != NULL) {
89*3d6ee46bSPatrick Mooney 		free(tp->tp_bytes);
90*3d6ee46bSPatrick Mooney 	}
91*3d6ee46bSPatrick Mooney 	free(tp);
92*3d6ee46bSPatrick Mooney }
93*3d6ee46bSPatrick Mooney 
94*3d6ee46bSPatrick Mooney static void
tp_append(test_pkt_t * tp,const void * bytes,size_t sz)95*3d6ee46bSPatrick Mooney tp_append(test_pkt_t *tp, const void *bytes, size_t sz)
96*3d6ee46bSPatrick Mooney {
97*3d6ee46bSPatrick Mooney 	if (tp->tp_bytes == NULL) {
98*3d6ee46bSPatrick Mooney 		VERIFY(tp->tp_sz == 0);
99*3d6ee46bSPatrick Mooney 
100*3d6ee46bSPatrick Mooney 		tp->tp_bytes = malloc(sz);
101*3d6ee46bSPatrick Mooney 		VERIFY(tp->tp_bytes != NULL);
102*3d6ee46bSPatrick Mooney 		bcopy(bytes, tp->tp_bytes, sz);
103*3d6ee46bSPatrick Mooney 		tp->tp_sz = sz;
104*3d6ee46bSPatrick Mooney 	} else {
105*3d6ee46bSPatrick Mooney 		const size_t new_sz = tp->tp_sz + sz;
106*3d6ee46bSPatrick Mooney 
107*3d6ee46bSPatrick Mooney 		tp->tp_bytes = realloc(tp->tp_bytes, new_sz);
108*3d6ee46bSPatrick Mooney 		VERIFY(tp->tp_bytes != NULL);
109*3d6ee46bSPatrick Mooney 		bcopy(bytes, &tp->tp_bytes[tp->tp_sz], sz);
110*3d6ee46bSPatrick Mooney 		tp->tp_sz = new_sz;
111*3d6ee46bSPatrick Mooney 	}
112*3d6ee46bSPatrick Mooney }
113*3d6ee46bSPatrick Mooney 
114*3d6ee46bSPatrick Mooney static void
append_ether(test_pkt_t * tp,uint16_t ethertype)115*3d6ee46bSPatrick Mooney append_ether(test_pkt_t *tp, uint16_t ethertype)
116*3d6ee46bSPatrick Mooney {
117*3d6ee46bSPatrick Mooney 	struct ether_header hdr_ether = {
118*3d6ee46bSPatrick Mooney 		.ether_type = htons(ethertype),
119*3d6ee46bSPatrick Mooney 	};
120*3d6ee46bSPatrick Mooney 
121*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_ether, sizeof (hdr_ether));
122*3d6ee46bSPatrick Mooney }
123*3d6ee46bSPatrick Mooney 
124*3d6ee46bSPatrick Mooney static void
append_ip4(test_pkt_t * tp,uint8_t ipproto)125*3d6ee46bSPatrick Mooney append_ip4(test_pkt_t *tp, uint8_t ipproto)
126*3d6ee46bSPatrick Mooney {
127*3d6ee46bSPatrick Mooney 	struct ip hdr_ip = {
128*3d6ee46bSPatrick Mooney 		.ip_v = 4,
129*3d6ee46bSPatrick Mooney 		.ip_hl = 5,
130*3d6ee46bSPatrick Mooney 		.ip_p = ipproto,
131*3d6ee46bSPatrick Mooney 	};
132*3d6ee46bSPatrick Mooney 
133*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_ip, sizeof (hdr_ip));
134*3d6ee46bSPatrick Mooney }
135*3d6ee46bSPatrick Mooney 
136*3d6ee46bSPatrick Mooney static void
append_ip6(test_pkt_t * tp,uint8_t ipproto)137*3d6ee46bSPatrick Mooney append_ip6(test_pkt_t *tp, uint8_t ipproto)
138*3d6ee46bSPatrick Mooney {
139*3d6ee46bSPatrick Mooney 	struct ip6_hdr hdr_ip6 = { 0 };
140*3d6ee46bSPatrick Mooney 	hdr_ip6.ip6_vfc = 0x60;
141*3d6ee46bSPatrick Mooney 	hdr_ip6.ip6_nxt = ipproto;
142*3d6ee46bSPatrick Mooney 
143*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_ip6, sizeof (hdr_ip6));
144*3d6ee46bSPatrick Mooney }
145*3d6ee46bSPatrick Mooney 
146*3d6ee46bSPatrick Mooney static void
append_tcp(test_pkt_t * tp)147*3d6ee46bSPatrick Mooney append_tcp(test_pkt_t *tp)
148*3d6ee46bSPatrick Mooney {
149*3d6ee46bSPatrick Mooney 	struct tcphdr hdr_tcp = {
150*3d6ee46bSPatrick Mooney 		.th_off = 5
151*3d6ee46bSPatrick Mooney 	};
152*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_tcp, sizeof (hdr_tcp));
153*3d6ee46bSPatrick Mooney }
154*3d6ee46bSPatrick Mooney 
155*3d6ee46bSPatrick Mooney static test_pkt_t *
build_tcp4(mac_ether_offload_info_t * meoi)156*3d6ee46bSPatrick Mooney build_tcp4(mac_ether_offload_info_t *meoi)
157*3d6ee46bSPatrick Mooney {
158*3d6ee46bSPatrick Mooney 	test_pkt_t *tp = tp_alloc();
159*3d6ee46bSPatrick Mooney 	append_ether(tp, ETHERTYPE_IP);
160*3d6ee46bSPatrick Mooney 	append_ip4(tp, IPPROTO_TCP);
161*3d6ee46bSPatrick Mooney 	append_tcp(tp);
162*3d6ee46bSPatrick Mooney 
163*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t expected = {
164*3d6ee46bSPatrick Mooney 		.meoi_flags =
165*3d6ee46bSPatrick Mooney 		    MEOI_L2INFO_SET | MEOI_L3INFO_SET | MEOI_L4INFO_SET,
166*3d6ee46bSPatrick Mooney 		.meoi_len = tp->tp_sz,
167*3d6ee46bSPatrick Mooney 		.meoi_l2hlen = sizeof (struct ether_header),
168*3d6ee46bSPatrick Mooney 		.meoi_l3proto = ETHERTYPE_IP,
169*3d6ee46bSPatrick Mooney 		.meoi_l3hlen = sizeof (struct ip),
170*3d6ee46bSPatrick Mooney 		.meoi_l4proto = IPPROTO_TCP,
171*3d6ee46bSPatrick Mooney 		.meoi_l4hlen = sizeof (struct tcphdr),
172*3d6ee46bSPatrick Mooney 	};
173*3d6ee46bSPatrick Mooney 	*meoi = expected;
174*3d6ee46bSPatrick Mooney 
175*3d6ee46bSPatrick Mooney 	return (tp);
176*3d6ee46bSPatrick Mooney }
177*3d6ee46bSPatrick Mooney 
178*3d6ee46bSPatrick Mooney static test_pkt_t *
build_tcp6(mac_ether_offload_info_t * meoi)179*3d6ee46bSPatrick Mooney build_tcp6(mac_ether_offload_info_t *meoi)
180*3d6ee46bSPatrick Mooney {
181*3d6ee46bSPatrick Mooney 	test_pkt_t *tp = tp_alloc();
182*3d6ee46bSPatrick Mooney 	append_ether(tp, ETHERTYPE_IPV6);
183*3d6ee46bSPatrick Mooney 	append_ip6(tp, IPPROTO_TCP);
184*3d6ee46bSPatrick Mooney 	append_tcp(tp);
185*3d6ee46bSPatrick Mooney 
186*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t expected = {
187*3d6ee46bSPatrick Mooney 		.meoi_flags =
188*3d6ee46bSPatrick Mooney 		    MEOI_L2INFO_SET | MEOI_L3INFO_SET | MEOI_L4INFO_SET,
189*3d6ee46bSPatrick Mooney 		.meoi_len = tp->tp_sz,
190*3d6ee46bSPatrick Mooney 		.meoi_l2hlen = sizeof (struct ether_header),
191*3d6ee46bSPatrick Mooney 		.meoi_l3proto = ETHERTYPE_IPV6,
192*3d6ee46bSPatrick Mooney 		.meoi_l3hlen = sizeof (struct ip6_hdr),
193*3d6ee46bSPatrick Mooney 		.meoi_l4proto = IPPROTO_TCP,
194*3d6ee46bSPatrick Mooney 		.meoi_l4hlen = sizeof (struct tcphdr),
195*3d6ee46bSPatrick Mooney 	};
196*3d6ee46bSPatrick Mooney 	*meoi = expected;
197*3d6ee46bSPatrick Mooney 
198*3d6ee46bSPatrick Mooney 	return (tp);
199*3d6ee46bSPatrick Mooney }
200*3d6ee46bSPatrick Mooney 
201*3d6ee46bSPatrick Mooney static test_pkt_t *
build_frag_v4(mac_ether_offload_info_t * meoi)202*3d6ee46bSPatrick Mooney build_frag_v4(mac_ether_offload_info_t *meoi)
203*3d6ee46bSPatrick Mooney {
204*3d6ee46bSPatrick Mooney 	test_pkt_t *tp = tp_alloc();
205*3d6ee46bSPatrick Mooney 	append_ether(tp, ETHERTYPE_IP);
206*3d6ee46bSPatrick Mooney 
207*3d6ee46bSPatrick Mooney 	struct ip hdr_ip = {
208*3d6ee46bSPatrick Mooney 		.ip_v = 4,
209*3d6ee46bSPatrick Mooney 		.ip_hl = 5,
210*3d6ee46bSPatrick Mooney 		.ip_off = IP_MF,
211*3d6ee46bSPatrick Mooney 		.ip_p = IPPROTO_TCP,
212*3d6ee46bSPatrick Mooney 	};
213*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_ip, sizeof (hdr_ip));
214*3d6ee46bSPatrick Mooney 
215*3d6ee46bSPatrick Mooney 	append_tcp(tp);
216*3d6ee46bSPatrick Mooney 
217*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t expected = {
218*3d6ee46bSPatrick Mooney 		.meoi_flags = MEOI_L2INFO_SET | MEOI_L3INFO_SET |
219*3d6ee46bSPatrick Mooney 		    MEOI_L4INFO_SET | MEOI_L3_FRAGMENT,
220*3d6ee46bSPatrick Mooney 		.meoi_l2hlen = sizeof (struct ether_header),
221*3d6ee46bSPatrick Mooney 		.meoi_l3hlen = sizeof (struct ip),
222*3d6ee46bSPatrick Mooney 		.meoi_l4hlen = sizeof (struct tcphdr),
223*3d6ee46bSPatrick Mooney 		.meoi_l3proto = ETHERTYPE_IP,
224*3d6ee46bSPatrick Mooney 		.meoi_l4proto = IPPROTO_TCP
225*3d6ee46bSPatrick Mooney 	};
226*3d6ee46bSPatrick Mooney 	*meoi = expected;
227*3d6ee46bSPatrick Mooney 
228*3d6ee46bSPatrick Mooney 	return (tp);
229*3d6ee46bSPatrick Mooney }
230*3d6ee46bSPatrick Mooney 
231*3d6ee46bSPatrick Mooney static test_pkt_t *
build_frag_v6(mac_ether_offload_info_t * meoi)232*3d6ee46bSPatrick Mooney build_frag_v6(mac_ether_offload_info_t *meoi)
233*3d6ee46bSPatrick Mooney {
234*3d6ee46bSPatrick Mooney 	test_pkt_t *tp = tp_alloc();
235*3d6ee46bSPatrick Mooney 	append_ether(tp, ETHERTYPE_IPV6);
236*3d6ee46bSPatrick Mooney 
237*3d6ee46bSPatrick Mooney 	struct ip6_hdr hdr_ip6 = { 0 };
238*3d6ee46bSPatrick Mooney 	hdr_ip6.ip6_vfc = 0x60;
239*3d6ee46bSPatrick Mooney 	hdr_ip6.ip6_nxt = IPPROTO_ROUTING;
240*3d6ee46bSPatrick Mooney 
241*3d6ee46bSPatrick Mooney 	struct ip6_rthdr0 eh_route = {
242*3d6ee46bSPatrick Mooney 		.ip6r0_nxt = IPPROTO_FRAGMENT,
243*3d6ee46bSPatrick Mooney 		.ip6r0_len = 0,
244*3d6ee46bSPatrick Mooney 		/* Has padding for len=0 8-byte boundary */
245*3d6ee46bSPatrick Mooney 	};
246*3d6ee46bSPatrick Mooney 	struct ip6_frag eh_frag = {
247*3d6ee46bSPatrick Mooney 		.ip6f_nxt = IPPROTO_DSTOPTS,
248*3d6ee46bSPatrick Mooney 	};
249*3d6ee46bSPatrick Mooney 	struct ip6_dstopt {
250*3d6ee46bSPatrick Mooney 		struct ip6_opt ip6dst_hdr;
251*3d6ee46bSPatrick Mooney 		/* pad out to required 8-byte boundary */
252*3d6ee46bSPatrick Mooney 		uint8_t ip6dst_data[6];
253*3d6ee46bSPatrick Mooney 	} eh_dstopts = {
254*3d6ee46bSPatrick Mooney 		.ip6dst_hdr = {
255*3d6ee46bSPatrick Mooney 			.ip6o_type = IPPROTO_TCP,
256*3d6ee46bSPatrick Mooney 			.ip6o_len = 0,
257*3d6ee46bSPatrick Mooney 		}
258*3d6ee46bSPatrick Mooney 	};
259*3d6ee46bSPatrick Mooney 
260*3d6ee46bSPatrick Mooney 	/*
261*3d6ee46bSPatrick Mooney 	 * Mark the packet for fragmentation, but do so in the middle of the EHs
262*3d6ee46bSPatrick Mooney 	 * as a more contrived case.
263*3d6ee46bSPatrick Mooney 	 */
264*3d6ee46bSPatrick Mooney 	VERIFY(tp->tp_sz == sizeof (struct ether_header));
265*3d6ee46bSPatrick Mooney 	tp_append(tp, &hdr_ip6, sizeof (hdr_ip6));
266*3d6ee46bSPatrick Mooney 	tp_append(tp, &eh_route, sizeof (eh_route));
267*3d6ee46bSPatrick Mooney 	tp_append(tp, &eh_frag, sizeof (eh_frag));
268*3d6ee46bSPatrick Mooney 	tp_append(tp, &eh_dstopts, sizeof (eh_dstopts));
269*3d6ee46bSPatrick Mooney 	const size_t l3sz = tp->tp_sz - sizeof (struct ether_header);
270*3d6ee46bSPatrick Mooney 
271*3d6ee46bSPatrick Mooney 	append_tcp(tp);
272*3d6ee46bSPatrick Mooney 
273*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t expected = {
274*3d6ee46bSPatrick Mooney 		.meoi_flags = MEOI_L2INFO_SET | MEOI_L3INFO_SET |
275*3d6ee46bSPatrick Mooney 		    MEOI_L4INFO_SET | MEOI_L3_FRAGMENT,
276*3d6ee46bSPatrick Mooney 		.meoi_l2hlen = sizeof (struct ether_header),
277*3d6ee46bSPatrick Mooney 		.meoi_l3hlen = l3sz,
278*3d6ee46bSPatrick Mooney 		.meoi_l4hlen = sizeof (struct tcphdr),
279*3d6ee46bSPatrick Mooney 		.meoi_l3proto = ETHERTYPE_IPV6,
280*3d6ee46bSPatrick Mooney 		.meoi_l4proto = IPPROTO_TCP
281*3d6ee46bSPatrick Mooney 	};
282*3d6ee46bSPatrick Mooney 	*meoi = expected;
283*3d6ee46bSPatrick Mooney 
284*3d6ee46bSPatrick Mooney 	return (tp);
285*3d6ee46bSPatrick Mooney }
286*3d6ee46bSPatrick Mooney 
287*3d6ee46bSPatrick Mooney static nvlist_t *
meoi_to_nvlist(const mac_ether_offload_info_t * meoi)288*3d6ee46bSPatrick Mooney meoi_to_nvlist(const mac_ether_offload_info_t *meoi)
289*3d6ee46bSPatrick Mooney {
290*3d6ee46bSPatrick Mooney 	nvlist_t *out = fnvlist_alloc();
291*3d6ee46bSPatrick Mooney 	fnvlist_add_int32(out, "meoi_flags", meoi->meoi_flags);
292*3d6ee46bSPatrick Mooney 	fnvlist_add_uint64(out, "meoi_len", meoi->meoi_len);
293*3d6ee46bSPatrick Mooney 	fnvlist_add_uint8(out, "meoi_l2hlen", meoi->meoi_l2hlen);
294*3d6ee46bSPatrick Mooney 	fnvlist_add_uint16(out, "meoi_l3proto", meoi->meoi_l3proto);
295*3d6ee46bSPatrick Mooney 	fnvlist_add_uint16(out, "meoi_l3hlen", meoi->meoi_l3hlen);
296*3d6ee46bSPatrick Mooney 	fnvlist_add_uint8(out, "meoi_l4proto", meoi->meoi_l4proto);
297*3d6ee46bSPatrick Mooney 	fnvlist_add_uint8(out, "meoi_l4hlen", meoi->meoi_l4hlen);
298*3d6ee46bSPatrick Mooney 
299*3d6ee46bSPatrick Mooney 	return (out);
300*3d6ee46bSPatrick Mooney }
301*3d6ee46bSPatrick Mooney 
302*3d6ee46bSPatrick Mooney static nvlist_t *
build_meoi_payload(test_pkt_t * tp,const mac_ether_offload_info_t * results,uint32_t * splits,uint_t num_splits)303*3d6ee46bSPatrick Mooney build_meoi_payload(test_pkt_t *tp, const mac_ether_offload_info_t *results,
304*3d6ee46bSPatrick Mooney     uint32_t *splits, uint_t num_splits)
305*3d6ee46bSPatrick Mooney {
306*3d6ee46bSPatrick Mooney 	nvlist_t *nvl_results = meoi_to_nvlist(results);
307*3d6ee46bSPatrick Mooney 
308*3d6ee46bSPatrick Mooney 	nvlist_t *payload = fnvlist_alloc();
309*3d6ee46bSPatrick Mooney 	fnvlist_add_byte_array(payload, "pkt_bytes", tp->tp_bytes, tp->tp_sz);
310*3d6ee46bSPatrick Mooney 	if (num_splits != 0 && splits != NULL) {
311*3d6ee46bSPatrick Mooney 		fnvlist_add_uint32_array(payload, "splits", splits,
312*3d6ee46bSPatrick Mooney 		    num_splits);
313*3d6ee46bSPatrick Mooney 	}
314*3d6ee46bSPatrick Mooney 	fnvlist_add_nvlist(payload, "results", nvl_results);
315*3d6ee46bSPatrick Mooney 
316*3d6ee46bSPatrick Mooney 	nvlist_free(nvl_results);
317*3d6ee46bSPatrick Mooney 
318*3d6ee46bSPatrick Mooney 	return (payload);
319*3d6ee46bSPatrick Mooney }
320*3d6ee46bSPatrick Mooney 
321*3d6ee46bSPatrick Mooney static nvlist_t *
build_partial_payload(test_pkt_t * tp,uint_t offset,const mac_ether_offload_info_t * partial,const mac_ether_offload_info_t * results,uint32_t * splits,uint_t num_splits)322*3d6ee46bSPatrick Mooney build_partial_payload(test_pkt_t *tp, uint_t offset,
323*3d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *partial,
324*3d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *results,
325*3d6ee46bSPatrick Mooney     uint32_t *splits, uint_t num_splits)
326*3d6ee46bSPatrick Mooney {
327*3d6ee46bSPatrick Mooney 	nvlist_t *nvl_partial = meoi_to_nvlist(partial);
328*3d6ee46bSPatrick Mooney 	nvlist_t *nvl_results = meoi_to_nvlist(results);
329*3d6ee46bSPatrick Mooney 
330*3d6ee46bSPatrick Mooney 	nvlist_t *payload = fnvlist_alloc();
331*3d6ee46bSPatrick Mooney 	fnvlist_add_byte_array(payload, "pkt_bytes", tp->tp_bytes, tp->tp_sz);
332*3d6ee46bSPatrick Mooney 	if (num_splits != 0 && splits != NULL) {
333*3d6ee46bSPatrick Mooney 		fnvlist_add_uint32_array(payload, "splits", splits,
334*3d6ee46bSPatrick Mooney 		    num_splits);
335*3d6ee46bSPatrick Mooney 	}
336*3d6ee46bSPatrick Mooney 	fnvlist_add_nvlist(payload, "results", nvl_results);
337*3d6ee46bSPatrick Mooney 	fnvlist_add_nvlist(payload, "partial", nvl_partial);
338*3d6ee46bSPatrick Mooney 	fnvlist_add_uint32(payload, "offset", offset);
339*3d6ee46bSPatrick Mooney 
340*3d6ee46bSPatrick Mooney 	nvlist_free(nvl_partial);
341*3d6ee46bSPatrick Mooney 	nvlist_free(nvl_results);
342*3d6ee46bSPatrick Mooney 
343*3d6ee46bSPatrick Mooney 	return (payload);
344*3d6ee46bSPatrick Mooney }
345*3d6ee46bSPatrick Mooney 
346*3d6ee46bSPatrick Mooney static nvlist_t *
build_ether_payload(test_pkt_t * tp,uint8_t * dstaddr,uint32_t tci,uint32_t * splits,uint_t num_splits)347*3d6ee46bSPatrick Mooney build_ether_payload(test_pkt_t *tp, uint8_t *dstaddr, uint32_t tci,
348*3d6ee46bSPatrick Mooney     uint32_t *splits, uint_t num_splits)
349*3d6ee46bSPatrick Mooney {
350*3d6ee46bSPatrick Mooney 	nvlist_t *payload = fnvlist_alloc();
351*3d6ee46bSPatrick Mooney 	fnvlist_add_byte_array(payload, "pkt_bytes", tp->tp_bytes, tp->tp_sz);
352*3d6ee46bSPatrick Mooney 	if (num_splits != 0 && splits != NULL) {
353*3d6ee46bSPatrick Mooney 		fnvlist_add_uint32_array(payload, "splits", splits,
354*3d6ee46bSPatrick Mooney 		    num_splits);
355*3d6ee46bSPatrick Mooney 	}
356*3d6ee46bSPatrick Mooney 	fnvlist_add_byte_array(payload, "dstaddr", dstaddr, ETHERADDRL);
357*3d6ee46bSPatrick Mooney 	fnvlist_add_uint32(payload, "tci", tci);
358*3d6ee46bSPatrick Mooney 
359*3d6ee46bSPatrick Mooney 	return (payload);
360*3d6ee46bSPatrick Mooney }
361*3d6ee46bSPatrick Mooney 
362*3d6ee46bSPatrick Mooney struct test_tuple {
363*3d6ee46bSPatrick Mooney 	const char *tt_module;
364*3d6ee46bSPatrick Mooney 	const char *tt_suite;
365*3d6ee46bSPatrick Mooney 	const char *tt_test;
366*3d6ee46bSPatrick Mooney };
367*3d6ee46bSPatrick Mooney const struct test_tuple tuple_meoi = {
368*3d6ee46bSPatrick Mooney 	.tt_module = "mac",
369*3d6ee46bSPatrick Mooney 	.tt_suite = "parsing",
370*3d6ee46bSPatrick Mooney 	.tt_test = "mac_ether_offload_info_test"
371*3d6ee46bSPatrick Mooney };
372*3d6ee46bSPatrick Mooney const struct test_tuple tuple_partial_meoi = {
373*3d6ee46bSPatrick Mooney 	.tt_module = "mac",
374*3d6ee46bSPatrick Mooney 	.tt_suite = "parsing",
375*3d6ee46bSPatrick Mooney 	.tt_test = "mac_partial_offload_info_test"
376*3d6ee46bSPatrick Mooney };
377*3d6ee46bSPatrick Mooney const struct test_tuple tuple_l2info = {
378*3d6ee46bSPatrick Mooney 	.tt_module = "mac",
379*3d6ee46bSPatrick Mooney 	.tt_suite = "parsing",
380*3d6ee46bSPatrick Mooney 	.tt_test = "mac_ether_l2_info_test"
381*3d6ee46bSPatrick Mooney };
382*3d6ee46bSPatrick Mooney 
383*3d6ee46bSPatrick Mooney static bool
run_test(nvlist_t * payload,const struct test_tuple * tuple)384*3d6ee46bSPatrick Mooney run_test(nvlist_t *payload, const struct test_tuple *tuple)
385*3d6ee46bSPatrick Mooney {
386*3d6ee46bSPatrick Mooney 	size_t payload_sz;
387*3d6ee46bSPatrick Mooney 	char *payload_packed = fnvlist_pack(payload, &payload_sz);
388*3d6ee46bSPatrick Mooney 	VERIFY(payload_packed != NULL);
389*3d6ee46bSPatrick Mooney 	nvlist_free(payload);
390*3d6ee46bSPatrick Mooney 
391*3d6ee46bSPatrick Mooney 	ktest_run_req_t req = {
392*3d6ee46bSPatrick Mooney 		.krq_module = tuple->tt_module,
393*3d6ee46bSPatrick Mooney 		.krq_suite = tuple->tt_suite,
394*3d6ee46bSPatrick Mooney 		.krq_test = tuple->tt_test,
395*3d6ee46bSPatrick Mooney 		.krq_input = (uchar_t *)payload_packed,
396*3d6ee46bSPatrick Mooney 		.krq_input_len = payload_sz,
397*3d6ee46bSPatrick Mooney 	};
398*3d6ee46bSPatrick Mooney 	ktest_run_result_t result = { 0 };
399*3d6ee46bSPatrick Mooney 
400*3d6ee46bSPatrick Mooney 	if (!ktest_run(kthdl, &req, &result)) {
401*3d6ee46bSPatrick Mooney 		err(EXIT_FAILURE, "error while attempting ktest_run()");
402*3d6ee46bSPatrick Mooney 	}
403*3d6ee46bSPatrick Mooney 
404*3d6ee46bSPatrick Mooney 	const char *cname = ktest_code_name(result.krr_code);
405*3d6ee46bSPatrick Mooney 	if (result.krr_code == KTEST_CODE_PASS) {
406*3d6ee46bSPatrick Mooney 		(void) printf("%s: %s\n", tuple->tt_test, cname);
407*3d6ee46bSPatrick Mooney 		free(result.krr_msg);
408*3d6ee46bSPatrick Mooney 		return (true);
409*3d6ee46bSPatrick Mooney 	} else {
410*3d6ee46bSPatrick Mooney 		(void) printf("%s: %s @ line %u\n",
411*3d6ee46bSPatrick Mooney 		    tuple->tt_test, cname, result.krr_line);
412*3d6ee46bSPatrick Mooney 		(void) printf("\tmsg: %s", result.krr_msg);
413*3d6ee46bSPatrick Mooney 		free(result.krr_msg);
414*3d6ee46bSPatrick Mooney 		return (false);
415*3d6ee46bSPatrick Mooney 	}
416*3d6ee46bSPatrick Mooney }
417*3d6ee46bSPatrick Mooney 
418*3d6ee46bSPatrick Mooney static uint32_t *
split_gen_single(uint_t num_bytes)419*3d6ee46bSPatrick Mooney split_gen_single(uint_t num_bytes)
420*3d6ee46bSPatrick Mooney {
421*3d6ee46bSPatrick Mooney 	uint32_t *splits = calloc(num_bytes, sizeof (uint32_t));
422*3d6ee46bSPatrick Mooney 	VERIFY(splits != NULL);
423*3d6ee46bSPatrick Mooney 	for (uint_t i = 0; i < num_bytes; i++) {
424*3d6ee46bSPatrick Mooney 		splits[i] = 1;
425*3d6ee46bSPatrick Mooney 	}
426*3d6ee46bSPatrick Mooney 	return (splits);
427*3d6ee46bSPatrick Mooney }
428*3d6ee46bSPatrick Mooney static uint32_t *
split_gen_random(uint_t num_bytes,uint_t * num_splits)429*3d6ee46bSPatrick Mooney split_gen_random(uint_t num_bytes, uint_t *num_splits)
430*3d6ee46bSPatrick Mooney {
431*3d6ee46bSPatrick Mooney 	/*
432*3d6ee46bSPatrick Mooney 	 * Generate split points between 0-10 bytes in size.  Assuming an
433*3d6ee46bSPatrick Mooney 	 * average size of 5 when allocating a fixed buffer, with any remaining
434*3d6ee46bSPatrick Mooney 	 * bytes going into one large trailing mblk.
435*3d6ee46bSPatrick Mooney 	 */
436*3d6ee46bSPatrick Mooney 	*num_splits = num_bytes / 5;
437*3d6ee46bSPatrick Mooney 
438*3d6ee46bSPatrick Mooney 	uint32_t *splits = calloc(*num_splits, sizeof (uint32_t));
439*3d6ee46bSPatrick Mooney 	VERIFY(splits != NULL);
440*3d6ee46bSPatrick Mooney 	for (uint_t i = 0; i < *num_splits; i++) {
441*3d6ee46bSPatrick Mooney 		/*
442*3d6ee46bSPatrick Mooney 		 * This uses random() rather than something like
443*3d6ee46bSPatrick Mooney 		 * arc4random_uniform() so we can have deterministic splits for
444*3d6ee46bSPatrick Mooney 		 * the test case.  This is achieved with a prior srand() call
445*3d6ee46bSPatrick Mooney 		 * with a fixed seed.
446*3d6ee46bSPatrick Mooney 		 */
447*3d6ee46bSPatrick Mooney 		splits[i] = random() % 11;
448*3d6ee46bSPatrick Mooney 	}
449*3d6ee46bSPatrick Mooney 
450*3d6ee46bSPatrick Mooney 	return (splits);
451*3d6ee46bSPatrick Mooney }
452*3d6ee46bSPatrick Mooney static void
split_print(const uint32_t * splits,uint_t num_splits)453*3d6ee46bSPatrick Mooney split_print(const uint32_t *splits, uint_t num_splits)
454*3d6ee46bSPatrick Mooney {
455*3d6ee46bSPatrick Mooney 	if (num_splits == 0) {
456*3d6ee46bSPatrick Mooney 		(void) printf("\tsplits: []\n");
457*3d6ee46bSPatrick Mooney 	} else {
458*3d6ee46bSPatrick Mooney 		(void) printf("\tsplits: [");
459*3d6ee46bSPatrick Mooney 		for (uint_t i = 0; i < num_splits; i++) {
460*3d6ee46bSPatrick Mooney 			(void) printf("%s%u", i == 0 ? "" : ", ", splits[i]);
461*3d6ee46bSPatrick Mooney 		}
462*3d6ee46bSPatrick Mooney 		(void) printf("]\n");
463*3d6ee46bSPatrick Mooney 	}
464*3d6ee46bSPatrick Mooney }
465*3d6ee46bSPatrick Mooney 
466*3d6ee46bSPatrick Mooney /*
467*3d6ee46bSPatrick Mooney  * Run variations of mac_ether_offload_info() test against packet/meoi pair.
468*3d6ee46bSPatrick Mooney  * Returns true if any variation failed.
469*3d6ee46bSPatrick Mooney  */
470*3d6ee46bSPatrick Mooney static bool
run_meoi_variants(const char * prefix,test_pkt_t * tp,const mac_ether_offload_info_t * meoi)471*3d6ee46bSPatrick Mooney run_meoi_variants(const char *prefix, test_pkt_t *tp,
472*3d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *meoi)
473*3d6ee46bSPatrick Mooney {
474*3d6ee46bSPatrick Mooney 	nvlist_t *payload;
475*3d6ee46bSPatrick Mooney 	bool any_failed = false;
476*3d6ee46bSPatrick Mooney 	uint32_t *splits = NULL;
477*3d6ee46bSPatrick Mooney 	uint_t num_splits;
478*3d6ee46bSPatrick Mooney 
479*3d6ee46bSPatrick Mooney 	(void) printf("%s - simple - ", prefix);
480*3d6ee46bSPatrick Mooney 	payload = build_meoi_payload(tp, meoi, NULL, 0);
481*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_meoi);
482*3d6ee46bSPatrick Mooney 
483*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-single-bytes - ", prefix);
484*3d6ee46bSPatrick Mooney 	splits = split_gen_single(tp->tp_sz);
485*3d6ee46bSPatrick Mooney 	payload = build_meoi_payload(tp, meoi, splits, tp->tp_sz);
486*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_meoi);
487*3d6ee46bSPatrick Mooney 	free(splits);
488*3d6ee46bSPatrick Mooney 
489*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-random - ", prefix);
490*3d6ee46bSPatrick Mooney 	splits = split_gen_random(tp->tp_sz, &num_splits);
491*3d6ee46bSPatrick Mooney 	payload = build_meoi_payload(tp, meoi, splits, num_splits);
492*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_meoi);
493*3d6ee46bSPatrick Mooney 	split_print(splits, num_splits);
494*3d6ee46bSPatrick Mooney 	free(splits);
495*3d6ee46bSPatrick Mooney 
496*3d6ee46bSPatrick Mooney 	return (any_failed);
497*3d6ee46bSPatrick Mooney }
498*3d6ee46bSPatrick Mooney 
499*3d6ee46bSPatrick Mooney /*
500*3d6ee46bSPatrick Mooney  * Run variations of mac_partial_offload_info() test against packet/meoi pair.
501*3d6ee46bSPatrick Mooney  * Returns true if any variation failed.
502*3d6ee46bSPatrick Mooney  */
503*3d6ee46bSPatrick Mooney static bool
run_partial_variants(const char * prefix,test_pkt_t * tp,const mac_ether_offload_info_t * meoi)504*3d6ee46bSPatrick Mooney run_partial_variants(const char *prefix, test_pkt_t *tp,
505*3d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *meoi)
506*3d6ee46bSPatrick Mooney {
507*3d6ee46bSPatrick Mooney 	nvlist_t *payload;
508*3d6ee46bSPatrick Mooney 	bool any_failed = false;
509*3d6ee46bSPatrick Mooney 	uint32_t *splits = NULL;
510*3d6ee46bSPatrick Mooney 	uint_t num_splits;
511*3d6ee46bSPatrick Mooney 
512*3d6ee46bSPatrick Mooney 	/* skip over the l2 header but ask for the rest to be filled */
513*3d6ee46bSPatrick Mooney 	uint32_t offset = meoi->meoi_l2hlen;
514*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t partial = {
515*3d6ee46bSPatrick Mooney 		.meoi_flags = MEOI_L2INFO_SET,
516*3d6ee46bSPatrick Mooney 		.meoi_l3proto = meoi->meoi_l3proto,
517*3d6ee46bSPatrick Mooney 	};
518*3d6ee46bSPatrick Mooney 	/* And the result should reflect that ignored l2 header */
519*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t result;
520*3d6ee46bSPatrick Mooney 	bcopy(meoi, &result, sizeof (result));
521*3d6ee46bSPatrick Mooney 	result.meoi_l2hlen = 0;
522*3d6ee46bSPatrick Mooney 
523*3d6ee46bSPatrick Mooney 	(void) printf("%s - simple - ", prefix);
524*3d6ee46bSPatrick Mooney 	payload = build_partial_payload(tp, offset, &partial, &result, NULL, 0);
525*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_partial_meoi);
526*3d6ee46bSPatrick Mooney 
527*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-single-bytes - ", prefix);
528*3d6ee46bSPatrick Mooney 	splits = split_gen_single(tp->tp_sz);
529*3d6ee46bSPatrick Mooney 	payload = build_partial_payload(tp, offset, &partial, &result, splits,
530*3d6ee46bSPatrick Mooney 	    tp->tp_sz);
531*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_partial_meoi);
532*3d6ee46bSPatrick Mooney 	free(splits);
533*3d6ee46bSPatrick Mooney 
534*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-random - ", prefix);
535*3d6ee46bSPatrick Mooney 	splits = split_gen_random(tp->tp_sz, &num_splits);
536*3d6ee46bSPatrick Mooney 	payload = build_partial_payload(tp, offset, &partial, &result, splits,
537*3d6ee46bSPatrick Mooney 	    num_splits);
538*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_partial_meoi);
539*3d6ee46bSPatrick Mooney 	split_print(splits, num_splits);
540*3d6ee46bSPatrick Mooney 	free(splits);
541*3d6ee46bSPatrick Mooney 
542*3d6ee46bSPatrick Mooney 	return (any_failed);
543*3d6ee46bSPatrick Mooney }
544*3d6ee46bSPatrick Mooney 
545*3d6ee46bSPatrick Mooney /*
546*3d6ee46bSPatrick Mooney  * Run variations of mac_ether_l2_info() test against packet/data pairing.
547*3d6ee46bSPatrick Mooney  * Returns true if any variation failed.
548*3d6ee46bSPatrick Mooney  */
549*3d6ee46bSPatrick Mooney static bool
run_ether_variants(const char * prefix,test_pkt_t * tp,uint8_t * dstaddr,uint32_t tci)550*3d6ee46bSPatrick Mooney run_ether_variants(const char *prefix, test_pkt_t *tp, uint8_t *dstaddr,
551*3d6ee46bSPatrick Mooney     uint32_t tci)
552*3d6ee46bSPatrick Mooney {
553*3d6ee46bSPatrick Mooney 	nvlist_t *payload;
554*3d6ee46bSPatrick Mooney 	bool any_failed = false;
555*3d6ee46bSPatrick Mooney 	uint32_t *splits = NULL;
556*3d6ee46bSPatrick Mooney 
557*3d6ee46bSPatrick Mooney 	(void) printf("%s - simple - ", prefix);
558*3d6ee46bSPatrick Mooney 	payload = build_ether_payload(tp, dstaddr, tci, NULL, 0);
559*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_l2info);
560*3d6ee46bSPatrick Mooney 
561*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-single-bytes - ", prefix);
562*3d6ee46bSPatrick Mooney 	splits = split_gen_single(tp->tp_sz);
563*3d6ee46bSPatrick Mooney 	payload = build_ether_payload(tp, dstaddr, tci, splits, tp->tp_sz);
564*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_l2info);
565*3d6ee46bSPatrick Mooney 	free(splits);
566*3d6ee46bSPatrick Mooney 
567*3d6ee46bSPatrick Mooney 	/* intentionally split dstaddr, tpid, tci, and ethertype */
568*3d6ee46bSPatrick Mooney 	uint32_t intentional_splits[] = { 4, 9, 2, 2 };
569*3d6ee46bSPatrick Mooney 	(void) printf("%s - split-intentional - ", prefix);
570*3d6ee46bSPatrick Mooney 	payload = build_ether_payload(tp, dstaddr, tci, intentional_splits,
571*3d6ee46bSPatrick Mooney 	    ARRAY_SIZE(intentional_splits));
572*3d6ee46bSPatrick Mooney 	any_failed |= !run_test(payload, &tuple_l2info);
573*3d6ee46bSPatrick Mooney 	split_print(intentional_splits, ARRAY_SIZE(intentional_splits));
574*3d6ee46bSPatrick Mooney 
575*3d6ee46bSPatrick Mooney 	return (any_failed);
576*3d6ee46bSPatrick Mooney }
577*3d6ee46bSPatrick Mooney 
578*3d6ee46bSPatrick Mooney int
main(int argc,char * argv[])579*3d6ee46bSPatrick Mooney main(int argc, char *argv[])
580*3d6ee46bSPatrick Mooney {
581*3d6ee46bSPatrick Mooney 	if (!ktest_mod_load("mac")) {
582*3d6ee46bSPatrick Mooney 		err(EXIT_FAILURE, "could not load mac ktest module");
583*3d6ee46bSPatrick Mooney 	}
584*3d6ee46bSPatrick Mooney 	if ((kthdl = ktest_init()) == NULL) {
585*3d6ee46bSPatrick Mooney 		err(EXIT_FAILURE, "could not initialize libktest");
586*3d6ee46bSPatrick Mooney 	}
587*3d6ee46bSPatrick Mooney 
588*3d6ee46bSPatrick Mooney 	bool any_failed = false;
589*3d6ee46bSPatrick Mooney 
590*3d6ee46bSPatrick Mooney 	/* Use fixed seed for deterministic "random" output */
591*3d6ee46bSPatrick Mooney 	srandom(0x1badbeef);
592*3d6ee46bSPatrick Mooney 
593*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi_tcp4 = { 0 };
594*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_tcp4 = build_tcp4(&meoi_tcp4);
595*3d6ee46bSPatrick Mooney 
596*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi_tcp6 = { 0 };
597*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_tcp6 = build_tcp6(&meoi_tcp6);
598*3d6ee46bSPatrick Mooney 
599*3d6ee46bSPatrick Mooney 	any_failed |=
600*3d6ee46bSPatrick Mooney 	    run_meoi_variants("basic tcp4", tp_tcp4, &meoi_tcp4);
601*3d6ee46bSPatrick Mooney 	any_failed |=
602*3d6ee46bSPatrick Mooney 	    run_meoi_variants("basic tcp6", tp_tcp6, &meoi_tcp6);
603*3d6ee46bSPatrick Mooney 	any_failed |= run_partial_variants("basic tcp4", tp_tcp4, &meoi_tcp4);
604*3d6ee46bSPatrick Mooney 	any_failed |= run_partial_variants("basic tcp6", tp_tcp6, &meoi_tcp6);
605*3d6ee46bSPatrick Mooney 
606*3d6ee46bSPatrick Mooney 	/*
607*3d6ee46bSPatrick Mooney 	 * Truncate the tcp header to induce a parse failure, but expect that
608*3d6ee46bSPatrick Mooney 	 * the packet info is still populated
609*3d6ee46bSPatrick Mooney 	 */
610*3d6ee46bSPatrick Mooney 	tp_tcp4->tp_sz -= 4;
611*3d6ee46bSPatrick Mooney 	tp_tcp6->tp_sz -= 4;
612*3d6ee46bSPatrick Mooney 	meoi_tcp4.meoi_flags &= ~MEOI_L4INFO_SET;
613*3d6ee46bSPatrick Mooney 	meoi_tcp6.meoi_flags &= ~MEOI_L4INFO_SET;
614*3d6ee46bSPatrick Mooney 
615*3d6ee46bSPatrick Mooney 	any_failed |=
616*3d6ee46bSPatrick Mooney 	    run_meoi_variants("truncated tcp4", tp_tcp4, &meoi_tcp4);
617*3d6ee46bSPatrick Mooney 	any_failed |=
618*3d6ee46bSPatrick Mooney 	    run_meoi_variants("truncated tcp6", tp_tcp6, &meoi_tcp6);
619*3d6ee46bSPatrick Mooney 
620*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi_frag_v4 = { 0 };
621*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi_frag_v6 = { 0 };
622*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_frag_v4 = build_frag_v4(&meoi_frag_v4);
623*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_frag_v6 = build_frag_v6(&meoi_frag_v6);
624*3d6ee46bSPatrick Mooney 
625*3d6ee46bSPatrick Mooney 	any_failed |= run_meoi_variants("fragment ipv4", tp_frag_v4,
626*3d6ee46bSPatrick Mooney 	    &meoi_frag_v4);
627*3d6ee46bSPatrick Mooney 	any_failed |= run_meoi_variants("fragment ipv6", tp_frag_v6,
628*3d6ee46bSPatrick Mooney 	    &meoi_frag_v6);
629*3d6ee46bSPatrick Mooney 
630*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_ether_plain = tp_alloc();
631*3d6ee46bSPatrick Mooney 	struct ether_header hdr_l2_plain = {
632*3d6ee46bSPatrick Mooney 		.ether_dhost = { 0x86, 0x1d, 0xe0, 0x11, 0x22, 0x33},
633*3d6ee46bSPatrick Mooney 		.ether_type = htons(ETHERTYPE_IP),
634*3d6ee46bSPatrick Mooney 	};
635*3d6ee46bSPatrick Mooney 	tp_append(tp_ether_plain, &hdr_l2_plain, sizeof (hdr_l2_plain));
636*3d6ee46bSPatrick Mooney 
637*3d6ee46bSPatrick Mooney 	test_pkt_t *tp_ether_vlan = tp_alloc();
638*3d6ee46bSPatrick Mooney 	const uint16_t arb_vlan = 201;
639*3d6ee46bSPatrick Mooney 	struct ether_vlan_header hdr_l2_vlan = {
640*3d6ee46bSPatrick Mooney 		.ether_dhost = { 0x86, 0x1d, 0xe0, 0x11, 0x22, 0x33},
641*3d6ee46bSPatrick Mooney 		.ether_tpid = htons(ETHERTYPE_VLAN),
642*3d6ee46bSPatrick Mooney 		.ether_tci = htons(arb_vlan),
643*3d6ee46bSPatrick Mooney 		.ether_type = htons(ETHERTYPE_IP),
644*3d6ee46bSPatrick Mooney 	};
645*3d6ee46bSPatrick Mooney 	tp_append(tp_ether_vlan, &hdr_l2_vlan, sizeof (hdr_l2_vlan));
646*3d6ee46bSPatrick Mooney 
647*3d6ee46bSPatrick Mooney 	any_failed |= run_ether_variants("ether plain", tp_ether_plain,
648*3d6ee46bSPatrick Mooney 	    hdr_l2_plain.ether_dhost.ether_addr_octet, UINT32_MAX);
649*3d6ee46bSPatrick Mooney 	any_failed |= run_ether_variants("ether vlan", tp_ether_vlan,
650*3d6ee46bSPatrick Mooney 	    hdr_l2_vlan.ether_dhost.ether_addr_octet, arb_vlan);
651*3d6ee46bSPatrick Mooney 
652*3d6ee46bSPatrick Mooney 	tp_free(tp_tcp4);
653*3d6ee46bSPatrick Mooney 	tp_free(tp_tcp6);
654*3d6ee46bSPatrick Mooney 	tp_free(tp_frag_v4);
655*3d6ee46bSPatrick Mooney 	tp_free(tp_frag_v6);
656*3d6ee46bSPatrick Mooney 	tp_free(tp_ether_plain);
657*3d6ee46bSPatrick Mooney 	tp_free(tp_ether_vlan);
658*3d6ee46bSPatrick Mooney 
659*3d6ee46bSPatrick Mooney 	ktest_fini(kthdl);
660*3d6ee46bSPatrick Mooney 	return (any_failed ? EXIT_FAILURE : EXIT_SUCCESS);
661*3d6ee46bSPatrick Mooney }
662