xref: /illumos-gate/usr/src/test/os-tests/tests/mac/mac_ktest_common.c (revision 10597944279b73141546abca67a8e947810e5bb2)
1*10597944SRyan Goodfellow /*
2*10597944SRyan Goodfellow  * This file and its contents are supplied under the terms of the
3*10597944SRyan Goodfellow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*10597944SRyan Goodfellow  * You may only use this file in accordance with the terms of version
5*10597944SRyan Goodfellow  * 1.0 of the CDDL.
6*10597944SRyan Goodfellow  *
7*10597944SRyan Goodfellow  * A full copy of the text of the CDDL should have accompanied this
8*10597944SRyan Goodfellow  * source.  A copy of the CDDL is also available via the Internet at
9*10597944SRyan Goodfellow  * http://www.illumos.org/license/CDDL.
10*10597944SRyan Goodfellow  */
11*10597944SRyan Goodfellow 
12*10597944SRyan Goodfellow /*
13*10597944SRyan Goodfellow  * Copyright 2025 Oxide Computer Compnay
14*10597944SRyan Goodfellow  */
15*10597944SRyan Goodfellow 
16*10597944SRyan Goodfellow #include <stdio.h>
17*10597944SRyan Goodfellow #include <stdlib.h>
18*10597944SRyan Goodfellow #include <fcntl.h>
19*10597944SRyan Goodfellow #include <unistd.h>
20*10597944SRyan Goodfellow #include <err.h>
21*10597944SRyan Goodfellow #include <errno.h>
22*10597944SRyan Goodfellow #include <strings.h>
23*10597944SRyan Goodfellow #include <netinet/in.h>
24*10597944SRyan Goodfellow #include <sys/mman.h>
25*10597944SRyan Goodfellow #include <sys/dlpi.h>
26*10597944SRyan Goodfellow #include <sys/stat.h>
27*10597944SRyan Goodfellow #include <sys/sysmacros.h>
28*10597944SRyan Goodfellow #include <sys/ethernet.h>
29*10597944SRyan Goodfellow 
30*10597944SRyan Goodfellow #include <libnvpair.h>
31*10597944SRyan Goodfellow 
32*10597944SRyan Goodfellow #include "mac_ktest_common.h"
33*10597944SRyan Goodfellow 
34*10597944SRyan Goodfellow static const char snoop_magic[8] = "snoop\0\0\0";
35*10597944SRyan Goodfellow static const uint_t snoop_acceptable_vers = 2;
36*10597944SRyan Goodfellow 
37*10597944SRyan Goodfellow pkt_cap_iter_t *
pkt_cap_open(int fd)38*10597944SRyan Goodfellow pkt_cap_open(int fd)
39*10597944SRyan Goodfellow {
40*10597944SRyan Goodfellow 	struct stat info;
41*10597944SRyan Goodfellow 	if (fstat(fd, &info) != 0) {
42*10597944SRyan Goodfellow 		return (NULL);
43*10597944SRyan Goodfellow 	}
44*10597944SRyan Goodfellow 	if (info.st_size < sizeof (snoop_file_hdr_t)) {
45*10597944SRyan Goodfellow 		errno = EINVAL;
46*10597944SRyan Goodfellow 		return (NULL);
47*10597944SRyan Goodfellow 	}
48*10597944SRyan Goodfellow 
49*10597944SRyan Goodfellow 	const size_t page_sz = (size_t)sysconf(_SC_PAGESIZE);
50*10597944SRyan Goodfellow 	const size_t map_sz = P2ROUNDUP(info.st_size, page_sz);
51*10597944SRyan Goodfellow 	void *map = mmap(NULL, map_sz, PROT_READ, MAP_PRIVATE, fd, 0);
52*10597944SRyan Goodfellow 	if (map == NULL) {
53*10597944SRyan Goodfellow 		return (NULL);
54*10597944SRyan Goodfellow 	}
55*10597944SRyan Goodfellow 
56*10597944SRyan Goodfellow 	const snoop_file_hdr_t *hdr = (const snoop_file_hdr_t *)map;
57*10597944SRyan Goodfellow 	if (bcmp(&hdr->sfh_magic, snoop_magic, sizeof (hdr->sfh_magic)) != 0 ||
58*10597944SRyan Goodfellow 	    ntohl(hdr->sfh_vers) != snoop_acceptable_vers ||
59*10597944SRyan Goodfellow 	    ntohl(hdr->sfh_mac_type) != DL_ETHER) {
60*10597944SRyan Goodfellow 		(void) munmap(map, map_sz);
61*10597944SRyan Goodfellow 		errno = EINVAL;
62*10597944SRyan Goodfellow 		return (NULL);
63*10597944SRyan Goodfellow 	}
64*10597944SRyan Goodfellow 
65*10597944SRyan Goodfellow 	struct pkt_cap_iter *iter = malloc(sizeof (struct pkt_cap_iter));
66*10597944SRyan Goodfellow 	if (iter == NULL) {
67*10597944SRyan Goodfellow 		(void) munmap(map, map_sz);
68*10597944SRyan Goodfellow 		errno = ENOMEM;
69*10597944SRyan Goodfellow 		return (NULL);
70*10597944SRyan Goodfellow 	}
71*10597944SRyan Goodfellow 
72*10597944SRyan Goodfellow 	iter->pci_fd = fd;
73*10597944SRyan Goodfellow 	iter->pci_base = (const char *)map;
74*10597944SRyan Goodfellow 	iter->pci_map_sz = map_sz;
75*10597944SRyan Goodfellow 	iter->pci_sz = info.st_size;
76*10597944SRyan Goodfellow 	iter->pci_offset = sizeof (*hdr);
77*10597944SRyan Goodfellow 
78*10597944SRyan Goodfellow 	return (iter);
79*10597944SRyan Goodfellow }
80*10597944SRyan Goodfellow 
81*10597944SRyan Goodfellow void
pkt_cap_close(pkt_cap_iter_t * iter)82*10597944SRyan Goodfellow pkt_cap_close(pkt_cap_iter_t *iter)
83*10597944SRyan Goodfellow {
84*10597944SRyan Goodfellow 	(void) munmap((void *)iter->pci_base, iter->pci_map_sz);
85*10597944SRyan Goodfellow 	(void) close(iter->pci_fd);
86*10597944SRyan Goodfellow 	free(iter);
87*10597944SRyan Goodfellow }
88*10597944SRyan Goodfellow 
89*10597944SRyan Goodfellow void
pkt_cap_reset(pkt_cap_iter_t * iter)90*10597944SRyan Goodfellow pkt_cap_reset(pkt_cap_iter_t *iter)
91*10597944SRyan Goodfellow {
92*10597944SRyan Goodfellow 	iter->pci_offset = sizeof (snoop_file_hdr_t);
93*10597944SRyan Goodfellow }
94*10597944SRyan Goodfellow 
95*10597944SRyan Goodfellow bool
pkt_cap_next(pkt_cap_iter_t * iter,const void ** pkt_buf,uint_t * sizep)96*10597944SRyan Goodfellow pkt_cap_next(pkt_cap_iter_t *iter, const void **pkt_buf, uint_t *sizep)
97*10597944SRyan Goodfellow {
98*10597944SRyan Goodfellow 	size_t remain = iter->pci_sz - iter->pci_offset;
99*10597944SRyan Goodfellow 
100*10597944SRyan Goodfellow 	if (remain < sizeof (snoop_pkt_hdr_t)) {
101*10597944SRyan Goodfellow 		return (false);
102*10597944SRyan Goodfellow 	}
103*10597944SRyan Goodfellow 
104*10597944SRyan Goodfellow 	const snoop_pkt_hdr_t *hdr =
105*10597944SRyan Goodfellow 	    (const snoop_pkt_hdr_t *)&iter->pci_base[iter->pci_offset];
106*10597944SRyan Goodfellow 
107*10597944SRyan Goodfellow 	const uint_t msg_sz = ntohl(hdr->sph_msglen);
108*10597944SRyan Goodfellow 	const uint_t total_sz = ntohl(hdr->sph_totlen);
109*10597944SRyan Goodfellow 	if (remain < total_sz || remain < msg_sz) {
110*10597944SRyan Goodfellow 		return (false);
111*10597944SRyan Goodfellow 	}
112*10597944SRyan Goodfellow 
113*10597944SRyan Goodfellow 	*pkt_buf = (const void *)&hdr[1];
114*10597944SRyan Goodfellow 	*sizep = msg_sz;
115*10597944SRyan Goodfellow 	iter->pci_offset += total_sz;
116*10597944SRyan Goodfellow 	return (true);
117*10597944SRyan Goodfellow }
118*10597944SRyan Goodfellow 
119*10597944SRyan Goodfellow char *
serialize_pkt_chain(pkt_cap_iter_t * iter,uint_t * sizep)120*10597944SRyan Goodfellow serialize_pkt_chain(pkt_cap_iter_t *iter, uint_t *sizep)
121*10597944SRyan Goodfellow {
122*10597944SRyan Goodfellow 	/*
123*10597944SRyan Goodfellow 	 * First, figure out how many bytes are needed. We're serializing
124*10597944SRyan Goodfellow 	 * down to `uint32_t` (len) + <bytes> for each packet.
125*10597944SRyan Goodfellow 	 */
126*10597944SRyan Goodfellow 	const void *pkt_buf = NULL;
127*10597944SRyan Goodfellow 	*sizep = 0;
128*10597944SRyan Goodfellow 	uint_t pkt_sz;
129*10597944SRyan Goodfellow 	while (pkt_cap_next(iter, &pkt_buf, &pkt_sz)) {
130*10597944SRyan Goodfellow 		*sizep += sizeof (uint32_t) + pkt_sz;
131*10597944SRyan Goodfellow 	}
132*10597944SRyan Goodfellow 
133*10597944SRyan Goodfellow 	/*
134*10597944SRyan Goodfellow 	 * Rewalk, and copy all the bytes out.
135*10597944SRyan Goodfellow 	 */
136*10597944SRyan Goodfellow 	char *out = malloc(*sizep);
137*10597944SRyan Goodfellow 	pkt_cap_reset(iter);
138*10597944SRyan Goodfellow 
139*10597944SRyan Goodfellow 	if (out == NULL)
140*10597944SRyan Goodfellow 		return (out);
141*10597944SRyan Goodfellow 	char *cur = out;
142*10597944SRyan Goodfellow 	while (pkt_cap_next(iter, &pkt_buf, &pkt_sz)) {
143*10597944SRyan Goodfellow 		uint32_t ps = pkt_sz;
144*10597944SRyan Goodfellow 		bcopy(&ps, cur, sizeof (ps));
145*10597944SRyan Goodfellow 		cur += sizeof (ps);
146*10597944SRyan Goodfellow 		bcopy(pkt_buf, cur, pkt_sz);
147*10597944SRyan Goodfellow 		cur += pkt_sz;
148*10597944SRyan Goodfellow 	}
149*10597944SRyan Goodfellow 
150*10597944SRyan Goodfellow 	return (out);
151*10597944SRyan Goodfellow }
152*10597944SRyan Goodfellow 
153*10597944SRyan Goodfellow char *
build_payload(const void * pkt_buf,uint_t pkt_sz,const void * out_pkt_buf,uint_t out_pkt_sz,const struct payload_opts * popts,size_t * payload_sz)154*10597944SRyan Goodfellow build_payload(const void *pkt_buf, uint_t pkt_sz,
155*10597944SRyan Goodfellow     const void *out_pkt_buf, uint_t out_pkt_sz,
156*10597944SRyan Goodfellow     const struct payload_opts *popts, size_t *payload_sz)
157*10597944SRyan Goodfellow {
158*10597944SRyan Goodfellow 	nvlist_t *payload = fnvlist_alloc();
159*10597944SRyan Goodfellow 	fnvlist_add_byte_array(payload, "pkt_bytes",
160*10597944SRyan Goodfellow 	    (uchar_t *)pkt_buf, pkt_sz);
161*10597944SRyan Goodfellow 	if (out_pkt_buf != NULL) {
162*10597944SRyan Goodfellow 		fnvlist_add_byte_array(payload, "out_pkt_bytes",
163*10597944SRyan Goodfellow 		    (uchar_t *)out_pkt_buf, out_pkt_sz);
164*10597944SRyan Goodfellow 	}
165*10597944SRyan Goodfellow 	if (popts->po_mss) {
166*10597944SRyan Goodfellow 		fnvlist_add_uint32(payload, "mss", popts->po_mss);
167*10597944SRyan Goodfellow 	}
168*10597944SRyan Goodfellow 	if (popts->po_padding) {
169*10597944SRyan Goodfellow 		fnvlist_add_uint32(payload, "padding", popts->po_padding);
170*10597944SRyan Goodfellow 	}
171*10597944SRyan Goodfellow 	if (popts->po_cksum_partial) {
172*10597944SRyan Goodfellow 		fnvlist_add_boolean(payload, "cksum_partial");
173*10597944SRyan Goodfellow 	}
174*10597944SRyan Goodfellow 	if (popts->po_cksum_full) {
175*10597944SRyan Goodfellow 		fnvlist_add_boolean(payload, "cksum_full");
176*10597944SRyan Goodfellow 	}
177*10597944SRyan Goodfellow 	if (popts->po_cksum_ipv4) {
178*10597944SRyan Goodfellow 		fnvlist_add_boolean(payload, "cksum_ipv4");
179*10597944SRyan Goodfellow 	}
180*10597944SRyan Goodfellow 
181*10597944SRyan Goodfellow 	uint_t nsplit = 0;
182*10597944SRyan Goodfellow 	uint32_t splits[2];
183*10597944SRyan Goodfellow 	if (popts->po_split_ether) {
184*10597944SRyan Goodfellow 		splits[nsplit++] = sizeof (struct ether_header);
185*10597944SRyan Goodfellow 	}
186*10597944SRyan Goodfellow 	if (popts->po_split_manual != 0) {
187*10597944SRyan Goodfellow 		splits[nsplit++] = popts->po_split_manual;
188*10597944SRyan Goodfellow 	}
189*10597944SRyan Goodfellow 	if (nsplit > 0) {
190*10597944SRyan Goodfellow 		fnvlist_add_uint32_array(payload, "cksum_splits", splits,
191*10597944SRyan Goodfellow 		    nsplit);
192*10597944SRyan Goodfellow 	}
193*10597944SRyan Goodfellow 
194*10597944SRyan Goodfellow 	char *packed = fnvlist_pack(payload, payload_sz);
195*10597944SRyan Goodfellow 	nvlist_free(payload);
196*10597944SRyan Goodfellow 
197*10597944SRyan Goodfellow 	return (packed);
198*10597944SRyan Goodfellow }
199