/* Flush and close. */ static void netmap_cleanup(NetClientState *nc) { NetmapState *s = DO_UPCAST(NetmapState, nc, nc); qemu_purge_queued_packets(nc); netmap_poll(nc, false); nm_close(s->nmd); s->nmd = NULL; }
/* * Remap linux arguments into the FreeBSD call. * - pwait is the poll table, passed as 'dev'; * If pwait == NULL someone else already woke up before. We can report * events but they are filtered upstream. * If pwait != NULL, then pwait->key contains the list of events. * - events is computed from pwait as above. * - file is passed as 'td'; */ static u_int linux_netmap_poll(struct file * file, struct poll_table_struct *pwait) { #ifdef NETMAP_LINUX_PWAIT_KEY int events = pwait ? pwait->NETMAP_LINUX_PWAIT_KEY : \ POLLIN | POLLOUT | POLLERR; #else int events = POLLIN | POLLOUT; /* XXX maybe... */ #endif /* PWAIT_KEY */ return netmap_poll((void *)pwait, events, (void *)file); }
NTSTATUS ioctlDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION irpSp; NTSTATUS NtStatus = STATUS_SUCCESS; int ret = 0; union { struct nm_ifreq ifr; struct nmreq nmr; } arg; size_t argsize = 0; PVOID data; struct sockopt *sopt; int space, len = 0; (void)DeviceObject; // XXX irpSp = IoGetCurrentIrpStackLocation(Irp); argsize = irpSp->Parameters.DeviceIoControl.InputBufferLength; data = Irp->AssociatedIrp.SystemBuffer; switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case NIOCGINFO: DbgPrint("Netmap.sys: NIOCGINFO"); argsize = sizeof(arg.nmr); break; case NIOCREGIF: DbgPrint("Netmap.sys: NIOCREGIF"); argsize = sizeof(arg.nmr); #if 0 struct nmreq* test = (struct nmreq*) Irp->AssociatedIrp.SystemBuffer; DbgPrint("IFNAMSIZ: %i , sizeof(nmreq): %i\n", IFNAMSIZ, sizeof(struct nmreq)); DbgPrint("nr_version: %i , nr_ringid: %i\n", test->nr_version, test->nr_ringid); DbgPrint("nr_cmd: %i , nr_name: %s\n", test->nr_cmd, test->nr_name); DbgPrint("nr_tx_rings: %i , nr_tx_slots: %i\n", test->nr_tx_rings, test->nr_tx_slots); DbgPrint("nr_offset: %i , nr_flags: %s\n", test->nr_offset, test->nr_flags); #endif break; case NIOCTXSYNC: //DbgPrint("Netmap.sys: NIOCTXSYNC"); break; case NIOCRXSYNC: //DbgPrint("Netmap.sys: NIOCRXSYNC"); break; case NIOCCONFIG: DbgPrint("Netmap.sys: NIOCCONFIG"); argsize = sizeof(arg.ifr); break; case NETMAP_MMAP: DbgPrint("Netmap.sys: NETMAP_MMAP"); NtStatus = windows_netmap_mmap(Irp); Irp->IoStatus.Status = NtStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); return NtStatus; case NETMAP_GETSOCKOPT: case NETMAP_SETSOCKOPT: DbgPrint("Netmap.sys: NETMAP_SET/GET-SOCKOPT (Common code)"); if (argsize < sizeof(struct sockopt)) { NtStatus = STATUS_BAD_DATA; Irp->IoStatus.Status = NtStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); return NtStatus; } sopt = Irp->AssociatedIrp.SystemBuffer; len = sopt->sopt_valsize; if (irpSp->Parameters.DeviceIoControl.IoControlCode == NETMAP_SETSOCKOPT) { DbgPrint("Netmap.sys: NETMAP_SETSOCKOPT"); NtStatus = do_netmap_set_ctl(NULL, sopt->sopt_name, sopt + 1, len); Irp->IoStatus.Information = 0; } else { DbgPrint("Netmap.sys: NETMAP_GETSOCKOPT"); NtStatus = do_netmap_get_ctl(NULL, sopt->sopt_name, sopt + 1, &len); sopt->sopt_valsize = len; // XXX should we use OutputBufferLength ? space = irpSp->Parameters.DeviceIoControl.InputBufferLength; if (len + sizeof(struct sockopt) <= space) { Irp->IoStatus.Information = len + sizeof(struct sockopt); } else { Irp->IoStatus.Information = space; } } Irp->IoStatus.Status = NtStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); return NtStatus; case NETMAP_POLL: { //DbgPrint("%i: Requested call to POLL \n", PsGetCurrentThreadId()); POLL_REQUEST_DATA *pollData = data; LARGE_INTEGER tout; tout.QuadPart = -(int)(pollData->timeout) * 1000 * 10; struct netmap_priv_d *priv = irpSp->FileObject->FsContext; if (priv == NULL) { NtStatus = STATUS_DEVICE_DATA_ERROR; goto done; } irpSp->FileObject->FsContext2 = NULL; pollData->revents = netmap_poll(priv, pollData->events, irpSp); while ((irpSp->FileObject->FsContext2 != NULL) && (pollData->revents == 0)) { NTSTATUS waitResult = KeWaitForSingleObject(&((win_SELINFO*)irpSp->FileObject->FsContext2)->queue, UserRequest, KernelMode, FALSE, &tout); if (waitResult == STATUS_TIMEOUT) { DbgPrint("%i: Timeout on 0x%p \n", PsGetCurrentThreadId(), irpSp->FileObject->FsContext2); pollData->revents = STATUS_TIMEOUT; NtStatus = STATUS_TIMEOUT; break; } pollData->revents = netmap_poll(priv, pollData->events, irpSp); } irpSp->FileObject->FsContext2 = NULL; copy_to_user((void*)data, &arg, sizeof(POLL_REQUEST_DATA), Irp); } Irp->IoStatus.Status = NtStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); return NtStatus; default: //bail out if unknown request issued DbgPrint("Netmap.sys: wrong request issued! (%i)", irpSp->Parameters.DeviceIoControl.IoControlCode); NtStatus = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return NtStatus; } if (argsize) { if (!data) { NtStatus = STATUS_DATA_ERROR; } else { bzero(&arg, argsize); if (!NT_SUCCESS(copy_from_user(&arg, (void *)data, argsize, Irp))) { NtStatus = STATUS_DATA_ERROR; } } } if (NT_SUCCESS(NtStatus)) { struct netmap_priv_d *priv = irpSp->FileObject->FsContext; if (priv == NULL) { NtStatus = STATUS_DEVICE_DATA_ERROR; goto done; } ret = netmap_ioctl(priv, irpSp->Parameters.DeviceIoControl.IoControlCode, (caddr_t)&arg, NULL); if (NT_SUCCESS(ret)) { if (data && !NT_SUCCESS(copy_to_user((void*)data, &arg, argsize, Irp))) { DbgPrint("Netmap.sys: ioctl failure/cannot copy data to user"); NtStatus = STATUS_DATA_ERROR; } } else { DbgPrint("Netmap.sys: ioctl failure (%i)", ret); NtStatus = STATUS_BAD_DATA; } } done: Irp->IoStatus.Status = NtStatus; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return NtStatus; }