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 + -
显示快捷键?