⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wrapndis.c

📁 ndis在linux下的无线网卡驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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 "ndis.h"#include "iw_ndis.h"#include "pnp.h"#include "loader.h"#include "wrapndis.h"#include <linux/inetdevice.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/in.h>extern char *if_name;extern int hangcheck_interval;extern struct iw_handler_def ndis_handler_def;extern NT_SPIN_LOCK timer_lock;static int set_packet_filter(struct wrap_ndis_device *wnd,			     ULONG packet_filter);static void add_iw_stats_timer(struct wrap_ndis_device *wnd);static void del_iw_stats_timer(struct wrap_ndis_device *wnd);static NDIS_STATUS wrap_ndis_start_device(struct wrap_ndis_device *wnd);static int wrap_ndis_remove_device(struct wrap_ndis_device *wnd);static void set_multicast_list(struct wrap_ndis_device *wnd);static int ndis_net_dev_open(struct net_device *net_dev);static int ndis_net_dev_close(struct net_device *net_dev);/* MiniportReset */NDIS_STATUS miniport_reset(struct wrap_ndis_device *wnd){	NDIS_STATUS res;	struct miniport_char *miniport;	UINT cur_lookahead, max_lookahead;	BOOLEAN reset_address;	KIRQL irql;	ENTER2("wnd: %p", wnd);	if (down_interruptible(&wnd->tx_ring_mutex))		EXIT3(return NDIS_STATUS_FAILURE);	if (down_interruptible(&wnd->ndis_comm_mutex)) {		up(&wnd->tx_ring_mutex);		EXIT3(return NDIS_STATUS_FAILURE);	}	miniport = &wnd->wd->driver->ndis_driver->miniport;	cur_lookahead = wnd->nmb->cur_lookahead;	max_lookahead = wnd->nmb->max_lookahead;	wnd->ndis_comm_done = 0;	wnd->ndis_comm_task = current;	WARNING("%s is being reset", wnd->net_dev->name);	irql = serialize_lock_irql(wnd);	res = LIN2WIN2(miniport->reset, &reset_address, wnd->nmb->adapter_ctx);	serialize_unlock_irql(wnd, irql);	TRACE2("%08X, %08X", res, reset_address);	if (res == NDIS_STATUS_PENDING) {		/* wait for NdisMResetComplete */		if (wrap_wait_event((wnd->ndis_comm_done > 0), 0,				    TASK_INTERRUPTIBLE) < 0)			res = NDIS_STATUS_FAILURE;		else {			res = wnd->ndis_comm_status;			reset_address = wnd->ndis_comm_done - 1;		}		TRACE2("%08X, %08X", res, reset_address);	}	up(&wnd->ndis_comm_mutex);	if (res == NDIS_STATUS_SUCCESS && reset_address) {		wnd->nmb->cur_lookahead = cur_lookahead;		wnd->nmb->max_lookahead = max_lookahead;		set_packet_filter(wnd, wnd->packet_filter);		set_multicast_list(wnd);	}	up(&wnd->tx_ring_mutex);	EXIT3(return res);}/* MiniportQueryInformation */NDIS_STATUS miniport_query_info_needed(struct wrap_ndis_device *wnd,				       ndis_oid oid, void *buf,				       ULONG bufsize, ULONG *needed){	NDIS_STATUS res;	ULONG written;	struct miniport_char *miniport;	KIRQL irql;	ENTER2("oid: %08X", oid);	if (down_interruptible(&wnd->ndis_comm_mutex))		EXIT3(return NDIS_STATUS_FAILURE);	miniport = &wnd->wd->driver->ndis_driver->miniport;	TRACE2("%p, %08X", miniport->query, oid);	wnd->ndis_comm_done = 0;	wnd->ndis_comm_task = current;	irql = serialize_lock_irql(wnd);	res = LIN2WIN6(miniport->query, wnd->nmb->adapter_ctx, oid, buf,		       bufsize, &written, needed);	serialize_unlock_irql(wnd, irql);	TRACE2("%08X, %08X", res, oid);	if (res == NDIS_STATUS_PENDING) {		/* wait for NdisMQueryInformationComplete */		if (wrap_wait_event((wnd->ndis_comm_done > 0), 0,				    TASK_INTERRUPTIBLE) < 0)			res = NDIS_STATUS_FAILURE;		else			res = wnd->ndis_comm_status;		TRACE2("%08X, %08X", res, oid);	}	up(&wnd->ndis_comm_mutex);	DBG_BLOCK(2) {		if (res || needed)			TRACE2("%08X, %d, %d, %d", res, bufsize, written,			       *needed);	}	EXIT3(return res);}NDIS_STATUS miniport_query_info(struct wrap_ndis_device *wnd, ndis_oid oid,				void *buf, ULONG bufsize){	NDIS_STATUS res;	ULONG needed;	res = miniport_query_info_needed(wnd, oid, buf, bufsize, &needed);	return res;}/* MiniportSetInformation */NDIS_STATUS miniport_set_info(struct wrap_ndis_device *wnd, ndis_oid oid,			      void *buf, ULONG bufsize){	NDIS_STATUS res;	ULONG written, needed;	struct miniport_char *miniport;	KIRQL irql;	ENTER2("oid: %08X", oid);	if (down_interruptible(&wnd->ndis_comm_mutex))		EXIT3(return NDIS_STATUS_FAILURE);	miniport = &wnd->wd->driver->ndis_driver->miniport;	TRACE2("%p, %08X", miniport->query, oid);	wnd->ndis_comm_done = 0;	wnd->ndis_comm_task = current;	irql = serialize_lock_irql(wnd);	res = LIN2WIN6(miniport->setinfo, wnd->nmb->adapter_ctx, oid,		       buf, bufsize, &written, &needed);	serialize_unlock_irql(wnd, irql);	TRACE2("%08X, %08X", res, oid);	if (res == NDIS_STATUS_PENDING) {		/* wait for NdisMQueryInformationComplete */		if (wrap_wait_event((wnd->ndis_comm_done > 0), 0,				    TASK_INTERRUPTIBLE) < 0)			res = NDIS_STATUS_FAILURE;		else			res = wnd->ndis_comm_status;		TRACE2("%08X, %08X", res, oid);	}	up(&wnd->ndis_comm_mutex);	DBG_BLOCK(2) {		if (res && needed)			TRACE2("%08X, %d, %d, %d", res, bufsize, written,			       needed);	}	EXIT3(return res);}NDIS_STATUS miniport_query_int(struct wrap_ndis_device *wnd, ndis_oid oid,			       ULONG *data){	return miniport_query_info(wnd, oid, data, sizeof(ULONG));}NDIS_STATUS miniport_set_int(struct wrap_ndis_device *wnd, ndis_oid oid,			     ULONG data){	return miniport_set_info(wnd, oid, &data, sizeof(data));}/* MiniportPnPEventNotify */static NDIS_STATUS miniport_pnp_event(struct wrap_ndis_device *wnd,				      enum ndis_device_pnp_event event,				      ULONG power_profile){	struct miniport_char *miniport;	ENTER1("%p, %d", wnd, event);	miniport = &wnd->wd->driver->ndis_driver->miniport;	if (!miniport->pnp_event_notify) {		TRACE1("Windows driver %s doesn't support "		       "MiniportPnpEventNotify", wnd->wd->driver->name);		return NDIS_STATUS_FAILURE;	}	/* RNDIS driver doesn't like to be notified if device is	 * already halted */	if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status))		EXIT1(return NDIS_STATUS_SUCCESS);	switch (event) {	case NdisDevicePnPEventSurpriseRemoved:		TRACE1("%u, %p",		       (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK),		       miniport->pnp_event_notify);		if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&		    !test_bit(HW_PRESENT, &wnd->wd->hw_status) &&		    miniport->pnp_event_notify) {			TRACE1("calling surprise_removed");			LIN2WIN4(miniport->pnp_event_notify,				 wnd->nmb->adapter_ctx,				 NdisDevicePnPEventSurpriseRemoved, NULL, 0);		} else			TRACE1("Windows driver %s doesn't support "			       "MiniportPnpEventNotify for safe unplugging",			       wnd->wd->driver->name);		return NDIS_STATUS_SUCCESS;	case NdisDevicePnPEventPowerProfileChanged:		if (power_profile)			power_profile = NdisPowerProfileAcOnLine;		LIN2WIN4(miniport->pnp_event_notify, wnd->nmb->adapter_ctx,			 NdisDevicePnPEventPowerProfileChanged,			 &power_profile, (ULONG)sizeof(power_profile));		return NDIS_STATUS_SUCCESS;	default:		WARNING("event %d not yet implemented", event);		return NDIS_STATUS_SUCCESS;	}}/* MiniportInitialize */static NDIS_STATUS miniport_init(struct wrap_ndis_device *wnd){	NDIS_STATUS error_status, status;	UINT medium_index, medium_array[] = {NdisMedium802_3};	struct miniport_char *miniport;	struct ndis_pnp_capabilities pnp_capa;	ENTER1("irql: %d", current_irql());	if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {		WARNING("device %p already initialized!", wnd);		return NDIS_STATUS_FAILURE;	}	if (!wnd->wd->driver->ndis_driver ||	    !wnd->wd->driver->ndis_driver->miniport.init) {		WARNING("assuming WDM (non-NDIS) driver");		EXIT1(return NDIS_STATUS_NOT_RECOGNIZED);	}	miniport = &wnd->wd->driver->ndis_driver->miniport;	status = LIN2WIN6(miniport->init, &error_status,			  &medium_index, medium_array,			  sizeof(medium_array) / sizeof(medium_array[0]),			  wnd->nmb, wnd->nmb);	TRACE1("init returns: %08X, irql: %d", status, current_irql());	if (status != NDIS_STATUS_SUCCESS) {		WARNING("couldn't initialize device: %08X", status);		EXIT1(return NDIS_STATUS_FAILURE);	}	/* Wait a little to let card power up otherwise ifup might	 * fail after boot */	sleep_hz(HZ / 5);	status = miniport_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged,				    NdisPowerProfileAcOnLine);	if (status != NDIS_STATUS_SUCCESS)		TRACE1("setting power failed: %08X", status);	set_bit(HW_INITIALIZED, &wnd->wd->hw_status);	/* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is	 * misleading/confusing */	status = miniport_query_info(wnd, OID_PNP_CAPABILITIES,				     &pnp_capa, sizeof(pnp_capa));	if (status == NDIS_STATUS_SUCCESS)		wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;	else		wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;	TRACE1("%d", pnp_capa.wakeup_capa.min_magic_packet_wakeup);	/* although some NDIS drivers support suspend, Linux kernel	 * has issues with suspending USB devices */	if (wrap_is_usb_bus(wnd->wd->dev_bus))		wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;	EXIT1(return NDIS_STATUS_SUCCESS);}/* MiniportHalt */static void miniport_halt(struct wrap_ndis_device *wnd){	struct miniport_char *miniport;	ENTER1("%p", wnd);	if (test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {		hangcheck_del(wnd);		del_iw_stats_timer(wnd);		miniport = &wnd->wd->driver->ndis_driver->miniport;		TRACE1("halt: %p", miniport->miniport_halt);		LIN2WIN1(miniport->miniport_halt, wnd->nmb->adapter_ctx);		/* cancel any timers left by bugyy windows driver; also free		 * the memory for timers */		while (1) {			KIRQL irql;			struct nt_list *ent;			struct wrap_timer *wrap_timer;			irql = nt_spin_lock_irql(&timer_lock, DISPATCH_LEVEL);			ent = RemoveHeadList(&wnd->wrap_timer_list);			nt_spin_unlock_irql(&timer_lock, irql);			if (!ent)				break;			wrap_timer = container_of(ent, struct wrap_timer, list);			wrap_timer->repeat = 0;			/* ktimer that this wrap_timer is associated to can't			 * be touched, as it may have been freed by the driver			 * already */			if (del_timer_sync(&wrap_timer->timer))				WARNING("Buggy Windows driver left timer %p "					"running", wrap_timer->nt_timer);			memset(wrap_timer, 0, sizeof(*wrap_timer));			kfree(wrap_timer);		}	} else		WARNING("device %p is not initialized - not halting", wnd);	EXIT1(return);}static NDIS_STATUS miniport_set_power_state(struct wrap_ndis_device *wnd,					    enum ndis_power_state state){	NDIS_STATUS status;	TRACE1("%d", state);	if (state == NdisDeviceStateD0) {		status = NDIS_STATUS_SUCCESS;		up(&wnd->ndis_comm_mutex);		if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) {			status = miniport_init(wnd);			if (status == NDIS_STATUS_SUCCESS) {				set_packet_filter(wnd, wnd->packet_filter);				set_multicast_list(wnd);			}		} else if (test_and_clear_bit(HW_SUSPENDED,					      &wnd->wd->hw_status)) {			status = miniport_set_int(wnd, OID_PNP_SET_POWER,						  state);			if (status != NDIS_STATUS_SUCCESS)				WARNING("%s: setting power to state %d failed? "					"%08X", wnd->net_dev->name, state,					status);			if (wnd->ndis_wolopts &&			    wrap_is_pci_bus(wnd->wd->dev_bus))				pci_enable_wake(wnd->wd->pci.pdev, PCI_D0, 0);		} else			return NDIS_STATUS_FAILURE;		if (status == NDIS_STATUS_SUCCESS) {			up(&wnd->tx_ring_mutex);			netif_device_attach(wnd->net_dev);			hangcheck_add(wnd);			add_iw_stats_timer(wnd);			set_scan(wnd);		} else			WARNING("%s: couldn't set power to state %d; device not"				" resumed", wnd->net_dev->name, state);		EXIT1(return status);	} else {		if (down_interruptible(&wnd->tx_ring_mutex))			EXIT1(return NDIS_STATUS_FAILURE);		netif_device_detach(wnd->net_dev);		hangcheck_del(wnd);		del_iw_stats_timer(wnd);		status = NDIS_STATUS_NOT_SUPPORTED;		if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {			if (wnd->ndis_wolopts) {				status =					miniport_set_int(wnd,							 OID_PNP_ENABLE_WAKE_UP,							 wnd->ndis_wolopts);				if (status == NDIS_STATUS_SUCCESS &&				    wrap_is_pci_bus(wnd->wd->dev_bus))					pci_enable_wake(wnd->wd->pci.pdev,							PCI_D0, 1);				else					WARNING("%s: couldn't enable WOL: %08x",						wnd->net_dev->name, status);			}			status = miniport_set_int(wnd, OID_PNP_SET_POWER,						  state);			if (status == NDIS_STATUS_SUCCESS)				set_bit(HW_SUSPENDED, &wnd->wd->hw_status);			else				WARNING("suspend failed: %08X", status);		}		if (status != NDIS_STATUS_SUCCESS) {			WARNING("%s does not support power management; "				"halting the device", wnd->net_dev->name);			miniport_halt(wnd);			set_bit(HW_HALTED, &wnd->wd->hw_status);			status = STATUS_SUCCESS;		}		if (down_interruptible(&wnd->ndis_comm_mutex))			WARNING("couldn't lock ndis_comm_mutex");		EXIT1(return status);	}}static int ndis_set_mac_address(struct net_device *dev, void *p){	struct wrap_ndis_device *wnd = netdev_priv(dev);	struct sockaddr *addr = p;	struct ndis_configuration_parameter param;	struct unicode_string key;	struct ansi_string ansi;	NDIS_STATUS res;	unsigned char mac_string[3 * ETH_ALEN];	mac_address mac;	memcpy(mac, addr->sa_data, sizeof(mac));	memset(mac_string, 0, sizeof(mac_string));	res = snprintf(mac_string, sizeof(mac_string), MACSTRSEP, MAC2STR(mac));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -