📄 ndis.c
字号:
/* * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include "ndis.h"#include "iw_ndis.h"#include "wrapndis.h"#include "pnp.h"#include "loader.h"#define MAX_ALLOCATED_NDIS_PACKETS 20#define MAX_ALLOCATED_NDIS_BUFFERS 20static struct workqueue_struct *ndis_wq;static void ndis_worker(void *dummy);static struct work_struct ndis_work;static struct nt_list ndis_worker_list;static NT_SPIN_LOCK ndis_work_list_lock;extern struct semaphore loader_mutex;/* ndis_init is called once when module is loaded */int ndis_init(void){#ifdef USE_OWN_WORKQUEUE ndis_wq = create_singlethread_workqueue("ndis_wq");#else ndis_wq = NULL;#endif InitializeListHead(&ndis_worker_list); nt_spin_lock_init(&ndis_work_list_lock); INIT_WORK(&ndis_work, ndis_worker, NULL); return 0;}/* ndis_exit is called once when module is removed */void ndis_exit(void){#ifdef USE_OWN_WORKQUEUE destroy_workqueue(ndis_wq);#endif TRACEEXIT1(return);}/* ndis_exit_device is called for each handle */void ndis_exit_device(struct wrap_ndis_device *wnd){ struct wrap_device_setting *setting; DBGTRACE2("%p", wnd); /* TI driver doesn't call NdisMDeregisterInterrupt during halt! */ if (wnd->ndis_irq) NdisMDeregisterInterrupt(wnd->ndis_irq); if (down_interruptible(&loader_mutex)) WARNING("couldn't obtain loader_mutex"); nt_list_for_each_entry(setting, &wnd->wd->settings, list) { struct ndis_configuration_parameter *param; param = setting->encoded; if (param) { if (param->type == NdisParameterString) RtlFreeUnicodeString(¶m->data.string); ExFreePool(param); setting->encoded = NULL; } } up(&loader_mutex);}wstdcall void WIN_FUNC(NdisInitializeWrapper,4) (void **driver_handle, struct driver_object *driver, struct unicode_string *reg_path, void *unused){ TRACEENTER1("handle: %p, driver: %p", driver_handle, driver); *driver_handle = driver; TRACEEXIT1(return);}wstdcall void WIN_FUNC(NdisTerminateWrapper,2) (struct device_object *dev_obj, void *system_specific){ TRACEEXIT1(return);}wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3) (struct driver_object *drv_obj, struct miniport_char *miniport_char, UINT length){ int min_length; struct wrap_driver *wrap_driver; struct wrap_ndis_driver *ndis_driver; min_length = ((char *)&miniport_char->co_create_vc) - ((char *)miniport_char); TRACEENTER1("%p %p %d", drv_obj, miniport_char, length); if (miniport_char->major_version < 4) { ERROR("Driver is using ndis version %d which is too old.", miniport_char->major_version); TRACEEXIT1(return NDIS_STATUS_BAD_VERSION); } if (length < min_length) { ERROR("Characteristics length %d is too small", length); TRACEEXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS); } DBGTRACE1("%d.%d, %d, %u", miniport_char->major_version, miniport_char->minor_version, length, (u32)sizeof(struct miniport_char)); wrap_driver = IoGetDriverObjectExtension(drv_obj, (void *)WRAP_DRIVER_CLIENT_ID); if (!wrap_driver) { ERROR("couldn't get wrap_driver"); TRACEEXIT1(return NDIS_STATUS_RESOURCES); } if (IoAllocateDriverObjectExtension( drv_obj, (void *)NDIS_DRIVER_CLIENT_ID, sizeof(*ndis_driver), (void **)&ndis_driver) != STATUS_SUCCESS) TRACEEXIT1(return NDIS_STATUS_RESOURCES); wrap_driver->ndis_driver = ndis_driver; TRACEENTER1("driver: %p", ndis_driver); memcpy(&ndis_driver->miniport, miniport_char, length > sizeof(*miniport_char) ? sizeof(*miniport_char) : length); DBG_BLOCK(2) { int i; void **func; char *miniport_funcs[] = { "query", "reconfig", "reset", "send", "setinfo", "tx_data", "return_packet", "send_packets", "alloc_complete", "co_create_vc", "co_delete_vc", "co_activate_vc", "co_deactivate_vc", "co_send_packets", "co_request", "cancel_send_packets", "pnp_event_notify", "shutdown", }; func = (void **)&ndis_driver->miniport.query; for (i = 0; i < (sizeof(miniport_funcs) / sizeof(miniport_funcs[0])); i++) DBGTRACE2("function '%s' is at %p", miniport_funcs[i], func[i]); } TRACEEXIT1(return NDIS_STATUS_SUCCESS);}wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6) (struct driver_object *drv_obj, struct unicode_string *dev_name, struct unicode_string *link, void **funcs, struct device_object **dev_obj, void **dev_obj_handle){ NTSTATUS status; struct device_object *tmp; int i; TRACEENTER1("%p, %p, %p", drv_obj, dev_name, link); status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0, FALSE, &tmp); if (status != STATUS_SUCCESS) TRACEEXIT1(return NDIS_STATUS_RESOURCES); if (link) status = IoCreateSymbolicLink(link, dev_name); if (status != STATUS_SUCCESS) { IoDeleteDevice(tmp); TRACEEXIT1(return NDIS_STATUS_RESOURCES); } *dev_obj = tmp; *dev_obj_handle = *dev_obj; for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) { drv_obj->major_func[i] = funcs[i]; DBGTRACE1("mj_fn for 0x%x is at %p", i, funcs[i]); } TRACEEXIT1(return NDIS_STATUS_SUCCESS);}wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1) (struct device_object *dev_obj){ TRACEENTER2("%p", dev_obj); IoDeleteDevice(dev_obj); return NDIS_STATUS_SUCCESS;}wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3) (void **dest, UINT length, ULONG tag){ void *res; res = ExAllocatePoolWithTag(NonPagedPool, length, tag); if (res) { *dest = res; TRACEEXIT4(return NDIS_STATUS_SUCCESS); } else TRACEEXIT4(return NDIS_STATUS_FAILURE);}wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4) (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address){ return NdisAllocateMemoryWithTag(dest, length, 0);}/* length_tag is either length or tag, depending on if * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate * memory */wstdcall void WIN_FUNC(NdisFreeMemory,3) (void *addr, UINT length_tag, UINT flags){ ExFreePool(addr);}noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12) (struct driver_object *drv_obj, ULONG error, ULONG count, ...){ va_list args; int i; ULONG code; va_start(args, count); ERROR("log: %08X, count: %d, return_address: %p", error, count, __builtin_return_address(0)); for (i = 0; i < count; i++) { code = va_arg(args, ULONG); ERROR("code: %u", code); } va_end(args); TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisOpenConfiguration,3) (NDIS_STATUS *status, struct ndis_miniport_block **conf_handle, struct ndis_miniport_block *handle){ TRACEENTER2("%p", conf_handle); *conf_handle = handle; *status = NDIS_STATUS_SUCCESS; TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3) (NDIS_STATUS *status, void **confhandle, struct unicode_string *section){ TRACEENTER2("%p", confhandle); *status = NDIS_STATUS_SUCCESS; TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4) (NDIS_STATUS *status, void *handle, struct unicode_string *key, void **subkeyhandle){ struct ansi_string ansi; TRACEENTER2(""); if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) { DBGTRACE2("%s", ansi.buf); RtlFreeAnsiString(&ansi); } *subkeyhandle = handle; *status = NDIS_STATUS_SUCCESS; TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5) (NDIS_STATUS *status, void *handle, ULONG index, struct unicode_string *key, void **subkeyhandle){ TRACEENTER2("%u", index);// *subkeyhandle = handle; *status = NDIS_STATUS_FAILURE; TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisCloseConfiguration,1) (void *handle){ /* instead of freeing all configuration parameters as we are * supposed to do here, we free them when the device is * removed */ TRACEENTER2("%p", handle); return;}wstdcall void WIN_FUNC(NdisOpenFile,5) (NDIS_STATUS *status, struct wrap_bin_file **file, UINT *filelength, struct unicode_string *filename, NDIS_PHY_ADDRESS highest_address){ struct ansi_string ansi; struct wrap_bin_file *bin_file; TRACEENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file); if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) != STATUS_SUCCESS) { *status = NDIS_STATUS_RESOURCES; TRACEEXIT2(return); } DBGTRACE2("%s", ansi.buf); bin_file = get_bin_file(ansi.buf); if (bin_file) { *file = bin_file; *filelength = bin_file->size; *status = NDIS_STATUS_SUCCESS; } else *status = NDIS_STATUS_FILE_NOT_FOUND; RtlFreeAnsiString(&ansi); TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisMapFile,3) (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file){ TRACEENTER2("%p", file); if (!file) { *status = NDIS_STATUS_ALREADY_MAPPED; TRACEEXIT2(return); } *status = NDIS_STATUS_SUCCESS; *mappedbuffer = file->data; TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisUnmapFile,1) (struct wrap_bin_file *file){ TRACEENTER2("%p", file); TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisCloseFile,1) (struct wrap_bin_file *file){ TRACEENTER2("%p", file); free_bin_file(file); TRACEEXIT2(return);}wstdcall void WIN_FUNC(NdisGetSystemUpTime,1) (ULONG *ms){ TRACEENTER5(""); *ms = 1000 * jiffies / HZ; TRACEEXIT5(return);}wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1) (ndis_buffer *buffer){ ULONG n, length; if (buffer == NULL) return 0; if (MmGetMdlByteCount(buffer) == 0) return 1; length = MmGetMdlByteCount(buffer); n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length); DBGTRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva, length, n); TRACEEXIT3(return n);}wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2) (ndis_buffer *buffer, UINT *arraysize){ TRACEENTER3("%p", buffer); *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer); TRACEEXIT3(return);}static struct ndis_configuration_parameter *ndis_encode_setting(struct wrap_device_setting *setting, enum ndis_parameter_type type){ struct ansi_string ansi; struct ndis_configuration_parameter *param; param = setting->encoded; if (param) { if (param->type == type) TRACEEXIT2(return param); if (param->type == NdisParameterString) RtlFreeUnicodeString(¶m->data.string); setting->encoded = NULL; } else param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0); if (!param) { ERROR("couldn't allocate memory"); return NULL; } switch(type) { case NdisParameterInteger: param->data.integer = simple_strtol(setting->value, NULL, 0); DBGTRACE2("%u", (ULONG)param->data.integer); break; case NdisParameterHexInteger: param->data.integer = simple_strtol(setting->value, NULL, 16); DBGTRACE2("%u", (ULONG)param->data.integer); break; case NdisParameterString: RtlInitAnsiString(&ansi, setting->value); DBGTRACE2("'%s'", ansi.buf); if (RtlAnsiStringToUnicodeString(¶m->data.string, &ansi, TRUE)) { ExFreePool(param); TRACEEXIT2(return NULL); } break; default: ERROR("unknown type: %d", type); ExFreePool(param); return NULL; } param->type = type; setting->encoded = param; TRACEEXIT2(return param);}static int ndis_decode_setting(struct wrap_device_setting *setting, struct ndis_configuration_parameter *param){ struct ansi_string ansi; struct ndis_configuration_parameter *prev; TRACEENTER2("%p, %p", setting, param); prev = setting->encoded; if (prev && prev->type == NdisParameterString) { RtlFreeUnicodeString(&prev->data.string); setting->encoded = NULL; } switch(param->type) { case NdisParameterInteger: snprintf(setting->value, sizeof(u32), "%u", param->data.integer); setting->value[sizeof(ULONG)] = 0; break; case NdisParameterHexInteger: snprintf(setting->value, sizeof(u32), "%x", param->data.integer); setting->value[sizeof(ULONG)] = 0; break; case NdisParameterString: ansi.buf = setting->value; ansi.max_length = MAX_SETTING_VALUE_LEN; if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, FALSE) != STATUS_SUCCESS) || ansi.length >= MAX_SETTING_VALUE_LEN) { TRACEEXIT1(return -1); } if (ansi.length == ansi.max_length) ansi.length--; setting->value[ansi.length] = 0; break; default: DBGTRACE2("unknown setting type: %d", param->type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -