📄 wrapndis.c
字号:
ndis_key.struct_size = sizeof(ndis_key); res = miniport_set_info(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); TRACE2("%08X, %lu", res, (unsigned long)sizeof(ndis_key)); if (res && res != NDIS_STATUS_INVALID_DATA) EXIT1(return); res = miniport_query_info(wnd, OID_802_11_ASSOCIATION_INFORMATION, &ndis_assoc_info, sizeof(ndis_assoc_info)); TRACE1("%08X", res); if (res == NDIS_STATUS_NOT_SUPPORTED) EXIT1(return); set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr); if (mode == Ndis802_11Encryption3Enabled) set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr); /* not all drivers support OID_802_11_CAPABILITY, so we don't * know for sure if driver support WPA or WPAPSK; assume * WPA */ set_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth); memset(buf, 0, buf_len); c = (struct ndis_capability *)buf; res = miniport_query_info(wnd, OID_802_11_CAPABILITY, buf, buf_len); if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) EXIT1(return); wnd->num_pmkids = c->num_PMKIDs; for (i = 0; i < c->num_auth_encr_pair; i++) { struct ndis_auth_encr_pair *ae; ae = &c->auth_encr_pair[i]; if ((char *)(ae + 1) > buf + buf_len) break; switch (ae->auth_mode) { case Ndis802_11AuthModeOpen: case Ndis802_11AuthModeShared: case Ndis802_11AuthModeWPA: case Ndis802_11AuthModeWPAPSK: case Ndis802_11AuthModeWPANone: case Ndis802_11AuthModeWPA2: case Ndis802_11AuthModeWPA2PSK: set_bit(ae->auth_mode, &wnd->capa.auth); break; default: WARNING("unknown auth_mode: %d", ae->auth_mode); break; } switch (ae->encr_mode) { case Ndis802_11EncryptionDisabled: case Ndis802_11Encryption1Enabled: case Ndis802_11Encryption2Enabled: case Ndis802_11Encryption3Enabled: set_bit(ae->encr_mode, &wnd->capa.encr); break; default: WARNING("unknown encr_mode: %d", ae->encr_mode); break; } } EXIT1(return);}wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, struct irp *irp){ struct wrap_ndis_device *wnd; TRACE3("fdo: %p", fdo); /* for now, we don't have anything intresting here, so pass it * down to bus driver */ wnd = fdo->reserved; return IoPassIrpDown(wnd->nmb->pdo, irp);}WIN_FUNC_DECL(NdisDispatchDeviceControl,2)wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp){ struct io_stack_location *irp_sl; struct wrap_ndis_device *wnd; enum ndis_power_state state; NTSTATUS status; NDIS_STATUS ndis_status; irp_sl = IoGetCurrentIrpStackLocation(irp); wnd = fdo->reserved; IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn, irp_sl->minor_fn, wnd); if ((irp_sl->params.power.type == SystemPowerState && irp_sl->params.power.state.system_state > PowerSystemWorking) || (irp_sl->params.power.type == DevicePowerState && irp_sl->params.power.state.device_state > PowerDeviceD0)) state = NdisDeviceStateD3; else state = NdisDeviceStateD0; switch (irp_sl->minor_fn) { case IRP_MN_SET_POWER: if (state == NdisDeviceStateD0) { status = IoSyncForwardIrp(wnd->nmb->pdo, irp); if (status != STATUS_SUCCESS) break; ndis_status = miniport_set_power_state(wnd, state); if (ndis_status != NDIS_STATUS_SUCCESS) WARNING("couldn't set power to %d: %08X", state, ndis_status); TRACE2("%s: device resumed", wnd->net_dev->name); irp->io_status.status = status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); break; } else { ndis_status = miniport_set_power_state(wnd, state); /* TODO: handle error case */ if (ndis_status != NDIS_STATUS_SUCCESS) WARNING("setting power to %d failed: %08X", state, ndis_status); status = IoAsyncForwardIrp(wnd->nmb->pdo, irp); } break; case IRP_MN_QUERY_POWER: if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { ndis_status = miniport_query_info(wnd, OID_PNP_QUERY_POWER, &state, sizeof(state)); TRACE2("%d, %08X", state, ndis_status); /* this OID must always succeed */ if (ndis_status != NDIS_STATUS_SUCCESS) TRACE1("query power returns %08X", ndis_status); irp->io_status.status = STATUS_SUCCESS; } else irp->io_status.status = STATUS_SUCCESS; status = IoPassIrpDown(wnd->nmb->pdo, irp); break; case IRP_MN_WAIT_WAKE: case IRP_MN_POWER_SEQUENCE: /* TODO: implement WAIT_WAKE */ status = IoPassIrpDown(wnd->nmb->pdo, irp); break; default: status = IoPassIrpDown(wnd->nmb->pdo, irp); break; } IOEXIT(return status);}WIN_FUNC_DECL(NdisDispatchPower,2)wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp){ struct io_stack_location *irp_sl; struct wrap_ndis_device *wnd; struct device_object *pdo; NTSTATUS status; IOTRACE("fdo: %p, irp: %p", fdo, irp); irp_sl = IoGetCurrentIrpStackLocation(irp); wnd = fdo->reserved; pdo = wnd->nmb->pdo; switch (irp_sl->minor_fn) { case IRP_MN_START_DEVICE: status = IoSyncForwardIrp(pdo, irp); if (status != STATUS_SUCCESS) break; if (wrap_ndis_start_device(wnd) == NDIS_STATUS_SUCCESS) status = STATUS_SUCCESS; else status = STATUS_FAILURE; irp->io_status.status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case IRP_MN_QUERY_STOP_DEVICE: /* TODO: implement in NDIS */ status = IoPassIrpDown(wnd->nmb->pdo, irp); break; case IRP_MN_STOP_DEVICE: miniport_halt(wnd); irp->io_status.status = STATUS_SUCCESS; status = IoAsyncForwardIrp(pdo, irp); break; case IRP_MN_REMOVE_DEVICE: TRACE1("%s", wnd->net_dev->name); miniport_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0); if (wrap_ndis_remove_device(wnd)) { status = STATUS_FAILURE; break; } /* wnd is already freed */ status = IoAsyncForwardIrp(pdo, irp); IoDetachDevice(fdo); IoDeleteDevice(fdo); break; default: status = IoAsyncForwardIrp(pdo, irp); break; } IOTRACE("status: %08X", status); IOEXIT(return status);}WIN_FUNC_DECL(NdisDispatchPnp,2)static void set_task_offload(struct wrap_ndis_device *wnd, void *buf, const int buf_size){ struct ndis_task_offload_header *task_offload_header; struct ndis_task_offload *task_offload; struct ndis_task_tcp_ip_checksum *csum = NULL; struct ndis_task_tcp_large_send *tso = NULL; NDIS_STATUS status; memset(buf, 0, buf_size); task_offload_header = buf; task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION; task_offload_header->size = sizeof(*task_offload_header); task_offload_header->encap_format.flags.fixed_header_size = 1; task_offload_header->encap_format.header_size = sizeof(struct ethhdr); task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation; status = miniport_query_info(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size); TRACE1("%08X", status); if (status != NDIS_STATUS_SUCCESS) EXIT1(return); if (task_offload_header->offset_first_task == 0) EXIT1(return); task_offload = ((void *)task_offload_header + task_offload_header->offset_first_task); while (1) { TRACE1("%d, %d", task_offload->version, task_offload->task); switch(task_offload->task) { case TcpIpChecksumNdisTask: csum = (void *)task_offload->task_buf; break; case TcpLargeSendNdisTask: tso = (void *)task_offload->task_buf; break; default: TRACE1("%d", task_offload->task); break; } if (task_offload->offset_next_task == 0) break; task_offload = (void *)task_offload + task_offload->offset_next_task; } if (tso) TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count, tso->tcp_opts, tso->ip_opts); if (!csum) EXIT1(return); TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value); task_offload_header->encap_format.flags.fixed_header_size = 1; task_offload_header->encap_format.header_size = sizeof(struct ethhdr); task_offload_header->offset_first_task = sizeof(*task_offload_header); task_offload = ((void *)task_offload_header + task_offload_header->offset_first_task); task_offload->offset_next_task = 0; task_offload->size = sizeof(*task_offload); task_offload->task = TcpIpChecksumNdisTask; memcpy(task_offload->task_buf, csum, sizeof(*csum)); task_offload->task_buf_length = sizeof(*csum); status = miniport_set_info(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header, sizeof(*task_offload_header) + sizeof(*task_offload) + sizeof(*csum)); TRACE1("%08X", status); if (status != NDIS_STATUS_SUCCESS) EXIT2(return); wnd->tx_csum = csum->v4_tx; if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) { if (csum->v4_tx.ip_csum) { wnd->net_dev->features |= NETIF_F_HW_CSUM; TRACE1("hw checksum enabled"); } else { wnd->net_dev->features |= NETIF_F_IP_CSUM; TRACE1("IP checksum enabled"); } if (wnd->sg_dma_size) wnd->net_dev->features |= NETIF_F_SG; } wnd->rx_csum = csum->v4_rx; EXIT1(return);}static void get_supported_oids(struct wrap_ndis_device *wnd){ NDIS_STATUS res; int i, n, needed; ndis_oid *oids; res = miniport_query_info_needed(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, &needed); if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT || res == NDIS_STATUS_INVALID_LENGTH)) EXIT1(return); oids = kmalloc(needed, GFP_KERNEL); if (!oids) { TRACE1("couldn't allocate memory"); EXIT1(return); } res = miniport_query_info(wnd, OID_GEN_SUPPORTED_LIST, oids, needed); if (res) { TRACE1("failed: %08X", res); kfree(oids); EXIT1(return); } for (i = 0, n = needed / sizeof(*oids); i < n; i++) { TRACE1("oid: %08X", oids[i]); /* if a wireless device didn't say so for * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan && oids[i] == OID_802_11_SSID) wnd->physical_medium = NdisPhysicalMediumWirelessLan; } kfree(oids); EXIT1(return);}#if defined(HAVE_ETHTOOL)static void ndis_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct wrap_ndis_device *wnd = netdev_priv(dev); strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, wnd->wd->driver->version, sizeof(info->fw_version) - 1); if (wrap_is_pci_bus(wnd->wd->dev_bus)) strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev), sizeof(info->bus_info) - 1);#ifdef CONFIG_USB else usb_make_path(wnd->wd->usb.udev, info->bus_info, sizeof(info->bus_info) - 1);#endif return;}static u32 ndis_get_link(struct net_device *dev){ struct wrap_ndis_device *wnd = netdev_priv(dev); return netif_carrier_ok(wnd->net_dev);}static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET) wol->wolopts |= WAKE_MAGIC; /* no other options supported */ return;}static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct wrap_ndis_device *wnd = netdev_priv(dev); struct ndis_pnp_capabilities pnp_capa; NDIS_STATUS status; if (!(wol->wolopts & WAKE_MAGIC)) return -EINVAL; if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) return -EOPNOTSUPP; status = miniport_query_info(wnd, OID_PNP_CAPABILITIES, &pnp_capa, sizeof(pnp_capa)); if (status != NDIS_STATUS_SUCCESS) return -EOPNOTSUPP; /* we always suspend to D3 */ TRACE1("%d, %d", pnp_capa.wakeup_capa.min_magic_packet_wakeup, pnp_capa.wakeup_capa.min_pattern_wakeup); if (pnp_capa.wakeup_capa.min_magic_packet_wakeup != NdisDeviceStateD3) return -EOPNOTSUPP; /* no other options supported */ wnd->ndis_wolopts = NDIS_PNP_WAKE_UP_MAGIC_PACKET; return 0;}static u32 ndis_get_tx_csum(struct net_device *dev){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum) return 1; else return 0;}static u32 ndis_get_rx_csum(struct net_device *dev){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (wnd->rx_csum.value) return 1; else return 0;} static int ndis_set_tx_csum(struct net_device *dev, u32 data){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (data && (wnd->tx_csum.value == 0)) return -EOPNOTSUPP; if (wnd->tx_csum.ip_csum) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) ethtool_op_set_tx_hw_csum(dev, data);#else dev->features |= NETIF_F_HW_CSUM;#endif } else ethtool_op_set_tx_csum(dev, data); return 0;}static int ndis_set_rx_csum(struct net_device *dev, u32 data){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (data && (wnd->tx_csum.value == 0)) return -EOPNOTSUPP; /* TODO: enable/disable rx csum through NDIS */ return 0;}static u32 ndis_get_sg(struct net_device *dev){ struct wrap_ndis_device *wnd = netdev_priv(dev); if (wnd->sg_dma_size) return ethtool_op_get_sg(dev); else return 0;} static int ndis_set_sg(struct net_device *dev, u32 data){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -