wrapper.c
来自「改文件可以安装无线网卡在linux下的驱动,大家可以在网站上查找一下用法」· C语言 代码 · 共 1,551 行 · 第 1/3 页
C
1,551 行
/* * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/vmalloc.h>#include <linux/kmod.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/miscdevice.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/if_arp.h>#include <net/iw_handler.h>#include <linux/rtnetlink.h>#include <asm/scatterlist.h>#include <asm/uaccess.h>#include "wrapper.h"#include "iw_ndis.h"#include "loader.h"#ifdef CONFIG_X86_64#include "wrapper_exports.h"#endif#ifndef NDISWRAPPER_VERSION#error ndiswrapper version is not defined; run 'make' only from ndiswrapper \ directory or driver directory#endifstatic char *if_name = "wlan%d";int proc_uid, proc_gid;static int hangcheck_interval;int debug;/* used to implement Windows spinlocks */spinlock_t spinlock_kspin_lock;NW_MODULE_PARM_STRING(if_name, 0400);MODULE_PARM_DESC(if_name, "Network interface name or template " "(default: wlan%d)");NW_MODULE_PARM_INT(proc_uid, 0600);MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc " "(default: 0).");NW_MODULE_PARM_INT(proc_gid, 0600);MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc " "(default: 0).");NW_MODULE_PARM_INT(hangcheck_interval, 0600);/* 0 - default value provided by NDIS driver, * positive value - force hangcheck interval to that many seconds * negative value - disable hangcheck */NW_MODULE_PARM_INT(debug, 0600);MODULE_PARM_DESC(debug, "debug level");MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking" " if driver is hung. (default: 0)");MODULE_AUTHOR("ndiswrapper team <ndiswrapper-general@lists.sourceforge.net>");#ifdef MODULE_VERSIONMODULE_VERSION(NDISWRAPPER_VERSION);#endifstatic void ndis_set_rx_mode(struct net_device *dev);static void set_multicast_list(struct net_device *dev, struct ndis_handle *handle);/* * MiniportReset */NDIS_STATUS miniport_reset(struct ndis_handle *handle){ KIRQL irql; NDIS_STATUS res = 0; struct miniport_char *miniport; UINT cur_lookahead; UINT max_lookahead; TRACEENTER2("handle: %p", handle); if (handle->reset_status) return NDIS_STATUS_PENDING; if (down_interruptible(&handle->ndis_comm_mutex)) TRACEEXIT3(return NDIS_STATUS_FAILURE); miniport = &handle->driver->miniport_char; /* reset_status is used for two purposes: to check if windows * driver needs us to reset filters etc (as per NDIS) and to * check if another reset is in progress */ handle->reset_status = NDIS_STATUS_PENDING; handle->ndis_comm_res = NDIS_STATUS_PENDING; handle->ndis_comm_done = 0; cur_lookahead = handle->cur_lookahead; max_lookahead = handle->max_lookahead; irql = raise_irql(DISPATCH_LEVEL); res = LIN2WIN2(miniport->reset, &handle->reset_status, handle->adapter_ctx); lower_irql(irql); DBGTRACE2("res = %08X, reset_status = %08X", res, handle->reset_status); if (res == NDIS_STATUS_PENDING) { if (wait_event_interruptible_timeout( handle->ndis_comm_wq, (handle->ndis_comm_done == 1), 1*HZ)) res = handle->ndis_comm_res; else res = NDIS_STATUS_FAILURE; DBGTRACE2("res = %08X, reset_status = %08X", res, handle->reset_status); } up(&handle->ndis_comm_mutex); DBGTRACE2("reset: res = %08X, reset status = %08X", res, handle->reset_status); if (res == NDIS_STATUS_SUCCESS && handle->reset_status) { /* NDIS says we should set lookahead size (?) * functional address (?) or multicast filter */ handle->cur_lookahead = cur_lookahead; handle->max_lookahead = max_lookahead; ndis_set_rx_mode(handle->net_dev); } handle->reset_status = 0; TRACEEXIT3(return res);}/* * MiniportQueryInformation * Perform a sync query and deal with the possibility of an async operation. * This function must be called from process context as it will sleep. */NDIS_STATUS miniport_query_info_needed(struct ndis_handle *handle, ndis_oid oid, void *buf, ULONG bufsize, ULONG *needed){ NDIS_STATUS res; ULONG written; struct miniport_char *miniport = &handle->driver->miniport_char; KIRQL irql; TRACEENTER3("query is at %p", miniport->query); if (down_interruptible(&handle->ndis_comm_mutex)) TRACEEXIT3(return NDIS_STATUS_FAILURE); handle->ndis_comm_done = 0; irql = raise_irql(DISPATCH_LEVEL); res = LIN2WIN6(miniport->query, handle->adapter_ctx, oid, buf, bufsize, &written, needed); lower_irql(irql); DBGTRACE3("res = %08x", res); if (res == NDIS_STATUS_PENDING) { /* wait for NdisMQueryInformationComplete upto HZ */ if (wait_event_interruptible_timeout( handle->ndis_comm_wq, (handle->ndis_comm_done == 1), 1*HZ)) res = handle->ndis_comm_res; else res = NDIS_STATUS_FAILURE; } up(&handle->ndis_comm_mutex); TRACEEXIT3(return res);}NDIS_STATUS miniport_query_info(struct ndis_handle *handle, ndis_oid oid, void *buf, ULONG bufsize){ NDIS_STATUS res; ULONG needed; res = miniport_query_info_needed(handle, oid, buf, bufsize, &needed); return res;}/* * MiniportSetInformation * Perform a sync setinfo and deal with the possibility of an async operation. * This function must be called from process context as it will sleep. */NDIS_STATUS miniport_set_info(struct ndis_handle *handle, ndis_oid oid, void *buf, ULONG bufsize){ NDIS_STATUS res; ULONG written, needed; struct miniport_char *miniport = &handle->driver->miniport_char; KIRQL irql; TRACEENTER3("setinfo is at %p", miniport->setinfo); if (down_interruptible(&handle->ndis_comm_mutex)) TRACEEXIT3(return NDIS_STATUS_FAILURE); handle->ndis_comm_done = 0; irql = raise_irql(DISPATCH_LEVEL); res = LIN2WIN6(miniport->setinfo, handle->adapter_ctx, oid, buf, bufsize, &written, &needed); lower_irql(irql); DBGTRACE3("res = %08x", res); if (res == NDIS_STATUS_PENDING) { /* wait for NdisMSetInformationComplete upto HZ */ if (wait_event_interruptible_timeout( handle->ndis_comm_wq, (handle->ndis_comm_done == 1), 1*HZ)) res = handle->ndis_comm_res; else res = NDIS_STATUS_FAILURE; } up(&handle->ndis_comm_mutex); if (needed) DBGTRACE2("%s failed: bufsize: %d, written: %d, needed: %d", __FUNCTION__, bufsize, written, needed); TRACEEXIT3(return res);}/* Make a query that has an int as the result. */NDIS_STATUS miniport_query_int(struct ndis_handle *handle, ndis_oid oid, void *data){ NDIS_STATUS res; res = miniport_query_info(handle, oid, data, sizeof(ULONG)); if (!res) return 0; *((char *)data) = 0; return res;}/* Set an int */NDIS_STATUS miniport_set_int(struct ndis_handle *handle, ndis_oid oid, ULONG data){ return miniport_set_info(handle, oid, &data, sizeof(data));}/* * MiniportInitialize */NDIS_STATUS miniport_init(struct ndis_handle *handle){ NDIS_STATUS status, res; UINT medium_index; UINT medium_array[] = {NdisMedium802_3}; struct miniport_char *miniport = &handle->driver->miniport_char; TRACEENTER1("driver init routine is at %p", miniport->init); if (miniport->init == NULL) { ERROR("%s", "initialization function is not setup correctly"); return -EINVAL; } res = LIN2WIN6(miniport->init, &status, &medium_index, medium_array, sizeof(medium_array) / sizeof(medium_array[0]), handle, handle); if (res) return res; return 0;}/* * MiniportHalt */void miniport_halt(struct ndis_handle *handle){ struct miniport_char *miniport = &handle->driver->miniport_char; TRACEENTER1("driver halt is at %p", miniport->halt); miniport_set_int(handle, OID_PNP_SET_POWER, NdisDeviceStateD3); LIN2WIN1(miniport->halt, handle->adapter_ctx); ndis_exit_handle(handle); misc_funcs_exit_handle(handle); if (handle->device->bustype == NDIS_PCI_BUS) pci_set_power_state(handle->dev.pci, 3); TRACEEXIT1(return);}static void hangcheck_proc(unsigned long data){ struct ndis_handle *handle = (struct ndis_handle *)data; KIRQL irql; TRACEENTER3("%s", ""); if (handle->reset_status == 0) { NDIS_STATUS res; struct miniport_char *miniport; miniport = &handle->driver->miniport_char; irql = raise_irql(DISPATCH_LEVEL); res = LIN2WIN1(miniport->hangcheck, handle->adapter_ctx); lower_irql(irql); if (res) { WARNING("%s is being reset", handle->net_dev->name); res = miniport_reset(handle); DBGTRACE3("reset returns %08X, %d", res, handle->reset_status); } } kspin_lock(&handle->timers_lock); if (handle->hangcheck_active) { handle->hangcheck_timer.expires = jiffies + handle->hangcheck_interval; add_timer(&handle->hangcheck_timer); } kspin_unlock(&handle->timers_lock); TRACEEXIT3(return);}void hangcheck_add(struct ndis_handle *handle){ if (!handle->driver->miniport_char.hangcheck || handle->hangcheck_interval <= 0) { handle->hangcheck_active = 0; return; } init_timer(&handle->hangcheck_timer); handle->hangcheck_timer.data = (unsigned long)handle; handle->hangcheck_timer.function = &hangcheck_proc; kspin_lock(&handle->timers_lock); add_timer(&handle->hangcheck_timer); handle->hangcheck_active = 1; kspin_unlock(&handle->timers_lock); return;}void hangcheck_del(struct ndis_handle *handle){ if (!handle->driver->miniport_char.hangcheck || handle->hangcheck_interval <= 0) return; kspin_lock(&handle->timers_lock); handle->hangcheck_active = 0; del_timer(&handle->hangcheck_timer); kspin_unlock(&handle->timers_lock);}static void stats_proc(unsigned long data){ struct ndis_handle *handle = (struct ndis_handle *)data; set_bit(COLLECT_STATS, &handle->wrapper_work); schedule_work(&handle->wrapper_worker); handle->stats_timer.expires = jiffies + 2 * HZ; add_timer(&handle->stats_timer);}static void stats_timer_add(struct ndis_handle *handle){ init_timer(&handle->stats_timer); handle->stats_timer.data = (unsigned long)handle; handle->stats_timer.function = &stats_proc; handle->stats_timer.expires = jiffies + 2 * HZ; add_timer(&handle->stats_timer);}static void stats_timer_del(struct ndis_handle *handle){ kspin_lock(&handle->timers_lock); del_timer_sync(&handle->stats_timer); kspin_unlock(&handle->timers_lock);}static int ndis_open(struct net_device *dev){ TRACEENTER1("%s", ""); netif_device_attach(dev); netif_start_queue(dev); return 0;}static int ndis_close(struct net_device *dev){ TRACEENTER1("%s", ""); if (netif_running(dev)) { netif_stop_queue(dev); netif_device_detach(dev); } return 0;}/* * query functions may not be called from this function as they might * sleep which is not allowed from the context this function is * running in. */static struct net_device_stats *ndis_get_stats(struct net_device *dev){ struct ndis_handle *handle = dev->priv; return &handle->stats;}static int ndis_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ int rc = -ENODEV; return rc;}static void set_multicast_list(struct net_device *dev, struct ndis_handle *handle){ struct dev_mc_list *mclist; int i, size = 0; char *list = handle->multicast_list; NDIS_STATUS res; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count && size < handle->multicast_list_size; i++, mclist = mclist->next) { memcpy(list, mclist->dmi_addr, ETH_ALEN); list += ETH_ALEN; size += ETH_ALEN; } DBGTRACE1("%d entries. size=%d", dev->mc_count, size); res = miniport_set_info(handle, OID_802_3_MULTICAST_LIST, list, size); if (res) ERROR("Unable to set multicast list (%08X)", res);}/* * This function is called fom BH context...no sleep! */static void ndis_set_rx_mode(struct net_device *dev){ struct ndis_handle *handle = dev->priv; set_bit(SET_PACKET_FILTER, &handle->wrapper_work); schedule_work(&handle->wrapper_worker);}static struct ndis_packet *allocate_send_packet(struct ndis_handle *handle, ndis_buffer *buffer){ struct ndis_packet *packet; packet = allocate_ndis_packet(); if (!packet) return NULL; packet->private.nr_pages = NDIS_BUFFER_TO_SPAN_PAGES(buffer); packet->private.len = MmGetMdlByteCount(buffer); packet->private.count = 1; packet->private.valid_counts = TRUE; packet->private.buffer_head = buffer; packet->private.buffer_tail = buffer; if (handle->use_sg_dma) { packet->ndis_sg_element.address = PCI_DMA_MAP_SINGLE(handle->dev.pci, MmGetMdlVirtualAddress(buffer), MmGetMdlByteCount(buffer), PCI_DMA_TODEVICE); packet->ndis_sg_element.length = MmGetMdlByteCount(buffer); packet->ndis_sg_list.nent = 1; packet->ndis_sg_list.elements = &packet->ndis_sg_element; packet->extension.info[ScatterGatherListPacketInfo] = &packet->ndis_sg_list; } return packet;}static void free_send_packet(struct ndis_handle *handle, struct ndis_packet *packet){ ndis_buffer *buffer; TRACEENTER3("packet: %p", packet); if (!packet) { ERROR("illegal packet from %p", handle); return; } buffer = packet->private.buffer_head; if (handle->use_sg_dma) PCI_DMA_UNMAP_SINGLE(handle->dev.pci, packet->ndis_sg_element.address, packet->ndis_sg_element.length, PCI_DMA_TODEVICE); DBGTRACE3("freeing buffer %p", buffer); kfree(MmGetMdlVirtualAddress(buffer)); free_mdl(buffer); DBGTRACE3("freeing packet %p", packet); free_ndis_packet(packet); TRACEEXIT3(return);}/* * MiniportSend and MiniportSendPackets
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?