📄 ndis.c
字号:
wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx){ struct ndis_mp_interrupt *mp_interrupt = ctx; struct wrap_ndis_device *wnd = mp_interrupt->nmb->wnd; BOOLEAN recognized, queue_handler; TRACE6("%p", wnd); /* kernel may call ISR when registering interrupt, in * the same context if DEBUG_SHIRQ is enabled */ assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL); if (mp_interrupt->shared) LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler, wnd->nmb->mp_ctx); else { struct miniport *mp; mp = &wnd->wd->driver->ndis_driver->mp; LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx); /* it is not shared interrupt, so handler must be called */ recognized = queue_handler = TRUE; } if (recognized) { if (queue_handler) { TRACE5("%p", &wnd->irq_kdpc); queue_kdpc(&wnd->irq_kdpc); } EXIT6(return TRUE); } EXIT6(return FALSE);}WIN_FUNC_DECL(ndis_isr,2)wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7) (struct ndis_mp_interrupt *mp_interrupt, struct ndis_mp_block *nmb, UINT vector, UINT level, BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode){ struct wrap_ndis_device *wnd = nmb->wnd; struct miniport *mp; ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d", mp_interrupt, vector, level, req_isr, shared, mode); mp = &wnd->wd->driver->ndis_driver->mp; nt_spin_lock_init(&mp_interrupt->lock); mp_interrupt->irq = vector; mp_interrupt->isr = mp->isr; mp_interrupt->mp_dpc = mp->handle_interrupt; mp_interrupt->nmb = nmb; mp_interrupt->req_isr = req_isr; if (shared && !req_isr) WARNING("shared but dynamic interrupt!"); mp_interrupt->shared = shared; wnd->mp_interrupt = mp_interrupt; if (mp->enable_interrupt) mp_interrupt->enable = TRUE; else mp_interrupt->enable = FALSE; if (deserialized_driver(wnd)) { KeInitializeDpc(&wnd->irq_kdpc, WIN_FUNC_PTR(deserialized_irq_handler,4), nmb->wnd); wnd->irq_kdpc.arg1 = mp->handle_interrupt; wnd->irq_kdpc.arg2 = mp; TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, nmb->wnd, nmb->mp_ctx); } else { KeInitializeDpc(&wnd->irq_kdpc, WIN_FUNC_PTR(serialized_irq_handler,4), nmb->wnd); wnd->irq_kdpc.arg1 = mp->handle_interrupt; wnd->irq_kdpc.arg2 = nmb->mp_ctx; TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, nmb->wnd, nmb->mp_ctx); } if (IoConnectInterrupt(&mp_interrupt->kinterrupt, WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL, vector, DIRQL, DIRQL, mode, shared, 0, FALSE) != STATUS_SUCCESS) { printk(KERN_WARNING "%s: request for IRQ %d failed\n", DRIVER_NAME, vector); return NDIS_STATUS_RESOURCES; } printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector); EXIT1(return NDIS_STATUS_SUCCESS);}wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1) (struct ndis_mp_interrupt *mp_interrupt){ struct ndis_mp_block *nmb; ENTER1("%p", mp_interrupt); nmb = xchg(&mp_interrupt->nmb, NULL); TRACE1("%p", nmb); if (!nmb) { WARNING("interrupt already freed?"); return; } nmb->wnd->mp_interrupt = NULL; if (dequeue_kdpc(&nmb->wnd->irq_kdpc)) TRACE2("interrupt kdpc was pending"); IoDisconnectInterrupt(mp_interrupt->kinterrupt); EXIT1(return);}wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) (struct ndis_mp_interrupt *mp_interrupt, PKSYNCHRONIZE_ROUTINE sync_func, void *ctx){ return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx);}/* called via function pointer; but 64-bit RNDIS driver calls directly */wstdcall void WIN_FUNC(NdisMIndicateStatus,4) (struct ndis_mp_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_CONNECT: netif_carrier_on(wnd->net_dev); wnd->tx_ok = 1; if (netif_queue_stopped(wnd->net_dev)) netif_wake_queue(wnd->net_dev); if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { set_bit(LINK_STATUS_ON, &wnd->wrap_ndis_pending_work); schedule_wrapndis_work(&wnd->wrap_ndis_work); } break; case NDIS_STATUS_MEDIA_DISCONNECT: netif_carrier_off(wnd->net_dev); netif_stop_queue(wnd->net_dev); wnd->tx_ok = 0; if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { memset(&wnd->essid, 0, sizeof(wnd->essid)); set_bit(LINK_STATUS_OFF, &wnd->wrap_ndis_pending_work); schedule_wrapndis_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_MediaStreamMode: break;#ifdef CONFIG_WIRELESS_EXT case Ndis802_11StatusType_Authentication: buf = (char *)buf + sizeof(*si); len -= sizeof(*si); while (len > 0) { int pairwise_error = 0, group_error = 0; auth_req = (struct ndis_auth_req *)buf; TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); if (auth_req->flags & 0x01) TRACE2("reauth request"); if (auth_req->flags & 0x02) TRACE2("key update request"); if (auth_req->flags & 0x06) { pairwise_error = 1; TRACE2("pairwise_error"); } if (auth_req->flags & 0x0E) { group_error = 1; TRACE2("group_error"); }#if WIRELESS_EXT > 17 if (pairwise_error || group_error) { union iwreq_data wrqu; struct iw_michaelmicfailure micfailure; memset(&micfailure, 0, sizeof(micfailure)); if (pairwise_error) micfailure.flags |= IW_MICFAILURE_PAIRWISE; if (group_error) micfailure.flags |= IW_MICFAILURE_GROUP; memcpy(micfailure.src_addr.sa_data, auth_req->bssid, ETH_ALEN); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(micfailure); wireless_send_event(wnd->net_dev, IWEVMICHAELMICFAILURE, &wrqu, (u8 *)&micfailure); }#endif len -= auth_req->length; buf = (char *)buf + auth_req->length; } break; 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 ignored"); EXIT1(return); } end = (u8 *)buf + len; TRACE2("PMKID ver %d num_cand %d", 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"); break; } TRACE2("%ld: " MACSTRSEP " 0x%x", 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_mp_block *nmb){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER2("%p", wnd); if (wnd->tx_ok) schedule_wrapndis_work(&wnd->tx_work);}/* called via function pointer */wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet, NDIS_STATUS status){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER4("%p, %08X", packet, status); assert_irql(_irql_ <= DISPATCH_LEVEL); 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_wrapndis_work(&wnd->tx_work); } } EXIT3(return);}/* called via function pointer */wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_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_wrapndis_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 *mp; KIRQL irql; wnd = arg1; packet = arg2; ENTER4("%p, %p", wnd, packet); mp = &wnd->wd->driver->ndis_driver->mp; irql = serialize_lock_irql(wnd); assert_irql(_irql_ == DISPATCH_LEVEL); LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet); serialize_unlock_irql(wnd, irql); EXIT4(return);}WIN_FUNC_DECL(return_packet,2)/* called via function pointer */wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_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); assert_irql(_irql_ <= DISPATCH_LEVEL); 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; if (in_interrupt()) netif_rx(skb); else netif_rx_ni(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_mp_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 *mp; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -