📄 wrapndis.c
字号:
TRACE1("%d", res); if (res != (2 * sizeof(mac) + sizeof(mac) - 1)) EXIT1(return -EINVAL); RtlInitAnsiString(&ansi, mac_string); if (RtlAnsiStringToUnicodeString(¶m.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, ¶m); RtlFreeUnicodeString(&key); RtlFreeUnicodeString(¶m.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 + -