xref: /freebsd-14.2/sys/dev/netmap/netmap_legacy.c (revision 2ff91c17)
1*2ff91c17SVincenzo Maffione /*-
2*2ff91c17SVincenzo Maffione  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*2ff91c17SVincenzo Maffione  *
4*2ff91c17SVincenzo Maffione  * Copyright (C) 2018 Vincenzo Maffione
5*2ff91c17SVincenzo Maffione  * All rights reserved.
6*2ff91c17SVincenzo Maffione  *
7*2ff91c17SVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
8*2ff91c17SVincenzo Maffione  * modification, are permitted provided that the following conditions
9*2ff91c17SVincenzo Maffione  * are met:
10*2ff91c17SVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
11*2ff91c17SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
12*2ff91c17SVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
13*2ff91c17SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
14*2ff91c17SVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
15*2ff91c17SVincenzo Maffione  *
16*2ff91c17SVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*2ff91c17SVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*2ff91c17SVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*2ff91c17SVincenzo Maffione  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*2ff91c17SVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*2ff91c17SVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*2ff91c17SVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*2ff91c17SVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*2ff91c17SVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*2ff91c17SVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*2ff91c17SVincenzo Maffione  * SUCH DAMAGE.
27*2ff91c17SVincenzo Maffione  */
28*2ff91c17SVincenzo Maffione 
29*2ff91c17SVincenzo Maffione /* $FreeBSD$ */
30*2ff91c17SVincenzo Maffione 
31*2ff91c17SVincenzo Maffione #if defined(__FreeBSD__)
32*2ff91c17SVincenzo Maffione #include <sys/cdefs.h> /* prerequisite */
33*2ff91c17SVincenzo Maffione #include <sys/types.h>
34*2ff91c17SVincenzo Maffione #include <sys/param.h>	/* defines used in kernel.h */
35*2ff91c17SVincenzo Maffione #include <sys/filio.h>	/* FIONBIO */
36*2ff91c17SVincenzo Maffione #include <sys/malloc.h>
37*2ff91c17SVincenzo Maffione #include <sys/socketvar.h>	/* struct socket */
38*2ff91c17SVincenzo Maffione #include <sys/socket.h> /* sockaddrs */
39*2ff91c17SVincenzo Maffione #include <sys/sysctl.h>
40*2ff91c17SVincenzo Maffione #include <net/if.h>
41*2ff91c17SVincenzo Maffione #include <net/if_var.h>
42*2ff91c17SVincenzo Maffione #include <net/bpf.h>		/* BIOCIMMEDIATE */
43*2ff91c17SVincenzo Maffione #include <machine/bus.h>	/* bus_dmamap_* */
44*2ff91c17SVincenzo Maffione #include <sys/endian.h>
45*2ff91c17SVincenzo Maffione #elif defined(linux)
46*2ff91c17SVincenzo Maffione #include "bsd_glue.h"
47*2ff91c17SVincenzo Maffione #elif defined(__APPLE__)
48*2ff91c17SVincenzo Maffione #warning OSX support is only partial
49*2ff91c17SVincenzo Maffione #include "osx_glue.h"
50*2ff91c17SVincenzo Maffione #elif defined (_WIN32)
51*2ff91c17SVincenzo Maffione #include "win_glue.h"
52*2ff91c17SVincenzo Maffione #endif
53*2ff91c17SVincenzo Maffione 
54*2ff91c17SVincenzo Maffione /*
55*2ff91c17SVincenzo Maffione  * common headers
56*2ff91c17SVincenzo Maffione  */
57*2ff91c17SVincenzo Maffione #include <net/netmap.h>
58*2ff91c17SVincenzo Maffione #include <dev/netmap/netmap_kern.h>
59*2ff91c17SVincenzo Maffione 
60*2ff91c17SVincenzo Maffione static int
61*2ff91c17SVincenzo Maffione nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
62*2ff91c17SVincenzo Maffione 				struct nmreq_register *req)
63*2ff91c17SVincenzo Maffione {
64*2ff91c17SVincenzo Maffione 	req->nr_offset = nmr->nr_offset;
65*2ff91c17SVincenzo Maffione 	req->nr_memsize = nmr->nr_memsize;
66*2ff91c17SVincenzo Maffione 	req->nr_tx_slots = nmr->nr_tx_slots;
67*2ff91c17SVincenzo Maffione 	req->nr_rx_slots = nmr->nr_rx_slots;
68*2ff91c17SVincenzo Maffione 	req->nr_tx_rings = nmr->nr_tx_rings;
69*2ff91c17SVincenzo Maffione 	req->nr_rx_rings = nmr->nr_rx_rings;
70*2ff91c17SVincenzo Maffione 	req->nr_mem_id = nmr->nr_arg2;
71*2ff91c17SVincenzo Maffione 	req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
72*2ff91c17SVincenzo Maffione 	if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
73*2ff91c17SVincenzo Maffione 		/* Convert the older nmr->nr_ringid (original
74*2ff91c17SVincenzo Maffione 		 * netmap control API) to nmr->nr_flags. */
75*2ff91c17SVincenzo Maffione 		u_int regmode = NR_REG_DEFAULT;
76*2ff91c17SVincenzo Maffione 		if (req->nr_ringid & NETMAP_SW_RING) {
77*2ff91c17SVincenzo Maffione 			regmode = NR_REG_SW;
78*2ff91c17SVincenzo Maffione 		} else if (req->nr_ringid & NETMAP_HW_RING) {
79*2ff91c17SVincenzo Maffione 			regmode = NR_REG_ONE_NIC;
80*2ff91c17SVincenzo Maffione 		} else {
81*2ff91c17SVincenzo Maffione 			regmode = NR_REG_ALL_NIC;
82*2ff91c17SVincenzo Maffione 		}
83*2ff91c17SVincenzo Maffione 		nmr->nr_flags = regmode |
84*2ff91c17SVincenzo Maffione 			(nmr->nr_flags & (~NR_REG_MASK));
85*2ff91c17SVincenzo Maffione 	}
86*2ff91c17SVincenzo Maffione 	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
87*2ff91c17SVincenzo Maffione 	/* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */
88*2ff91c17SVincenzo Maffione 	if (req->nr_mode == NR_REG_PIPE_MASTER ||
89*2ff91c17SVincenzo Maffione 			req->nr_mode == NR_REG_PIPE_SLAVE) {
90*2ff91c17SVincenzo Maffione 		char suffix[10];
91*2ff91c17SVincenzo Maffione 		snprintf(suffix, sizeof(suffix), "%c%d",
92*2ff91c17SVincenzo Maffione 			(req->nr_mode == NR_REG_PIPE_MASTER ? '{' : '}'),
93*2ff91c17SVincenzo Maffione 			req->nr_ringid);
94*2ff91c17SVincenzo Maffione 		if (strlen(hdr->nr_name) + strlen(suffix)
95*2ff91c17SVincenzo Maffione 					>= sizeof(hdr->nr_name)) {
96*2ff91c17SVincenzo Maffione 			/* No space for the pipe suffix. */
97*2ff91c17SVincenzo Maffione 			return ENOBUFS;
98*2ff91c17SVincenzo Maffione 		}
99*2ff91c17SVincenzo Maffione 		strncat(hdr->nr_name, suffix, strlen(suffix));
100*2ff91c17SVincenzo Maffione 		req->nr_mode = NR_REG_ALL_NIC;
101*2ff91c17SVincenzo Maffione 		req->nr_ringid = 0;
102*2ff91c17SVincenzo Maffione 	}
103*2ff91c17SVincenzo Maffione 	req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
104*2ff91c17SVincenzo Maffione 	if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
105*2ff91c17SVincenzo Maffione 		req->nr_flags |= NR_NO_TX_POLL;
106*2ff91c17SVincenzo Maffione 	}
107*2ff91c17SVincenzo Maffione 	if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
108*2ff91c17SVincenzo Maffione 		req->nr_flags |= NR_DO_RX_POLL;
109*2ff91c17SVincenzo Maffione 	}
110*2ff91c17SVincenzo Maffione 	/* nmr->nr_arg1 (nr_pipes) ignored */
111*2ff91c17SVincenzo Maffione 	req->nr_extra_bufs = nmr->nr_arg3;
112*2ff91c17SVincenzo Maffione 
113*2ff91c17SVincenzo Maffione 	return 0;
114*2ff91c17SVincenzo Maffione }
115*2ff91c17SVincenzo Maffione 
116*2ff91c17SVincenzo Maffione /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
117*2ff91c17SVincenzo Maffione  * (new API). The new struct is dynamically allocated. */
118*2ff91c17SVincenzo Maffione static struct nmreq_header *
119*2ff91c17SVincenzo Maffione nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
120*2ff91c17SVincenzo Maffione {
121*2ff91c17SVincenzo Maffione 	struct nmreq_header *hdr = nm_os_malloc(sizeof(*hdr));
122*2ff91c17SVincenzo Maffione 
123*2ff91c17SVincenzo Maffione 	if (hdr == NULL) {
124*2ff91c17SVincenzo Maffione 		goto oom;
125*2ff91c17SVincenzo Maffione 	}
126*2ff91c17SVincenzo Maffione 
127*2ff91c17SVincenzo Maffione 	/* Sanitize nmr->nr_name by adding the string terminator. */
128*2ff91c17SVincenzo Maffione 	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
129*2ff91c17SVincenzo Maffione 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
130*2ff91c17SVincenzo Maffione 	}
131*2ff91c17SVincenzo Maffione 
132*2ff91c17SVincenzo Maffione 	/* First prepare the request header. */
133*2ff91c17SVincenzo Maffione 	hdr->nr_version = NETMAP_API; /* new API */
134*2ff91c17SVincenzo Maffione 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
135*2ff91c17SVincenzo Maffione 	hdr->nr_options = (uint64_t)NULL;
136*2ff91c17SVincenzo Maffione 	hdr->nr_body = (uint64_t)NULL;
137*2ff91c17SVincenzo Maffione 
138*2ff91c17SVincenzo Maffione 	switch (ioctl_cmd) {
139*2ff91c17SVincenzo Maffione 	case NIOCREGIF: {
140*2ff91c17SVincenzo Maffione 		switch (nmr->nr_cmd) {
141*2ff91c17SVincenzo Maffione 		case 0: {
142*2ff91c17SVincenzo Maffione 			/* Regular NIOCREGIF operation. */
143*2ff91c17SVincenzo Maffione 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
144*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
145*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
146*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
147*2ff91c17SVincenzo Maffione 			if (nmreq_register_from_legacy(nmr, hdr, req)) {
148*2ff91c17SVincenzo Maffione 				goto oom;
149*2ff91c17SVincenzo Maffione 			}
150*2ff91c17SVincenzo Maffione 			break;
151*2ff91c17SVincenzo Maffione 		}
152*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_ATTACH: {
153*2ff91c17SVincenzo Maffione 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
154*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
155*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
156*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
157*2ff91c17SVincenzo Maffione 			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
158*2ff91c17SVincenzo Maffione 				goto oom;
159*2ff91c17SVincenzo Maffione 			}
160*2ff91c17SVincenzo Maffione 			/* Fix nr_mode, starting from nr_arg1. */
161*2ff91c17SVincenzo Maffione 			if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
162*2ff91c17SVincenzo Maffione 				req->reg.nr_mode = NR_REG_NIC_SW;
163*2ff91c17SVincenzo Maffione 			} else {
164*2ff91c17SVincenzo Maffione 				req->reg.nr_mode = NR_REG_ALL_NIC;
165*2ff91c17SVincenzo Maffione 			}
166*2ff91c17SVincenzo Maffione 			break;
167*2ff91c17SVincenzo Maffione 		}
168*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_DETACH: {
169*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
170*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)nm_os_malloc(sizeof(struct nmreq_vale_detach));
171*2ff91c17SVincenzo Maffione 			break;
172*2ff91c17SVincenzo Maffione 		}
173*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_VNET_HDR:
174*2ff91c17SVincenzo Maffione 		case NETMAP_VNET_HDR_GET: {
175*2ff91c17SVincenzo Maffione 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
176*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
177*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
178*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
179*2ff91c17SVincenzo Maffione 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
180*2ff91c17SVincenzo Maffione 			req->nr_hdr_len = nmr->nr_arg1;
181*2ff91c17SVincenzo Maffione 			break;
182*2ff91c17SVincenzo Maffione 		}
183*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_NEWIF : {
184*2ff91c17SVincenzo Maffione 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
185*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
186*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
187*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
188*2ff91c17SVincenzo Maffione 			req->nr_tx_slots = nmr->nr_tx_slots;
189*2ff91c17SVincenzo Maffione 			req->nr_rx_slots = nmr->nr_rx_slots;
190*2ff91c17SVincenzo Maffione 			req->nr_tx_rings = nmr->nr_tx_rings;
191*2ff91c17SVincenzo Maffione 			req->nr_rx_rings = nmr->nr_rx_rings;
192*2ff91c17SVincenzo Maffione 			req->nr_mem_id = nmr->nr_arg2;
193*2ff91c17SVincenzo Maffione 			break;
194*2ff91c17SVincenzo Maffione 		}
195*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_DELIF: {
196*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_VALE_DELIF;
197*2ff91c17SVincenzo Maffione 			break;
198*2ff91c17SVincenzo Maffione 		}
199*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_POLLING_ON:
200*2ff91c17SVincenzo Maffione 		case NETMAP_BDG_POLLING_OFF: {
201*2ff91c17SVincenzo Maffione 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
202*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
203*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
204*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
205*2ff91c17SVincenzo Maffione 				NETMAP_REQ_VALE_POLLING_ENABLE :
206*2ff91c17SVincenzo Maffione 				NETMAP_REQ_VALE_POLLING_DISABLE;
207*2ff91c17SVincenzo Maffione 			switch (nmr->nr_flags & NR_REG_MASK) {
208*2ff91c17SVincenzo Maffione 			default:
209*2ff91c17SVincenzo Maffione 				req->nr_mode = 0; /* invalid */
210*2ff91c17SVincenzo Maffione 				break;
211*2ff91c17SVincenzo Maffione 			case NR_REG_ONE_NIC:
212*2ff91c17SVincenzo Maffione 				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
213*2ff91c17SVincenzo Maffione 				break;
214*2ff91c17SVincenzo Maffione 			case NR_REG_ALL_NIC:
215*2ff91c17SVincenzo Maffione 				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
216*2ff91c17SVincenzo Maffione 				break;
217*2ff91c17SVincenzo Maffione 			}
218*2ff91c17SVincenzo Maffione 			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
219*2ff91c17SVincenzo Maffione 			req->nr_num_polling_cpus = nmr->nr_arg1;
220*2ff91c17SVincenzo Maffione 			break;
221*2ff91c17SVincenzo Maffione 		}
222*2ff91c17SVincenzo Maffione 		case NETMAP_PT_HOST_CREATE:
223*2ff91c17SVincenzo Maffione 		case NETMAP_PT_HOST_DELETE: {
224*2ff91c17SVincenzo Maffione 			D("Netmap passthrough not supported yet");
225*2ff91c17SVincenzo Maffione 			return NULL;
226*2ff91c17SVincenzo Maffione 			break;
227*2ff91c17SVincenzo Maffione 		}
228*2ff91c17SVincenzo Maffione 		}
229*2ff91c17SVincenzo Maffione 		break;
230*2ff91c17SVincenzo Maffione 	}
231*2ff91c17SVincenzo Maffione 	case NIOCGINFO: {
232*2ff91c17SVincenzo Maffione 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
233*2ff91c17SVincenzo Maffione 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
234*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
235*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
236*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
237*2ff91c17SVincenzo Maffione 			req->nr_bridge_idx = nmr->nr_arg1;
238*2ff91c17SVincenzo Maffione 			req->nr_port_idx = nmr->nr_arg2;
239*2ff91c17SVincenzo Maffione 		} else {
240*2ff91c17SVincenzo Maffione 			/* Regular NIOCGINFO. */
241*2ff91c17SVincenzo Maffione 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
242*2ff91c17SVincenzo Maffione 			if (!req) { goto oom; }
243*2ff91c17SVincenzo Maffione 			hdr->nr_body = (uint64_t)req;
244*2ff91c17SVincenzo Maffione 			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
245*2ff91c17SVincenzo Maffione 			req->nr_offset = nmr->nr_offset;
246*2ff91c17SVincenzo Maffione 			req->nr_memsize = nmr->nr_memsize;
247*2ff91c17SVincenzo Maffione 			req->nr_tx_slots = nmr->nr_tx_slots;
248*2ff91c17SVincenzo Maffione 			req->nr_rx_slots = nmr->nr_rx_slots;
249*2ff91c17SVincenzo Maffione 			req->nr_tx_rings = nmr->nr_tx_rings;
250*2ff91c17SVincenzo Maffione 			req->nr_rx_rings = nmr->nr_rx_rings;
251*2ff91c17SVincenzo Maffione 			req->nr_mem_id = nmr->nr_arg2;
252*2ff91c17SVincenzo Maffione 		}
253*2ff91c17SVincenzo Maffione 		break;
254*2ff91c17SVincenzo Maffione 	}
255*2ff91c17SVincenzo Maffione 	}
256*2ff91c17SVincenzo Maffione 
257*2ff91c17SVincenzo Maffione 	return hdr;
258*2ff91c17SVincenzo Maffione oom:
259*2ff91c17SVincenzo Maffione 	if (hdr) {
260*2ff91c17SVincenzo Maffione 		if (hdr->nr_body) {
261*2ff91c17SVincenzo Maffione 			nm_os_free((void *)hdr->nr_body);
262*2ff91c17SVincenzo Maffione 		}
263*2ff91c17SVincenzo Maffione 		nm_os_free(hdr);
264*2ff91c17SVincenzo Maffione 	}
265*2ff91c17SVincenzo Maffione 	D("Failed to allocate memory for nmreq_xyz struct");
266*2ff91c17SVincenzo Maffione 
267*2ff91c17SVincenzo Maffione 	return NULL;
268*2ff91c17SVincenzo Maffione }
269*2ff91c17SVincenzo Maffione 
270*2ff91c17SVincenzo Maffione static void
271*2ff91c17SVincenzo Maffione nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
272*2ff91c17SVincenzo Maffione {
273*2ff91c17SVincenzo Maffione 	nmr->nr_offset = req->nr_offset;
274*2ff91c17SVincenzo Maffione 	nmr->nr_memsize = req->nr_memsize;
275*2ff91c17SVincenzo Maffione 	nmr->nr_tx_slots = req->nr_tx_slots;
276*2ff91c17SVincenzo Maffione 	nmr->nr_rx_slots = req->nr_rx_slots;
277*2ff91c17SVincenzo Maffione 	nmr->nr_tx_rings = req->nr_tx_rings;
278*2ff91c17SVincenzo Maffione 	nmr->nr_rx_rings = req->nr_rx_rings;
279*2ff91c17SVincenzo Maffione 	nmr->nr_arg2 = req->nr_mem_id;
280*2ff91c17SVincenzo Maffione 	nmr->nr_arg3 = req->nr_extra_bufs;
281*2ff91c17SVincenzo Maffione }
282*2ff91c17SVincenzo Maffione 
283*2ff91c17SVincenzo Maffione /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
284*2ff91c17SVincenzo Maffione  * It also frees the nmreq_xyz struct, as it was allocated by
285*2ff91c17SVincenzo Maffione  * nmreq_from_legacy(). */
286*2ff91c17SVincenzo Maffione static int
287*2ff91c17SVincenzo Maffione nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
288*2ff91c17SVincenzo Maffione {
289*2ff91c17SVincenzo Maffione 	int ret = 0;
290*2ff91c17SVincenzo Maffione 
291*2ff91c17SVincenzo Maffione 	/* We only write-back the fields that the user expects to be
292*2ff91c17SVincenzo Maffione 	 * written back. */
293*2ff91c17SVincenzo Maffione 	switch (hdr->nr_reqtype) {
294*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_REGISTER: {
295*2ff91c17SVincenzo Maffione 		struct nmreq_register *req =
296*2ff91c17SVincenzo Maffione 			(struct nmreq_register *)hdr->nr_body;
297*2ff91c17SVincenzo Maffione 		nmreq_register_to_legacy(req, nmr);
298*2ff91c17SVincenzo Maffione 		break;
299*2ff91c17SVincenzo Maffione 	}
300*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_PORT_INFO_GET: {
301*2ff91c17SVincenzo Maffione 		struct nmreq_port_info_get *req =
302*2ff91c17SVincenzo Maffione 			(struct nmreq_port_info_get *)hdr->nr_body;
303*2ff91c17SVincenzo Maffione 		nmr->nr_offset = req->nr_offset;
304*2ff91c17SVincenzo Maffione 		nmr->nr_memsize = req->nr_memsize;
305*2ff91c17SVincenzo Maffione 		nmr->nr_tx_slots = req->nr_tx_slots;
306*2ff91c17SVincenzo Maffione 		nmr->nr_rx_slots = req->nr_rx_slots;
307*2ff91c17SVincenzo Maffione 		nmr->nr_tx_rings = req->nr_tx_rings;
308*2ff91c17SVincenzo Maffione 		nmr->nr_rx_rings = req->nr_rx_rings;
309*2ff91c17SVincenzo Maffione 		nmr->nr_arg2 = req->nr_mem_id;
310*2ff91c17SVincenzo Maffione 		break;
311*2ff91c17SVincenzo Maffione 	}
312*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_ATTACH: {
313*2ff91c17SVincenzo Maffione 		struct nmreq_vale_attach *req =
314*2ff91c17SVincenzo Maffione 			(struct nmreq_vale_attach *)hdr->nr_body;
315*2ff91c17SVincenzo Maffione 		nmreq_register_to_legacy(&req->reg, nmr);
316*2ff91c17SVincenzo Maffione 		break;
317*2ff91c17SVincenzo Maffione 	}
318*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_DETACH: {
319*2ff91c17SVincenzo Maffione 		break;
320*2ff91c17SVincenzo Maffione 	}
321*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_LIST: {
322*2ff91c17SVincenzo Maffione 		struct nmreq_vale_list *req =
323*2ff91c17SVincenzo Maffione 			(struct nmreq_vale_list *)hdr->nr_body;
324*2ff91c17SVincenzo Maffione 		strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
325*2ff91c17SVincenzo Maffione 		nmr->nr_arg1 = req->nr_bridge_idx;
326*2ff91c17SVincenzo Maffione 		nmr->nr_arg2 = req->nr_port_idx;
327*2ff91c17SVincenzo Maffione 		break;
328*2ff91c17SVincenzo Maffione 	}
329*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_PORT_HDR_SET:
330*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_PORT_HDR_GET: {
331*2ff91c17SVincenzo Maffione 		struct nmreq_port_hdr *req =
332*2ff91c17SVincenzo Maffione 			(struct nmreq_port_hdr *)hdr->nr_body;
333*2ff91c17SVincenzo Maffione 		nmr->nr_arg1 = req->nr_hdr_len;
334*2ff91c17SVincenzo Maffione 		break;
335*2ff91c17SVincenzo Maffione 	}
336*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_NEWIF: {
337*2ff91c17SVincenzo Maffione 		struct nmreq_vale_newif *req =
338*2ff91c17SVincenzo Maffione 			(struct nmreq_vale_newif *)hdr->nr_body;
339*2ff91c17SVincenzo Maffione 		nmr->nr_tx_slots = req->nr_tx_slots;
340*2ff91c17SVincenzo Maffione 		nmr->nr_rx_slots = req->nr_rx_slots;
341*2ff91c17SVincenzo Maffione 		nmr->nr_tx_rings = req->nr_tx_rings;
342*2ff91c17SVincenzo Maffione 		nmr->nr_rx_rings = req->nr_rx_rings;
343*2ff91c17SVincenzo Maffione 		nmr->nr_arg2 = req->nr_mem_id;
344*2ff91c17SVincenzo Maffione 		break;
345*2ff91c17SVincenzo Maffione 	}
346*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_DELIF:
347*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_POLLING_ENABLE:
348*2ff91c17SVincenzo Maffione 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
349*2ff91c17SVincenzo Maffione 		break;
350*2ff91c17SVincenzo Maffione 	}
351*2ff91c17SVincenzo Maffione 	}
352*2ff91c17SVincenzo Maffione 
353*2ff91c17SVincenzo Maffione 	return ret;
354*2ff91c17SVincenzo Maffione }
355*2ff91c17SVincenzo Maffione 
356*2ff91c17SVincenzo Maffione int
357*2ff91c17SVincenzo Maffione netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
358*2ff91c17SVincenzo Maffione 			struct thread *td)
359*2ff91c17SVincenzo Maffione {
360*2ff91c17SVincenzo Maffione 	int error = 0;
361*2ff91c17SVincenzo Maffione 
362*2ff91c17SVincenzo Maffione 	switch (cmd) {
363*2ff91c17SVincenzo Maffione 	case NIOCGINFO:
364*2ff91c17SVincenzo Maffione 	case NIOCREGIF: {
365*2ff91c17SVincenzo Maffione 		/* Request for the legacy control API. Convert it to a
366*2ff91c17SVincenzo Maffione 		 * NIOCCTRL request. */
367*2ff91c17SVincenzo Maffione 		struct nmreq *nmr = (struct nmreq *) data;
368*2ff91c17SVincenzo Maffione 		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
369*2ff91c17SVincenzo Maffione 		if (hdr == NULL) { /* out of memory */
370*2ff91c17SVincenzo Maffione 			return ENOMEM;
371*2ff91c17SVincenzo Maffione 		}
372*2ff91c17SVincenzo Maffione 		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td,
373*2ff91c17SVincenzo Maffione 					/*nr_body_is_user=*/0);
374*2ff91c17SVincenzo Maffione 		if (error == 0) {
375*2ff91c17SVincenzo Maffione 			nmreq_to_legacy(hdr, nmr);
376*2ff91c17SVincenzo Maffione 		}
377*2ff91c17SVincenzo Maffione 		if (hdr->nr_body) {
378*2ff91c17SVincenzo Maffione 			nm_os_free((void *)hdr->nr_body);
379*2ff91c17SVincenzo Maffione 		}
380*2ff91c17SVincenzo Maffione 		nm_os_free(hdr);
381*2ff91c17SVincenzo Maffione 		break;
382*2ff91c17SVincenzo Maffione 	}
383*2ff91c17SVincenzo Maffione #ifdef WITH_VALE
384*2ff91c17SVincenzo Maffione 	case NIOCCONFIG: {
385*2ff91c17SVincenzo Maffione 		struct nm_ifreq *nr = (struct nm_ifreq *)data;
386*2ff91c17SVincenzo Maffione 		error = netmap_bdg_config(nr);
387*2ff91c17SVincenzo Maffione 		break;
388*2ff91c17SVincenzo Maffione 	}
389*2ff91c17SVincenzo Maffione #endif
390*2ff91c17SVincenzo Maffione #ifdef __FreeBSD__
391*2ff91c17SVincenzo Maffione 	case FIONBIO:
392*2ff91c17SVincenzo Maffione 	case FIOASYNC:
393*2ff91c17SVincenzo Maffione 		ND("FIONBIO/FIOASYNC are no-ops");
394*2ff91c17SVincenzo Maffione 		break;
395*2ff91c17SVincenzo Maffione 
396*2ff91c17SVincenzo Maffione 	case BIOCIMMEDIATE:
397*2ff91c17SVincenzo Maffione 	case BIOCGHDRCMPLT:
398*2ff91c17SVincenzo Maffione 	case BIOCSHDRCMPLT:
399*2ff91c17SVincenzo Maffione 	case BIOCSSEESENT:
400*2ff91c17SVincenzo Maffione 		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
401*2ff91c17SVincenzo Maffione 		break;
402*2ff91c17SVincenzo Maffione 
403*2ff91c17SVincenzo Maffione 	default:	/* allow device-specific ioctls */
404*2ff91c17SVincenzo Maffione 	    {
405*2ff91c17SVincenzo Maffione 		struct nmreq *nmr = (struct nmreq *)data;
406*2ff91c17SVincenzo Maffione 		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
407*2ff91c17SVincenzo Maffione 		if (ifp == NULL) {
408*2ff91c17SVincenzo Maffione 			error = ENXIO;
409*2ff91c17SVincenzo Maffione 		} else {
410*2ff91c17SVincenzo Maffione 			struct socket so;
411*2ff91c17SVincenzo Maffione 
412*2ff91c17SVincenzo Maffione 			bzero(&so, sizeof(so));
413*2ff91c17SVincenzo Maffione 			so.so_vnet = ifp->if_vnet;
414*2ff91c17SVincenzo Maffione 			// so->so_proto not null.
415*2ff91c17SVincenzo Maffione 			error = ifioctl(&so, cmd, data, td);
416*2ff91c17SVincenzo Maffione 			if_rele(ifp);
417*2ff91c17SVincenzo Maffione 		}
418*2ff91c17SVincenzo Maffione 		break;
419*2ff91c17SVincenzo Maffione 	    }
420*2ff91c17SVincenzo Maffione 
421*2ff91c17SVincenzo Maffione #else /* linux */
422*2ff91c17SVincenzo Maffione 	default:
423*2ff91c17SVincenzo Maffione 		error = EOPNOTSUPP;
424*2ff91c17SVincenzo Maffione #endif /* linux */
425*2ff91c17SVincenzo Maffione 	}
426*2ff91c17SVincenzo Maffione 
427*2ff91c17SVincenzo Maffione 	return error;
428*2ff91c17SVincenzo Maffione }
429