📄 ndis.c
字号:
}wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) (struct ndis_mp_interrupt *mp_interrupt, PKSYNCHRONIZE_ROUTINE sync_func, void *ctx){ BOOLEAN ret; unsigned long flags; ENTER6("%p %p", sync_func, ctx); nt_spin_lock_irqsave(&mp_interrupt->lock, flags); ret = LIN2WIN1(sync_func, ctx); nt_spin_unlock_irqrestore(&mp_interrupt->lock, flags); TRACE6("ret: %d", ret); EXIT6(return ret);}/* called via function pointer; but 64-bit RNDIS driver calls directly */wstdcall void WIN_FUNC(NdisMIndicateStatus,4) (struct ndis_miniport_block *nmb, NDIS_STATUS status, void *buf, UINT len){ struct wrap_ndis_device *wnd = nmb->wnd; struct ndis_status_indication *si; struct ndis_auth_req *auth_req; struct ndis_radio_status_indication *radio_status; ENTER2("status=0x%x len=%d", status, len); switch (status) { case NDIS_STATUS_MEDIA_DISCONNECT: if (!netif_carrier_ok(wnd->net_dev)) break; netif_carrier_off(wnd->net_dev); set_bit(LINK_STATUS_CHANGED, &wnd->wrap_ndis_pending_work); schedule_wrap_work(&wnd->wrap_ndis_work); break; case NDIS_STATUS_MEDIA_CONNECT: if (netif_carrier_ok(wnd->net_dev)) break; netif_carrier_on(wnd->net_dev); set_bit(LINK_STATUS_CHANGED, &wnd->wrap_ndis_pending_work); schedule_wrap_work(&wnd->wrap_ndis_work); break; case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: if (!buf) break; si = buf; TRACE2("status_type=%d", si->status_type); switch (si->status_type) { case Ndis802_11StatusType_Authentication: buf = (char *)buf + sizeof(*si); len -= sizeof(*si); while (len > 0) { auth_req = (struct ndis_auth_req *)buf; TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); if (auth_req->flags & 0x01) TRACE2("reqauth"); if (auth_req->flags & 0x02) TRACE2("keyupdate"); if (auth_req->flags & 0x06) TRACE2("pairwise_error"); if (auth_req->flags & 0x0E) TRACE2("group_error"); /* TODO: report to wpa_supplicant */ len -= auth_req->length; buf = (char *)buf + auth_req->length; } break; case Ndis802_11StatusType_MediaStreamMode: break;#ifdef CONFIG_NET_RADIO case Ndis802_11StatusType_PMKID_CandidateList: { u8 *end; unsigned long i; struct ndis_pmkid_candidate_list *cand; cand = buf + sizeof(struct ndis_status_indication); if (len < sizeof(struct ndis_status_indication) + sizeof(struct ndis_pmkid_candidate_list) || cand->version != 1) { WARNING("Unrecognized PMKID_CANDIDATE_LIST" " ignored"); EXIT1(return); } end = (u8 *)buf + len; TRACE2("PMKID_CANDIDATE_LIST ver %ld num_cand %ld", cand->version, cand->num_candidates); for (i = 0; i < cand->num_candidates; i++) {#if WIRELESS_EXT > 17 struct iw_pmkid_cand pcand; union iwreq_data wrqu;#endif struct ndis_pmkid_candidate *c = &cand->candidates[i]; if ((u8 *)(c + 1) > end) { TRACE2("Truncated PMKID_CANDIDATE_LIST"); break; } TRACE2("%ld: " MACSTRSEP " 0x%lx", i, MAC2STR(c->bssid), c->flags);#if WIRELESS_EXT > 17 memset(&pcand, 0, sizeof(pcand)); if (c->flags & 0x01) pcand.flags |= IW_PMKID_CAND_PREAUTH; pcand.index = i; memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(pcand); wireless_send_event(wnd->net_dev, IWEVPMKIDCAND, &wrqu, (u8 *)&pcand);#endif } break; } case Ndis802_11StatusType_RadioState: radio_status = buf; if (radio_status->radio_state == Ndis802_11RadioStatusOn) INFO("radio is turned on"); else if (radio_status->radio_state == Ndis802_11RadioStatusHardwareOff) INFO("radio is turned off by hardware"); else if (radio_status->radio_state == Ndis802_11RadioStatusSoftwareOff) INFO("radio is turned off by software"); break;#endif default: /* is this RSSI indication? */ TRACE2("unknown indication: %x", si->status_type); break; } break; default: TRACE2("unknown status: %08X", status); break; } EXIT2(return);}/* called via function pointer; but 64-bit RNDIS driver calls directly */wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1) (struct ndis_miniport_block *nmb){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER2("%p", wnd); schedule_wrap_work(&wnd->wrap_ndis_work); if (wnd->tx_ok) schedule_wrap_work(&wnd->tx_work);}/* called via function pointer */wstdcall void NdisMSendComplete(struct ndis_miniport_block *nmb, struct ndis_packet *packet, NDIS_STATUS status){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER4("%p, %08X", packet, status); if (deserialized_driver(wnd)) free_tx_packet(wnd, packet, status); else { struct ndis_packet_oob_data *oob_data; NDIS_STATUS pkt_status; TRACE3("%p, %08x", packet, status); oob_data = NDIS_PACKET_OOB_DATA(packet); switch ((pkt_status = xchg(&oob_data->status, status))) { case NDIS_STATUS_NOT_RECOGNIZED: free_tx_packet(wnd, packet, status); break; case NDIS_STATUS_PENDING: case 0: break; default: WARNING("%p: invalid status: %08X", packet, pkt_status); break; } /* In case a serialized driver has earlier requested a * pause by returning NDIS_STATUS_RESOURCES during * MiniportSend(Packets), wakeup tx worker now. */ if (xchg(&wnd->tx_ok, 1) == 0) { TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); schedule_wrap_work(&wnd->tx_work); } } EXIT3(return);}/* called via function pointer */wstdcall void NdisMSendResourcesAvailable(struct ndis_miniport_block *nmb){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); wnd->tx_ok = 1; schedule_wrap_work(&wnd->tx_work); EXIT3(return);}wstdcall void return_packet(void *arg1, void *arg2){ struct wrap_ndis_device *wnd; struct ndis_packet *packet; struct miniport_char *miniport; KIRQL irql; wnd = arg1; packet = arg2; ENTER4("%p, %p", wnd, packet); miniport = &wnd->wd->driver->ndis_driver->miniport; irql = serialize_lock_irql(wnd); LIN2WIN2(miniport->return_packet, wnd->nmb->adapter_ctx, packet); serialize_unlock_irql(wnd, irql); EXIT4(return);}WIN_FUNC_DECL(return_packet,2)/* called via function pointer */wstdcall void NdisMIndicateReceivePacket(struct ndis_miniport_block *nmb, struct ndis_packet **packets, UINT nr_packets){ struct wrap_ndis_device *wnd; ndis_buffer *buffer; struct ndis_packet *packet; struct sk_buff *skb; ULONG i, length, total_length; struct ndis_packet_oob_data *oob_data; void *virt; struct ndis_tcp_ip_checksum_packet_info csum; ENTER3("%p, %d", nmb, nr_packets); wnd = nmb->wnd; for (i = 0; i < nr_packets; i++) { packet = packets[i]; if (!packet) { WARNING("empty packet ignored"); continue; } wnd->net_dev->last_rx = jiffies; /* get total number of bytes in packet */ NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt, &length, &total_length, NormalPagePriority); TRACE3("%d, %d", length, total_length); oob_data = NDIS_PACKET_OOB_DATA(packet); TRACE3("0x%x, 0x%x, %Lu", packet->private.flags, packet->private.packet_flags, oob_data->time_rxed); skb = dev_alloc_skb(total_length); if (skb) { while (buffer) { memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), MmGetMdlByteCount(buffer)); buffer = buffer->next; } skb->dev = wnd->net_dev; skb->protocol = eth_type_trans(skb, wnd->net_dev); pre_atomic_add(wnd->net_stats.rx_bytes, total_length); atomic_inc_var(wnd->net_stats.rx_packets); csum.value = (typeof(csum.value))(ULONG_PTR) oob_data->ext.info[TcpIpChecksumPacketInfo]; TRACE3("0x%05x", csum.value); if (wnd->rx_csum.value && (csum.rx.tcp_succeeded || csum.rx.udp_succeeded || csum.rx.ip_succeeded)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); } else { WARNING("couldn't allocate skb; packet dropped"); atomic_inc_var(wnd->net_stats.rx_dropped); } /* serialized drivers check the status upon return * from this function */ if (!deserialized_driver(wnd)) { oob_data->status = NDIS_STATUS_SUCCESS; continue; } /* if a deserialized driver sets * NDIS_STATUS_RESOURCES, then it reclaims the packet * upon return from this function */ if (oob_data->status == NDIS_STATUS_RESOURCES) continue; assert(oob_data->status == NDIS_STATUS_SUCCESS); /* deserialized driver doesn't check the status upon * return from this function; we need to call * MiniportReturnPacket later for this packet. Calling * MiniportReturnPacket from here is not correct - the * driver doesn't expect it (at least Centrino driver * crashes) */ schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2), wnd, packet); } EXIT3(return);}/* called via function pointer (by NdisMEthIndicateReceive macro); the * first argument is nmb->eth_db */wstdcall void EthRxIndicateHandler(struct ndis_miniport_block *nmb, void *rx_ctx, char *header1, char *header, UINT header_size, void *look_ahead, UINT look_ahead_size, UINT packet_size){ struct sk_buff *skb = NULL; struct wrap_ndis_device *wnd; unsigned int skb_size = 0; KIRQL irql; struct ndis_packet_oob_data *oob_data; ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, " "size = %d, packet = %d", nmb, rx_ctx, header, header_size, look_ahead, look_ahead_size, packet_size); wnd = nmb->wnd; TRACE3("wnd = %p", wnd); if (!wnd) { ERROR("nmb is NULL"); EXIT3(return); } wnd->net_dev->last_rx = jiffies; if (look_ahead_size < packet_size) { struct ndis_packet *packet; struct miniport_char *miniport; unsigned int bytes_txed; NDIS_STATUS res; NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool); if (res != NDIS_STATUS_SUCCESS) { atomic_inc_var(wnd->net_stats.rx_dropped); EXIT3(return); } oob_data = NDIS_PACKET_OOB_DATA(packet); miniport = &wnd->wd->driver->ndis_driver->miniport; irql = serialize_lock_irql(wnd); res = LIN2WIN6(miniport->tx_data, packet, &bytes_txed, nmb, rx_ctx, look_ahead_size, packet_size); serialize_unlock_irql(wnd, irql); TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed); if (res == NDIS_STATUS_SUCCESS) { ndis_buffer *buffer; struct ndis_tcp_ip_checksum_packet_info csum; skb = dev_alloc_skb(header_size + look_ahead_size + bytes_txed); if (!skb) { ERROR("couldn't allocate skb; packet dropped"); atomic_inc_var(wnd->net_stats.rx_dropped); NdisFreePacket(packet); return; } memcpy_skb(skb, header, header_size); memcpy_skb(skb, look_ahead, look_ahead_size); buffer = packet->private.buffer_head; while (buffer) { memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), MmGetMdlByteCount(buffer)); buffer = buffer->next; } skb_size = header_size + look_ahead_size + bytes_txed; csum.value = (typeof(csum.value))(ULONG_PTR) oob_data->ext.info[TcpIpChecksumPacketInfo]; TRACE3("0x%05x", csum.value); if (wnd->rx_csum.value && (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; NdisFreePacket(packet); } else if (res == NDIS_STATUS_PENDING) { /* driver will call td_complete */ oob_data->look_ahead = kmalloc(look_ahead_size, GFP_ATOMIC); if (!oob_data->look_ahead) { NdisFreePacket(packet); ERROR("packet dropped"); atomic_inc_var(wnd->net_stats.rx_dropped); EXIT3(return); } assert(sizeof(oob_data->header) == header_size); memcpy(oob_data->header, header, sizeof(oob_data->header)); memcpy(oob_data->look_ahead, look_ahead, look_ahead_size); oob_data->look_ahead_size = look_ahead_size; EXIT3(return); } else { WARNING("packet dropped: %08X", res); atomic_inc_var(wnd->net_stats.rx_dropped); NdisFreePacket(packet); EXIT3(return); } } else { skb_size = header_size + packet_size; skb = dev_alloc_skb(skb_size); if (skb) { memcpy_skb(skb, header, header_size); memcpy_skb(skb, look_ahead, packet_size); } } if (skb) { skb->dev = wnd->net_dev; skb->protocol = eth_type_trans(skb, wnd->net_dev); pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); atomic_inc_var(wnd->net_stats.rx_packets); netif_rx(skb); } EXIT3(return);}/* called via function pointer */wstdcall void NdisMTransferDataComplete(struct ndis_miniport_block *nmb, struct ndis_packet *packet, NDIS_STATUS status, UINT bytes_txed){ struct wrap_ndis_device *wnd = nmb->wnd; struct sk_buff *skb; unsigned int skb_size; struct ndis_packet_oob_data *oob_data; ndis_buffer *buffer; struct ndis_tcp_ip_checksum_packet_info csum; ENTER3("wnd = %p, packet = %p, bytes_txed = %d", wnd, packet, bytes_txed); if (!packet) { WARNING("illegal packet"); EXIT3(return); } wnd->net_dev->last_rx = jiffies; oob_data = NDIS_PACKET_OOB_DATA(packet); skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size + bytes_txed; skb = dev_alloc_skb(skb_size); if (!skb) { kfree(oob_data->look_ahead); NdisFreePacket(packet); ERROR("couldn't allocate skb; packet dropped"); atomic_inc_var(wnd->net_stats.rx_dropped); EXIT3(return); } memcpy_skb(skb, oob_data->header, sizeof(oob_data->header)); memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size); buffer = packet->private.buffer_head; while (buffer) { memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), MmGetMdlByteCount(buffer)); buffer = buffer->next; } kfree(oob_data->look_ahead); NdisFreePacket(packet); skb->dev = wnd->net_dev; skb->protocol = eth_type_trans(skb, wnd->net_dev); pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); atomic_inc_var(wnd->net_stats
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -