📄 ndis.c
字号:
} if (dmasize == NDIS_DMA_24BITS) { if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_24BIT_MASK) || pci_set_consistent_dma_mask(wnd->wd->pci.pdev, DMA_24BIT_MASK)) WARNING("setting dma mask failed"); } else if (dmasize == NDIS_DMA_32BITS) { /* consistent dma is in low 32-bits by default */ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_32BIT_MASK)) WARNING("setting dma mask failed");#ifdef CONFIG_X86_64 } else if (dmasize == NDIS_DMA_64BITS) { if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_64BIT_MASK) || pci_set_consistent_dma_mask(wnd->wd->pci.pdev, DMA_64BIT_MASK)) WARNING("setting dma mask failed"); else wnd->net_dev->features |= NETIF_F_HIGHDMA;#endif } /* since memory for buffer is allocated with kmalloc, buffer * is physically contiguous, so entire map will fit in one * register */ if (basemap > 64) { WARNING("Windows driver %s requesting too many (%u) " "map registers", wnd->wd->driver->name, basemap); /* As per NDIS, NDIS_STATUS_RESOURCES should be * returned, but with that Atheros PCI driver fails - * for now tolerate it */// EXIT2(return NDIS_STATUS_RESOURCES); } wnd->dma_map_addr = kmalloc(basemap * sizeof(*(wnd->dma_map_addr)), GFP_KERNEL); if (!wnd->dma_map_addr) EXIT2(return NDIS_STATUS_RESOURCES); memset(wnd->dma_map_addr, 0, basemap * sizeof(*(wnd->dma_map_addr))); wnd->dma_map_count = basemap; TRACE2("%u", wnd->dma_map_count); EXIT2(return NDIS_STATUS_SUCCESS);}wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1) (struct ndis_mp_block *nmb){ struct wrap_ndis_device *wnd = nmb->wnd; int i; ENTER2("wnd: %p", wnd); if (wnd->dma_map_addr) { for (i = 0; i < wnd->dma_map_count; i++) { if (wnd->dma_map_addr[i]) WARNING("%s: dma addr %p not freed by " "Windows driver", wnd->net_dev->name, (void *)wnd->dma_map_addr[i]); } kfree(wnd->dma_map_addr); wnd->dma_map_addr = NULL; } else WARNING("map registers already freed?"); wnd->dma_map_count = 0; EXIT2(return);}wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6) (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index, BOOLEAN write_to_dev, struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count); if (unlikely(wnd->sg_dma_size || !write_to_dev || index >= wnd->dma_map_count)) { WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size, write_to_dev, index, wnd->dma_map_count); phy_addr_array[0].phy_addr = 0; phy_addr_array[0].length = 0; *array_size = 0; return; } if (wnd->dma_map_addr[index]) { TRACE2("buffer %p at %d is already mapped: %lx", buf, index, (unsigned long)wnd->dma_map_addr[index]);// *array_size = 1; return; } TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf), MmGetMdlByteCount(buf)); DBG_BLOCK(4) { dump_bytes(__FUNCTION__, MmGetSystemAddressForMdl(buf), MmGetMdlByteCount(buf)); } wnd->dma_map_addr[index] = PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, MmGetSystemAddressForMdl(buf), MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); phy_addr_array[0].phy_addr = wnd->dma_map_addr[index]; phy_addr_array[0].length = MmGetMdlByteCount(buf); TRACE4("%Lx, %d, %d", phy_addr_array[0].phy_addr, phy_addr_array[0].length, index); *array_size = 1;}wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3) (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index){ struct wrap_ndis_device *wnd = nmb->wnd; ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count); if (unlikely(wnd->sg_dma_size)) WARNING("buffer %p may have been unmapped already", buf); if (index >= wnd->dma_map_count) { ERROR("invalid map register (%u >= %u)", index, wnd->dma_map_count); return; } TRACE4("%lx", (unsigned long)wnd->dma_map_addr[index]); if (wnd->dma_map_addr[index]) { PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index], MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); wnd->dma_map_addr[index] = 0; } else WARNING("map registers at %u not used", index);}wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5) (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys){ dma_addr_t dma_addr; struct wrap_device *wd = nmb->wnd->wd; ENTER3("size: %u, cached: %d", size, cached); *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr); if (*virt) *phys = dma_addr; else WARNING("couldn't allocate %d bytes of %scached DMA memory", size, cached ? "" : "un-"); EXIT3(return);}wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5) (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *virt, NDIS_PHY_ADDRESS addr){ struct wrap_device *wd = nmb->wnd->wd; ENTER3("%p, %Lx, %u", virt, addr, size); PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr); EXIT3(return);}wstdcall void alloc_shared_memory_async(void *arg1, void *arg2){ struct wrap_ndis_device *wnd; struct alloc_shared_mem *alloc_shared_mem; struct miniport *mp; void *virt; NDIS_PHY_ADDRESS phys; KIRQL irql; wnd = arg1; alloc_shared_mem = arg2; mp = &wnd->wd->driver->ndis_driver->mp; NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size, alloc_shared_mem->cached, &virt, &phys); irql = serialize_lock_irql(wnd); assert_irql(_irql_ == DISPATCH_LEVEL); LIN2WIN5(mp->alloc_complete, wnd->nmb, virt, &phys, alloc_shared_mem->size, alloc_shared_mem->ctx); serialize_unlock_irql(wnd, irql); kfree(alloc_shared_mem);}WIN_FUNC_DECL(alloc_shared_memory_async,2)wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4) (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx){ struct wrap_ndis_device *wnd = nmb->wnd; struct alloc_shared_mem *alloc_shared_mem; ENTER3("wnd: %p", wnd); alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp()); if (!alloc_shared_mem) { WARNING("couldn't allocate memory"); return NDIS_STATUS_FAILURE; } alloc_shared_mem->size = size; alloc_shared_mem->cached = cached; alloc_shared_mem->ctx = ctx; if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2), wnd, alloc_shared_mem)) EXIT3(return NDIS_STATUS_FAILURE); EXIT3(return NDIS_STATUS_PENDING);}/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of * allocating and freeing with kernel functions, we chain them into * ndis_buffer_pool. When an MDL is freed, it is added to the list of * free MDLs. When allocated, we first check if there is one in free * list and if so just return it; otherwise, we allocate a new one and * return that. This reduces memory fragmentation. Windows DDK says * that the driver itself shouldn't check what is returned in * pool_handle, presumably because buffer pools are not used in * XP. However, as long as driver follows rest of the semantics - that * it should indicate maximum number of MDLs used with num_descr and * pass the same pool_handle in other buffer functions, this should * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle, * so we use 'process' field of MDL to store pool_handle. */wstdcall void WIN_FUNC(NdisAllocateBufferPool,3) (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle, UINT num_descr){ struct ndis_buffer_pool *pool; ENTER1("buffers: %d", num_descr); pool = kmalloc(sizeof(*pool), irql_gfp()); if (!pool) { *status = NDIS_STATUS_RESOURCES; EXIT3(return); } spin_lock_init(&pool->lock); pool->max_descr = num_descr; pool->num_allocated_descr = 0; pool->free_descr = NULL; *pool_handle = pool; *status = NDIS_STATUS_SUCCESS; TRACE1("pool: %p, num_descr: %d", pool, num_descr); EXIT1(return);}wstdcall void WIN_FUNC(NdisAllocateBuffer,5) (NDIS_STATUS *status, ndis_buffer **buffer, struct ndis_buffer_pool *pool, void *virt, UINT length){ ndis_buffer *descr; ENTER4("pool: %p, allocated: %d", pool, pool->num_allocated_descr); /* NDIS drivers should call this at DISPATCH_LEVEL, but * alloc_tx_packet calls at SOFT_IRQL */ assert_irql(_irql_ <= SOFT_LEVEL); if (!pool) { *status = NDIS_STATUS_FAILURE; *buffer = NULL; EXIT4(return); } spin_lock_bh(&pool->lock); if ((descr = pool->free_descr)) pool->free_descr = descr->next; spin_unlock_bh(&pool->lock); if (descr) { typeof(descr->flags) flags; flags = descr->flags; memset(descr, 0, sizeof(*descr)); MmInitializeMdl(descr, virt, length); if (flags & MDL_CACHE_ALLOCATED) descr->flags |= MDL_CACHE_ALLOCATED; } else { if (pool->num_allocated_descr > pool->max_descr) { TRACE2("pool %p is full: %d(%d)", pool, pool->num_allocated_descr, pool->max_descr);#ifndef ALLOW_POOL_OVERFLOW *status = NDIS_STATUS_FAILURE; *buffer = NULL; return;#endif } descr = allocate_init_mdl(virt, length); if (!descr) { WARNING("couldn't allocate buffer"); *status = NDIS_STATUS_FAILURE; *buffer = NULL; EXIT4(return); } TRACE4("buffer %p for %p, %d", descr, virt, length); atomic_inc_var(pool->num_allocated_descr); } /* TODO: make sure this mdl can map given buffer */ MmBuildMdlForNonPagedPool(descr);// descr->flags |= MDL_ALLOCATED_FIXED_SIZE |// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED; descr->pool = pool; *buffer = descr; *status = NDIS_STATUS_SUCCESS; TRACE4("buffer: %p", descr); EXIT4(return);}wstdcall void WIN_FUNC(NdisFreeBuffer,1) (ndis_buffer *buffer){ struct ndis_buffer_pool *pool; ENTER4("%p", buffer); if (!buffer || !buffer->pool) { ERROR("invalid buffer"); EXIT4(return); } pool = buffer->pool; spin_lock_bh(&pool->lock); if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) { /* NB NB NB: set mdl's 'pool' field to NULL before * calling free_mdl; otherwise free_mdl calls * NdisFreeBuffer causing deadlock (for spinlock) */ pool->num_allocated_descr--; buffer->pool = NULL; spin_unlock_bh(&pool->lock); free_mdl(buffer); } else { buffer->next = pool->free_descr; pool->free_descr = buffer; spin_unlock_bh(&pool->lock); } EXIT4(return);}wstdcall void WIN_FUNC(NdisFreeBufferPool,1) (struct ndis_buffer_pool *pool){ ndis_buffer *cur, *next; TRACE3("pool: %p", pool); if (!pool) { WARNING("invalid pool"); EXIT3(return); } spin_lock_bh(&pool->lock); cur = pool->free_descr; while (cur) { next = cur->next; cur->pool = NULL; free_mdl(cur); cur = next; } spin_unlock_bh(&pool->lock); kfree(pool); pool = NULL; EXIT3(return);}wstdcall void WIN_FUNC(NdisAdjustBufferLength,2) (ndis_buffer *buffer, UINT length){ ENTER4("%p, %d", buffer, length); buffer->bytecount = length;}wstdcall void WIN_FUNC(NdisQueryBuffer,3) (ndis_buffer *buffer, void **virt, UINT *length){ ENTER4("buffer: %p", buffer); if (virt) *virt = MmGetSystemAddressForMdl(buffer); *length = MmGetMdlByteCount(buffer); TRACE4("%p, %u", virt? *virt : NULL, *length); return;}wstdcall void WIN_FUNC(NdisQueryBufferSafe,4) (ndis_buffer *buffer, void **virt, UINT *length, enum mm_page_priority priority){ ENTER4("%p, %p, %p, %d", buffer, virt, length, priority); if (virt) *virt = MmGetSystemAddressForMdlSafe(buffer, priority); *length = MmGetMdlByteCount(buffer); TRACE4("%p, %u", virt? *virt : NULL, *length);}wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1) (ndis_buffer *buffer){ ENTER3("%p", buffer); return MmGetSystemAddressForMdl(buffer);}wstdcall ULONG WIN_FUNC(NdisBufferLength,1) (ndis_buffer *buffer){ ENTER3("%p", buffer); return MmGetMdlByteCount(buffer);}wstdcall void WIN_FUNC(NdisQueryBufferOffset,3) (ndis_buffer *buffer, UINT *offset, UINT *length){ ENTER3("%p", buffer); *offset = MmGetMdlByteOffset(buffer); *length = MmGetMdlByteCount(buffer); TRACE3("%d, %d", *offset, *length);}wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2) (struct ndis_packet *packet, ndis_buffer **buffer){ ndis_buffer *b, *btail; ENTER3("%p", packet); b = packet->private.buffer_head; if (!b) { /* no buffer in packet */ *buffer = NULL; EXIT3(return); } btail = packet->private.buffer_tail; *buffer = btail; if (b == btail) { /* one buffer in packet */ packet->private.buffer_head = NULL; packet->private.buffer_tail = NULL; } else { while (b->next != btail) b = b->next; packet->private.buffer_tail = b; b->next = NULL; } packet->private.valid_counts = FALSE; EXIT3(return);}wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2) (struct ndis_packet *packet, ndis_buffer **buffer){ ENTER3("%p", packet); if (packet->private.buffer_head == NULL) { /* no buffer in packet */ *buffer = NULL; EXIT3(return); } *buffer = packet->private.buffer_head; if (packet->private.buffer_head == packet->private.buffer_tail) { /* one buffer in packet */ packet->private.buffer_head = NULL; packet->private.buffer_tail = NULL; } else packet->private.buffer_head = (*buffer)->next; packet->private.valid_counts = FALSE; EXIT3(return);}wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6) (struct ndis_packet *packet, ndis_buffer **first_buffer, void **first_buffer_va, UINT *first_buffer_length, UINT *total_buffer_length, enum mm_page_priority priority){ ndis_buffer *b = packet->private.buffer_head; ENTER3("%p(%p)", packet, b); *first_buffer = b; if (b) { *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority); *first_buffer_length = *total_buffer_length = MmGetMdlByteCount(b); for (b = b->next; b; b = b->next) *total_buffer_length += MmGetMdlByteCount(b); } else { *first_buffer_va = NULL; *first_buffer_length = 0; *total_buffer_length = 0; } TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length, *total_buffer_length); EXIT3(return);}wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6) (struct ndis_packet *packet, ndis_buffer **first_buffer,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -