wrapper.c
来自「改文件可以安装无线网卡在linux下的驱动,大家可以在网站上查找一下用法」· C语言 代码 · 共 1,551 行 · 第 1/3 页
C
1,551 行
* this function is called with lock held in DISPATCH_LEVEL, so no need * to raise irql to DISPATCH_LEVEL during MiniportSend(Packets)*/static int send_packets(struct ndis_handle *handle, unsigned int start, unsigned int pending){ NDIS_STATUS res; struct miniport_char *miniport = &handle->driver->miniport_char; unsigned int sent, n; struct ndis_packet *packet; TRACEENTER3("start: %d, pending: %d", start, pending); if (pending > handle->max_send_packets) n = handle->max_send_packets; else n = pending; if (miniport->send_packets) { unsigned int i; /* copy packets from xmit ring to linear xmit array */ for (i = 0; i < n; i++) { int j = (start + i) % XMIT_RING_SIZE; handle->xmit_array[i] = handle->xmit_ring[j]; } LIN2WIN3(miniport->send_packets, handle->adapter_ctx, handle->xmit_array, n); DBGTRACE3("sent"); if (test_bit(ATTR_SERIALIZED, &handle->attributes)) { for (sent = 0; sent < n && handle->send_ok; sent++) { packet = handle->xmit_array[sent]; switch(packet->oob_data.status) { case NDIS_STATUS_SUCCESS: sendpacket_done(handle, packet); break; case NDIS_STATUS_PENDING: break; case NDIS_STATUS_RESOURCES: handle->send_ok = 0; break; case NDIS_STATUS_FAILURE: default: free_send_packet(handle, packet); break; } } } else { sent = n; } } else { packet = handle->xmit_ring[start]; res = LIN2WIN3(miniport->send, handle->adapter_ctx, packet, 0); sent = 1; switch (res) { case NDIS_STATUS_SUCCESS: sendpacket_done(handle, packet); break; case NDIS_STATUS_PENDING: break; case NDIS_STATUS_RESOURCES: handle->send_ok = 0; sent = 0; break; case NDIS_STATUS_FAILURE: free_send_packet(handle, packet); break; } } TRACEEXIT3(return sent);}static void xmit_worker(void *param){ struct ndis_handle *handle = (struct ndis_handle *)param; int n; KIRQL irql; TRACEENTER3("send_ok %d", handle->send_ok); /* some drivers e.g., new RT2500 driver, crash if any packets * are sent when the card is not associated */ while (handle->send_ok) { irql = kspin_lock_irql(&handle->xmit_lock, DISPATCH_LEVEL); if (handle->xmit_ring_pending == 0) { kspin_unlock_irql(&handle->xmit_lock, irql); break; } n = send_packets(handle, handle->xmit_ring_start, handle->xmit_ring_pending); handle->xmit_ring_start = (handle->xmit_ring_start + n) % XMIT_RING_SIZE; handle->xmit_ring_pending -= n; if (n > 0 && netif_queue_stopped(handle->net_dev)) netif_wake_queue(handle->net_dev); kspin_unlock_irql(&handle->xmit_lock, irql); } TRACEEXIT3(return);}/* * Free and unmap packet created in xmit */void sendpacket_done(struct ndis_handle *handle, struct ndis_packet *packet){ TRACEENTER3("%s", ""); kspin_lock(&handle->send_packet_done_lock); handle->stats.tx_bytes += packet->private.len; handle->stats.tx_packets++; free_send_packet(handle, packet); kspin_unlock(&handle->send_packet_done_lock); TRACEEXIT3(return);}/* * This function is called in BH disabled context and ndis drivers * must have their send-functions called from sleepeable context so we * just queue the packets up here and schedule a workqueue to run * later. */static int start_xmit(struct sk_buff *skb, struct net_device *dev){ struct ndis_handle *handle = dev->priv; ndis_buffer *buffer; struct ndis_packet *packet; unsigned int xmit_ring_next_slot; char *data; KIRQL irql; data = kmalloc(skb->len, GFP_ATOMIC); if (!data) return 1; buffer = allocate_init_mdl(data, skb->len); if (!buffer) { kfree(data); return 1; } packet = allocate_send_packet(handle, buffer); if (!packet) { free_mdl(buffer); kfree(data); return 1; } skb_copy_and_csum_dev(skb, data); dev_kfree_skb(skb); irql = kspin_lock_irql(&handle->xmit_lock, DISPATCH_LEVEL); xmit_ring_next_slot = (handle->xmit_ring_start + handle->xmit_ring_pending) % XMIT_RING_SIZE; handle->xmit_ring[xmit_ring_next_slot] = packet; handle->xmit_ring_pending++; if (handle->xmit_ring_pending == XMIT_RING_SIZE) netif_stop_queue(handle->net_dev); kspin_unlock_irql(&handle->xmit_lock, irql); schedule_work(&handle->xmit_work); return 0;}int ndiswrapper_suspend_pci(struct pci_dev *pdev, u32 state){ struct net_device *dev; struct ndis_handle *handle; int pm_state; NDIS_STATUS res; if (!pdev) return -1; handle = pci_get_drvdata(pdev); if (!handle) return -1; dev = handle->net_dev; if (test_bit(HW_SUSPENDED, &handle->hw_status) || test_bit(HW_HALTED, &handle->hw_status)) return -1; DBGTRACE2("irql: %d", current_irql()); DBGTRACE2("%s: detaching device", dev->name); if (netif_running(dev)) { netif_stop_queue(dev); netif_device_detach(dev); } hangcheck_del(handle); stats_timer_del(handle); if (test_bit(ATTR_HALT_ON_SUSPEND, &handle->attributes)) { DBGTRACE2("%s", "driver requests halt_on_suspend"); miniport_halt(handle); set_bit(HW_HALTED, &handle->hw_status); } else { int i; /* some drivers don't support D2, so force D3 */ pm_state = NdisDeviceStateD3; /* use copy; query_power changes this value */ i = pm_state; res = miniport_query_int(handle, OID_PNP_QUERY_POWER, &i); DBGTRACE2("%s: query power to state %d returns %08X", dev->name, pm_state, res); if (res) { WARNING("No pnp capabilities for pm (%08X); halting", res); miniport_halt(handle); set_bit(HW_HALTED, &handle->hw_status); } else { res = miniport_set_int(handle, OID_PNP_SET_POWER, pm_state); DBGTRACE2("suspending returns %08X", res); set_bit(HW_SUSPENDED, &handle->hw_status); } }#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) pci_save_state(pdev);#else pci_save_state(pdev, handle->pci_state);#endif pci_disable_device(pdev); pci_set_power_state(pdev, 3); DBGTRACE2("%s: device suspended", dev->name); return 0;}int ndiswrapper_resume_pci(struct pci_dev *pdev){ struct net_device *dev; struct ndis_handle *handle; if (!pdev) return -1; handle = pci_get_drvdata(pdev); if (!handle) return -1; dev = handle->net_dev; if (!(test_bit(HW_SUSPENDED, &handle->hw_status) || test_bit(HW_HALTED, &handle->hw_status))) return -1; pci_enable_device(pdev);#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) pci_restore_state(pdev);#else pci_restore_state(pdev, handle->pci_state);#endif DBGTRACE2("irql: %d", current_irql()); set_bit(SUSPEND_RESUME, &handle->wrapper_work); schedule_work(&handle->wrapper_worker); return 0;}void ndiswrapper_remove_one_dev(struct ndis_handle *handle){ KIRQL irql; TRACEENTER1("%s", handle->net_dev->name); set_bit(SHUTDOWN, &handle->wrapper_work); stats_timer_del(handle); hangcheck_del(handle); ndiswrapper_procfs_remove_iface(handle); ndis_close(handle->net_dev); netif_carrier_off(handle->net_dev); /* flush_scheduled_work here causes crash with 2.4 kernels */ /* instead, throw away pending packets */ irql = kspin_lock_irql(&handle->xmit_lock, DISPATCH_LEVEL); while (handle->xmit_ring_pending) { struct ndis_packet *packet; packet = handle->xmit_ring[handle->xmit_ring_start]; free_send_packet(handle, packet); handle->xmit_ring_start = (handle->xmit_ring_start + 1) % XMIT_RING_SIZE; handle->xmit_ring_pending--; } kspin_unlock_irql(&handle->xmit_lock, irql); miniport_set_int(handle, OID_802_11_DISASSOCIATE, 0); if (handle->net_dev) unregister_netdev(handle->net_dev); printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME, handle->net_dev->name);#if 0 DBGTRACE1("%d, %p", test_bit(ATTR_SURPRISE_REMOVE, &handle->attributes), miniport->pnp_event_notify); if (test_bit(ATTR_SURPRISE_REMOVE, &handle->attributes) && miniport->pnp_event_notify) { LIN2WIN4(miniport->pnp_event_notify, handle->adapter_ctx, NdisDevicePnPEventSurpriseRemoved, NULL, 0); }#endif DBGTRACE1("halting device %s", handle->driver->name); miniport_halt(handle); DBGTRACE1("halt successful"); if (handle->xmit_array) kfree(handle->xmit_array); if (handle->multicast_list) kfree(handle->multicast_list); if (handle->net_dev) free_netdev(handle->net_dev); TRACEEXIT1(return);}static void link_status_handler(struct ndis_handle *handle){ struct ndis_assoc_info *ndis_assoc_info; unsigned char *wpa_assoc_info, *assoc_info, *p, *ies; union iwreq_data wrqu; unsigned int i; NDIS_STATUS res; const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX; struct encr_info *encr_info = &handle->encr_info; TRACEENTER2("link status: %d", handle->link_status); if (handle->link_status == 0) { if (handle->encr_mode == Ndis802_11Encryption1Enabled || handle->infrastructure_mode == Ndis802_11IBSS) { for (i = 0; i < MAX_ENCR_KEYS; i++) { if (encr_info->keys[i].length == 0) continue; add_wep_key(handle, encr_info->keys[i].key, encr_info->keys[i].length, i); } set_bit(SET_ESSID, &handle->wrapper_work); schedule_work(&handle->wrapper_worker); TRACEEXIT2(return); } /* FIXME: not clear if NDIS says keys should * be cleared here */ for (i = 0; i < MAX_ENCR_KEYS; i++) handle->encr_info.keys[i].length = 0; memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(handle->net_dev, SIOCGIWAP, &wrqu, NULL); TRACEEXIT2(return); } if (!test_bit(Ndis802_11Encryption2Enabled, &handle->capa) && !test_bit(Ndis802_11Encryption3Enabled, &handle->capa)) TRACEEXIT2(return); assoc_info = kmalloc(assoc_size, GFP_KERNEL); if (!assoc_info) { ERROR("%s", "couldn't allocate memory"); TRACEEXIT2(return); } memset(assoc_info, 0, assoc_size); ndis_assoc_info = (struct ndis_assoc_info *)assoc_info; ndis_assoc_info->length = sizeof(*ndis_assoc_info); ndis_assoc_info->offset_req_ies = sizeof(*ndis_assoc_info); ndis_assoc_info->req_ie_length = IW_CUSTOM_MAX / 2; ndis_assoc_info->offset_resp_ies = sizeof(*ndis_assoc_info) + ndis_assoc_info->req_ie_length; ndis_assoc_info->resp_ie_length = IW_CUSTOM_MAX / 2; res = miniport_query_info(handle, OID_802_11_ASSOCIATION_INFORMATION, assoc_info, assoc_size); if (res) { DBGTRACE2("query assoc_info failed (%08X)", res); kfree(assoc_info); TRACEEXIT2(return); } /* we need 28 extra bytes for the format strings */ if ((ndis_assoc_info->req_ie_length + ndis_assoc_info->resp_ie_length + 28) > IW_CUSTOM_MAX) { WARNING("information element is too long! (%u,%u)," "association information dropped", ndis_assoc_info->req_ie_length, ndis_assoc_info->resp_ie_length); kfree(assoc_info); TRACEEXIT2(return); } wpa_assoc_info = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); if (!wpa_assoc_info) { ERROR("%s", "couldn't allocate memory"); kfree(assoc_info); TRACEEXIT2(return); } p = wpa_assoc_info; p += sprintf(p, "ASSOCINFO(ReqIEs="); ies = ((char *)ndis_assoc_info) + ndis_assoc_info->offset_req_ies; for (i = 0; i < ndis_assoc_info->req_ie_length; i++) p += sprintf(p, "%02x", ies[i]); p += sprintf(p, " RespIEs="); ies = ((char *)ndis_assoc_info) + ndis_assoc_info->offset_resp_ies; for (i = 0; i < ndis_assoc_info->resp_ie_length; i++) p += sprintf(p, "%02x", ies[i]); p += sprintf(p, ")"); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = p - wpa_assoc_info; DBGTRACE2("adding %d bytes", wrqu.data.length); wireless_send_event(handle->net_dev, IWEVCUSTOM, &wrqu, wpa_assoc_info); kfree(wpa_assoc_info); kfree(assoc_info); get_ap_address(handle, (char *)&wrqu.ap_addr.sa_data); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(handle->net_dev, SIOCGIWAP, &wrqu, NULL); DBGTRACE2("%s", "associate_event"); TRACEEXIT2(return);}static void set_packet_filter(struct ndis_handle *handle){ struct net_device *dev = (struct net_device *)handle->net_dev; ULONG packet_filter; NDIS_STATUS res; packet_filter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_ALL_MULTICAST); if (dev->flags & IFF_PROMISC) { packet_filter |= NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_PROMISCUOUS; } else if ((dev->mc_count > handle->multicast_list_size) || (dev->flags & IFF_ALLMULTI) || (handle->multicast_list == 0)) { /* too many to filter perfectly -- accept all multicasts. */ DBGTRACE1("multicast list too long; accepting all"); packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; } else if (dev->mc_count > 0) { packet_filter |= NDIS_PACKET_TYPE_MULTICAST; set_multicast_list(dev, handle); } res = miniport_set_info(handle, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter, sizeof(packet_filter)); if (res && (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)) { /* 802.11 drivers may fail when PROMISCUOUS flag is * set, so try without */ packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; res = miniport_set_info(handle, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter, sizeof(packet_filter)); } if (res && res != NDIS_STATUS_NOT_SUPPORTED) ERROR("unable to set packet filter (%08X)", res); TRACEEXIT2(return);}static void update_wireless_stats(struct ndis_handle *handle){ struct iw_statistics *iw_stats = &handle->wireless_stats; struct ndis_wireless_stats ndis_stats; ndis_rssi rssi; NDIS_STATUS res; if (handle->reset_status) return; res = miniport_query_info(handle, OID_802_11_RSSI, &rssi, sizeof(rssi)); iw_stats->qual.level = rssi; memset(&ndis_stats, 0, sizeof(ndis_stats)); res = miniport_query_info(handle, OID_802_11_STATISTICS, &ndis_stats, sizeof(ndis_stats)); if (res == NDIS_STATUS_NOT_SUPPORTED) iw_stats->qual.qual = ((rssi & 0x7F) * 100) / 154; else { iw_stats->discard.retries = (u32)ndis_stats.retry + (u32)ndis_stats.multi_retry; iw_stats->discard.misc = (u32)ndis_stats.fcs_err + (u32)ndis_stats.rtss_fail + (u32)ndis_stats.ack_fail + (u32)ndis_stats.frame_dup; if ((u32)ndis_stats.tx_frag) iw_stats->qual.qual = 100 - 100 * ((u32)ndis_stats.retry + 2 * (u32)ndis_stats.multi_retry + 3 * (u32)ndis_stats.failed) / (6 * (u32)ndis_stats.tx_frag); else iw_stats->qual.qual = 100; } TRACEEXIT2(return);}static struct iw_statistics *get_wireless_stats(struct net_device *dev){ struct ndis_handle *handle = dev->priv; return &handle->wireless_stats;}#ifdef HAVE_ETHTOOLstatic u32 ndis_get_link(struct net_device *dev){ struct ndis_handle *handle = dev->priv; return handle->link_status;}static struct ethtool_ops ndis_ethtool_ops = {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?