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

📄 wrapndis.c

📁 ndis在linux下的无线网卡驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	TRACE1("%d", res);	if (res != (2 * sizeof(mac) + sizeof(mac) - 1))		EXIT1(return -EINVAL);	RtlInitAnsiString(&ansi, mac_string);	if (RtlAnsiStringToUnicodeString(&param.data.string, &ansi, TRUE)) {		RtlFreeUnicodeString(&key);		EXIT1(return -EINVAL);	}	param.type = NdisParameterString;	RtlInitAnsiString(&ansi, "mac_address");	if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE))		EXIT1(return -EINVAL);	NdisWriteConfiguration(&res, wnd->nmb, &key, &param);	RtlFreeUnicodeString(&key);	RtlFreeUnicodeString(&param.data.string);	if (res != NDIS_STATUS_SUCCESS)		EXIT1(return -EINVAL);	if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) {		res = miniport_query_info(wnd, OID_802_3_CURRENT_ADDRESS,					  mac, sizeof(mac));		if (res == NDIS_STATUS_SUCCESS) {			TRACE1("mac:" MACSTRSEP, MAC2STR(mac));			memcpy(dev->dev_addr, mac, sizeof(mac));		} else			ERROR("couldn't get mac address: %08X", res);	}	EXIT1(return 0);}static int setup_tx_sg_list(struct wrap_ndis_device *wnd, struct sk_buff *skb,			    struct ndis_packet_oob_data *oob_data){	struct ndis_sg_element *sg_element;	struct ndis_sg_list *sg_list;	int i;	ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags);	if (skb_shinfo(skb)->nr_frags <= 1) {		sg_element = &oob_data->wrap_tx_sg_list.elements[0];		sg_element->address =			PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,					   skb->len, PCI_DMA_TODEVICE);		sg_element->length = skb->len;		oob_data->wrap_tx_sg_list.nent = 1;		oob_data->ext.info[ScatterGatherListPacketInfo] =			&oob_data->wrap_tx_sg_list;		TRACE3("%Lx, %u", sg_element->address, sg_element->length);		return 0;	}	sg_list = kmalloc(sizeof(*sg_list) +			  (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element),			  GFP_ATOMIC);	if (!sg_list)		return -ENOMEM;	sg_list->nent = skb_shinfo(skb)->nr_frags + 1;	TRACE3("%p, %d", sg_list, sg_list->nent);	sg_element = sg_list->elements;	sg_element->length = skb_headlen(skb);	sg_element->address =		PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,				   skb_headlen(skb), PCI_DMA_TODEVICE);	sg_element++;	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, sg_element++) {		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];		sg_element->length = frag->size;		sg_element->address =			pci_map_page(wnd->wd->pci.pdev, frag->page,				     frag->page_offset, frag->size,				     PCI_DMA_TODEVICE);		TRACE3("%Lx, %u", sg_element->address, sg_element->length);	}	oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list;	return 0;}static void free_tx_sg_list(struct wrap_ndis_device *wnd,			    struct ndis_packet_oob_data *oob_data){	int i;	struct ndis_sg_element *sg_element;	struct ndis_sg_list *sg_list =		oob_data->ext.info[ScatterGatherListPacketInfo];	sg_element = sg_list->elements;	TRACE3("%p, %d", sg_list, sg_list->nent);	PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address,			     sg_element->length, PCI_DMA_TODEVICE);	if (sg_list->nent == 1)		EXIT3(return);	for (i = 1; i < sg_list->nent; i++, sg_element++) {		TRACE3("%Lx, %u", sg_element->address, sg_element->length);		pci_unmap_page(wnd->wd->pci.pdev, sg_element->address,			       sg_element->length, PCI_DMA_TODEVICE);	}	TRACE3("%p", sg_list);	kfree(sg_list);}static struct ndis_packet *alloc_tx_packet(struct wrap_ndis_device *wnd,					   struct sk_buff *skb){	struct ndis_packet *packet;	ndis_buffer *buffer;	struct ndis_packet_oob_data *oob_data;	NDIS_STATUS status;	NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool);	if (status != NDIS_STATUS_SUCCESS)		return NULL;	/* TODO: should a buffer be mapped even if driver supports	 * scatter/gather? */	NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool,			   skb->data, skb->len);	if (status != NDIS_STATUS_SUCCESS) {		NdisFreePacket(packet);		return NULL;	}	packet->private.buffer_head = buffer;	packet->private.buffer_tail = buffer;	oob_data = NDIS_PACKET_OOB_DATA(packet);	oob_data->tx_skb = skb;	if (wnd->sg_dma_size) {		if (setup_tx_sg_list(wnd, skb, oob_data)) {			NdisFreeBuffer(buffer);			NdisFreePacket(packet);			return NULL;		}	}	if (skb->ip_summed == CHECKSUM_PARTIAL) {		struct ndis_tcp_ip_checksum_packet_info csum;		struct iphdr *ip = skb->nh.iph;		csum.value = 0;		csum.tx.v4 = 1;		if (ip->protocol == IPPROTO_TCP)			csum.tx.tcp = 1;		else if (ip->protocol == IPPROTO_UDP)			csum.tx.udp = 1;//		csum->tx.ip = 1;		packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP;		oob_data->ext.info[TcpIpChecksumPacketInfo] =			(void *)(ULONG_PTR)csum.value;	}	DBG_BLOCK(4) {		dump_bytes(__FUNCTION__, skb->data, skb->len);	}	TRACE3("packet: %p, buffer: %p, skb: %p", packet, buffer, skb);	return packet;}void free_tx_packet(struct wrap_ndis_device *wnd, struct ndis_packet *packet,		    NDIS_STATUS status){	ndis_buffer *buffer;	struct ndis_packet_oob_data *oob_data;	ENTER3("%p, %08X", packet, status);	if (status == NDIS_STATUS_SUCCESS) {		pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len);		atomic_inc_var(wnd->net_stats.tx_packets);	} else {		TRACE1("packet dropped: %08X", status);		atomic_inc_var(wnd->net_stats.tx_dropped);	}	oob_data = NDIS_PACKET_OOB_DATA(packet);	if (wnd->sg_dma_size)		free_tx_sg_list(wnd, oob_data);	buffer = packet->private.buffer_head;	NdisFreeBuffer(buffer);	dev_kfree_skb_any(oob_data->tx_skb);	NdisFreePacket(packet);	EXIT3(return);}/* MiniportSend and MiniportSendPackets *//* this function is called holding tx_ring_mutex. start and n are such * that start + n < TX_RING_SIZE; i.e., packets don't wrap around * ring */static u8 miniport_tx_packets(struct wrap_ndis_device *wnd, u8 start, u8 n){	NDIS_STATUS res;	struct miniport_char *miniport;	struct ndis_packet *packet;	u8 sent;	KIRQL irql;	TRACE3("%d, %d", start, n);	miniport = &wnd->wd->driver->ndis_driver->miniport;	if (miniport->send_packets) {		if (deserialized_driver(wnd)) {			LIN2WIN3(miniport->send_packets, wnd->nmb->adapter_ctx,				 &wnd->tx_ring[start], n);			sent = n;		} else {			irql = raise_irql(DISPATCH_LEVEL);			serialize_lock(wnd);			LIN2WIN3(miniport->send_packets, wnd->nmb->adapter_ctx,				 &wnd->tx_ring[start], n);			serialize_unlock(wnd);			lower_irql(irql);			for (sent = 0; sent < n && wnd->tx_ok; sent++) {				struct ndis_packet_oob_data *oob_data;				packet = wnd->tx_ring[start + sent];				oob_data = NDIS_PACKET_OOB_DATA(packet);				switch ((res =					 xchg(&oob_data->status,					      NDIS_STATUS_NOT_RECOGNIZED))) {				case NDIS_STATUS_SUCCESS:					free_tx_packet(wnd, packet,						       NDIS_STATUS_SUCCESS);					break;				case NDIS_STATUS_PENDING:					break;				case NDIS_STATUS_RESOURCES:					wnd->tx_ok = 0;					/* resubmit this packet and					 * the rest when resources					 * become available */					sent--;					break;				case NDIS_STATUS_FAILURE:					free_tx_packet(wnd, packet,						       NDIS_STATUS_FAILURE);					break;				default:					ERROR("%p: invalid status: %08X",					      packet, res);					free_tx_packet(wnd, packet,						       oob_data->status);					break;				}				TRACE3("%p, %d", packet, res);			}		}		TRACE3("sent: %d(%d)", sent, n);	} else {		for (sent = 0; sent < n && wnd->tx_ok; sent++) {			struct ndis_packet_oob_data *oob_data;			packet = wnd->tx_ring[start + sent];			oob_data = NDIS_PACKET_OOB_DATA(packet);			oob_data->status = NDIS_STATUS_NOT_RECOGNIZED;			irql = serialize_lock_irql(wnd);			res = LIN2WIN3(miniport->send, wnd->nmb->adapter_ctx,				       packet, packet->private.flags);			serialize_unlock_irql(wnd, irql);			switch (res) {			case NDIS_STATUS_SUCCESS:				free_tx_packet(wnd, packet, res);				break;			case NDIS_STATUS_PENDING:				break;			case NDIS_STATUS_RESOURCES:				wnd->tx_ok = 0;				/* resend this packet when resources				 * become available */				sent--;				break;			case NDIS_STATUS_FAILURE:				free_tx_packet(wnd, packet, res);				break;			default:				ERROR("packet %p: invalid status: %08X",				      packet, res);				break;			}		}	}	EXIT3(return sent);}static void tx_worker(worker_param_t param){	struct wrap_ndis_device *wnd;	s8 n;	KIRQL irql;	wnd = worker_param_data(param, struct wrap_ndis_device, tx_work);	ENTER3("tx_ok %d", wnd->tx_ok);	while (wnd->tx_ok) {		if (down_interruptible(&wnd->tx_ring_mutex))			break;		irql = nt_spin_lock_irql(&wnd->tx_ring_lock, DISPATCH_LEVEL);		n = wnd->tx_ring_end - wnd->tx_ring_start;		nt_spin_unlock_irql(&wnd->tx_ring_lock, irql);		TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);		/* end == start if either ring is empty or full; in		 * the latter case is_tx_ring_full is set */		if (n == 0) {			if (wnd->is_tx_ring_full)				n = TX_RING_SIZE - wnd->tx_ring_start;			else {				up(&wnd->tx_ring_mutex);				break;			}		} else if (n < 0)			n = TX_RING_SIZE - wnd->tx_ring_start;		if (unlikely(n > wnd->max_tx_packets))			n = wnd->max_tx_packets;		n = miniport_tx_packets(wnd, wnd->tx_ring_start, n);		if (n > 0) {			wnd->net_dev->trans_start = jiffies;			wnd->tx_ring_start =				(wnd->tx_ring_start + n) % TX_RING_SIZE;			wnd->is_tx_ring_full = 0;			if (netif_queue_stopped(wnd->net_dev))				netif_wake_queue(wnd->net_dev);		}		up(&wnd->tx_ring_mutex);		TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);	}	EXIT3(return);}static int tx_skbuff(struct sk_buff *skb, struct net_device *dev){	struct wrap_ndis_device *wnd = netdev_priv(dev);	struct ndis_packet *packet;	packet = alloc_tx_packet(wnd, skb);	if (!packet) {		WARNING("couldn't allocate packet");		return NETDEV_TX_BUSY;	}	nt_spin_lock(&wnd->tx_ring_lock);	wnd->tx_ring[wnd->tx_ring_end++] = packet;	if (wnd->tx_ring_end == TX_RING_SIZE)		wnd->tx_ring_end = 0;	if (wnd->tx_ring_end == wnd->tx_ring_start) {		wnd->is_tx_ring_full = 1;		netif_stop_queue(wnd->net_dev);	}	nt_spin_unlock(&wnd->tx_ring_lock);	TRACE3("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end);	schedule_wrap_work(&wnd->tx_work);	return NETDEV_TX_OK;}static int set_packet_filter(struct wrap_ndis_device *wnd, ULONG packet_filter){	NDIS_STATUS res;	while (1) {		res = miniport_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,				       packet_filter);		if (res == NDIS_STATUS_SUCCESS)			break;		TRACE2("couldn't set filter 0x%08x", packet_filter);		/* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */		if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {			packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;			continue;		}		if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) {			packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL;			continue;		}		if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) {			packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL;			continue;		}		if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) {			packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST;			packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;			continue;		}		if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) {			packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;			continue;		}		break;	}	wnd->packet_filter = packet_filter;	res = miniport_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,				 &packet_filter);	if (packet_filter != wnd->packet_filter) {		WARNING("filter not set: 0x%08x, 0x%08x",			packet_filter, wnd->packet_filter);		wnd->packet_filter = packet_filter;	}	if (wnd->packet_filter)		EXIT3(return 0);	else		EXIT3(return -1);}static int ndis_net_dev_open(struct net_device *net_dev){	struct wrap_ndis_device *wnd = netdev_priv(net_dev);	ENTER1("%p", wnd);	if (set_packet_filter(wnd, wnd->packet_filter)) {		WARNING("couldn't set packet filter");		return -ENODEV;	}	netif_wake_queue(net_dev);	netif_poll_enable(net_dev);	return 0;}static int ndis_net_dev_close(struct net_device *net_dev){	netif_poll_disable(net_dev);	netif_tx_disable(net_dev);	return 0;}static int ndis_change_mtu(struct net_device *net_dev, int mtu){	struct wrap_ndis_device *wnd = netdev_priv(net_dev);	int max;	if (mtu < ETH_ZLEN)		return -EINVAL;	if (miniport_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) !=	    NDIS_STATUS_SUCCESS)		return -EOPNOTSUPP;	TRACE1("%d", max);	max -= ETH_HLEN;	if (max <= ETH_ZLEN)		return -EINVAL;	if (mtu + ETH_HLEN > max)		return -EINVAL;	net_dev->mtu = mtu;	return 0;}

⌨️ 快捷键说明

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