xref: /illumos-gate/usr/src/uts/common/io/mac/mac_ktest.c (revision 1f8b8a0145321ca42ee324565958ceb82a14ee7a)
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>
226e4a39ccSPatrick Mooney #include <sys/dlpi.h>
236e4a39ccSPatrick Mooney #include <sys/ethernet.h>
246e4a39ccSPatrick Mooney #include <sys/ktest.h>
256e4a39ccSPatrick Mooney #include <sys/mac_provider.h>
263d6ee46bSPatrick Mooney #include <sys/pattr.h>
273d6ee46bSPatrick Mooney #include <sys/strsun.h>
286e4a39ccSPatrick Mooney 
293d6ee46bSPatrick Mooney typedef mblk_t *(*mac_sw_cksum_t)(mblk_t *, mac_emul_t);
303d6ee46bSPatrick Mooney 
31*1f8b8a01SPatrick Mooney /* Arbitrary limits for cksum tests */
32*1f8b8a01SPatrick Mooney #define	PADDING_MAX	32
33*1f8b8a01SPatrick Mooney #define	SPLITS_MAX	8
34*1f8b8a01SPatrick Mooney 
353d6ee46bSPatrick Mooney typedef struct cksum_test_params {
363d6ee46bSPatrick Mooney 	mblk_t		*ctp_mp;
373d6ee46bSPatrick Mooney 	uchar_t		*ctp_raw;
383d6ee46bSPatrick Mooney 	uint_t		ctp_raw_sz;
393d6ee46bSPatrick Mooney 	boolean_t	ctp_do_partial;
403d6ee46bSPatrick Mooney 	boolean_t	ctp_do_full;
413d6ee46bSPatrick Mooney 	boolean_t	ctp_do_ipv4;
42*1f8b8a01SPatrick Mooney 	uint_t		ctp_splits[SPLITS_MAX];
433d6ee46bSPatrick Mooney } cksum_test_params_t;
443d6ee46bSPatrick Mooney 
45*1f8b8a01SPatrick Mooney static mblk_t *
cksum_alloc_pkt(const cksum_test_params_t * ctp,uint32_t padding)46*1f8b8a01SPatrick Mooney cksum_alloc_pkt(const cksum_test_params_t *ctp, uint32_t padding)
47*1f8b8a01SPatrick Mooney {
48*1f8b8a01SPatrick Mooney 	uint32_t remain = ctp->ctp_raw_sz;
49*1f8b8a01SPatrick Mooney 	uint_t split_idx = 0;
50*1f8b8a01SPatrick Mooney 	const uint8_t *pkt_bytes = ctp->ctp_raw;
51*1f8b8a01SPatrick Mooney 
52*1f8b8a01SPatrick Mooney 	mblk_t *head = NULL, *tail = NULL;
53*1f8b8a01SPatrick Mooney 	while (remain > 0) {
54*1f8b8a01SPatrick Mooney 		const boolean_t has_split = ctp->ctp_splits[split_idx] != 0;
55*1f8b8a01SPatrick Mooney 		const uint32_t to_copy = has_split ?
56*1f8b8a01SPatrick Mooney 		    MIN(remain, ctp->ctp_splits[split_idx]) : remain;
57*1f8b8a01SPatrick Mooney 		const uint32_t to_alloc = padding + to_copy;
58*1f8b8a01SPatrick Mooney 
59*1f8b8a01SPatrick Mooney 		mblk_t *mp = allocb(to_alloc, 0);
60*1f8b8a01SPatrick Mooney 		if (mp == NULL) {
61*1f8b8a01SPatrick Mooney 			freemsg(head);
62*1f8b8a01SPatrick Mooney 			return (NULL);
63*1f8b8a01SPatrick Mooney 		}
64*1f8b8a01SPatrick Mooney 		if (head == NULL) {
65*1f8b8a01SPatrick Mooney 			head = mp;
66*1f8b8a01SPatrick Mooney 		}
67*1f8b8a01SPatrick Mooney 		if (tail != NULL) {
68*1f8b8a01SPatrick Mooney 			tail->b_cont = mp;
69*1f8b8a01SPatrick Mooney 		}
70*1f8b8a01SPatrick Mooney 		tail = mp;
71*1f8b8a01SPatrick Mooney 
72*1f8b8a01SPatrick Mooney 		/* Pad the first mblk with zeros, if requested */
73*1f8b8a01SPatrick Mooney 		if (padding != 0) {
74*1f8b8a01SPatrick Mooney 			bzero(mp->b_rptr, padding);
75*1f8b8a01SPatrick Mooney 			mp->b_rptr += padding;
76*1f8b8a01SPatrick Mooney 			mp->b_wptr += padding;
77*1f8b8a01SPatrick Mooney 			padding = 0;
78*1f8b8a01SPatrick Mooney 		}
79*1f8b8a01SPatrick Mooney 
80*1f8b8a01SPatrick Mooney 		bcopy(pkt_bytes, mp->b_rptr, to_copy);
81*1f8b8a01SPatrick Mooney 		mp->b_wptr += to_copy;
82*1f8b8a01SPatrick Mooney 		pkt_bytes += to_copy;
83*1f8b8a01SPatrick Mooney 		remain -= to_copy;
84*1f8b8a01SPatrick Mooney 		if (has_split) {
85*1f8b8a01SPatrick Mooney 			split_idx++;
86*1f8b8a01SPatrick Mooney 		}
87*1f8b8a01SPatrick Mooney 	}
88*1f8b8a01SPatrick Mooney 	return (head);
89*1f8b8a01SPatrick Mooney }
903d6ee46bSPatrick Mooney 
913d6ee46bSPatrick Mooney static boolean_t
cksum_test_parse_input(ktest_ctx_hdl_t * ctx,cksum_test_params_t * ctp)923d6ee46bSPatrick Mooney cksum_test_parse_input(ktest_ctx_hdl_t *ctx, cksum_test_params_t *ctp)
936e4a39ccSPatrick Mooney {
946e4a39ccSPatrick Mooney 	uchar_t *bytes;
956e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
963d6ee46bSPatrick Mooney 
973d6ee46bSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
983d6ee46bSPatrick Mooney 	bzero(ctp, sizeof (*ctp));
993d6ee46bSPatrick Mooney 
1003d6ee46bSPatrick Mooney 	nvlist_t *params = NULL;
1013d6ee46bSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
1023d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
1033d6ee46bSPatrick Mooney 		return (B_FALSE);
1043d6ee46bSPatrick Mooney 	}
1053d6ee46bSPatrick Mooney 
1063d6ee46bSPatrick Mooney 	uchar_t *pkt_bytes;
1073d6ee46bSPatrick Mooney 	uint_t pkt_sz;
1083d6ee46bSPatrick Mooney 
1093d6ee46bSPatrick Mooney 	if (nvlist_lookup_byte_array(params, "pkt_bytes", &pkt_bytes,
1103d6ee46bSPatrick Mooney 	    &pkt_sz) != 0) {
1113d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Input missing pkt_bytes field");
112*1f8b8a01SPatrick Mooney 		goto bail;
1133d6ee46bSPatrick Mooney 	}
1143d6ee46bSPatrick Mooney 	if (pkt_sz == 0) {
1153d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "Packet must not be 0-length");
116*1f8b8a01SPatrick Mooney 		goto bail;
1173d6ee46bSPatrick Mooney 	}
1183d6ee46bSPatrick Mooney 
1193d6ee46bSPatrick Mooney 	uint32_t padding = 0;
1203d6ee46bSPatrick Mooney 	(void) nvlist_lookup_uint32(params, "padding", &padding);
1213d6ee46bSPatrick Mooney 	if (padding & 1) {
1223d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "padding must be even");
123*1f8b8a01SPatrick Mooney 		goto bail;
1243d6ee46bSPatrick Mooney 	} else if (padding > PADDING_MAX) {
1253d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "padding greater than max of %u", PADDING_MAX);
126*1f8b8a01SPatrick Mooney 		goto bail;
1273d6ee46bSPatrick Mooney 	}
1283d6ee46bSPatrick Mooney 
1293d6ee46bSPatrick Mooney 	ctp->ctp_do_ipv4 = fnvlist_lookup_boolean(params, "cksum_ipv4");
1303d6ee46bSPatrick Mooney 	ctp->ctp_do_partial = fnvlist_lookup_boolean(params, "cksum_partial");
1313d6ee46bSPatrick Mooney 	ctp->ctp_do_full = fnvlist_lookup_boolean(params, "cksum_full");
1323d6ee46bSPatrick Mooney 
133*1f8b8a01SPatrick Mooney 	uint32_t *splits;
134*1f8b8a01SPatrick Mooney 	uint_t nsplits;
135*1f8b8a01SPatrick Mooney 	if (nvlist_lookup_uint32_array(params, "cksum_splits", &splits,
136*1f8b8a01SPatrick Mooney 	    &nsplits) == 0) {
137*1f8b8a01SPatrick Mooney 		if (nsplits > SPLITS_MAX) {
138*1f8b8a01SPatrick Mooney 			KT_ERROR(ctx, "Too many splits requested");
139*1f8b8a01SPatrick Mooney 			goto bail;
140*1f8b8a01SPatrick Mooney 		}
141*1f8b8a01SPatrick Mooney 		for (uint_t i = 0; i < nsplits; i++) {
142*1f8b8a01SPatrick Mooney 			if (splits[i] == 0) {
143*1f8b8a01SPatrick Mooney 				KT_ERROR(ctx, "Splits should not be 0");
144*1f8b8a01SPatrick Mooney 				goto bail;
145*1f8b8a01SPatrick Mooney 			} else if (splits[i] & 1) {
146*1f8b8a01SPatrick Mooney 				KT_ERROR(ctx, "Splits must be 2-byte aligned");
147*1f8b8a01SPatrick Mooney 				goto bail;
148*1f8b8a01SPatrick Mooney 			}
149*1f8b8a01SPatrick Mooney 			ctp->ctp_splits[i] = splits[i];
150*1f8b8a01SPatrick Mooney 		}
1513d6ee46bSPatrick Mooney 	}
1523d6ee46bSPatrick Mooney 
153*1f8b8a01SPatrick Mooney 	if (ctp->ctp_do_partial && ctp->ctp_do_full) {
154*1f8b8a01SPatrick Mooney 		KT_ERROR(ctx, "Cannot request full and partial cksum");
155*1f8b8a01SPatrick Mooney 		goto bail;
1563d6ee46bSPatrick Mooney 	}
1573d6ee46bSPatrick Mooney 
1583d6ee46bSPatrick Mooney 	ctp->ctp_raw = kmem_alloc(pkt_sz, KM_SLEEP);
1593d6ee46bSPatrick Mooney 	bcopy(pkt_bytes, ctp->ctp_raw, pkt_sz);
1603d6ee46bSPatrick Mooney 	ctp->ctp_raw_sz = pkt_sz;
1613d6ee46bSPatrick Mooney 
162*1f8b8a01SPatrick Mooney 	ctp->ctp_mp = cksum_alloc_pkt(ctp, padding);
163*1f8b8a01SPatrick Mooney 	if (ctp->ctp_mp == NULL) {
164*1f8b8a01SPatrick Mooney 		KT_ERROR(ctx, "Could not allocate mblk");
165*1f8b8a01SPatrick Mooney 		goto bail;
166*1f8b8a01SPatrick Mooney 	}
167*1f8b8a01SPatrick Mooney 
1683d6ee46bSPatrick Mooney 	nvlist_free(params);
1693d6ee46bSPatrick Mooney 	return (B_TRUE);
170*1f8b8a01SPatrick Mooney 
171*1f8b8a01SPatrick Mooney bail:
172*1f8b8a01SPatrick Mooney 	if (ctp->ctp_raw != NULL) {
173*1f8b8a01SPatrick Mooney 		kmem_free(ctp->ctp_raw, ctp->ctp_raw_sz);
174*1f8b8a01SPatrick Mooney 	}
175*1f8b8a01SPatrick Mooney 	if (params != NULL) {
176*1f8b8a01SPatrick Mooney 		nvlist_free(params);
177*1f8b8a01SPatrick Mooney 	}
178*1f8b8a01SPatrick Mooney 	return (B_FALSE);
1793d6ee46bSPatrick Mooney }
1803d6ee46bSPatrick Mooney 
1813d6ee46bSPatrick Mooney /* Calculate pseudo-header checksum for a packet */
1823d6ee46bSPatrick Mooney static uint16_t
cksum_calc_pseudo(ktest_ctx_hdl_t * ctx,const uint8_t * pkt_data,const mac_ether_offload_info_t * meoi)183*1f8b8a01SPatrick Mooney cksum_calc_pseudo(ktest_ctx_hdl_t *ctx, const uint8_t *pkt_data,
1843d6ee46bSPatrick Mooney     const mac_ether_offload_info_t *meoi)
1853d6ee46bSPatrick Mooney {
1863d6ee46bSPatrick Mooney 	if ((meoi->meoi_flags & MEOI_L4INFO_SET) == 0) {
1873d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "MEOI lacks L4 info");
1883d6ee46bSPatrick Mooney 		return (0);
1893d6ee46bSPatrick Mooney 	}
1903d6ee46bSPatrick Mooney 
191*1f8b8a01SPatrick Mooney 	const uint16_t *iphs = (const uint16_t *)(pkt_data + meoi->meoi_l2hlen);
1923d6ee46bSPatrick Mooney 	uint32_t cksum = 0;
1933d6ee46bSPatrick Mooney 
1943d6ee46bSPatrick Mooney 	/* Copied from ip_input_cksum_pseudo_v[46]() */
1953d6ee46bSPatrick Mooney 	if (meoi->meoi_l3proto == ETHERTYPE_IP) {
1963d6ee46bSPatrick Mooney 		cksum += iphs[6] + iphs[7] + iphs[8] + iphs[9];
1973d6ee46bSPatrick Mooney 	} else if (meoi->meoi_l3proto == ETHERTYPE_IPV6) {
1983d6ee46bSPatrick Mooney 		cksum += iphs[4] + iphs[5] + iphs[6] + iphs[7] +
1993d6ee46bSPatrick Mooney 		    iphs[8] + iphs[9] + iphs[10] + iphs[11] +
2003d6ee46bSPatrick Mooney 		    iphs[12] + iphs[13] + iphs[14] + iphs[15] +
2013d6ee46bSPatrick Mooney 		    iphs[16] + iphs[17] + iphs[18] + iphs[19];
2023d6ee46bSPatrick Mooney 	} else {
2033d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "unexpected proto %u", meoi->meoi_l3proto);
2043d6ee46bSPatrick Mooney 		return (0);
2053d6ee46bSPatrick Mooney 	}
2063d6ee46bSPatrick Mooney 
2073d6ee46bSPatrick Mooney 	switch (meoi->meoi_l4proto) {
2083d6ee46bSPatrick Mooney 	case IPPROTO_TCP:
2093d6ee46bSPatrick Mooney 		cksum += IP_TCP_CSUM_COMP;
2103d6ee46bSPatrick Mooney 		break;
2113d6ee46bSPatrick Mooney 	case IPPROTO_UDP:
2123d6ee46bSPatrick Mooney 		cksum += IP_UDP_CSUM_COMP;
2133d6ee46bSPatrick Mooney 		break;
2143d6ee46bSPatrick Mooney 	case IPPROTO_ICMPV6:
2153d6ee46bSPatrick Mooney 		cksum += IP_ICMPV6_CSUM_COMP;
2163d6ee46bSPatrick Mooney 		break;
2173d6ee46bSPatrick Mooney 	default:
218*1f8b8a01SPatrick Mooney 		KT_ERROR(ctx, "unexpected L4 proto %u", meoi->meoi_l4proto);
2193d6ee46bSPatrick Mooney 		return (0);
2203d6ee46bSPatrick Mooney 	}
2213d6ee46bSPatrick Mooney 
2223d6ee46bSPatrick Mooney 	uint16_t ulp_len =
2233d6ee46bSPatrick Mooney 	    meoi->meoi_len - ((uint16_t)meoi->meoi_l2hlen + meoi->meoi_l3hlen);
2243d6ee46bSPatrick Mooney 	if (meoi->meoi_l3proto == ETHERTYPE_IP) {
2253d6ee46bSPatrick Mooney 		/*
2263d6ee46bSPatrick Mooney 		 * IPv4 packets can fall below the 60-byte minimum for ethernet,
2273d6ee46bSPatrick Mooney 		 * resulting in padding which makes the "easy" means of
2283d6ee46bSPatrick Mooney 		 * determining ULP length potentially inaccurate.
2293d6ee46bSPatrick Mooney 		 *
2303d6ee46bSPatrick Mooney 		 * Reach into the v4 header to make that calculation.
2313d6ee46bSPatrick Mooney 		 */
2323d6ee46bSPatrick Mooney 		const ipha_t *ipha =
233*1f8b8a01SPatrick Mooney 		    (const ipha_t *)(pkt_data + meoi->meoi_l2hlen);
2343d6ee46bSPatrick Mooney 		ulp_len = ntohs(ipha->ipha_length) - meoi->meoi_l3hlen;
2353d6ee46bSPatrick Mooney 	}
2363d6ee46bSPatrick Mooney 
2373d6ee46bSPatrick Mooney 	cksum += htons(ulp_len);
2383d6ee46bSPatrick Mooney 
2393d6ee46bSPatrick Mooney 	cksum = (cksum >> 16) + (cksum & 0xffff);
2403d6ee46bSPatrick Mooney 	cksum = (cksum >> 16) + (cksum & 0xffff);
2413d6ee46bSPatrick Mooney 	return (cksum);
2423d6ee46bSPatrick Mooney }
2433d6ee46bSPatrick Mooney 
2443d6ee46bSPatrick Mooney /*
245*1f8b8a01SPatrick Mooney  * Overwrite 2 bytes in mblk at given offset.
246*1f8b8a01SPatrick Mooney  *
247*1f8b8a01SPatrick Mooney  * Assumes:
248*1f8b8a01SPatrick Mooney  * - offset is 2-byte aligned
249*1f8b8a01SPatrick Mooney  * - mblk(s) in chain reference memory which is 2-byte aligned
250*1f8b8a01SPatrick Mooney  * - offset is within mblk chain
251*1f8b8a01SPatrick Mooney  */
252*1f8b8a01SPatrick Mooney static void
mblk_write16(mblk_t * mp,uint_t off,uint16_t val)253*1f8b8a01SPatrick Mooney mblk_write16(mblk_t *mp, uint_t off, uint16_t val)
254*1f8b8a01SPatrick Mooney {
255*1f8b8a01SPatrick Mooney 	VERIFY(mp != NULL);
256*1f8b8a01SPatrick Mooney 	VERIFY3U(off & 1, ==, 0);
257*1f8b8a01SPatrick Mooney 	VERIFY3U(off + 2, <=, msgdsize(mp));
258*1f8b8a01SPatrick Mooney 
259*1f8b8a01SPatrick Mooney 	while (off >= MBLKL(mp)) {
260*1f8b8a01SPatrick Mooney 		off -= MBLKL(mp);
261*1f8b8a01SPatrick Mooney 		mp = mp->b_cont;
262*1f8b8a01SPatrick Mooney 		VERIFY(mp != NULL);
263*1f8b8a01SPatrick Mooney 	}
264*1f8b8a01SPatrick Mooney 
265*1f8b8a01SPatrick Mooney 	uint16_t *datap = (uint16_t *)(mp->b_rptr + off);
266*1f8b8a01SPatrick Mooney 	*datap = val;
267*1f8b8a01SPatrick Mooney }
268*1f8b8a01SPatrick Mooney 
269*1f8b8a01SPatrick Mooney /* Compare resulting mblk with known good value in test parameters.  */
270*1f8b8a01SPatrick Mooney static boolean_t
cksum_result_compare(ktest_ctx_hdl_t * ctx,const cksum_test_params_t * ctp,mblk_t * mp)271*1f8b8a01SPatrick Mooney cksum_result_compare(ktest_ctx_hdl_t *ctx, const cksum_test_params_t *ctp,
272*1f8b8a01SPatrick Mooney     mblk_t *mp)
273*1f8b8a01SPatrick Mooney {
274*1f8b8a01SPatrick Mooney 	if (msgdsize(mp) != ctp->ctp_raw_sz) {
275*1f8b8a01SPatrick Mooney 		KT_FAIL(ctx, "mp size %u != %u", msgdsize(mp), ctp->ctp_raw_sz);
276*1f8b8a01SPatrick Mooney 		return (B_FALSE);
277*1f8b8a01SPatrick Mooney 	}
278*1f8b8a01SPatrick Mooney 
279*1f8b8a01SPatrick Mooney 	uint32_t fail_val = 0, good_val = 0;
280*1f8b8a01SPatrick Mooney 	uint_t mp_off = 0, fail_len = 0, i;
281*1f8b8a01SPatrick Mooney 	for (i = 0; i < ctp->ctp_raw_sz; i++) {
282*1f8b8a01SPatrick Mooney 		/*
283*1f8b8a01SPatrick Mooney 		 * If we encounter a mismatch, collect up to 4 bytes of context
284*1f8b8a01SPatrick Mooney 		 * to print with the failure.
285*1f8b8a01SPatrick Mooney 		 */
286*1f8b8a01SPatrick Mooney 		if (mp->b_rptr[mp_off] != ctp->ctp_raw[i] || fail_len != 0) {
287*1f8b8a01SPatrick Mooney 			fail_val |= mp->b_rptr[mp_off] << (fail_len * 8);
288*1f8b8a01SPatrick Mooney 			good_val |= ctp->ctp_raw[i] << (fail_len * 8);
289*1f8b8a01SPatrick Mooney 
290*1f8b8a01SPatrick Mooney 			fail_len++;
291*1f8b8a01SPatrick Mooney 			if (fail_len == 4) {
292*1f8b8a01SPatrick Mooney 				break;
293*1f8b8a01SPatrick Mooney 			}
294*1f8b8a01SPatrick Mooney 		}
295*1f8b8a01SPatrick Mooney 
296*1f8b8a01SPatrick Mooney 		mp_off++;
297*1f8b8a01SPatrick Mooney 		if (mp_off == MBLKL(mp)) {
298*1f8b8a01SPatrick Mooney 			mp = mp->b_cont;
299*1f8b8a01SPatrick Mooney 			mp_off = 0;
300*1f8b8a01SPatrick Mooney 		}
301*1f8b8a01SPatrick Mooney 	}
302*1f8b8a01SPatrick Mooney 
303*1f8b8a01SPatrick Mooney 	if (fail_len != 0) {
304*1f8b8a01SPatrick Mooney 		KT_FAIL(ctx, "mp[%02X] %08X != %08X", (i - fail_len),
305*1f8b8a01SPatrick Mooney 		    fail_val, good_val);
306*1f8b8a01SPatrick Mooney 		return (B_FALSE);
307*1f8b8a01SPatrick Mooney 	}
308*1f8b8a01SPatrick Mooney 
309*1f8b8a01SPatrick Mooney 	return (B_TRUE);
310*1f8b8a01SPatrick Mooney }
311*1f8b8a01SPatrick Mooney 
312*1f8b8a01SPatrick Mooney /*
3133d6ee46bSPatrick Mooney  * Verify mac_sw_cksum() emulation against an arbitrary input packet.  If the
3143d6ee46bSPatrick Mooney  * packet is of a support protocol, any L3 and L4 checksums are cleared, and
3153d6ee46bSPatrick Mooney  * then mac_sw_cksum() is called to perform the offload emulation.  Afterwards,
3163d6ee46bSPatrick Mooney  * the packet is compared to see if it equasl the input, which is assumed to
3173d6ee46bSPatrick Mooney  * have correct checksums.
3183d6ee46bSPatrick Mooney  *
3193d6ee46bSPatrick Mooney  * This can request either emulation via HCK_PARTIALCKSUM or HCK_FULLCKSUM.
3203d6ee46bSPatrick Mooney  */
3213d6ee46bSPatrick Mooney static void
mac_sw_cksum_test(ktest_ctx_hdl_t * ctx)3223d6ee46bSPatrick Mooney mac_sw_cksum_test(ktest_ctx_hdl_t *ctx)
3233d6ee46bSPatrick Mooney {
3243d6ee46bSPatrick Mooney 	ddi_modhandle_t hdl = NULL;
3253d6ee46bSPatrick Mooney 	mac_sw_cksum_t mac_sw_cksum = NULL;
3266e4a39ccSPatrick Mooney 
3276e4a39ccSPatrick Mooney 	if (ktest_hold_mod("mac", &hdl) != 0) {
3286e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "failed to hold 'mac' module");
3296e4a39ccSPatrick Mooney 		return;
3306e4a39ccSPatrick Mooney 	}
3313d6ee46bSPatrick Mooney 	if (ktest_get_fn(hdl, "mac_sw_cksum", (void **)&mac_sw_cksum) != 0) {
3323d6ee46bSPatrick Mooney 		KT_ERROR(ctx, "failed to resolve symbol mac`mac_sw_cksum");
3336e4a39ccSPatrick Mooney 		goto cleanup;
3346e4a39ccSPatrick Mooney 	}
3356e4a39ccSPatrick Mooney 
3363d6ee46bSPatrick Mooney 	cksum_test_params_t ctp;
3373d6ee46bSPatrick Mooney 	if (!cksum_test_parse_input(ctx, &ctp)) {
3383d6ee46bSPatrick Mooney 		goto cleanup;
3393d6ee46bSPatrick Mooney 	}
3403d6ee46bSPatrick Mooney 	mblk_t *mp = ctp.ctp_mp;
3416e4a39ccSPatrick Mooney 
3423d6ee46bSPatrick Mooney 	mac_ether_offload_info_t meoi;
3433d6ee46bSPatrick Mooney 	mac_ether_offload_info(mp, &meoi);
3446e4a39ccSPatrick Mooney 
3453d6ee46bSPatrick Mooney 	if ((meoi.meoi_flags & MEOI_L3INFO_SET) == 0 ||
3463d6ee46bSPatrick Mooney 	    (meoi.meoi_l3proto != ETHERTYPE_IP &&
3473d6ee46bSPatrick Mooney 	    meoi.meoi_l3proto != ETHERTYPE_IPV6)) {
3483d6ee46bSPatrick Mooney 		KT_SKIP(ctx, "l3 protocol not recognized/supported");
3493d6ee46bSPatrick Mooney 		goto cleanup;
3503d6ee46bSPatrick Mooney 	}
3513d6ee46bSPatrick Mooney 
3523d6ee46bSPatrick Mooney 	mac_emul_t emul_flags = 0;
3533d6ee46bSPatrick Mooney 	uint_t hck_flags = 0, hck_start = 0, hck_stuff = 0, hck_end = 0;
3543d6ee46bSPatrick Mooney 	if (meoi.meoi_l3proto == ETHERTYPE_IP && ctp.ctp_do_ipv4) {
355*1f8b8a01SPatrick Mooney 		mblk_write16(mp,
356*1f8b8a01SPatrick Mooney 		    meoi.meoi_l2hlen + offsetof(ipha_t, ipha_hdr_checksum), 0);
3573d6ee46bSPatrick Mooney 		emul_flags |= MAC_IPCKSUM_EMUL;
3583d6ee46bSPatrick Mooney 		hck_flags |= HCK_IPV4_HDRCKSUM;
3593d6ee46bSPatrick Mooney 	}
3603d6ee46bSPatrick Mooney 
3613d6ee46bSPatrick Mooney 	const boolean_t do_l4 = ctp.ctp_do_partial || ctp.ctp_do_full;
3623d6ee46bSPatrick Mooney 	if ((meoi.meoi_flags & MEOI_L4INFO_SET) != 0 && do_l4) {
363*1f8b8a01SPatrick Mooney 		boolean_t skip_pseudo = B_FALSE;
3643d6ee46bSPatrick Mooney 		hck_start = meoi.meoi_l2hlen + meoi.meoi_l3hlen;
3653d6ee46bSPatrick Mooney 		hck_stuff = hck_start;
3663d6ee46bSPatrick Mooney 		hck_end = meoi.meoi_len;
3673d6ee46bSPatrick Mooney 
3683d6ee46bSPatrick Mooney 		switch (meoi.meoi_l4proto) {
3693d6ee46bSPatrick Mooney 		case IPPROTO_TCP:
370*1f8b8a01SPatrick Mooney 			hck_stuff += TCP_CHECKSUM_OFFSET;
3713d6ee46bSPatrick Mooney 			break;
3723d6ee46bSPatrick Mooney 		case IPPROTO_UDP:
373*1f8b8a01SPatrick Mooney 			hck_stuff += UDP_CHECKSUM_OFFSET;
374*1f8b8a01SPatrick Mooney 			break;
375*1f8b8a01SPatrick Mooney 		case IPPROTO_ICMP:
376*1f8b8a01SPatrick Mooney 			hck_stuff += ICMP_CHECKSUM_OFFSET;
377*1f8b8a01SPatrick Mooney 			/*
378*1f8b8a01SPatrick Mooney 			 * ICMP does not include the pseudo-header content in
379*1f8b8a01SPatrick Mooney 			 * its checksum, but we can still do a partial with that
380*1f8b8a01SPatrick Mooney 			 * field cleared.
381*1f8b8a01SPatrick Mooney 			 */
382*1f8b8a01SPatrick Mooney 			skip_pseudo = B_TRUE;
3833d6ee46bSPatrick Mooney 			break;
3843d6ee46bSPatrick Mooney 		case IPPROTO_ICMPV6:
385*1f8b8a01SPatrick Mooney 			hck_stuff += ICMPV6_CHECKSUM_OFFSET;
3863d6ee46bSPatrick Mooney 			break;
3873d6ee46bSPatrick Mooney 		case IPPROTO_SCTP:
3883d6ee46bSPatrick Mooney 			/*
3893d6ee46bSPatrick Mooney 			 * Only full checksums are supported for SCTP, and the
3903d6ee46bSPatrick Mooney 			 * test logic for clearing the existing sum needs to
3913d6ee46bSPatrick Mooney 			 * account for its increased width.
3923d6ee46bSPatrick Mooney 			 */
393*1f8b8a01SPatrick Mooney 			hck_stuff += SCTP_CHECKSUM_OFFSET;
3943d6ee46bSPatrick Mooney 			if (ctp.ctp_do_full) {
395*1f8b8a01SPatrick Mooney 				mblk_write16(mp, hck_stuff, 0);
396*1f8b8a01SPatrick Mooney 				mblk_write16(mp, hck_stuff + 2, 0);
397*1f8b8a01SPatrick Mooney 			} else {
398*1f8b8a01SPatrick Mooney 				KT_SKIP(ctx,
399*1f8b8a01SPatrick Mooney 				    "Partial L4 cksum not supported for SCTP");
4003d6ee46bSPatrick Mooney 			}
4013d6ee46bSPatrick Mooney 			break;
4023d6ee46bSPatrick Mooney 		default:
403*1f8b8a01SPatrick Mooney 			KT_SKIP(ctx,
404*1f8b8a01SPatrick Mooney 			    "Partial L4 cksum not supported for proto");
405*1f8b8a01SPatrick Mooney 			goto cleanup;
4066e4a39ccSPatrick Mooney 		}
4076e4a39ccSPatrick Mooney 
4083d6ee46bSPatrick Mooney 		emul_flags |= MAC_HWCKSUM_EMUL;
4093d6ee46bSPatrick Mooney 		if (ctp.ctp_do_partial) {
4103d6ee46bSPatrick Mooney 			hck_flags |= HCK_PARTIALCKSUM;
411*1f8b8a01SPatrick Mooney 			if (!skip_pseudo) {
4123d6ee46bSPatrick Mooney 				/* Populate L4 pseudo-header cksum */
413*1f8b8a01SPatrick Mooney 				const uint16_t pcksum =
414*1f8b8a01SPatrick Mooney 				    cksum_calc_pseudo(ctx, ctp.ctp_raw, &meoi);
415*1f8b8a01SPatrick Mooney 				mblk_write16(mp, hck_stuff, pcksum);
416*1f8b8a01SPatrick Mooney 			} else {
417*1f8b8a01SPatrick Mooney 				mblk_write16(mp, hck_stuff, 0);
418*1f8b8a01SPatrick Mooney 			}
4196e4a39ccSPatrick Mooney 		} else {
4203d6ee46bSPatrick Mooney 			hck_flags |= HCK_FULLCKSUM;
4213d6ee46bSPatrick Mooney 			/* Zero out the L4 cksum */
422*1f8b8a01SPatrick Mooney 			mblk_write16(mp, hck_stuff, 0);
4236e4a39ccSPatrick Mooney 		}
4243d6ee46bSPatrick Mooney 	}
4253d6ee46bSPatrick Mooney 	if (do_l4 && (hck_flags & (HCK_FULLCKSUM|HCK_PARTIALCKSUM)) == 0) {
426*1f8b8a01SPatrick Mooney 		KT_SKIP(ctx, "L4 checksum not supported for packet");
4276e4a39ccSPatrick Mooney 		goto cleanup;
4286e4a39ccSPatrick Mooney 	}
4296e4a39ccSPatrick Mooney 
4303d6ee46bSPatrick Mooney 	if (emul_flags != 0) {
4313d6ee46bSPatrick Mooney 		if ((hck_flags & HCK_PARTIALCKSUM) == 0) {
4323d6ee46bSPatrick Mooney 			hck_start = hck_stuff = hck_end = 0;
4333d6ee46bSPatrick Mooney 		} else {
4343d6ee46bSPatrick Mooney 			/*
4353d6ee46bSPatrick Mooney 			 * The offsets for mac_hcksum_set are all relative to
4363d6ee46bSPatrick Mooney 			 * the start of the L3 header.  Prior to here, these
4373d6ee46bSPatrick Mooney 			 * values were relative to the start of the packet.
4383d6ee46bSPatrick Mooney 			 */
4393d6ee46bSPatrick Mooney 			hck_start -= meoi.meoi_l2hlen;
4403d6ee46bSPatrick Mooney 			hck_stuff -= meoi.meoi_l2hlen;
4413d6ee46bSPatrick Mooney 			hck_end -= meoi.meoi_l2hlen;
4423d6ee46bSPatrick Mooney 		}
443*1f8b8a01SPatrick Mooney 		/* Set hcksum information on all mblks in chain */
444*1f8b8a01SPatrick Mooney 		for (mblk_t *cmp = mp; cmp != NULL; cmp = cmp->b_cont) {
445*1f8b8a01SPatrick Mooney 			mac_hcksum_set(cmp, hck_start, hck_stuff, hck_end, 0,
446*1f8b8a01SPatrick Mooney 			    hck_flags);
447*1f8b8a01SPatrick Mooney 		}
4483d6ee46bSPatrick Mooney 		ctp.ctp_mp = mp = mac_sw_cksum(mp, emul_flags);
4493d6ee46bSPatrick Mooney 
4503d6ee46bSPatrick Mooney 		KT_ASSERT3UG(mp, !=, NULL, ctx, cleanup);
451*1f8b8a01SPatrick Mooney 		if (!cksum_result_compare(ctx, &ctp, mp)) {
4523d6ee46bSPatrick Mooney 			goto cleanup;
4533d6ee46bSPatrick Mooney 		}
4543d6ee46bSPatrick Mooney 	} else {
4553d6ee46bSPatrick Mooney 		KT_SKIP(ctx, "no checksums supported for packet");
4563d6ee46bSPatrick Mooney 		goto cleanup;
4573d6ee46bSPatrick Mooney 	}
4583d6ee46bSPatrick Mooney 
4596e4a39ccSPatrick Mooney 	KT_PASS(ctx);
4606e4a39ccSPatrick Mooney 
4616e4a39ccSPatrick Mooney cleanup:
4626e4a39ccSPatrick Mooney 	if (hdl != NULL) {
4636e4a39ccSPatrick Mooney 		ktest_release_mod(hdl);
4646e4a39ccSPatrick Mooney 	}
4653d6ee46bSPatrick Mooney 	if (ctp.ctp_mp != NULL) {
466*1f8b8a01SPatrick Mooney 		freemsg(ctp.ctp_mp);
4676e4a39ccSPatrick Mooney 	}
4683d6ee46bSPatrick Mooney 	if (ctp.ctp_raw != NULL) {
4693d6ee46bSPatrick Mooney 		kmem_free(ctp.ctp_raw, ctp.ctp_raw_sz);
4706e4a39ccSPatrick Mooney 	}
4716e4a39ccSPatrick Mooney }
4726e4a39ccSPatrick Mooney 
4736e4a39ccSPatrick Mooney typedef struct meoi_test_params {
4746e4a39ccSPatrick Mooney 	mblk_t				*mtp_mp;
4756e4a39ccSPatrick Mooney 	mac_ether_offload_info_t	mtp_partial;
4766e4a39ccSPatrick Mooney 	mac_ether_offload_info_t	mtp_results;
4776e4a39ccSPatrick Mooney 	uint_t				mtp_offset;
4786e4a39ccSPatrick Mooney } meoi_test_params_t;
4796e4a39ccSPatrick Mooney 
4806e4a39ccSPatrick Mooney static void
nvlist_to_meoi(nvlist_t * results,mac_ether_offload_info_t * meoi)4816e4a39ccSPatrick Mooney nvlist_to_meoi(nvlist_t *results, mac_ether_offload_info_t *meoi)
4826e4a39ccSPatrick Mooney {
4836e4a39ccSPatrick Mooney 	uint64_t u64_val;
4846e4a39ccSPatrick Mooney 	int int_val;
4856e4a39ccSPatrick Mooney 	uint16_t u16_val;
4866e4a39ccSPatrick Mooney 	uint8_t u8_val;
4876e4a39ccSPatrick Mooney 
4886e4a39ccSPatrick Mooney 	bzero(meoi, sizeof (*meoi));
4896e4a39ccSPatrick Mooney 	if (nvlist_lookup_int32(results, "meoi_flags", &int_val) == 0) {
4906e4a39ccSPatrick Mooney 		meoi->meoi_flags = int_val;
4916e4a39ccSPatrick Mooney 	}
4926e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint64(results, "meoi_len", &u64_val) == 0) {
4936e4a39ccSPatrick Mooney 		meoi->meoi_len = u64_val;
4946e4a39ccSPatrick Mooney 	}
4956e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l2hlen", &u8_val) == 0) {
4966e4a39ccSPatrick Mooney 		meoi->meoi_l2hlen = u8_val;
4976e4a39ccSPatrick Mooney 	}
4986e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint16(results, "meoi_l3proto", &u16_val) == 0) {
4996e4a39ccSPatrick Mooney 		meoi->meoi_l3proto = u16_val;
5006e4a39ccSPatrick Mooney 	}
5016e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint16(results, "meoi_l3hlen", &u16_val) == 0) {
5026e4a39ccSPatrick Mooney 		meoi->meoi_l3hlen = u16_val;
5036e4a39ccSPatrick Mooney 	}
5046e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l4proto", &u8_val) == 0) {
5056e4a39ccSPatrick Mooney 		meoi->meoi_l4proto = u8_val;
5066e4a39ccSPatrick Mooney 	}
5076e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint8(results, "meoi_l4hlen", &u8_val) == 0) {
5086e4a39ccSPatrick Mooney 		meoi->meoi_l4hlen = u8_val;
5096e4a39ccSPatrick Mooney 	}
5106e4a39ccSPatrick Mooney }
5116e4a39ccSPatrick Mooney 
5126e4a39ccSPatrick Mooney static mblk_t *
alloc_split_pkt(ktest_ctx_hdl_t * ctx,nvlist_t * nvl,const char * pkt_field)5136e4a39ccSPatrick Mooney alloc_split_pkt(ktest_ctx_hdl_t *ctx, nvlist_t *nvl, const char *pkt_field)
5146e4a39ccSPatrick Mooney {
5156e4a39ccSPatrick Mooney 	uchar_t *pkt_bytes;
5166e4a39ccSPatrick Mooney 	uint_t pkt_sz;
5176e4a39ccSPatrick Mooney 
5186e4a39ccSPatrick Mooney 	if (nvlist_lookup_byte_array(nvl, pkt_field, &pkt_bytes,
5196e4a39ccSPatrick Mooney 	    &pkt_sz) != 0) {
5206e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing %s field", pkt_field);
5216e4a39ccSPatrick Mooney 		return (NULL);
5226e4a39ccSPatrick Mooney 	}
5236e4a39ccSPatrick Mooney 
5246e4a39ccSPatrick Mooney 	const uint32_t *splits = NULL;
5256e4a39ccSPatrick Mooney 	uint_t num_splits = 0;
5266e4a39ccSPatrick Mooney 	(void) nvlist_lookup_uint32_array(nvl, "splits", (uint32_t **)&splits,
5276e4a39ccSPatrick Mooney 	    &num_splits);
5286e4a39ccSPatrick Mooney 
5296e4a39ccSPatrick Mooney 	uint_t split_idx = 0;
5306e4a39ccSPatrick Mooney 	mblk_t *result = NULL, *tail = NULL;
5316e4a39ccSPatrick Mooney 
5326e4a39ccSPatrick Mooney 	do {
5336e4a39ccSPatrick Mooney 		uint_t block_sz = pkt_sz;
5346e4a39ccSPatrick Mooney 		if (split_idx < num_splits) {
5356e4a39ccSPatrick Mooney 			block_sz = MIN(block_sz, splits[split_idx]);
5366e4a39ccSPatrick Mooney 		}
5376e4a39ccSPatrick Mooney 
5386e4a39ccSPatrick Mooney 		mblk_t *mp = allocb(block_sz, 0);
5396e4a39ccSPatrick Mooney 		if (mp == NULL) {
5406e4a39ccSPatrick Mooney 			KT_ERROR(ctx, "mblk alloc failure");
5416e4a39ccSPatrick Mooney 			freemsg(result);
5426e4a39ccSPatrick Mooney 			return (NULL);
5436e4a39ccSPatrick Mooney 		}
5446e4a39ccSPatrick Mooney 
5456e4a39ccSPatrick Mooney 		if (result == NULL) {
5466e4a39ccSPatrick Mooney 			result = mp;
5476e4a39ccSPatrick Mooney 		} else {
5486e4a39ccSPatrick Mooney 			tail->b_cont = mp;
5496e4a39ccSPatrick Mooney 		}
5506e4a39ccSPatrick Mooney 		tail = mp;
5516e4a39ccSPatrick Mooney 
5526e4a39ccSPatrick Mooney 		if (block_sz != 0) {
5536e4a39ccSPatrick Mooney 			bcopy(pkt_bytes, mp->b_wptr, block_sz);
5546e4a39ccSPatrick Mooney 			mp->b_wptr += block_sz;
5556e4a39ccSPatrick Mooney 		}
5566e4a39ccSPatrick Mooney 		pkt_sz -= block_sz;
5576e4a39ccSPatrick Mooney 		pkt_bytes += block_sz;
5586e4a39ccSPatrick Mooney 		split_idx++;
5596e4a39ccSPatrick Mooney 	} while (pkt_sz > 0);
5606e4a39ccSPatrick Mooney 
5616e4a39ccSPatrick Mooney 	return (result);
5626e4a39ccSPatrick Mooney }
5636e4a39ccSPatrick Mooney 
5646e4a39ccSPatrick Mooney /*
5656e4a39ccSPatrick Mooney  * mac_ether_offload_info tests expect the following as input (via packed
5666e4a39ccSPatrick Mooney  * nvlist)
5676e4a39ccSPatrick Mooney  *
5686e4a39ccSPatrick Mooney  * - pkt_bytes (byte array): packet bytes to parse
5696e4a39ccSPatrick Mooney  * - splits (uint32 array, optional): byte sizes to split packet into mblks
5706e4a39ccSPatrick Mooney  * - results (nvlist): mac_ether_offload_info result struct to compare
5716e4a39ccSPatrick Mooney  *   - Field names and types should match those in the mac_ether_offload_info
5726e4a39ccSPatrick Mooney  *     struct. Any fields not specified will be assumed to be zero.
5736e4a39ccSPatrick Mooney  *
5746e4a39ccSPatrick Mooney  * For mac_partial_offload_info tests, two additional fields are parsed:
5756e4a39ccSPatrick Mooney  *
5766e4a39ccSPatrick Mooney  * - offset (uint32, optional): offset into the packet at which the parsing
5776e4a39ccSPatrick Mooney  *   should begin
5786e4a39ccSPatrick Mooney  * - partial (nvlist): mac_ether_offload_info input struct to be used as
5796e4a39ccSPatrick Mooney  *   starting point for partial parsing
5806e4a39ccSPatrick Mooney  */
5816e4a39ccSPatrick Mooney static boolean_t
meoi_test_parse_input(ktest_ctx_hdl_t * ctx,meoi_test_params_t * mtp,boolean_t test_partial)5826e4a39ccSPatrick Mooney meoi_test_parse_input(ktest_ctx_hdl_t *ctx, meoi_test_params_t *mtp,
5836e4a39ccSPatrick Mooney     boolean_t test_partial)
5846e4a39ccSPatrick Mooney {
5856e4a39ccSPatrick Mooney 	uchar_t *bytes;
5866e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
5876e4a39ccSPatrick Mooney 
5886e4a39ccSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
5896e4a39ccSPatrick Mooney 	bzero(mtp, sizeof (*mtp));
5906e4a39ccSPatrick Mooney 
5916e4a39ccSPatrick Mooney 	nvlist_t *params = NULL;
5926e4a39ccSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
5936e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
5946e4a39ccSPatrick Mooney 		return (B_FALSE);
5956e4a39ccSPatrick Mooney 	}
5966e4a39ccSPatrick Mooney 
5976e4a39ccSPatrick Mooney 	nvlist_t *results;
5986e4a39ccSPatrick Mooney 	if (nvlist_lookup_nvlist(params, "results", &results) != 0) {
5996e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing results field");
6006e4a39ccSPatrick Mooney 		nvlist_free(params);
6016e4a39ccSPatrick Mooney 		return (B_FALSE);
6026e4a39ccSPatrick Mooney 	}
6036e4a39ccSPatrick Mooney 
6046e4a39ccSPatrick Mooney 	if (test_partial) {
6056e4a39ccSPatrick Mooney 		nvlist_t *partial;
6066e4a39ccSPatrick Mooney 		if (nvlist_lookup_nvlist(params, "partial", &partial) != 0) {
6076e4a39ccSPatrick Mooney 			KT_ERROR(ctx, "Input missing partial field");
6086e4a39ccSPatrick Mooney 			nvlist_free(params);
6096e4a39ccSPatrick Mooney 			return (B_FALSE);
6106e4a39ccSPatrick Mooney 		} else {
6116e4a39ccSPatrick Mooney 			nvlist_to_meoi(partial, &mtp->mtp_partial);
6126e4a39ccSPatrick Mooney 		}
6136e4a39ccSPatrick Mooney 
6146e4a39ccSPatrick Mooney 		(void) nvlist_lookup_uint32(params, "offset", &mtp->mtp_offset);
6156e4a39ccSPatrick Mooney 	}
6166e4a39ccSPatrick Mooney 
6176e4a39ccSPatrick Mooney 	mtp->mtp_mp = alloc_split_pkt(ctx, params, "pkt_bytes");
6186e4a39ccSPatrick Mooney 	if (mtp->mtp_mp == NULL) {
6196e4a39ccSPatrick Mooney 		nvlist_free(params);
6206e4a39ccSPatrick Mooney 		return (B_FALSE);
6216e4a39ccSPatrick Mooney 	}
6226e4a39ccSPatrick Mooney 
6236e4a39ccSPatrick Mooney 	nvlist_to_meoi(results, &mtp->mtp_results);
6246e4a39ccSPatrick Mooney 
6256e4a39ccSPatrick Mooney 	nvlist_free(params);
6266e4a39ccSPatrick Mooney 	return (B_TRUE);
6276e4a39ccSPatrick Mooney }
6286e4a39ccSPatrick Mooney 
6296e4a39ccSPatrick Mooney void
mac_ether_offload_info_test(ktest_ctx_hdl_t * ctx)6306e4a39ccSPatrick Mooney mac_ether_offload_info_test(ktest_ctx_hdl_t *ctx)
6316e4a39ccSPatrick Mooney {
6326e4a39ccSPatrick Mooney 	meoi_test_params_t mtp = { 0 };
6336e4a39ccSPatrick Mooney 
6346e4a39ccSPatrick Mooney 	if (!meoi_test_parse_input(ctx, &mtp, B_FALSE)) {
6356e4a39ccSPatrick Mooney 		return;
6366e4a39ccSPatrick Mooney 	}
6376e4a39ccSPatrick Mooney 
6386e4a39ccSPatrick Mooney 	mac_ether_offload_info_t result;
639ca28c3d8SPatrick Mooney 	mac_ether_offload_info(mtp.mtp_mp, &result);
6406e4a39ccSPatrick Mooney 
6416e4a39ccSPatrick Mooney 	const mac_ether_offload_info_t *expect = &mtp.mtp_results;
6426e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_flags, ==, expect->meoi_flags, ctx, done);
6436e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l2hlen, ==, expect->meoi_l2hlen, ctx, done);
6446e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l3proto, ==, expect->meoi_l3proto, ctx, done);
6456e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l3hlen, ==, expect->meoi_l3hlen, ctx, done);
6466e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l4proto, ==, expect->meoi_l4proto, ctx, done);
6476e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result.meoi_l4hlen, ==, expect->meoi_l4hlen, ctx, done);
6486e4a39ccSPatrick Mooney 
6496e4a39ccSPatrick Mooney 	KT_PASS(ctx);
6506e4a39ccSPatrick Mooney 
6516e4a39ccSPatrick Mooney done:
6526e4a39ccSPatrick Mooney 	freemsg(mtp.mtp_mp);
6536e4a39ccSPatrick Mooney }
6546e4a39ccSPatrick Mooney 
6556e4a39ccSPatrick Mooney void
mac_partial_offload_info_test(ktest_ctx_hdl_t * ctx)6566e4a39ccSPatrick Mooney mac_partial_offload_info_test(ktest_ctx_hdl_t *ctx)
6576e4a39ccSPatrick Mooney {
6586e4a39ccSPatrick Mooney 	meoi_test_params_t mtp = { 0 };
6596e4a39ccSPatrick Mooney 
6606e4a39ccSPatrick Mooney 	if (!meoi_test_parse_input(ctx, &mtp, B_TRUE)) {
6616e4a39ccSPatrick Mooney 		return;
6626e4a39ccSPatrick Mooney 	}
6636e4a39ccSPatrick Mooney 
6646e4a39ccSPatrick Mooney 	mac_ether_offload_info_t *result = &mtp.mtp_partial;
665ca28c3d8SPatrick Mooney 	mac_partial_offload_info(mtp.mtp_mp, mtp.mtp_offset, result);
6666e4a39ccSPatrick Mooney 
6676e4a39ccSPatrick Mooney 	const mac_ether_offload_info_t *expect = &mtp.mtp_results;
6686e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_flags, ==, expect->meoi_flags, ctx, done);
6696e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l2hlen, ==, expect->meoi_l2hlen, ctx, done);
6706e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l3proto, ==, expect->meoi_l3proto, ctx, done);
6716e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l3hlen, ==, expect->meoi_l3hlen, ctx, done);
6726e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l4proto, ==, expect->meoi_l4proto, ctx, done);
6736e4a39ccSPatrick Mooney 	KT_ASSERT3UG(result->meoi_l4hlen, ==, expect->meoi_l4hlen, ctx, done);
6746e4a39ccSPatrick Mooney 
6756e4a39ccSPatrick Mooney 	KT_PASS(ctx);
6766e4a39ccSPatrick Mooney 
6776e4a39ccSPatrick Mooney done:
6786e4a39ccSPatrick Mooney 	freemsg(mtp.mtp_mp);
6796e4a39ccSPatrick Mooney }
6806e4a39ccSPatrick Mooney 
6816e4a39ccSPatrick Mooney typedef struct ether_test_params {
6826e4a39ccSPatrick Mooney 	mblk_t		*etp_mp;
6836e4a39ccSPatrick Mooney 	uint32_t	etp_tci;
6846e4a39ccSPatrick Mooney 	uint8_t		etp_dstaddr[ETHERADDRL];
6856e4a39ccSPatrick Mooney 	boolean_t	etp_is_err;
6866e4a39ccSPatrick Mooney } ether_test_params_t;
6876e4a39ccSPatrick Mooney 
6886e4a39ccSPatrick Mooney /*
6896e4a39ccSPatrick Mooney  * mac_ether_l2_info tests expect the following as input (via packed nvlist)
6906e4a39ccSPatrick Mooney  *
6916e4a39ccSPatrick Mooney  * - pkt_bytes (byte array): packet bytes to parse
6926e4a39ccSPatrick Mooney  * - splits (uint32 array, optional): byte sizes to split packet into mblks
6936e4a39ccSPatrick Mooney  * - tci (uint32): VLAN TCI result value to compare
6946e4a39ccSPatrick Mooney  * - dstaddr (byte array): MAC addr result value to compare
6956e4a39ccSPatrick Mooney  * - is_err (boolean): if test function should return error
6966e4a39ccSPatrick Mooney  */
6976e4a39ccSPatrick Mooney static boolean_t
ether_parse_input(ktest_ctx_hdl_t * ctx,ether_test_params_t * etp)6986e4a39ccSPatrick Mooney ether_parse_input(ktest_ctx_hdl_t *ctx, ether_test_params_t *etp)
6996e4a39ccSPatrick Mooney {
7006e4a39ccSPatrick Mooney 	uchar_t *bytes;
7016e4a39ccSPatrick Mooney 	size_t num_bytes = 0;
7026e4a39ccSPatrick Mooney 
7036e4a39ccSPatrick Mooney 	ktest_get_input(ctx, &bytes, &num_bytes);
7046e4a39ccSPatrick Mooney 	bzero(etp, sizeof (*etp));
7056e4a39ccSPatrick Mooney 
7066e4a39ccSPatrick Mooney 	nvlist_t *params = NULL;
7076e4a39ccSPatrick Mooney 	if (nvlist_unpack((char *)bytes, num_bytes, &params, KM_SLEEP) != 0) {
7086e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Invalid nvlist input");
7096e4a39ccSPatrick Mooney 		return (B_FALSE);
7106e4a39ccSPatrick Mooney 	}
7116e4a39ccSPatrick Mooney 
7126e4a39ccSPatrick Mooney 	etp->etp_mp = alloc_split_pkt(ctx, params, "pkt_bytes");
7136e4a39ccSPatrick Mooney 	if (etp->etp_mp == NULL) {
7146e4a39ccSPatrick Mooney 		nvlist_free(params);
7156e4a39ccSPatrick Mooney 		return (B_FALSE);
7166e4a39ccSPatrick Mooney 	}
7176e4a39ccSPatrick Mooney 
7186e4a39ccSPatrick Mooney 	if (nvlist_lookup_uint32(params, "tci", &etp->etp_tci) != 0) {
7196e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing tci field");
7206e4a39ccSPatrick Mooney 		nvlist_free(params);
7216e4a39ccSPatrick Mooney 		return (B_FALSE);
7226e4a39ccSPatrick Mooney 	}
7236e4a39ccSPatrick Mooney 
7246e4a39ccSPatrick Mooney 	uchar_t *dstaddr;
7256e4a39ccSPatrick Mooney 	uint_t dstaddr_sz;
7266e4a39ccSPatrick Mooney 	if (nvlist_lookup_byte_array(params, "dstaddr", &dstaddr,
7276e4a39ccSPatrick Mooney 	    &dstaddr_sz) != 0) {
7286e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "Input missing dstaddr field");
7296e4a39ccSPatrick Mooney 		nvlist_free(params);
7306e4a39ccSPatrick Mooney 		return (B_FALSE);
7316e4a39ccSPatrick Mooney 	} else if (dstaddr_sz != ETHERADDRL) {
7326e4a39ccSPatrick Mooney 		KT_ERROR(ctx, "bad dstaddr size %u != %u", dstaddr_sz,
7336e4a39ccSPatrick Mooney 		    ETHERADDRL);
7346e4a39ccSPatrick Mooney 		nvlist_free(params);
7356e4a39ccSPatrick Mooney 		return (B_FALSE);
7366e4a39ccSPatrick Mooney 	}
7376e4a39ccSPatrick Mooney 	bcopy(dstaddr, &etp->etp_dstaddr, ETHERADDRL);
7386e4a39ccSPatrick Mooney 
7396e4a39ccSPatrick Mooney 	etp->etp_is_err = nvlist_lookup_boolean(params, "is_err") == 0;
7406e4a39ccSPatrick Mooney 
7416e4a39ccSPatrick Mooney 	nvlist_free(params);
7426e4a39ccSPatrick Mooney 	return (B_TRUE);
7436e4a39ccSPatrick Mooney }
7446e4a39ccSPatrick Mooney 
7456e4a39ccSPatrick Mooney void
mac_ether_l2_info_test(ktest_ctx_hdl_t * ctx)7466e4a39ccSPatrick Mooney mac_ether_l2_info_test(ktest_ctx_hdl_t *ctx)
7476e4a39ccSPatrick Mooney {
7486e4a39ccSPatrick Mooney 	ether_test_params_t etp = { 0 };
7496e4a39ccSPatrick Mooney 
7506e4a39ccSPatrick Mooney 	if (!ether_parse_input(ctx, &etp)) {
7516e4a39ccSPatrick Mooney 		return;
7526e4a39ccSPatrick Mooney 	}
7536e4a39ccSPatrick Mooney 
7546e4a39ccSPatrick Mooney 	uint8_t dstaddr[ETHERADDRL];
7556e4a39ccSPatrick Mooney 	uint32_t vlan_tci = 0;
7566e4a39ccSPatrick Mooney 	const boolean_t is_err =
757ca28c3d8SPatrick Mooney 	    !mac_ether_l2_info(etp.etp_mp, dstaddr, &vlan_tci);
7586e4a39ccSPatrick Mooney 
7596e4a39ccSPatrick Mooney 	KT_ASSERTG(is_err == etp.etp_is_err, ctx, done);
7606e4a39ccSPatrick Mooney 	KT_ASSERTG(bcmp(dstaddr, etp.etp_dstaddr, ETHERADDRL) == 0, ctx,
7616e4a39ccSPatrick Mooney 	    done);
7626e4a39ccSPatrick Mooney 	KT_ASSERT3UG(vlan_tci, ==, etp.etp_tci, ctx, done);
7636e4a39ccSPatrick Mooney 
7646e4a39ccSPatrick Mooney 	KT_PASS(ctx);
7656e4a39ccSPatrick Mooney 
7666e4a39ccSPatrick Mooney done:
7676e4a39ccSPatrick Mooney 	freemsg(etp.etp_mp);
7686e4a39ccSPatrick Mooney }
7696e4a39ccSPatrick Mooney 
7706e4a39ccSPatrick Mooney 
7716e4a39ccSPatrick Mooney static struct modlmisc mac_ktest_modlmisc = {
7726e4a39ccSPatrick Mooney 	.misc_modops = &mod_miscops,
7736e4a39ccSPatrick Mooney 	.misc_linkinfo = "mac ktest module"
7746e4a39ccSPatrick Mooney };
7756e4a39ccSPatrick Mooney 
7766e4a39ccSPatrick Mooney static struct modlinkage mac_ktest_modlinkage = {
7776e4a39ccSPatrick Mooney 	.ml_rev = MODREV_1,
7786e4a39ccSPatrick Mooney 	.ml_linkage = { &mac_ktest_modlmisc, NULL }
7796e4a39ccSPatrick Mooney };
7806e4a39ccSPatrick Mooney 
7816e4a39ccSPatrick Mooney int
_init()7826e4a39ccSPatrick Mooney _init()
7836e4a39ccSPatrick Mooney {
7846e4a39ccSPatrick Mooney 	int ret;
7856e4a39ccSPatrick Mooney 	ktest_module_hdl_t *km = NULL;
7866e4a39ccSPatrick Mooney 	ktest_suite_hdl_t *ks = NULL;
7876e4a39ccSPatrick Mooney 
7886e4a39ccSPatrick Mooney 	VERIFY0(ktest_create_module("mac", &km));
7896e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_suite(km, "checksum", &ks));
7903d6ee46bSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_sw_cksum_test",
7913d6ee46bSPatrick Mooney 	    mac_sw_cksum_test, KTEST_FLAG_INPUT));
7926e4a39ccSPatrick Mooney 
7936e4a39ccSPatrick Mooney 	ks = NULL;
7946e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_suite(km, "parsing", &ks));
7956e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_ether_offload_info_test",
7966e4a39ccSPatrick Mooney 	    mac_ether_offload_info_test, KTEST_FLAG_INPUT));
7976e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_partial_offload_info_test",
7986e4a39ccSPatrick Mooney 	    mac_partial_offload_info_test, KTEST_FLAG_INPUT));
7996e4a39ccSPatrick Mooney 	VERIFY0(ktest_add_test(ks, "mac_ether_l2_info_test",
8006e4a39ccSPatrick Mooney 	    mac_ether_l2_info_test, KTEST_FLAG_INPUT));
8016e4a39ccSPatrick Mooney 
8026e4a39ccSPatrick Mooney 	if ((ret = ktest_register_module(km)) != 0) {
8036e4a39ccSPatrick Mooney 		ktest_free_module(km);
8046e4a39ccSPatrick Mooney 		return (ret);
8056e4a39ccSPatrick Mooney 	}
8066e4a39ccSPatrick Mooney 
8076e4a39ccSPatrick Mooney 	if ((ret = mod_install(&mac_ktest_modlinkage)) != 0) {
8086e4a39ccSPatrick Mooney 		ktest_unregister_module("mac");
8096e4a39ccSPatrick Mooney 		return (ret);
8106e4a39ccSPatrick Mooney 	}
8116e4a39ccSPatrick Mooney 
8126e4a39ccSPatrick Mooney 	return (0);
8136e4a39ccSPatrick Mooney }
8146e4a39ccSPatrick Mooney 
8156e4a39ccSPatrick Mooney int
_fini(void)8166e4a39ccSPatrick Mooney _fini(void)
8176e4a39ccSPatrick Mooney {
8186e4a39ccSPatrick Mooney 	ktest_unregister_module("mac");
8196e4a39ccSPatrick Mooney 	return (mod_remove(&mac_ktest_modlinkage));
8206e4a39ccSPatrick Mooney }
8216e4a39ccSPatrick Mooney 
8226e4a39ccSPatrick Mooney int
_info(struct modinfo * modinfop)8236e4a39ccSPatrick Mooney _info(struct modinfo *modinfop)
8246e4a39ccSPatrick Mooney {
8256e4a39ccSPatrick Mooney 	return (mod_info(&mac_ktest_modlinkage, modinfop));
8266e4a39ccSPatrick Mooney }
827