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