xref: /illumos-gate/usr/src/uts/common/io/mac/mac_ktest.c (revision 3d6ee46b4ddaa0ca6a00cc84d52edf88676f88ce)
16e4a39ccSPatrick Mooney /*
26e4a39ccSPatrick Mooney  * This file and its contents are supplied under the terms of the
36e4a39ccSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
46e4a39ccSPatrick Mooney  * You may only use this file in accordance with the terms of version
56e4a39ccSPatrick Mooney  * 1.0 of the CDDL.
66e4a39ccSPatrick Mooney  *
76e4a39ccSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
86e4a39ccSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
96e4a39ccSPatrick Mooney  * http://www.illumos.org/license/CDDL.
106e4a39ccSPatrick Mooney  */
116e4a39ccSPatrick Mooney 
126e4a39ccSPatrick Mooney /*
136e4a39ccSPatrick Mooney  * Copyright 2025 Oxide Computer Company
146e4a39ccSPatrick Mooney  * Copyright 2024 Ryan Zezeski
156e4a39ccSPatrick Mooney  */
166e4a39ccSPatrick Mooney 
176e4a39ccSPatrick Mooney /*
186e4a39ccSPatrick Mooney  * A test module for various mac routines.
196e4a39ccSPatrick Mooney  */
206e4a39ccSPatrick Mooney #include <inet/ip.h>
216e4a39ccSPatrick Mooney #include <inet/ip_impl.h>
22*3d6ee46bSPatrick Mooney #include <inet/sctp_ip.h>
236e4a39ccSPatrick Mooney #include <inet/tcp.h>
24*3d6ee46bSPatrick Mooney #include <inet/udp_impl.h>
256e4a39ccSPatrick Mooney #include <sys/dlpi.h>
266e4a39ccSPatrick Mooney #include <sys/ethernet.h>
276e4a39ccSPatrick Mooney #include <sys/ktest.h>
286e4a39ccSPatrick Mooney #include <sys/mac_provider.h>
29*3d6ee46bSPatrick Mooney #include <sys/pattr.h>
30*3d6ee46bSPatrick Mooney #include <sys/strsun.h>
316e4a39ccSPatrick Mooney 
32*3d6ee46bSPatrick Mooney typedef mblk_t *(*mac_sw_cksum_t)(mblk_t *, mac_emul_t);
33*3d6ee46bSPatrick Mooney 
34*3d6ee46bSPatrick Mooney typedef struct cksum_test_params {
35*3d6ee46bSPatrick Mooney 	mblk_t		*ctp_mp;
36*3d6ee46bSPatrick Mooney 	uchar_t		*ctp_raw;
37*3d6ee46bSPatrick Mooney 	uint_t		ctp_raw_sz;
38*3d6ee46bSPatrick Mooney 	boolean_t	ctp_do_partial;
39*3d6ee46bSPatrick Mooney 	boolean_t	ctp_do_full;
40*3d6ee46bSPatrick Mooney 	boolean_t	ctp_do_ipv4;
41*3d6ee46bSPatrick Mooney } cksum_test_params_t;
42*3d6ee46bSPatrick Mooney 
43*3d6ee46bSPatrick Mooney /* Arbitrary limit to padding allowed for cksum tests */
44*3d6ee46bSPatrick Mooney #define	PADDING_MAX	32
45*3d6ee46bSPatrick Mooney 
46*3d6ee46bSPatrick Mooney static boolean_t
cksum_test_parse_input(ktest_ctx_hdl_t * ctx,cksum_test_params_t * ctp)47*3d6ee46bSPatrick Mooney cksum_test_parse_input(ktest_ctx_hdl_t *ctx, cksum_test_params_t *ctp)
486e4a39ccSPatrick Mooney {
496e4a39ccSPatrick Mooney 	uchar_t *bytes;
506e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
51*3d6ee46bSPatrick Mooney 
52*3d6ee46bSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
53*3d6ee46bSPatrick Mooney 	bzero(ctp, sizeof (*ctp));
54*3d6ee46bSPatrick Mooney 
55*3d6ee46bSPatrick Mooney 	nvlist_t *params = NULL;
56*3d6ee46bSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
57*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
58*3d6ee46bSPatrick Mooney 		return (B_FALSE);
59*3d6ee46bSPatrick Mooney 	}
60*3d6ee46bSPatrick Mooney 
61*3d6ee46bSPatrick Mooney 	uchar_t *pkt_bytes;
62*3d6ee46bSPatrick Mooney 	uint_t pkt_sz;
63*3d6ee46bSPatrick Mooney 
64*3d6ee46bSPatrick Mooney 	if (nvlist_lookup_byte_array(params, "pkt_bytes", &pkt_bytes,
65*3d6ee46bSPatrick Mooney 	    &pkt_sz) != 0) {
66*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Input missing pkt_bytes field");
67*3d6ee46bSPatrick Mooney 		return (B_FALSE);
68*3d6ee46bSPatrick Mooney 	}
69*3d6ee46bSPatrick Mooney 	if (pkt_sz == 0) {
70*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Packet must not be 0-length");
71*3d6ee46bSPatrick Mooney 		return (B_FALSE);
72*3d6ee46bSPatrick Mooney 	}
73*3d6ee46bSPatrick Mooney 
74*3d6ee46bSPatrick Mooney 	uint32_t padding = 0;
75*3d6ee46bSPatrick Mooney 	(void) nvlist_lookup_uint32(params, "padding", &padding);
76*3d6ee46bSPatrick Mooney 	if (padding & 1) {
77*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "padding must be even");
78*3d6ee46bSPatrick Mooney 		return (B_FALSE);
79*3d6ee46bSPatrick Mooney 	} else if (padding > PADDING_MAX) {
80*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "padding greater than max of %u", PADDING_MAX);
81*3d6ee46bSPatrick Mooney 		return (B_FALSE);
82*3d6ee46bSPatrick Mooney 	}
83*3d6ee46bSPatrick Mooney 
84*3d6ee46bSPatrick Mooney 	ctp->ctp_do_ipv4 = fnvlist_lookup_boolean(params, "cksum_ipv4");
85*3d6ee46bSPatrick Mooney 	ctp->ctp_do_partial = fnvlist_lookup_boolean(params, "cksum_partial");
86*3d6ee46bSPatrick Mooney 	ctp->ctp_do_full = fnvlist_lookup_boolean(params, "cksum_full");
87*3d6ee46bSPatrick Mooney 
88*3d6ee46bSPatrick Mooney 	if (ctp->ctp_do_partial && ctp->ctp_do_full) {
89*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Cannot request full and partial cksum");
90*3d6ee46bSPatrick Mooney 		return (B_FALSE);
91*3d6ee46bSPatrick Mooney 	}
92*3d6ee46bSPatrick Mooney 
93*3d6ee46bSPatrick Mooney 	mblk_t *mp = allocb(pkt_sz + padding, 0);
94*3d6ee46bSPatrick Mooney 	if (mp == NULL) {
95*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Could not allocate mblk");
96*3d6ee46bSPatrick Mooney 		return (B_FALSE);
97*3d6ee46bSPatrick Mooney 	}
98*3d6ee46bSPatrick Mooney 	if (padding != 0) {
99*3d6ee46bSPatrick Mooney 		bzero(mp->b_rptr, padding);
100*3d6ee46bSPatrick Mooney 		mp->b_rptr += padding;
101*3d6ee46bSPatrick Mooney 		mp->b_wptr += padding;
102*3d6ee46bSPatrick Mooney 	}
103*3d6ee46bSPatrick Mooney 	bcopy(pkt_bytes, mp->b_rptr, pkt_sz);
104*3d6ee46bSPatrick Mooney 	mp->b_wptr += pkt_sz;
105*3d6ee46bSPatrick Mooney 	ctp->ctp_mp = mp;
106*3d6ee46bSPatrick Mooney 
107*3d6ee46bSPatrick Mooney 	ctp->ctp_raw = kmem_alloc(pkt_sz, KM_SLEEP);
108*3d6ee46bSPatrick Mooney 	bcopy(pkt_bytes, ctp->ctp_raw, pkt_sz);
109*3d6ee46bSPatrick Mooney 	ctp->ctp_raw_sz = pkt_sz;
110*3d6ee46bSPatrick Mooney 
111*3d6ee46bSPatrick Mooney 	nvlist_free(params);
112*3d6ee46bSPatrick Mooney 	return (B_TRUE);
113*3d6ee46bSPatrick Mooney }
114*3d6ee46bSPatrick Mooney 
115*3d6ee46bSPatrick Mooney /* Calculate pseudo-header checksum for a packet */
116*3d6ee46bSPatrick Mooney static uint16_t
cksum_calc_pseudo(ktest_ctx_hdl_t * ctx,mblk_t * mp,const mac_ether_offload_info_t * meoi)117*3d6ee46bSPatrick Mooney cksum_calc_pseudo(ktest_ctx_hdl_t *ctx, mblk_t *mp,
118*3d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *meoi)
119*3d6ee46bSPatrick Mooney {
120*3d6ee46bSPatrick Mooney 	if ((meoi->meoi_flags & MEOI_L4INFO_SET) == 0) {
121*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "MEOI lacks L4 info");
122*3d6ee46bSPatrick Mooney 		return (0);
123*3d6ee46bSPatrick Mooney 	}
124*3d6ee46bSPatrick Mooney 
125*3d6ee46bSPatrick Mooney 	const uint16_t *iphs =
126*3d6ee46bSPatrick Mooney 	    (const uint16_t *)(mp->b_rptr + meoi->meoi_l2hlen);
127*3d6ee46bSPatrick Mooney 	uint32_t cksum = 0;
128*3d6ee46bSPatrick Mooney 
129*3d6ee46bSPatrick Mooney 	/* Copied from ip_input_cksum_pseudo_v[46]() */
130*3d6ee46bSPatrick Mooney 	if (meoi->meoi_l3proto == ETHERTYPE_IP) {
131*3d6ee46bSPatrick Mooney 		cksum += iphs[6] + iphs[7] + iphs[8] + iphs[9];
132*3d6ee46bSPatrick Mooney 	} else if (meoi->meoi_l3proto == ETHERTYPE_IPV6) {
133*3d6ee46bSPatrick Mooney 		cksum += iphs[4] + iphs[5] + iphs[6] + iphs[7] +
134*3d6ee46bSPatrick Mooney 		    iphs[8] + iphs[9] + iphs[10] + iphs[11] +
135*3d6ee46bSPatrick Mooney 		    iphs[12] + iphs[13] + iphs[14] + iphs[15] +
136*3d6ee46bSPatrick Mooney 		    iphs[16] + iphs[17] + iphs[18] + iphs[19];
137*3d6ee46bSPatrick Mooney 	} else {
138*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "unexpected proto %u", meoi->meoi_l3proto);
139*3d6ee46bSPatrick Mooney 		return (0);
140*3d6ee46bSPatrick Mooney 	}
141*3d6ee46bSPatrick Mooney 
142*3d6ee46bSPatrick Mooney 	switch (meoi->meoi_l4proto) {
143*3d6ee46bSPatrick Mooney 	case IPPROTO_TCP:
144*3d6ee46bSPatrick Mooney 		cksum += IP_TCP_CSUM_COMP;
145*3d6ee46bSPatrick Mooney 		break;
146*3d6ee46bSPatrick Mooney 	case IPPROTO_UDP:
147*3d6ee46bSPatrick Mooney 		cksum += IP_UDP_CSUM_COMP;
148*3d6ee46bSPatrick Mooney 		break;
149*3d6ee46bSPatrick Mooney 	case IPPROTO_ICMPV6:
150*3d6ee46bSPatrick Mooney 		cksum += IP_ICMPV6_CSUM_COMP;
151*3d6ee46bSPatrick Mooney 		break;
152*3d6ee46bSPatrick Mooney 	default:
153*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "unexpected l4 proto %u", meoi->meoi_l4proto);
154*3d6ee46bSPatrick Mooney 		return (0);
155*3d6ee46bSPatrick Mooney 	}
156*3d6ee46bSPatrick Mooney 
157*3d6ee46bSPatrick Mooney 	uint16_t ulp_len =
158*3d6ee46bSPatrick Mooney 	    meoi->meoi_len - ((uint16_t)meoi->meoi_l2hlen + meoi->meoi_l3hlen);
159*3d6ee46bSPatrick Mooney 	if (meoi->meoi_l3proto == ETHERTYPE_IP) {
160*3d6ee46bSPatrick Mooney 		/*
161*3d6ee46bSPatrick Mooney 		 * IPv4 packets can fall below the 60-byte minimum for ethernet,
162*3d6ee46bSPatrick Mooney 		 * resulting in padding which makes the "easy" means of
163*3d6ee46bSPatrick Mooney 		 * determining ULP length potentially inaccurate.
164*3d6ee46bSPatrick Mooney 		 *
165*3d6ee46bSPatrick Mooney 		 * Reach into the v4 header to make that calculation.
166*3d6ee46bSPatrick Mooney 		 */
167*3d6ee46bSPatrick Mooney 		const ipha_t *ipha =
168*3d6ee46bSPatrick Mooney 		    (const ipha_t *)(mp->b_rptr + meoi->meoi_l2hlen);
169*3d6ee46bSPatrick Mooney 		ulp_len = ntohs(ipha->ipha_length) - meoi->meoi_l3hlen;
170*3d6ee46bSPatrick Mooney 	}
171*3d6ee46bSPatrick Mooney 
172*3d6ee46bSPatrick Mooney 	cksum += htons(ulp_len);
173*3d6ee46bSPatrick Mooney 
174*3d6ee46bSPatrick Mooney 	cksum = (cksum >> 16) + (cksum & 0xffff);
175*3d6ee46bSPatrick Mooney 	cksum = (cksum >> 16) + (cksum & 0xffff);
176*3d6ee46bSPatrick Mooney 	return (cksum);
177*3d6ee46bSPatrick Mooney }
178*3d6ee46bSPatrick Mooney 
179*3d6ee46bSPatrick Mooney /*
180*3d6ee46bSPatrick Mooney  * Verify mac_sw_cksum() emulation against an arbitrary input packet.  If the
181*3d6ee46bSPatrick Mooney  * packet is of a support protocol, any L3 and L4 checksums are cleared, and
182*3d6ee46bSPatrick Mooney  * then mac_sw_cksum() is called to perform the offload emulation.  Afterwards,
183*3d6ee46bSPatrick Mooney  * the packet is compared to see if it equasl the input, which is assumed to
184*3d6ee46bSPatrick Mooney  * have correct checksums.
185*3d6ee46bSPatrick Mooney  *
186*3d6ee46bSPatrick Mooney  * This can request either emulation via HCK_PARTIALCKSUM or HCK_FULLCKSUM.
187*3d6ee46bSPatrick Mooney  */
188*3d6ee46bSPatrick Mooney static void
mac_sw_cksum_test(ktest_ctx_hdl_t * ctx)189*3d6ee46bSPatrick Mooney mac_sw_cksum_test(ktest_ctx_hdl_t *ctx)
190*3d6ee46bSPatrick Mooney {
191*3d6ee46bSPatrick Mooney 	ddi_modhandle_t hdl = NULL;
192*3d6ee46bSPatrick Mooney 	mac_sw_cksum_t mac_sw_cksum = NULL;
1936e4a39ccSPatrick Mooney 
1946e4a39ccSPatrick Mooney 	if (ktest_hold_mod("mac", &hdl) != 0) {
1956e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "failed to hold 'mac' module");
1966e4a39ccSPatrick Mooney 		return;
1976e4a39ccSPatrick Mooney 	}
198*3d6ee46bSPatrick Mooney 	if (ktest_get_fn(hdl, "mac_sw_cksum", (void **)&mac_sw_cksum) != 0) {
199*3d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "failed to resolve symbol mac`mac_sw_cksum");
2006e4a39ccSPatrick Mooney 		goto cleanup;
2016e4a39ccSPatrick Mooney 	}
2026e4a39ccSPatrick Mooney 
203*3d6ee46bSPatrick Mooney 	cksum_test_params_t ctp;
204*3d6ee46bSPatrick Mooney 	if (!cksum_test_parse_input(ctx, &ctp)) {
205*3d6ee46bSPatrick Mooney 		goto cleanup;
206*3d6ee46bSPatrick Mooney 	}
207*3d6ee46bSPatrick Mooney 	mblk_t *mp = ctp.ctp_mp;
2086e4a39ccSPatrick Mooney 
209*3d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi;
210*3d6ee46bSPatrick Mooney 	mac_ether_offload_info(mp, &meoi);
2116e4a39ccSPatrick Mooney 
212*3d6ee46bSPatrick Mooney 	if ((meoi.meoi_flags & MEOI_L3INFO_SET) == 0 ||
213*3d6ee46bSPatrick Mooney 	    (meoi.meoi_l3proto != ETHERTYPE_IP &&
214*3d6ee46bSPatrick Mooney 	    meoi.meoi_l3proto != ETHERTYPE_IPV6)) {
215*3d6ee46bSPatrick Mooney 		KT_SKIP(ctx, "l3 protocol not recognized/supported");
216*3d6ee46bSPatrick Mooney 		goto cleanup;
217*3d6ee46bSPatrick Mooney 	}
218*3d6ee46bSPatrick Mooney 
219*3d6ee46bSPatrick Mooney 	mac_emul_t emul_flags = 0;
220*3d6ee46bSPatrick Mooney 	uint_t hck_flags = 0, hck_start = 0, hck_stuff = 0, hck_end = 0;
221*3d6ee46bSPatrick Mooney 	if (meoi.meoi_l3proto == ETHERTYPE_IP && ctp.ctp_do_ipv4) {
222*3d6ee46bSPatrick Mooney 		ipha_t *ipha = (ipha_t *)(mp->b_rptr + meoi.meoi_l2hlen);
223*3d6ee46bSPatrick Mooney 
224*3d6ee46bSPatrick Mooney 		ipha->ipha_hdr_checksum = 0;
225*3d6ee46bSPatrick Mooney 		emul_flags |= MAC_IPCKSUM_EMUL;
226*3d6ee46bSPatrick Mooney 		hck_flags |= HCK_IPV4_HDRCKSUM;
227*3d6ee46bSPatrick Mooney 	}
228*3d6ee46bSPatrick Mooney 
229*3d6ee46bSPatrick Mooney 	const boolean_t do_l4 = ctp.ctp_do_partial || ctp.ctp_do_full;
230*3d6ee46bSPatrick Mooney 	if ((meoi.meoi_flags & MEOI_L4INFO_SET) != 0 && do_l4) {
231*3d6ee46bSPatrick Mooney 		boolean_t valid_proto = B_FALSE;
232*3d6ee46bSPatrick Mooney 		hck_start = meoi.meoi_l2hlen + meoi.meoi_l3hlen;
233*3d6ee46bSPatrick Mooney 		hck_stuff = hck_start;
234*3d6ee46bSPatrick Mooney 		hck_end = meoi.meoi_len;
235*3d6ee46bSPatrick Mooney 
236*3d6ee46bSPatrick Mooney 		switch (meoi.meoi_l4proto) {
237*3d6ee46bSPatrick Mooney 		case IPPROTO_TCP:
238*3d6ee46bSPatrick Mooney 			hck_stuff += offsetof(tcpha_t, tha_sum);
239*3d6ee46bSPatrick Mooney 			valid_proto = B_TRUE;
240*3d6ee46bSPatrick Mooney 			break;
241*3d6ee46bSPatrick Mooney 		case IPPROTO_UDP:
242*3d6ee46bSPatrick Mooney 			hck_stuff += offsetof(udpha_t, uha_checksum);
243*3d6ee46bSPatrick Mooney 			valid_proto = B_TRUE;
244*3d6ee46bSPatrick Mooney 			break;
245*3d6ee46bSPatrick Mooney 		case IPPROTO_ICMPV6:
246*3d6ee46bSPatrick Mooney 			hck_stuff += offsetof(icmp6_t, icmp6_cksum);
247*3d6ee46bSPatrick Mooney 			valid_proto = B_TRUE;
248*3d6ee46bSPatrick Mooney 			break;
249*3d6ee46bSPatrick Mooney 		case IPPROTO_SCTP:
250*3d6ee46bSPatrick Mooney 			/*
251*3d6ee46bSPatrick Mooney 			 * Only full checksums are supported for SCTP, and the
252*3d6ee46bSPatrick Mooney 			 * test logic for clearing the existing sum needs to
253*3d6ee46bSPatrick Mooney 			 * account for its increased width.
254*3d6ee46bSPatrick Mooney 			 */
255*3d6ee46bSPatrick Mooney 			hck_stuff += offsetof(sctp_hdr_t, sh_chksum);
256*3d6ee46bSPatrick Mooney 			if (ctp.ctp_do_full) {
257*3d6ee46bSPatrick Mooney 				uint32_t *lckp =
258*3d6ee46bSPatrick Mooney 				    (uint32_t *)(mp->b_rptr + hck_stuff);
259*3d6ee46bSPatrick Mooney 				*lckp = 0;
260*3d6ee46bSPatrick Mooney 				/*
261*3d6ee46bSPatrick Mooney 				 * Set the emulation flags ourself, and skip the
262*3d6ee46bSPatrick Mooney 				 * logic below by leaving valid_proto as false.
263*3d6ee46bSPatrick Mooney 				 */
264*3d6ee46bSPatrick Mooney 				hck_flags |= HCK_FULLCKSUM;
265*3d6ee46bSPatrick Mooney 				emul_flags |= MAC_HWCKSUM_EMUL;
266*3d6ee46bSPatrick Mooney 			}
267*3d6ee46bSPatrick Mooney 			break;
268*3d6ee46bSPatrick Mooney 		default:
2696e4a39ccSPatrick Mooney 			break;
2706e4a39ccSPatrick Mooney 		}
2716e4a39ccSPatrick Mooney 
272*3d6ee46bSPatrick Mooney 		if (valid_proto) {
273*3d6ee46bSPatrick Mooney 			uint16_t *ckp = (uint16_t *)(mp->b_rptr + hck_stuff);
2746e4a39ccSPatrick Mooney 
275*3d6ee46bSPatrick Mooney 			emul_flags |= MAC_HWCKSUM_EMUL;
276*3d6ee46bSPatrick Mooney 			if (ctp.ctp_do_partial) {
277*3d6ee46bSPatrick Mooney 				hck_flags |= HCK_PARTIALCKSUM;
278*3d6ee46bSPatrick Mooney 				/* Populate L4 pseudo-header cksum */
279*3d6ee46bSPatrick Mooney 				*ckp = cksum_calc_pseudo(ctx, mp, &meoi);
2806e4a39ccSPatrick Mooney 			} else {
281*3d6ee46bSPatrick Mooney 				hck_flags |= HCK_FULLCKSUM;
282*3d6ee46bSPatrick Mooney 				/* Zero out the L4 cksum */
283*3d6ee46bSPatrick Mooney 				*ckp = 0;
2846e4a39ccSPatrick Mooney 			}
2856e4a39ccSPatrick Mooney 		}
286*3d6ee46bSPatrick Mooney 	}
287*3d6ee46bSPatrick Mooney 	if (do_l4 && (hck_flags & (HCK_FULLCKSUM|HCK_PARTIALCKSUM)) == 0) {
288*3d6ee46bSPatrick Mooney 		KT_SKIP(ctx, "L4 checksum not support for packet");
2896e4a39ccSPatrick Mooney 		goto cleanup;
2906e4a39ccSPatrick Mooney 	}
2916e4a39ccSPatrick Mooney 
292*3d6ee46bSPatrick Mooney 	if (emul_flags != 0) {
293*3d6ee46bSPatrick Mooney 		if ((hck_flags & HCK_PARTIALCKSUM) == 0) {
294*3d6ee46bSPatrick Mooney 			hck_start = hck_stuff = hck_end = 0;
295*3d6ee46bSPatrick Mooney 		} else {
296*3d6ee46bSPatrick Mooney 			/*
297*3d6ee46bSPatrick Mooney 			 * The offsets for mac_hcksum_set are all relative to
298*3d6ee46bSPatrick Mooney 			 * the start of the L3 header.  Prior to here, these
299*3d6ee46bSPatrick Mooney 			 * values were relative to the start of the packet.
300*3d6ee46bSPatrick Mooney 			 */
301*3d6ee46bSPatrick Mooney 			hck_start -= meoi.meoi_l2hlen;
302*3d6ee46bSPatrick Mooney 			hck_stuff -= meoi.meoi_l2hlen;
303*3d6ee46bSPatrick Mooney 			hck_end -= meoi.meoi_l2hlen;
304*3d6ee46bSPatrick Mooney 		}
305*3d6ee46bSPatrick Mooney 		mac_hcksum_set(mp, hck_start, hck_stuff, hck_end, 0, hck_flags);
306*3d6ee46bSPatrick Mooney 		ctp.ctp_mp = mp = mac_sw_cksum(mp, emul_flags);
307*3d6ee46bSPatrick Mooney 
308*3d6ee46bSPatrick Mooney 		KT_ASSERT3UG(mp, !=, NULL, ctx, cleanup);
309*3d6ee46bSPatrick Mooney 		const uint_t input_pkt_sz = ctp.ctp_raw_sz;
310*3d6ee46bSPatrick Mooney 		KT_ASSERT3UG(MBLKL(mp), ==, input_pkt_sz, ctx, cleanup);
311*3d6ee46bSPatrick Mooney 
312*3d6ee46bSPatrick Mooney 		for (uint_t i = 0; i < input_pkt_sz; i++) {
313*3d6ee46bSPatrick Mooney 			/*
314*3d6ee46bSPatrick Mooney 			 * If there is any mismatch from the expected output,
315*3d6ee46bSPatrick Mooney 			 * print the contents of the first "bad" byte.
316*3d6ee46bSPatrick Mooney 			 */
317*3d6ee46bSPatrick Mooney 			if (mp->b_rptr[i] != ctp.ctp_raw[i]) {
318*3d6ee46bSPatrick Mooney 				if (i + 2 < input_pkt_sz) {
319*3d6ee46bSPatrick Mooney 					KT_FAIL(ctx, "mp[%x] %04X != %04X",
320*3d6ee46bSPatrick Mooney 					    i,
321*3d6ee46bSPatrick Mooney 					    *(uint16_t *)&mp->b_rptr[i],
322*3d6ee46bSPatrick Mooney 					    *(uint16_t *)&ctp.ctp_raw[i]);
323*3d6ee46bSPatrick Mooney 				} else {
324*3d6ee46bSPatrick Mooney 					KT_FAIL(ctx, "mp[%x] %02X != %02X",
325*3d6ee46bSPatrick Mooney 					    i, mp->b_rptr[i], ctp.ctp_raw[i]);
326*3d6ee46bSPatrick Mooney 				}
327*3d6ee46bSPatrick Mooney 				goto cleanup;
328*3d6ee46bSPatrick Mooney 			}
329*3d6ee46bSPatrick Mooney 		}
330*3d6ee46bSPatrick Mooney 	} else {
331*3d6ee46bSPatrick Mooney 		KT_SKIP(ctx, "no checksums supported for packet");
332*3d6ee46bSPatrick Mooney 		goto cleanup;
333*3d6ee46bSPatrick Mooney 	}
334*3d6ee46bSPatrick Mooney 
3356e4a39ccSPatrick Mooney 	KT_PASS(ctx);
3366e4a39ccSPatrick Mooney 
3376e4a39ccSPatrick Mooney cleanup:
3386e4a39ccSPatrick Mooney 	if (hdl != NULL) {
3396e4a39ccSPatrick Mooney 		ktest_release_mod(hdl);
3406e4a39ccSPatrick Mooney 	}
341*3d6ee46bSPatrick Mooney 	if (ctp.ctp_mp != NULL) {
342*3d6ee46bSPatrick Mooney 		freeb(ctp.ctp_mp);
3436e4a39ccSPatrick Mooney 	}
344*3d6ee46bSPatrick Mooney 	if (ctp.ctp_raw != NULL) {
345*3d6ee46bSPatrick Mooney 		kmem_free(ctp.ctp_raw, ctp.ctp_raw_sz);
3466e4a39ccSPatrick Mooney 	}
3476e4a39ccSPatrick Mooney }
3486e4a39ccSPatrick Mooney 
3496e4a39ccSPatrick Mooney typedef struct meoi_test_params {
3506e4a39ccSPatrick Mooney 	mblk_t				*mtp_mp;
3516e4a39ccSPatrick Mooney 	mac_ether_offload_info_t	mtp_partial;
3526e4a39ccSPatrick Mooney 	mac_ether_offload_info_t	mtp_results;
3536e4a39ccSPatrick Mooney 	uint_t				mtp_offset;
3546e4a39ccSPatrick Mooney } meoi_test_params_t;
3556e4a39ccSPatrick Mooney 
3566e4a39ccSPatrick Mooney static void
nvlist_to_meoi(nvlist_t * results,mac_ether_offload_info_t * meoi)3576e4a39ccSPatrick Mooney nvlist_to_meoi(nvlist_t *results, mac_ether_offload_info_t *meoi)
3586e4a39ccSPatrick Mooney {
3596e4a39ccSPatrick Mooney 	uint64_t u64_val;
3606e4a39ccSPatrick Mooney 	int int_val;
3616e4a39ccSPatrick Mooney 	uint16_t u16_val;
3626e4a39ccSPatrick Mooney 	uint8_t u8_val;
3636e4a39ccSPatrick Mooney 
3646e4a39ccSPatrick Mooney 	bzero(meoi, sizeof (*meoi));
3656e4a39ccSPatrick Mooney 	if (nvlist_lookup_int32(results, "meoi_flags", &int_val) == 0) {
3666e4a39ccSPatrick Mooney 		meoi->meoi_flags = int_val;
3676e4a39ccSPatrick Mooney 	}
3686e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint64(results, "meoi_len", &u64_val) == 0) {
3696e4a39ccSPatrick Mooney 		meoi->meoi_len = u64_val;
3706e4a39ccSPatrick Mooney 	}
3716e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l2hlen", &u8_val) == 0) {
3726e4a39ccSPatrick Mooney 		meoi->meoi_l2hlen = u8_val;
3736e4a39ccSPatrick Mooney 	}
3746e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint16(results, "meoi_l3proto", &u16_val) == 0) {
3756e4a39ccSPatrick Mooney 		meoi->meoi_l3proto = u16_val;
3766e4a39ccSPatrick Mooney 	}
3776e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint16(results, "meoi_l3hlen", &u16_val) == 0) {
3786e4a39ccSPatrick Mooney 		meoi->meoi_l3hlen = u16_val;
3796e4a39ccSPatrick Mooney 	}
3806e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l4proto", &u8_val) == 0) {
3816e4a39ccSPatrick Mooney 		meoi->meoi_l4proto = u8_val;
3826e4a39ccSPatrick Mooney 	}
3836e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l4hlen", &u8_val) == 0) {
3846e4a39ccSPatrick Mooney 		meoi->meoi_l4hlen = u8_val;
3856e4a39ccSPatrick Mooney 	}
3866e4a39ccSPatrick Mooney }
3876e4a39ccSPatrick Mooney 
3886e4a39ccSPatrick Mooney static mblk_t *
alloc_split_pkt(ktest_ctx_hdl_t * ctx,nvlist_t * nvl,const char * pkt_field)3896e4a39ccSPatrick Mooney alloc_split_pkt(ktest_ctx_hdl_t *ctx, nvlist_t *nvl, const char *pkt_field)
3906e4a39ccSPatrick Mooney {
3916e4a39ccSPatrick Mooney 	uchar_t *pkt_bytes;
3926e4a39ccSPatrick Mooney 	uint_t pkt_sz;
3936e4a39ccSPatrick Mooney 
3946e4a39ccSPatrick Mooney 	if (nvlist_lookup_byte_array(nvl, pkt_field, &pkt_bytes,
3956e4a39ccSPatrick Mooney 	    &pkt_sz) != 0) {
3966e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing %s field", pkt_field);
3976e4a39ccSPatrick Mooney 		return (NULL);
3986e4a39ccSPatrick Mooney 	}
3996e4a39ccSPatrick Mooney 
4006e4a39ccSPatrick Mooney 	const uint32_t *splits = NULL;
4016e4a39ccSPatrick Mooney 	uint_t num_splits = 0;
4026e4a39ccSPatrick Mooney 	(void) nvlist_lookup_uint32_array(nvl, "splits", (uint32_t **)&splits,
4036e4a39ccSPatrick Mooney 	    &num_splits);
4046e4a39ccSPatrick Mooney 
4056e4a39ccSPatrick Mooney 	uint_t split_idx = 0;
4066e4a39ccSPatrick Mooney 	mblk_t *result = NULL, *tail = NULL;
4076e4a39ccSPatrick Mooney 
4086e4a39ccSPatrick Mooney 	do {
4096e4a39ccSPatrick Mooney 		uint_t block_sz = pkt_sz;
4106e4a39ccSPatrick Mooney 		if (split_idx < num_splits) {
4116e4a39ccSPatrick Mooney 			block_sz = MIN(block_sz, splits[split_idx]);
4126e4a39ccSPatrick Mooney 		}
4136e4a39ccSPatrick Mooney 
4146e4a39ccSPatrick Mooney 		mblk_t *mp = allocb(block_sz, 0);
4156e4a39ccSPatrick Mooney 		if (mp == NULL) {
4166e4a39ccSPatrick Mooney 			KT_ERROR(ctx, "mblk alloc failure");
4176e4a39ccSPatrick Mooney 			freemsg(result);
4186e4a39ccSPatrick Mooney 			return (NULL);
4196e4a39ccSPatrick Mooney 		}
4206e4a39ccSPatrick Mooney 
4216e4a39ccSPatrick Mooney 		if (result == NULL) {
4226e4a39ccSPatrick Mooney 			result = mp;
4236e4a39ccSPatrick Mooney 		} else {
4246e4a39ccSPatrick Mooney 			tail->b_cont = mp;
4256e4a39ccSPatrick Mooney 		}
4266e4a39ccSPatrick Mooney 		tail = mp;
4276e4a39ccSPatrick Mooney 
4286e4a39ccSPatrick Mooney 		if (block_sz != 0) {
4296e4a39ccSPatrick Mooney 			bcopy(pkt_bytes, mp->b_wptr, block_sz);
4306e4a39ccSPatrick Mooney 			mp->b_wptr += block_sz;
4316e4a39ccSPatrick Mooney 		}
4326e4a39ccSPatrick Mooney 		pkt_sz -= block_sz;
4336e4a39ccSPatrick Mooney 		pkt_bytes += block_sz;
4346e4a39ccSPatrick Mooney 		split_idx++;
4356e4a39ccSPatrick Mooney 	} while (pkt_sz > 0);
4366e4a39ccSPatrick Mooney 
4376e4a39ccSPatrick Mooney 	return (result);
4386e4a39ccSPatrick Mooney }
4396e4a39ccSPatrick Mooney 
4406e4a39ccSPatrick Mooney /*
4416e4a39ccSPatrick Mooney  * mac_ether_offload_info tests expect the following as input (via packed
4426e4a39ccSPatrick Mooney  * nvlist)
4436e4a39ccSPatrick Mooney  *
4446e4a39ccSPatrick Mooney  * - pkt_bytes (byte array): packet bytes to parse
4456e4a39ccSPatrick Mooney  * - splits (uint32 array, optional): byte sizes to split packet into mblks
4466e4a39ccSPatrick Mooney  * - results (nvlist): mac_ether_offload_info result struct to compare
4476e4a39ccSPatrick Mooney  *   - Field names and types should match those in the mac_ether_offload_info
4486e4a39ccSPatrick Mooney  *     struct. Any fields not specified will be assumed to be zero.
4496e4a39ccSPatrick Mooney  *
4506e4a39ccSPatrick Mooney  * For mac_partial_offload_info tests, two additional fields are parsed:
4516e4a39ccSPatrick Mooney  *
4526e4a39ccSPatrick Mooney  * - offset (uint32, optional): offset into the packet at which the parsing
4536e4a39ccSPatrick Mooney  *   should begin
4546e4a39ccSPatrick Mooney  * - partial (nvlist): mac_ether_offload_info input struct to be used as
4556e4a39ccSPatrick Mooney  *   starting point for partial parsing
4566e4a39ccSPatrick Mooney  */
4576e4a39ccSPatrick Mooney static boolean_t
meoi_test_parse_input(ktest_ctx_hdl_t * ctx,meoi_test_params_t * mtp,boolean_t test_partial)4586e4a39ccSPatrick Mooney meoi_test_parse_input(ktest_ctx_hdl_t *ctx, meoi_test_params_t *mtp,
4596e4a39ccSPatrick Mooney     boolean_t test_partial)
4606e4a39ccSPatrick Mooney {
4616e4a39ccSPatrick Mooney 	uchar_t *bytes;
4626e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
4636e4a39ccSPatrick Mooney 
4646e4a39ccSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
4656e4a39ccSPatrick Mooney 	bzero(mtp, sizeof (*mtp));
4666e4a39ccSPatrick Mooney 
4676e4a39ccSPatrick Mooney 	nvlist_t *params = NULL;
4686e4a39ccSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
4696e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
4706e4a39ccSPatrick Mooney 		return (B_FALSE);
4716e4a39ccSPatrick Mooney 	}
4726e4a39ccSPatrick Mooney 
4736e4a39ccSPatrick Mooney 	nvlist_t *results;
4746e4a39ccSPatrick Mooney 	if (nvlist_lookup_nvlist(params, "results", &results) != 0) {
4756e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing results field");
4766e4a39ccSPatrick Mooney 		nvlist_free(params);
4776e4a39ccSPatrick Mooney 		return (B_FALSE);
4786e4a39ccSPatrick Mooney 	}
4796e4a39ccSPatrick Mooney 
4806e4a39ccSPatrick Mooney 	if (test_partial) {
4816e4a39ccSPatrick Mooney 		nvlist_t *partial;
4826e4a39ccSPatrick Mooney 		if (nvlist_lookup_nvlist(params, "partial", &partial) != 0) {
4836e4a39ccSPatrick Mooney 			KT_ERROR(ctx, "Input missing partial field");
4846e4a39ccSPatrick Mooney 			nvlist_free(params);
4856e4a39ccSPatrick Mooney 			return (B_FALSE);
4866e4a39ccSPatrick Mooney 		} else {
4876e4a39ccSPatrick Mooney 			nvlist_to_meoi(partial, &mtp->mtp_partial);
4886e4a39ccSPatrick Mooney 		}
4896e4a39ccSPatrick Mooney 
4906e4a39ccSPatrick Mooney 		(void) nvlist_lookup_uint32(params, "offset", &mtp->mtp_offset);
4916e4a39ccSPatrick Mooney 	}
4926e4a39ccSPatrick Mooney 
4936e4a39ccSPatrick Mooney 	mtp->mtp_mp = alloc_split_pkt(ctx, params, "pkt_bytes");
4946e4a39ccSPatrick Mooney 	if (mtp->mtp_mp == NULL) {
4956e4a39ccSPatrick Mooney 		nvlist_free(params);
4966e4a39ccSPatrick Mooney 		return (B_FALSE);
4976e4a39ccSPatrick Mooney 	}
4986e4a39ccSPatrick Mooney 
4996e4a39ccSPatrick Mooney 	nvlist_to_meoi(results, &mtp->mtp_results);
5006e4a39ccSPatrick Mooney 
5016e4a39ccSPatrick Mooney 	nvlist_free(params);
5026e4a39ccSPatrick Mooney 	return (B_TRUE);
5036e4a39ccSPatrick Mooney }
5046e4a39ccSPatrick Mooney 
5056e4a39ccSPatrick Mooney void
mac_ether_offload_info_test(ktest_ctx_hdl_t * ctx)5066e4a39ccSPatrick Mooney mac_ether_offload_info_test(ktest_ctx_hdl_t *ctx)
5076e4a39ccSPatrick Mooney {
5086e4a39ccSPatrick Mooney 	meoi_test_params_t mtp = { 0 };
5096e4a39ccSPatrick Mooney 
5106e4a39ccSPatrick Mooney 	if (!meoi_test_parse_input(ctx, &mtp, B_FALSE)) {
5116e4a39ccSPatrick Mooney 		return;
5126e4a39ccSPatrick Mooney 	}
5136e4a39ccSPatrick Mooney 
5146e4a39ccSPatrick Mooney 	mac_ether_offload_info_t result;
515ca28c3d8SPatrick Mooney 	mac_ether_offload_info(mtp.mtp_mp, &result);
5166e4a39ccSPatrick Mooney 
5176e4a39ccSPatrick Mooney 	const mac_ether_offload_info_t *expect = &mtp.mtp_results;
5186e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_flags, ==, expect->meoi_flags, ctx, done);
5196e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l2hlen, ==, expect->meoi_l2hlen, ctx, done);
5206e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l3proto, ==, expect->meoi_l3proto, ctx, done);
5216e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l3hlen, ==, expect->meoi_l3hlen, ctx, done);
5226e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l4proto, ==, expect->meoi_l4proto, ctx, done);
5236e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l4hlen, ==, expect->meoi_l4hlen, ctx, done);
5246e4a39ccSPatrick Mooney 
5256e4a39ccSPatrick Mooney 	KT_PASS(ctx);
5266e4a39ccSPatrick Mooney 
5276e4a39ccSPatrick Mooney done:
5286e4a39ccSPatrick Mooney 	freemsg(mtp.mtp_mp);
5296e4a39ccSPatrick Mooney }
5306e4a39ccSPatrick Mooney 
5316e4a39ccSPatrick Mooney void
mac_partial_offload_info_test(ktest_ctx_hdl_t * ctx)5326e4a39ccSPatrick Mooney mac_partial_offload_info_test(ktest_ctx_hdl_t *ctx)
5336e4a39ccSPatrick Mooney {
5346e4a39ccSPatrick Mooney 	meoi_test_params_t mtp = { 0 };
5356e4a39ccSPatrick Mooney 
5366e4a39ccSPatrick Mooney 	if (!meoi_test_parse_input(ctx, &mtp, B_TRUE)) {
5376e4a39ccSPatrick Mooney 		return;
5386e4a39ccSPatrick Mooney 	}
5396e4a39ccSPatrick Mooney 
5406e4a39ccSPatrick Mooney 	mac_ether_offload_info_t *result = &mtp.mtp_partial;
541ca28c3d8SPatrick Mooney 	mac_partial_offload_info(mtp.mtp_mp, mtp.mtp_offset, result);
5426e4a39ccSPatrick Mooney 
5436e4a39ccSPatrick Mooney 	const mac_ether_offload_info_t *expect = &mtp.mtp_results;
5446e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_flags, ==, expect->meoi_flags, ctx, done);
5456e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l2hlen, ==, expect->meoi_l2hlen, ctx, done);
5466e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l3proto, ==, expect->meoi_l3proto, ctx, done);
5476e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l3hlen, ==, expect->meoi_l3hlen, ctx, done);
5486e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l4proto, ==, expect->meoi_l4proto, ctx, done);
5496e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l4hlen, ==, expect->meoi_l4hlen, ctx, done);
5506e4a39ccSPatrick Mooney 
5516e4a39ccSPatrick Mooney 	KT_PASS(ctx);
5526e4a39ccSPatrick Mooney 
5536e4a39ccSPatrick Mooney done:
5546e4a39ccSPatrick Mooney 	freemsg(mtp.mtp_mp);
5556e4a39ccSPatrick Mooney }
5566e4a39ccSPatrick Mooney 
5576e4a39ccSPatrick Mooney typedef struct ether_test_params {
5586e4a39ccSPatrick Mooney 	mblk_t		*etp_mp;
5596e4a39ccSPatrick Mooney 	uint32_t	etp_tci;
5606e4a39ccSPatrick Mooney 	uint8_t		etp_dstaddr[ETHERADDRL];
5616e4a39ccSPatrick Mooney 	boolean_t	etp_is_err;
5626e4a39ccSPatrick Mooney } ether_test_params_t;
5636e4a39ccSPatrick Mooney 
5646e4a39ccSPatrick Mooney /*
5656e4a39ccSPatrick Mooney  * mac_ether_l2_info tests expect the following as input (via packed nvlist)
5666e4a39ccSPatrick Mooney  *
5676e4a39ccSPatrick Mooney  * - pkt_bytes (byte array): packet bytes to parse
5686e4a39ccSPatrick Mooney  * - splits (uint32 array, optional): byte sizes to split packet into mblks
5696e4a39ccSPatrick Mooney  * - tci (uint32): VLAN TCI result value to compare
5706e4a39ccSPatrick Mooney  * - dstaddr (byte array): MAC addr result value to compare
5716e4a39ccSPatrick Mooney  * - is_err (boolean): if test function should return error
5726e4a39ccSPatrick Mooney  */
5736e4a39ccSPatrick Mooney static boolean_t
ether_parse_input(ktest_ctx_hdl_t * ctx,ether_test_params_t * etp)5746e4a39ccSPatrick Mooney ether_parse_input(ktest_ctx_hdl_t *ctx, ether_test_params_t *etp)
5756e4a39ccSPatrick Mooney {
5766e4a39ccSPatrick Mooney 	uchar_t *bytes;
5776e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
5786e4a39ccSPatrick Mooney 
5796e4a39ccSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
5806e4a39ccSPatrick Mooney 	bzero(etp, sizeof (*etp));
5816e4a39ccSPatrick Mooney 
5826e4a39ccSPatrick Mooney 	nvlist_t *params = NULL;
5836e4a39ccSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
5846e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
5856e4a39ccSPatrick Mooney 		return (B_FALSE);
5866e4a39ccSPatrick Mooney 	}
5876e4a39ccSPatrick Mooney 
5886e4a39ccSPatrick Mooney 	etp->etp_mp = alloc_split_pkt(ctx, params, "pkt_bytes");
5896e4a39ccSPatrick Mooney 	if (etp->etp_mp == NULL) {
5906e4a39ccSPatrick Mooney 		nvlist_free(params);
5916e4a39ccSPatrick Mooney 		return (B_FALSE);
5926e4a39ccSPatrick Mooney 	}
5936e4a39ccSPatrick Mooney 
5946e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint32(params, "tci", &etp->etp_tci) != 0) {
5956e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing tci field");
5966e4a39ccSPatrick Mooney 		nvlist_free(params);
5976e4a39ccSPatrick Mooney 		return (B_FALSE);
5986e4a39ccSPatrick Mooney 	}
5996e4a39ccSPatrick Mooney 
6006e4a39ccSPatrick Mooney 	uchar_t *dstaddr;
6016e4a39ccSPatrick Mooney 	uint_t dstaddr_sz;
6026e4a39ccSPatrick Mooney 	if (nvlist_lookup_byte_array(params, "dstaddr", &dstaddr,
6036e4a39ccSPatrick Mooney 	    &dstaddr_sz) != 0) {
6046e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing dstaddr field");
6056e4a39ccSPatrick Mooney 		nvlist_free(params);
6066e4a39ccSPatrick Mooney 		return (B_FALSE);
6076e4a39ccSPatrick Mooney 	} else if (dstaddr_sz != ETHERADDRL) {
6086e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "bad dstaddr size %u != %u", dstaddr_sz,
6096e4a39ccSPatrick Mooney 		    ETHERADDRL);
6106e4a39ccSPatrick Mooney 		nvlist_free(params);
6116e4a39ccSPatrick Mooney 		return (B_FALSE);
6126e4a39ccSPatrick Mooney 	}
6136e4a39ccSPatrick Mooney 	bcopy(dstaddr, &etp->etp_dstaddr, ETHERADDRL);
6146e4a39ccSPatrick Mooney 
6156e4a39ccSPatrick Mooney 	etp->etp_is_err = nvlist_lookup_boolean(params, "is_err") == 0;
6166e4a39ccSPatrick Mooney 
6176e4a39ccSPatrick Mooney 	nvlist_free(params);
6186e4a39ccSPatrick Mooney 	return (B_TRUE);
6196e4a39ccSPatrick Mooney }
6206e4a39ccSPatrick Mooney 
6216e4a39ccSPatrick Mooney void
mac_ether_l2_info_test(ktest_ctx_hdl_t * ctx)6226e4a39ccSPatrick Mooney mac_ether_l2_info_test(ktest_ctx_hdl_t *ctx)
6236e4a39ccSPatrick Mooney {
6246e4a39ccSPatrick Mooney 	ether_test_params_t etp = { 0 };
6256e4a39ccSPatrick Mooney 
6266e4a39ccSPatrick Mooney 	if (!ether_parse_input(ctx, &etp)) {
6276e4a39ccSPatrick Mooney 		return;
6286e4a39ccSPatrick Mooney 	}
6296e4a39ccSPatrick Mooney 
6306e4a39ccSPatrick Mooney 	uint8_t dstaddr[ETHERADDRL];
6316e4a39ccSPatrick Mooney 	uint32_t vlan_tci = 0;
6326e4a39ccSPatrick Mooney 	const boolean_t is_err =
633ca28c3d8SPatrick Mooney 	    !mac_ether_l2_info(etp.etp_mp, dstaddr, &vlan_tci);
6346e4a39ccSPatrick Mooney 
6356e4a39ccSPatrick Mooney 	KT_ASSERTG(is_err == etp.etp_is_err, ctx, done);
6366e4a39ccSPatrick Mooney 	KT_ASSERTG(bcmp(dstaddr, etp.etp_dstaddr, ETHERADDRL) == 0, ctx,
6376e4a39ccSPatrick Mooney 	    done);
6386e4a39ccSPatrick Mooney 	KT_ASSERT3UG(vlan_tci, ==, etp.etp_tci, ctx, done);
6396e4a39ccSPatrick Mooney 
6406e4a39ccSPatrick Mooney 	KT_PASS(ctx);
6416e4a39ccSPatrick Mooney 
6426e4a39ccSPatrick Mooney done:
6436e4a39ccSPatrick Mooney 	freemsg(etp.etp_mp);
6446e4a39ccSPatrick Mooney }
6456e4a39ccSPatrick Mooney 
6466e4a39ccSPatrick Mooney 
6476e4a39ccSPatrick Mooney static struct modlmisc mac_ktest_modlmisc = {
6486e4a39ccSPatrick Mooney 	.misc_modops = &mod_miscops,
6496e4a39ccSPatrick Mooney 	.misc_linkinfo = "mac ktest module"
6506e4a39ccSPatrick Mooney };
6516e4a39ccSPatrick Mooney 
6526e4a39ccSPatrick Mooney static struct modlinkage mac_ktest_modlinkage = {
6536e4a39ccSPatrick Mooney 	.ml_rev = MODREV_1,
6546e4a39ccSPatrick Mooney 	.ml_linkage = { &mac_ktest_modlmisc, NULL }
6556e4a39ccSPatrick Mooney };
6566e4a39ccSPatrick Mooney 
6576e4a39ccSPatrick Mooney int
_init()6586e4a39ccSPatrick Mooney _init()
6596e4a39ccSPatrick Mooney {
6606e4a39ccSPatrick Mooney 	int ret;
6616e4a39ccSPatrick Mooney 	ktest_module_hdl_t *km = NULL;
6626e4a39ccSPatrick Mooney 	ktest_suite_hdl_t *ks = NULL;
6636e4a39ccSPatrick Mooney 
6646e4a39ccSPatrick Mooney 	VERIFY0(ktest_create_module("mac", &km));
6656e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_suite(km, "checksum", &ks));
666*3d6ee46bSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_sw_cksum_test",
667*3d6ee46bSPatrick Mooney 	    mac_sw_cksum_test, KTEST_FLAG_INPUT));
6686e4a39ccSPatrick Mooney 
6696e4a39ccSPatrick Mooney 	ks = NULL;
6706e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_suite(km, "parsing", &ks));
6716e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_ether_offload_info_test",
6726e4a39ccSPatrick Mooney 	    mac_ether_offload_info_test, KTEST_FLAG_INPUT));
6736e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_partial_offload_info_test",
6746e4a39ccSPatrick Mooney 	    mac_partial_offload_info_test, KTEST_FLAG_INPUT));
6756e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_ether_l2_info_test",
6766e4a39ccSPatrick Mooney 	    mac_ether_l2_info_test, KTEST_FLAG_INPUT));
6776e4a39ccSPatrick Mooney 
6786e4a39ccSPatrick Mooney 	if ((ret = ktest_register_module(km)) != 0) {
6796e4a39ccSPatrick Mooney 		ktest_free_module(km);
6806e4a39ccSPatrick Mooney 		return (ret);
6816e4a39ccSPatrick Mooney 	}
6826e4a39ccSPatrick Mooney 
6836e4a39ccSPatrick Mooney 	if ((ret = mod_install(&mac_ktest_modlinkage)) != 0) {
6846e4a39ccSPatrick Mooney 		ktest_unregister_module("mac");
6856e4a39ccSPatrick Mooney 		return (ret);
6866e4a39ccSPatrick Mooney 	}
6876e4a39ccSPatrick Mooney 
6886e4a39ccSPatrick Mooney 	return (0);
6896e4a39ccSPatrick Mooney }
6906e4a39ccSPatrick Mooney 
6916e4a39ccSPatrick Mooney int
_fini(void)6926e4a39ccSPatrick Mooney _fini(void)
6936e4a39ccSPatrick Mooney {
6946e4a39ccSPatrick Mooney 	ktest_unregister_module("mac");
6956e4a39ccSPatrick Mooney 	return (mod_remove(&mac_ktest_modlinkage));
6966e4a39ccSPatrick Mooney }
6976e4a39ccSPatrick Mooney 
6986e4a39ccSPatrick Mooney int
_info(struct modinfo * modinfop)6996e4a39ccSPatrick Mooney _info(struct modinfo *modinfop)
7006e4a39ccSPatrick Mooney {
7016e4a39ccSPatrick Mooney 	return (mod_info(&mac_ktest_modlinkage, modinfop));
7026e4a39ccSPatrick Mooney }
703