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