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

📄 wrapndis.c

📁 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 spinlock_t ntoskernel_lock;workqueue_struct_t *wrapndis_wq;static struct nt_thread *wrapndis_worker_thread;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 mp_reset(struct wrap_ndis_device *wnd){	NDIS_STATUS res;	struct miniport *mp;	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_req_mutex)) {		up(&wnd->tx_ring_mutex);		EXIT3(return NDIS_STATUS_FAILURE);	}	mp = &wnd->wd->driver->ndis_driver->mp;	prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);	WARNING("%s is being reset", wnd->net_dev->name);	irql = serialize_lock_irql(wnd);	assert_irql(_irql_ == DISPATCH_LEVEL);	res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx);	serialize_unlock_irql(wnd, irql);	TRACE2("%08X, %08X", res, reset_address);	if (res == NDIS_STATUS_PENDING) {		/* wait for NdisMResetComplete */		if (wait_condition((wnd->ndis_req_done > 0), 0,				   TASK_INTERRUPTIBLE) < 0)			res = NDIS_STATUS_FAILURE;		else {			res = wnd->ndis_req_status;			reset_address = wnd->ndis_req_done - 1;		}		TRACE2("%08X, %08X", res, reset_address);	}	up(&wnd->ndis_req_mutex);	if (res == NDIS_STATUS_SUCCESS && reset_address) {		set_packet_filter(wnd, wnd->packet_filter);		set_multicast_list(wnd);	}	up(&wnd->tx_ring_mutex);	EXIT3(return res);}/* MiniportRequest(Query/Set)Information */NDIS_STATUS mp_request(enum ndis_request_type request,		       struct wrap_ndis_device *wnd, ndis_oid oid,		       void *buf, ULONG buflen, ULONG *written, ULONG *needed){	NDIS_STATUS res;	ULONG w, n;	struct miniport *mp;	KIRQL irql;	if (down_interruptible(&wnd->ndis_req_mutex))		EXIT3(return NDIS_STATUS_FAILURE);	if (!written)		written = &w;	if (!needed)		needed = &n;	mp = &wnd->wd->driver->ndis_driver->mp;	prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);	irql = serialize_lock_irql(wnd);	assert_irql(_irql_ == DISPATCH_LEVEL);	switch (request) {	case NdisRequestQueryInformation:		TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx);		res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf,			       buflen, written, needed);		break;	case NdisRequestSetInformation:		TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx);		res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf,			       buflen, written, needed);		break;	default:		WARNING("invalid request %d, %08X", request, oid);		res = NDIS_STATUS_NOT_SUPPORTED;		break;	}	serialize_unlock_irql(wnd, irql);	TRACE2("%08X, %08X", res, oid);	if (res == NDIS_STATUS_PENDING) {		/* wait for NdisMQueryInformationComplete */		if (wait_condition((wnd->ndis_req_done > 0), 0,				   TASK_INTERRUPTIBLE) < 0)			res = NDIS_STATUS_FAILURE;		else			res = wnd->ndis_req_status;		TRACE2("%08X, %08X", res, oid);	}	up(&wnd->ndis_req_mutex);	DBG_BLOCK(2) {		if (res || needed)			TRACE2("%08X, %d, %d, %d", res, buflen, *written,			       *needed);	}	EXIT3(return res);}/* MiniportPnPEventNotify */static NDIS_STATUS mp_pnp_event(struct wrap_ndis_device *wnd,				enum ndis_device_pnp_event event,				ULONG power_profile){	struct miniport *mp;	ENTER1("%p, %d", wnd, event);	mp = &wnd->wd->driver->ndis_driver->mp;	if (!mp->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),		       mp->pnp_event_notify);		if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&		    !test_bit(HW_PRESENT, &wnd->wd->hw_status) &&		    mp->pnp_event_notify) {			TRACE1("calling surprise_removed");			LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_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(mp->pnp_event_notify, wnd->nmb->mp_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 mp_init(struct wrap_ndis_device *wnd){	NDIS_STATUS error_status, status;	UINT medium_index, medium_array[] = {NdisMedium802_3};	struct miniport *mp;	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->mp.init) {		WARNING("assuming WDM (non-NDIS) driver");		EXIT1(return NDIS_STATUS_NOT_RECOGNIZED);	}	mp = &wnd->wd->driver->ndis_driver->mp;	status = LIN2WIN6(mp->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 = mp_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 = mp_query(wnd, OID_PNP_CAPABILITIES,			  &wnd->pnp_capa, sizeof(wnd->pnp_capa));	if (status == NDIS_STATUS_SUCCESS) {		TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup,		       wnd->pnp_capa.wakeup.min_pattern_wakeup);		wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;		status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP,				      &wnd->ndis_wolopts);		TRACE1("%08X, %x", status, wnd->ndis_wolopts);	} else if (status == NDIS_STATUS_NOT_SUPPORTED)		wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;	TRACE1("%d", wnd->pnp_capa.wakeup.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;		wnd->ndis_wolopts = 0;	}	mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);	EXIT1(return NDIS_STATUS_SUCCESS);}/* MiniportHalt */static void mp_halt(struct wrap_ndis_device *wnd){	struct miniport *mp;	ENTER1("%p", wnd);	if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {		WARNING("device %p is not initialized - not halting", wnd);		return;	}	hangcheck_del(wnd);	del_iw_stats_timer(wnd);	if (wnd->physical_medium == NdisPhysicalMediumWirelessLan &&	    wrap_is_pci_bus(wnd->wd->dev_bus)) {		up(&wnd->ndis_req_mutex);		disassociate(wnd, 0);		down_interruptible(&wnd->ndis_req_mutex);	}	mp = &wnd->wd->driver->ndis_driver->mp;	TRACE1("halt: %p", mp->mp_halt);	LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx);	/* if a driver doesn't call NdisMDeregisterInterrupt during	 * halt, deregister it now */	if (wnd->mp_interrupt)		NdisMDeregisterInterrupt(wnd->mp_interrupt);	/* cancel any timers left by bugyy windows driver; also free	 * the memory for timers */	while (1) {		struct nt_slist *slist;		struct wrap_timer *wrap_timer;		spin_lock_bh(&ntoskernel_lock);		if ((slist = wnd->wrap_timer_slist.next))			wnd->wrap_timer_slist.next = slist->next;		spin_unlock_bh(&ntoskernel_lock);		TIMERTRACE("%p", slist);		if (!slist)			break;		wrap_timer = container_of(slist, struct wrap_timer, slist);		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);	}	EXIT1(return);}static NDIS_STATUS mp_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_req_mutex);		if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) {			status = mp_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 = mp_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);		} else			return NDIS_STATUS_FAILURE;		if (wrap_is_pci_bus(wnd->wd->dev_bus)) {			pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0);			pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0);		}		if (status == NDIS_STATUS_SUCCESS) {			up(&wnd->tx_ring_mutex);			netif_device_attach(wnd->net_dev);			hangcheck_add(wnd);			add_iw_stats_timer(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) {			status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP,					    wnd->ndis_wolopts);			TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts);			if (status == NDIS_STATUS_SUCCESS) {				if (wnd->ndis_wolopts)					wnd->wd->pci.wake_state =						PowerDeviceD3;				else					wnd->wd->pci.wake_state =						PowerDeviceUnspecified;			} else				WARNING("couldn't set wake-on-lan options: "					"0x%x, %08X", wnd->ndis_wolopts, status);			status = mp_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);			mp_halt(wnd);			set_bit(HW_HALTED, &wnd->wd->hw_status);			status = STATUS_SUCCESS;		}		if (down_interruptible(&wnd->ndis_req_mutex))			WARNING("couldn't lock ndis_req_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[2 * ETH_ALEN + 1];	mac_address mac;	memcpy(mac, addr->sa_data, sizeof(mac));	memset(mac_string, 0, sizeof(mac_string));	res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac));	if (res != (sizeof(mac_string) - 1))		EXIT1(return -EINVAL);	TRACE1("new mac: %s", mac_string);	RtlInitAnsiString(&ansi, mac_string);	if (RtlAnsiStringToUnicodeString(&param.data.string, &ansi,					 TRUE) != STATUS_SUCCESS)		EXIT1(return -EINVAL);	param.type = NdisParameterString;	RtlInitAnsiString(&ansi, "NetworkAddress");	if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) {		RtlFreeUnicodeString(&param.data.string);		EXIT1(return -EINVAL);	}	NdisWriteConfiguration(&res, wnd->nmb, &key, &param);	RtlFreeUnicodeString(&key);	RtlFreeUnicodeString(&param.data.string);	if (res != NDIS_STATUS_SUCCESS)		EXIT1(return -EFAULT);	if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) {		res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS,			       mac, sizeof(mac));

⌨️ 快捷键说明

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