1341477Svmaffione/* 2341477Svmaffione * Copyright (C) 2018 Vincenzo Maffione 3341477Svmaffione * All rights reserved. 4341477Svmaffione * 5341477Svmaffione * Redistribution and use in source and binary forms, with or without 6341477Svmaffione * modification, are permitted provided that the following conditions 7341477Svmaffione * are met: 8341477Svmaffione * 1. Redistributions of source code must retain the above copyright 9341477Svmaffione * notice, this list of conditions and the following disclaimer. 10341477Svmaffione * 2. Redistributions in binary form must reproduce the above copyright 11341477Svmaffione * notice, this list of conditions and the following disclaimer in the 12341477Svmaffione * documentation and/or other materials provided with the distribution. 13341477Svmaffione * 14341477Svmaffione * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15341477Svmaffione * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16341477Svmaffione * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17341477Svmaffione * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18341477Svmaffione * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19341477Svmaffione * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20341477Svmaffione * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21341477Svmaffione * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22341477Svmaffione * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23341477Svmaffione * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24341477Svmaffione * SUCH DAMAGE. 25341477Svmaffione */ 26341477Svmaffione/* $FreeBSD: stable/11/sys/dev/netmap/netmap_legacy.c 364756 2020-08-25 11:12:30Z vmaffione $ */ 27341477Svmaffione 28341477Svmaffione#if defined(__FreeBSD__) 29341477Svmaffione#include <sys/cdefs.h> /* prerequisite */ 30341477Svmaffione#include <sys/types.h> 31341477Svmaffione#include <sys/param.h> /* defines used in kernel.h */ 32341477Svmaffione#include <sys/filio.h> /* FIONBIO */ 33341477Svmaffione#include <sys/malloc.h> 34341477Svmaffione#include <sys/socketvar.h> /* struct socket */ 35341477Svmaffione#include <sys/socket.h> /* sockaddrs */ 36341477Svmaffione#include <sys/sysctl.h> 37341477Svmaffione#include <net/if.h> 38341477Svmaffione#include <net/if_var.h> 39341477Svmaffione#include <net/bpf.h> /* BIOCIMMEDIATE */ 40341477Svmaffione#include <machine/bus.h> /* bus_dmamap_* */ 41341477Svmaffione#include <sys/endian.h> 42341477Svmaffione#elif defined(linux) 43341477Svmaffione#include "bsd_glue.h" 44341477Svmaffione#elif defined(__APPLE__) 45341477Svmaffione#warning OSX support is only partial 46341477Svmaffione#include "osx_glue.h" 47341477Svmaffione#elif defined (_WIN32) 48341477Svmaffione#include "win_glue.h" 49341477Svmaffione#endif 50341477Svmaffione 51341477Svmaffione/* 52341477Svmaffione * common headers 53341477Svmaffione */ 54341477Svmaffione#include <net/netmap.h> 55341477Svmaffione#include <dev/netmap/netmap_kern.h> 56342033Svmaffione#include <dev/netmap/netmap_bdg.h> 57341477Svmaffione 58341477Svmaffionestatic int 59341477Svmaffionenmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr, 60341477Svmaffione struct nmreq_register *req) 61341477Svmaffione{ 62341477Svmaffione req->nr_offset = nmr->nr_offset; 63341477Svmaffione req->nr_memsize = nmr->nr_memsize; 64341477Svmaffione req->nr_tx_slots = nmr->nr_tx_slots; 65341477Svmaffione req->nr_rx_slots = nmr->nr_rx_slots; 66341477Svmaffione req->nr_tx_rings = nmr->nr_tx_rings; 67341477Svmaffione req->nr_rx_rings = nmr->nr_rx_rings; 68341477Svmaffione req->nr_mem_id = nmr->nr_arg2; 69341477Svmaffione req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK; 70341477Svmaffione if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) { 71341477Svmaffione /* Convert the older nmr->nr_ringid (original 72341477Svmaffione * netmap control API) to nmr->nr_flags. */ 73341477Svmaffione u_int regmode = NR_REG_DEFAULT; 74364756Svmaffione if (nmr->nr_ringid & NETMAP_SW_RING) { 75341477Svmaffione regmode = NR_REG_SW; 76364756Svmaffione } else if (nmr->nr_ringid & NETMAP_HW_RING) { 77341477Svmaffione regmode = NR_REG_ONE_NIC; 78341477Svmaffione } else { 79341477Svmaffione regmode = NR_REG_ALL_NIC; 80341477Svmaffione } 81342033Svmaffione req->nr_mode = regmode; 82342033Svmaffione } else { 83342033Svmaffione req->nr_mode = nmr->nr_flags & NR_REG_MASK; 84341477Svmaffione } 85342033Svmaffione 86341477Svmaffione /* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */ 87341477Svmaffione if (req->nr_mode == NR_REG_PIPE_MASTER || 88341477Svmaffione req->nr_mode == NR_REG_PIPE_SLAVE) { 89341477Svmaffione char suffix[10]; 90341477Svmaffione snprintf(suffix, sizeof(suffix), "%c%d", 91341477Svmaffione (req->nr_mode == NR_REG_PIPE_MASTER ? '{' : '}'), 92341477Svmaffione req->nr_ringid); 93341477Svmaffione if (strlen(hdr->nr_name) + strlen(suffix) 94341477Svmaffione >= sizeof(hdr->nr_name)) { 95341477Svmaffione /* No space for the pipe suffix. */ 96341477Svmaffione return ENOBUFS; 97341477Svmaffione } 98341477Svmaffione strncat(hdr->nr_name, suffix, strlen(suffix)); 99341477Svmaffione req->nr_mode = NR_REG_ALL_NIC; 100341477Svmaffione req->nr_ringid = 0; 101341477Svmaffione } 102341477Svmaffione req->nr_flags = nmr->nr_flags & (~NR_REG_MASK); 103341477Svmaffione if (nmr->nr_ringid & NETMAP_NO_TX_POLL) { 104341477Svmaffione req->nr_flags |= NR_NO_TX_POLL; 105341477Svmaffione } 106341477Svmaffione if (nmr->nr_ringid & NETMAP_DO_RX_POLL) { 107341477Svmaffione req->nr_flags |= NR_DO_RX_POLL; 108341477Svmaffione } 109341477Svmaffione /* nmr->nr_arg1 (nr_pipes) ignored */ 110341477Svmaffione req->nr_extra_bufs = nmr->nr_arg3; 111341477Svmaffione 112341477Svmaffione return 0; 113341477Svmaffione} 114341477Svmaffione 115341477Svmaffione/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs 116341477Svmaffione * (new API). The new struct is dynamically allocated. */ 117341477Svmaffionestatic struct nmreq_header * 118341477Svmaffionenmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd) 119341477Svmaffione{ 120341477Svmaffione struct nmreq_header *hdr = nm_os_malloc(sizeof(*hdr)); 121341477Svmaffione 122341477Svmaffione if (hdr == NULL) { 123341477Svmaffione goto oom; 124341477Svmaffione } 125341477Svmaffione 126341477Svmaffione /* Sanitize nmr->nr_name by adding the string terminator. */ 127341477Svmaffione if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) { 128341477Svmaffione nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0'; 129341477Svmaffione } 130341477Svmaffione 131341477Svmaffione /* First prepare the request header. */ 132341477Svmaffione hdr->nr_version = NETMAP_API; /* new API */ 133342033Svmaffione strlcpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name)); 134341477Svmaffione hdr->nr_options = (uintptr_t)NULL; 135341477Svmaffione hdr->nr_body = (uintptr_t)NULL; 136341477Svmaffione 137341477Svmaffione switch (ioctl_cmd) { 138341477Svmaffione case NIOCREGIF: { 139341477Svmaffione switch (nmr->nr_cmd) { 140341477Svmaffione case 0: { 141341477Svmaffione /* Regular NIOCREGIF operation. */ 142341477Svmaffione struct nmreq_register *req = nm_os_malloc(sizeof(*req)); 143341477Svmaffione if (!req) { goto oom; } 144341477Svmaffione hdr->nr_body = (uintptr_t)req; 145341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_REGISTER; 146341477Svmaffione if (nmreq_register_from_legacy(nmr, hdr, req)) { 147341477Svmaffione goto oom; 148341477Svmaffione } 149341477Svmaffione break; 150341477Svmaffione } 151341477Svmaffione case NETMAP_BDG_ATTACH: { 152341477Svmaffione struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req)); 153341477Svmaffione if (!req) { goto oom; } 154341477Svmaffione hdr->nr_body = (uintptr_t)req; 155341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH; 156341477Svmaffione if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) { 157341477Svmaffione goto oom; 158341477Svmaffione } 159341477Svmaffione /* Fix nr_mode, starting from nr_arg1. */ 160341477Svmaffione if (nmr->nr_arg1 & NETMAP_BDG_HOST) { 161341477Svmaffione req->reg.nr_mode = NR_REG_NIC_SW; 162341477Svmaffione } else { 163341477Svmaffione req->reg.nr_mode = NR_REG_ALL_NIC; 164341477Svmaffione } 165341477Svmaffione break; 166341477Svmaffione } 167341477Svmaffione case NETMAP_BDG_DETACH: { 168341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH; 169341477Svmaffione hdr->nr_body = (uintptr_t)nm_os_malloc(sizeof(struct nmreq_vale_detach)); 170341477Svmaffione break; 171341477Svmaffione } 172341477Svmaffione case NETMAP_BDG_VNET_HDR: 173341477Svmaffione case NETMAP_VNET_HDR_GET: { 174341477Svmaffione struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req)); 175341477Svmaffione if (!req) { goto oom; } 176341477Svmaffione hdr->nr_body = (uintptr_t)req; 177341477Svmaffione hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ? 178341477Svmaffione NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET; 179341477Svmaffione req->nr_hdr_len = nmr->nr_arg1; 180341477Svmaffione break; 181341477Svmaffione } 182341477Svmaffione case NETMAP_BDG_NEWIF : { 183341477Svmaffione struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req)); 184341477Svmaffione if (!req) { goto oom; } 185341477Svmaffione hdr->nr_body = (uintptr_t)req; 186341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF; 187341477Svmaffione req->nr_tx_slots = nmr->nr_tx_slots; 188341477Svmaffione req->nr_rx_slots = nmr->nr_rx_slots; 189341477Svmaffione req->nr_tx_rings = nmr->nr_tx_rings; 190341477Svmaffione req->nr_rx_rings = nmr->nr_rx_rings; 191341477Svmaffione req->nr_mem_id = nmr->nr_arg2; 192341477Svmaffione break; 193341477Svmaffione } 194341477Svmaffione case NETMAP_BDG_DELIF: { 195341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_VALE_DELIF; 196341477Svmaffione break; 197341477Svmaffione } 198341477Svmaffione case NETMAP_BDG_POLLING_ON: 199341477Svmaffione case NETMAP_BDG_POLLING_OFF: { 200341477Svmaffione struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req)); 201341477Svmaffione if (!req) { goto oom; } 202341477Svmaffione hdr->nr_body = (uintptr_t)req; 203341477Svmaffione hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ? 204341477Svmaffione NETMAP_REQ_VALE_POLLING_ENABLE : 205341477Svmaffione NETMAP_REQ_VALE_POLLING_DISABLE; 206341477Svmaffione switch (nmr->nr_flags & NR_REG_MASK) { 207341477Svmaffione default: 208341477Svmaffione req->nr_mode = 0; /* invalid */ 209341477Svmaffione break; 210341477Svmaffione case NR_REG_ONE_NIC: 211341477Svmaffione req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU; 212341477Svmaffione break; 213341477Svmaffione case NR_REG_ALL_NIC: 214341477Svmaffione req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU; 215341477Svmaffione break; 216341477Svmaffione } 217341477Svmaffione req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK; 218341477Svmaffione req->nr_num_polling_cpus = nmr->nr_arg1; 219341477Svmaffione break; 220341477Svmaffione } 221341477Svmaffione case NETMAP_PT_HOST_CREATE: 222341477Svmaffione case NETMAP_PT_HOST_DELETE: { 223342033Svmaffione nm_prerr("Netmap passthrough not supported yet"); 224341477Svmaffione return NULL; 225341477Svmaffione break; 226341477Svmaffione } 227341477Svmaffione } 228341477Svmaffione break; 229341477Svmaffione } 230341477Svmaffione case NIOCGINFO: { 231341477Svmaffione if (nmr->nr_cmd == NETMAP_BDG_LIST) { 232341477Svmaffione struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req)); 233341477Svmaffione if (!req) { goto oom; } 234341477Svmaffione hdr->nr_body = (uintptr_t)req; 235341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_VALE_LIST; 236341477Svmaffione req->nr_bridge_idx = nmr->nr_arg1; 237341477Svmaffione req->nr_port_idx = nmr->nr_arg2; 238341477Svmaffione } else { 239341477Svmaffione /* Regular NIOCGINFO. */ 240341477Svmaffione struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req)); 241341477Svmaffione if (!req) { goto oom; } 242341477Svmaffione hdr->nr_body = (uintptr_t)req; 243341477Svmaffione hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; 244341477Svmaffione req->nr_memsize = nmr->nr_memsize; 245341477Svmaffione req->nr_tx_slots = nmr->nr_tx_slots; 246341477Svmaffione req->nr_rx_slots = nmr->nr_rx_slots; 247341477Svmaffione req->nr_tx_rings = nmr->nr_tx_rings; 248341477Svmaffione req->nr_rx_rings = nmr->nr_rx_rings; 249341477Svmaffione req->nr_mem_id = nmr->nr_arg2; 250341477Svmaffione } 251341477Svmaffione break; 252341477Svmaffione } 253341477Svmaffione } 254341477Svmaffione 255341477Svmaffione return hdr; 256341477Svmaffioneoom: 257341477Svmaffione if (hdr) { 258341477Svmaffione if (hdr->nr_body) { 259341477Svmaffione nm_os_free((void *)(uintptr_t)hdr->nr_body); 260341477Svmaffione } 261341477Svmaffione nm_os_free(hdr); 262341477Svmaffione } 263342033Svmaffione nm_prerr("Failed to allocate memory for nmreq_xyz struct"); 264341477Svmaffione 265341477Svmaffione return NULL; 266341477Svmaffione} 267341477Svmaffione 268341477Svmaffionestatic void 269341477Svmaffionenmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr) 270341477Svmaffione{ 271341477Svmaffione nmr->nr_offset = req->nr_offset; 272341477Svmaffione nmr->nr_memsize = req->nr_memsize; 273341477Svmaffione nmr->nr_tx_slots = req->nr_tx_slots; 274341477Svmaffione nmr->nr_rx_slots = req->nr_rx_slots; 275341477Svmaffione nmr->nr_tx_rings = req->nr_tx_rings; 276341477Svmaffione nmr->nr_rx_rings = req->nr_rx_rings; 277341477Svmaffione nmr->nr_arg2 = req->nr_mem_id; 278341477Svmaffione nmr->nr_arg3 = req->nr_extra_bufs; 279341477Svmaffione} 280341477Svmaffione 281341477Svmaffione/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct. 282341477Svmaffione * It also frees the nmreq_xyz struct, as it was allocated by 283341477Svmaffione * nmreq_from_legacy(). */ 284341477Svmaffionestatic int 285341477Svmaffionenmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr) 286341477Svmaffione{ 287341477Svmaffione int ret = 0; 288341477Svmaffione 289341477Svmaffione /* We only write-back the fields that the user expects to be 290341477Svmaffione * written back. */ 291341477Svmaffione switch (hdr->nr_reqtype) { 292341477Svmaffione case NETMAP_REQ_REGISTER: { 293341477Svmaffione struct nmreq_register *req = 294341477Svmaffione (struct nmreq_register *)(uintptr_t)hdr->nr_body; 295341477Svmaffione nmreq_register_to_legacy(req, nmr); 296341477Svmaffione break; 297341477Svmaffione } 298341477Svmaffione case NETMAP_REQ_PORT_INFO_GET: { 299341477Svmaffione struct nmreq_port_info_get *req = 300341477Svmaffione (struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body; 301341477Svmaffione nmr->nr_memsize = req->nr_memsize; 302341477Svmaffione nmr->nr_tx_slots = req->nr_tx_slots; 303341477Svmaffione nmr->nr_rx_slots = req->nr_rx_slots; 304341477Svmaffione nmr->nr_tx_rings = req->nr_tx_rings; 305341477Svmaffione nmr->nr_rx_rings = req->nr_rx_rings; 306341477Svmaffione nmr->nr_arg2 = req->nr_mem_id; 307341477Svmaffione break; 308341477Svmaffione } 309341477Svmaffione case NETMAP_REQ_VALE_ATTACH: { 310341477Svmaffione struct nmreq_vale_attach *req = 311341477Svmaffione (struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body; 312341477Svmaffione nmreq_register_to_legacy(&req->reg, nmr); 313341477Svmaffione break; 314341477Svmaffione } 315341477Svmaffione case NETMAP_REQ_VALE_DETACH: { 316341477Svmaffione break; 317341477Svmaffione } 318341477Svmaffione case NETMAP_REQ_VALE_LIST: { 319341477Svmaffione struct nmreq_vale_list *req = 320341477Svmaffione (struct nmreq_vale_list *)(uintptr_t)hdr->nr_body; 321342033Svmaffione strlcpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name)); 322341477Svmaffione nmr->nr_arg1 = req->nr_bridge_idx; 323341477Svmaffione nmr->nr_arg2 = req->nr_port_idx; 324341477Svmaffione break; 325341477Svmaffione } 326341477Svmaffione case NETMAP_REQ_PORT_HDR_SET: 327341477Svmaffione case NETMAP_REQ_PORT_HDR_GET: { 328341477Svmaffione struct nmreq_port_hdr *req = 329341477Svmaffione (struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body; 330341477Svmaffione nmr->nr_arg1 = req->nr_hdr_len; 331341477Svmaffione break; 332341477Svmaffione } 333341477Svmaffione case NETMAP_REQ_VALE_NEWIF: { 334341477Svmaffione struct nmreq_vale_newif *req = 335341477Svmaffione (struct nmreq_vale_newif *)(uintptr_t)hdr->nr_body; 336341477Svmaffione nmr->nr_tx_slots = req->nr_tx_slots; 337341477Svmaffione nmr->nr_rx_slots = req->nr_rx_slots; 338341477Svmaffione nmr->nr_tx_rings = req->nr_tx_rings; 339341477Svmaffione nmr->nr_rx_rings = req->nr_rx_rings; 340341477Svmaffione nmr->nr_arg2 = req->nr_mem_id; 341341477Svmaffione break; 342341477Svmaffione } 343341477Svmaffione case NETMAP_REQ_VALE_DELIF: 344341477Svmaffione case NETMAP_REQ_VALE_POLLING_ENABLE: 345341477Svmaffione case NETMAP_REQ_VALE_POLLING_DISABLE: { 346341477Svmaffione break; 347341477Svmaffione } 348341477Svmaffione } 349341477Svmaffione 350341477Svmaffione return ret; 351341477Svmaffione} 352341477Svmaffione 353341477Svmaffioneint 354341477Svmaffionenetmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data, 355341477Svmaffione struct thread *td) 356341477Svmaffione{ 357341477Svmaffione int error = 0; 358341477Svmaffione 359341477Svmaffione switch (cmd) { 360341477Svmaffione case NIOCGINFO: 361341477Svmaffione case NIOCREGIF: { 362341477Svmaffione /* Request for the legacy control API. Convert it to a 363341477Svmaffione * NIOCCTRL request. */ 364341477Svmaffione struct nmreq *nmr = (struct nmreq *) data; 365344047Svmaffione struct nmreq_header *hdr; 366344047Svmaffione 367344047Svmaffione if (nmr->nr_version < 11) { 368344047Svmaffione nm_prerr("Minimum supported API is 11 (requested %u)", 369344047Svmaffione nmr->nr_version); 370344047Svmaffione return EINVAL; 371344047Svmaffione } 372344047Svmaffione hdr = nmreq_from_legacy(nmr, cmd); 373341477Svmaffione if (hdr == NULL) { /* out of memory */ 374341477Svmaffione return ENOMEM; 375341477Svmaffione } 376341477Svmaffione error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td, 377341477Svmaffione /*nr_body_is_user=*/0); 378341477Svmaffione if (error == 0) { 379341477Svmaffione nmreq_to_legacy(hdr, nmr); 380341477Svmaffione } 381341477Svmaffione if (hdr->nr_body) { 382341477Svmaffione nm_os_free((void *)(uintptr_t)hdr->nr_body); 383341477Svmaffione } 384341477Svmaffione nm_os_free(hdr); 385341477Svmaffione break; 386341477Svmaffione } 387341477Svmaffione#ifdef WITH_VALE 388341477Svmaffione case NIOCCONFIG: { 389341477Svmaffione struct nm_ifreq *nr = (struct nm_ifreq *)data; 390341477Svmaffione error = netmap_bdg_config(nr); 391341477Svmaffione break; 392341477Svmaffione } 393341477Svmaffione#endif 394341477Svmaffione#ifdef __FreeBSD__ 395341477Svmaffione case FIONBIO: 396341477Svmaffione case FIOASYNC: 397344047Svmaffione /* FIONBIO/FIOASYNC are no-ops. */ 398341477Svmaffione break; 399341477Svmaffione 400341477Svmaffione case BIOCIMMEDIATE: 401341477Svmaffione case BIOCGHDRCMPLT: 402341477Svmaffione case BIOCSHDRCMPLT: 403341477Svmaffione case BIOCSSEESENT: 404344047Svmaffione /* Ignore these commands. */ 405341477Svmaffione break; 406341477Svmaffione 407341477Svmaffione default: /* allow device-specific ioctls */ 408341477Svmaffione { 409341477Svmaffione struct nmreq *nmr = (struct nmreq *)data; 410341477Svmaffione struct ifnet *ifp = ifunit_ref(nmr->nr_name); 411341477Svmaffione if (ifp == NULL) { 412341477Svmaffione error = ENXIO; 413341477Svmaffione } else { 414341477Svmaffione struct socket so; 415341477Svmaffione 416341477Svmaffione bzero(&so, sizeof(so)); 417341477Svmaffione so.so_vnet = ifp->if_vnet; 418341477Svmaffione // so->so_proto not null. 419341477Svmaffione error = ifioctl(&so, cmd, data, td); 420341477Svmaffione if_rele(ifp); 421341477Svmaffione } 422341477Svmaffione break; 423341477Svmaffione } 424341477Svmaffione 425341477Svmaffione#else /* linux */ 426341477Svmaffione default: 427341477Svmaffione error = EOPNOTSUPP; 428341477Svmaffione#endif /* linux */ 429341477Svmaffione } 430341477Svmaffione 431341477Svmaffione return error; 432341477Svmaffione} 433