📄 ndis.c
字号:
TRACEENTER1("%s", ""); ansi.buf = "mac_address"; ansi.buflen = strlen(ansi.buf); ansi.len = ansi.buflen; *len = 0; *status = NDIS_STATUS_FAILURE; if (RtlAnsiStringToUnicodeString(&key, &ansi, 1) != NDIS_STATUS_SUCCESS) TRACEEXIT1(return); NdisReadConfiguration(status, &setting, handle, &key, NDIS_CONFIG_PARAM_STRING); RtlFreeUnicodeString(&key); if (*status == NDIS_STATUS_SUCCESS) { int int_mac[ETH_ALEN]; ret = RtlUnicodeStringToAnsiString(&ansi, &setting->data.ustring, 1); if (ret != NDIS_STATUS_SUCCESS) TRACEEXIT1(return); ret = sscanf(ansi.buf, MACSTR, MACINTADR(int_mac)); RtlFreeAnsiString(&ansi); if (ret == ETH_ALEN) { int i; for (i = 0; i < ETH_ALEN; i++) handle->mac[i] = int_mac[i]; printk(KERN_INFO "%s: %s ethernet device " MACSTR "\n", handle->net_dev->name, DRIVER_NAME, MAC2STR(handle->mac)); *len = ETH_ALEN; *addr = handle->mac; *status = NDIS_STATUS_SUCCESS; } } TRACEEXIT1(return);}STDCALL void WRAP_EXPORT(NdisMRegisterAdapterShutdownHandler) (struct ndis_handle *handle, void *ctx, void *func){ TRACEENTER1("sp:%p", get_sp()); handle->driver->miniport_char.adapter_shutdown = func; handle->shutdown_ctx = ctx;}STDCALL void WRAP_EXPORT(NdisMDeregisterAdapterShutdownHandler) (struct ndis_handle *handle){ TRACEENTER1("sp:%p", get_sp()); handle->driver->miniport_char.adapter_shutdown = NULL; handle->shutdown_ctx = NULL;}/* bottom half of the irq handler */static void ndis_irq_bh(void *data){ struct ndis_irq *ndis_irq = (struct ndis_irq *)data; struct ndis_handle *handle = ndis_irq->handle; struct miniport_char *miniport = &handle->driver->miniport_char; KIRQL irql; if (ndis_irq->enabled) { irql = raise_irql(DISPATCH_LEVEL); LIN2WIN1(miniport->handle_interrupt, handle->adapter_ctx); if (miniport->enable_interrupts) LIN2WIN1(miniport->enable_interrupts, handle->adapter_ctx); lower_irql(irql); }}/* Top half of the irq handler */static irqreturn_t ndis_irq_th(int irq, void *data, struct pt_regs *pt_regs){ int recognized = 0; int handled = 0; struct ndis_irq *ndis_irq = (struct ndis_irq *)data; struct ndis_handle *handle; struct miniport_char *miniport; unsigned long flags; if (!ndis_irq || !ndis_irq->handle) return IRQ_NONE; handle = ndis_irq->handle; miniport = &handle->driver->miniport_char; /* this spinlock should be shared with NdisMSynchronizeWithInterrupt */ kspin_lock_irqsave(&ndis_irq->lock, flags); if (ndis_irq->req_isr) LIN2WIN3(miniport->isr, &recognized, &handled, handle->adapter_ctx); else { //if (miniport->disable_interrupts) LIN2WIN1(miniport->disable_interrupts, handle->adapter_ctx); /* it is not shared interrupt, so handler must be called */ recognized = handled = 1; } kspin_unlock_irqrestore(&ndis_irq->lock, flags); if (recognized && handled) schedule_work(&handle->irq_work); if (recognized) return IRQ_HANDLED; return IRQ_NONE;}STDCALL NDIS_STATUS WRAP_EXPORT(NdisMRegisterInterrupt) (struct ndis_irq *ndis_irq, struct ndis_handle *handle, UINT vector, UINT level, BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode){ TRACEENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, " "mode:%d sp:%p", ndis_irq, vector, level, req_isr, shared, mode, get_sp()); ndis_irq->irq.irq = vector; ndis_irq->handle = handle; ndis_irq->req_isr = req_isr; if (shared && !req_isr) WARNING("%s", "shared but dynamic interrupt!"); ndis_irq->shared = shared; kspin_lock_init(&ndis_irq->lock); INIT_WORK(&handle->irq_work, &ndis_irq_bh, ndis_irq); if (request_irq(vector, ndis_irq_th, shared? SA_SHIRQ : 0, "ndiswrapper", ndis_irq)) { printk(KERN_WARNING "%s: request for irq %d failed\n", DRIVER_NAME, vector); TRACEEXIT1(return NDIS_STATUS_RESOURCES); } ndis_irq->enabled = 1; printk(KERN_INFO "%s: using irq %d\n", DRIVER_NAME, vector); TRACEEXIT1(return NDIS_STATUS_SUCCESS);}STDCALL void WRAP_EXPORT(NdisMDeregisterInterrupt) (struct ndis_irq *ndis_irq){ struct ndis_handle *handle; TRACEENTER1("%p", ndis_irq); if (!ndis_irq) TRACEEXIT1(return); handle = ndis_irq->handle; if (!handle) TRACEEXIT1(return); ndis_irq->enabled = 0; /* flush irq_bh workqueue; calling it before enabled=0 will * crash since some drivers (Centrino at least) don't expect * irq hander to be called anymore */ /* cancel_delayed_work is probably better, but 2.4 kernels * don't have equivalent function */#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,6,0) flush_scheduled_work();#else set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10);#endif free_irq(ndis_irq->irq.irq, ndis_irq); ndis_irq->handle = NULL; handle->ndis_irq = NULL; TRACEEXIT1(return);}STDCALL BOOLEAN WRAP_EXPORT(NdisMSynchronizeWithInterrupt) (struct ndis_irq *ndis_irq, void *func, void *ctx){ unsigned char ret; unsigned char (*sync_func)(void *ctx) STDCALL; unsigned long flags; TRACEENTER5("%p %p %p\n", ndis_irq, func, ctx); if (func == NULL || ctx == NULL) TRACEEXIT5(return 0); sync_func = func; kspin_lock_irqsave(&ndis_irq->lock, flags); ret = LIN2WIN1(sync_func, ctx); kspin_unlock_irqrestore(&ndis_irq->lock, flags); DBGTRACE5("sync_func returns %u", ret); TRACEEXIT5(return ret);}/* called via function pointer */STDCALL voidNdisMIndicateStatus(struct ndis_handle *handle, NDIS_STATUS status, void *buf, UINT len){ TRACEENTER2("%08x", status); if (status == NDIS_STATUS_MEDIA_DISCONNECT) { handle->link_status = 0; handle->send_ok = 0; set_bit(LINK_STATUS_CHANGED, &handle->wrapper_work); } if (status == NDIS_STATUS_MEDIA_CONNECT) { handle->link_status = 1; handle->send_ok = 1; set_bit(LINK_STATUS_CHANGED, &handle->wrapper_work); } if (status == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION && buf) { struct ndis_status_indication *status = buf; struct ndis_auth_req *auth_req; struct ndis_radio_status_indication *radio_status; switch (status->status_type) { case Ndis802_11StatusType_Authentication: buf = (char *)buf + sizeof(*status); len -= sizeof(*status); while (len > 0) { auth_req = (struct ndis_auth_req *)buf; DBGTRACE1(MACSTR, MAC2STR(auth_req->bssid)); if (auth_req->flags & 0x01) DBGTRACE2("%s", "reqauth"); if (auth_req->flags & 0x02) DBGTRACE2("%s", "keyupdate"); if (auth_req->flags & 0x06) DBGTRACE2("%s", "pairwise_error"); if (auth_req->flags & 0x0E) DBGTRACE2("%s", "group_error"); len -= auth_req->length; buf = (char *)buf + auth_req->length; } break; case Ndis802_11StatusType_MediaStreamMode: break; case Ndis802_11StatusType_PMKID_CandidateList: 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; } } TRACEEXIT1(return);}/* called via function pointer */STDCALL void NdisMIndicateStatusComplete(struct ndis_handle *handle){ TRACEENTER3("%s", ""); schedule_work(&handle->wrapper_worker);}/* called via function pointer */STDCALL voidNdisMIndicateReceivePacket(struct ndis_handle *handle, struct ndis_packet **packets, UINT nr_packets){ ndis_buffer *buffer; struct ndis_packet *packet; struct sk_buff *skb; int i; struct ndis_work_entry *ndis_work_entry; KIRQL irql; TRACEENTER3("%s", ""); for (i = 0; i < nr_packets; i++) { packet = packets[i]; if (!packet) { WARNING("%s", "Skipping empty packet on receive"); continue; } buffer = packet->private.buffer_head; skb = dev_alloc_skb(MmGetMdlByteCount(buffer)); if (skb) { skb->dev = handle->net_dev; eth_copy_and_sum(skb, MmGetMdlVirtualAddress(buffer), MmGetMdlByteCount(buffer), 0); skb_put(skb, MmGetMdlByteCount(buffer)); skb->protocol = eth_type_trans(skb, handle->net_dev); handle->stats.rx_bytes += MmGetMdlByteCount(buffer); handle->stats.rx_packets++; netif_rx(skb); } else handle->stats.rx_dropped++; /* serialized drivers check the status upon return * from this function */ if (test_bit(ATTR_SERIALIZED, &handle->attributes)) { packet->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: it doesn't matter * what value we set in the status */ if (packet->oob_data.status == NDIS_STATUS_RESOURCES) { packet->oob_data.status = NDIS_STATUS_SUCCESS; DBGTRACE3("low on resources"); continue; } if (packet->oob_data.status != NDIS_STATUS_SUCCESS) WARNING("invalid packet status %08X", packet->oob_data.status); /* 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) */ packet->oob_data.status = NDIS_STATUS_PENDING; ndis_work_entry = kmalloc(sizeof(*ndis_work_entry), GFP_ATOMIC); if (!ndis_work_entry) { ERROR("couldn't allocate memory"); continue; } ndis_work_entry->type = NDIS_RETURN_PACKET_WORK_ITEM; ndis_work_entry->handle = handle; ndis_work_entry->entry.return_packet = packet; irql = kspin_lock_irql(&ndis_work_list_lock, DISPATCH_LEVEL); list_add_tail(&ndis_work_entry->list, &ndis_work_list); kspin_unlock_irql(&ndis_work_list_lock, irql); } schedule_work(&ndis_work); TRACEEXIT3(return);}STDCALL void WRAP_EXPORT(NdisMCoIndicateReceivePacket) (struct ndis_handle *handle, struct ndis_packet **packets, UINT nr_packets){ TRACEENTER3("handle = %p", handle); NdisMIndicateReceivePacket(handle, packets, nr_packets); TRACEEXIT3(return);}/* called via function pointer */STDCALL voidNdisMSendComplete(struct ndis_handle *handle, struct ndis_packet *packet, NDIS_STATUS status){ TRACEENTER3("%08x", status); sendpacket_done(handle, packet); /* In case a serialized driver has requested a pause by returning * NDIS_STATUS_RESOURCES we need to give the send-code a kick again. */ handle->send_ok = 1; schedule_work(&handle->xmit_work); TRACEEXIT3(return);}STDCALL void WRAP_EXPORT(NdisMCoSendComplete) (NDIS_STATUS status, struct ndis_handle *handle, struct ndis_packet *packet){ TRACEENTER3("%08x", status); NdisMSendComplete(handle, packet, status); TRACEEXIT3(return);}/* called via function pointer */STDCALL voidNdisMSendResourcesAvailable(struct ndis_handle *handle){ TRACEENTER3("%s", ""); /* sending packets immediately seem to result in NDIS_STATUS_FAILURE, so wait for a while before sending the packet again */ mdelay(5); handle->send_ok = 1; schedule_work(&handle->xmit_work); TRACEEXIT3(return);}/* called via function pointer (by NdisMEthIndicateReceive macro) */STDCALL voidEthRxIndicateHandler(void *adapter_ctx, 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 ndis_handle *handle = ctx_to_handle(rx_ctx); unsigned int skb_size = 0; KIRQL irql; TRACEENTER3("adapter_ctx = %p, rx_ctx = %p, buf = %p, size = %d, " "buf = %p, size = %d, packet = %d", adapter_ctx, rx_ctx, header, header_size, look_ahead, look_ahead_size, packet_size); DBGTRACE3("handle = %p", handle); if (!handle) TRACEEXIT3(return); if (look_ahead_size < packet_size) { struct ndis_packet *packet; struct miniport_char *miniport; unsigned int res, bytes_txed; packet = allocate_ndis_packet(); if (!packet) { handle->stats.rx_dropped++; TRACEEXIT3(return); } packet->private.pool = NULL; miniport = &handle->driver->miniport_char; irql = raise_irql(DISPATCH_LEVEL); res = LIN2WIN6(miniport->tx_data, packet, &bytes_txed, adapter_ctx, rx_ctx, look_ahead_size, packet_size); lower_irql(irql); if (res == NDIS_STATUS_SUCCESS) { ndis_buffer *buffer; skb = dev_alloc_skb(header_size+look_ahead_size+ bytes_txed); if (skb) { memcpy(skb->data, header, header_size); memcpy(skb->data+header_size, look_ahead, look_ahead_size); buffer = packet->private.buffer_head; memcpy(skb->data+header_size+look_ahead_size, MmGetMdlVirtualAddress(buffer), bytes_txed); skb_size = header_size+look_ahead_size+ bytes_txed; free_ndis_packet(packet); } } else if (res == NDIS_STATUS_PENDING) { /* driver will call td_complete */ packet->look_ahead = kmalloc(look_ahead_size, GFP_ATOMIC); if (!packet->look_ahead) { free_ndis_packet(packet); handle->stats.rx_dropped++; TRACEEXIT3(return); } memcpy(&packet->header, header, sizeof(packet->header)); memcpy(packet->look_ahead, look_ahead, look_ahead_size); packet->look_ahead_size = look_ahead_size; } else { free_ndis_packet(packet); handle->stats.rx_dropped++; TRACEEXIT3(return); } } else { skb_size = header_size+packet_size; skb = dev_alloc_skb(skb_size); if (skb) { memcpy(skb->data, header, header_size); memcpy(skb->data+header_size, look_ahead, packet_size); } } if (skb && skb_size > 0) { skb->dev = handle->net_dev; skb_put(skb, skb_size); skb->protocol = eth_type_trans(skb, handle->net_dev); handle->stats.rx_bytes += skb_size; handle->stats.rx_packets++; netif_rx(skb); } else handle->stats.rx_dropped++; TRACEEXIT3(return);}/* called via function pointer */STDCALL voidNdisMTransferDataComplete(struct ndis_handle *handle, struct ndis_packet *packet, NDIS_STATUS status, UINT bytes_txed){ struct sk_buff *skb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -