📄 loader.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 "loader.h"#include "wrapndis.h"#include "pnp.h"#include <linux/module.h>#include <linux/kmod.h>#include <linux/miscdevice.h>#include <asm/uaccess.h>/* Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318} Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318} PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318} USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}*//* the indices used here must match macros WRAP_NDIS_DEVICE etc. */static struct guid class_guids[] = { /* Network */ {0x4d36e972, 0xe325, 0x11ce, }, /* USB WDM */ {0x36fc9e60, 0xc465, 0x11cf, }, /* Bluetooth */ {0xe0cbf06c, 0xcd8b, 0x4647, }, /* ivtcorporatino.com's bluetooth device claims this is * bluetooth guid */ {0xf12d3cf8, 0xb11d, 0x457e, },};struct semaphore loader_mutex;static struct completion loader_complete;static struct nt_list wrap_devices;static struct nt_list wrap_drivers;static struct pci_device_id wrap_pci_device;static struct pci_driver wrap_pci_driver;#if defined(CONFIG_USB)static struct usb_device_id wrap_usb_device;static struct usb_driver wrap_usb_driver;#endifint wrap_device_type(int data1){ int i; for (i = 0; i < sizeof(class_guids) / sizeof(class_guids[0]); i++) if (data1 == class_guids[i].data1) return i; ERROR("unknown device: 0x%x\n", data1); return -1;}/* load driver for given device, if not already loaded */struct wrap_driver *load_wrap_driver(struct wrap_device *wd){ int ret; struct nt_list *cur; struct wrap_driver *wrap_driver; ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device, wd->subvendor, wd->subdevice); if (down_interruptible(&loader_mutex)) { WARNING("couldn't obtain loader_mutex"); EXIT1(return NULL); } wrap_driver = NULL; nt_list_for_each(cur, &wrap_drivers) { wrap_driver = container_of(cur, struct wrap_driver, list); if (!stricmp(wrap_driver->name, wd->driver_name)) { TRACE1("driver %s already loaded", wrap_driver->name); break; } else wrap_driver = NULL; } up(&loader_mutex); if (!wrap_driver) { char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER,#if defined(DEBUG) && DEBUG >= 1 "1",#else "0",#endif UTILS_VERSION, wd->driver_name, wd->conf_file_name, NULL}; char *env[] = {NULL}; TRACE1("loading driver %s", wd->driver_name); if (down_interruptible(&loader_mutex)) { WARNING("couldn't obtain loader_mutex"); EXIT1(return NULL); } INIT_COMPLETION(loader_complete); ret = call_usermodehelper("/sbin/loadndisdriver", argv, env#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) , 1#endif ); if (ret) { up(&loader_mutex); ERROR("couldn't load driver %s; check system log " "for messages from 'loadndisdriver'", wd->driver_name); EXIT1(return NULL); } wait_for_completion(&loader_complete); TRACE1("%s", wd->driver_name); wrap_driver = NULL; nt_list_for_each(cur, &wrap_drivers) { wrap_driver = container_of(cur, struct wrap_driver, list); if (!stricmp(wrap_driver->name, wd->driver_name)) { wd->driver = wrap_driver; break; } else wrap_driver = NULL; } up(&loader_mutex); if (wrap_driver) TRACE1("driver %s is loaded", wrap_driver->name); else ERROR("couldn't load driver '%s'", wd->driver_name); } EXIT1(return wrap_driver);}/* load the driver files from userspace. */static int load_sys_files(struct wrap_driver *driver, struct load_driver *load_driver){ int i, err; TRACE1("num_pe_images = %d", load_driver->nr_sys_files); TRACE1("loading driver: %s", load_driver->name); strncpy(driver->name, load_driver->name, sizeof(driver->name)); driver->name[sizeof(driver->name)-1] = 0; TRACE1("driver: %s", driver->name); err = 0; driver->num_pe_images = 0; for (i = 0; i < load_driver->nr_sys_files; i++) { struct pe_image *pe_image; pe_image = &driver->pe_images[driver->num_pe_images]; strncpy(pe_image->name, load_driver->sys_files[i].name, sizeof(pe_image->name)); pe_image->name[sizeof(pe_image->name)-1] = 0; TRACE1("image size: %lu bytes", (unsigned long)load_driver->sys_files[i].size);#ifdef CONFIG_X86_64#ifdef PAGE_KERNEL_EXECUTABLE pe_image->image = __vmalloc(load_driver->sys_files[i].size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXECUTABLE);#elif defined PAGE_KERNEL_EXEC pe_image->image = __vmalloc(load_driver->sys_files[i].size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);#else#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC#endif#else /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is * not available to modules! */#ifdef cpu_has_nx if (cpu_has_nx) pe_image->image = __vmalloc(load_driver->sys_files[i].size, GFP_KERNEL | __GFP_HIGHMEM, __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); else pe_image->image = vmalloc(load_driver->sys_files[i].size);#else pe_image->image = vmalloc(load_driver->sys_files[i].size);#endif#endif if (!pe_image->image) { ERROR("couldn't allocate memory"); err = -ENOMEM; break; } TRACE1("image is at %p", pe_image->image); if (copy_from_user(pe_image->image, load_driver->sys_files[i].data, load_driver->sys_files[i].size)) { ERROR("couldn't load file %s", load_driver->sys_files[i].name); err = -EFAULT; break; } pe_image->size = load_driver->sys_files[i].size; driver->num_pe_images++; } if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) { ERROR("couldn't prepare driver '%s'", load_driver->name); err = -EINVAL; } if (driver->num_pe_images < load_driver->nr_sys_files || err) { for (i = 0; i < driver->num_pe_images; i++) if (driver->pe_images[i].image) vfree(driver->pe_images[i].image); driver->num_pe_images = 0; EXIT1(return err); } else EXIT1(return 0);}struct wrap_bin_file *get_bin_file(char *bin_file_name){ int i = 0; struct wrap_driver *driver, *cur; ENTER1("%s", bin_file_name); if (down_interruptible(&loader_mutex)) { WARNING("couldn't obtain loader_mutex"); EXIT1(return NULL); } driver = NULL; nt_list_for_each_entry(cur, &wrap_drivers, list) { for (i = 0; i < cur->num_bin_files; i++) if (!stricmp(cur->bin_files[i].name, bin_file_name)) { driver = cur; break; } if (driver) break; } up(&loader_mutex); if (!driver) { TRACE1("coudln't find bin file '%s'", bin_file_name); return NULL; } if (!driver->bin_files[i].data) { char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE,#if defined(DEBUG) && DEBUG >= 1 "1",#else "0",#endif UTILS_VERSION, driver->name, driver->bin_files[i].name, NULL}; char *env[] = {NULL}; int ret; TRACE1("loading bin file %s/%s", driver->name, driver->bin_files[i].name); if (down_interruptible(&loader_mutex)) { WARNING("couldn't obtain loader_mutex"); EXIT1(return NULL); } INIT_COMPLETION(loader_complete); ret = call_usermodehelper("/sbin/loadndisdriver", argv, env#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) , 1#endif ); if (ret) { up(&loader_mutex); ERROR("couldn't load file %s/%s; check system log " "for messages from 'loadndisdriver'", driver->name, driver->bin_files[i].name); EXIT1(return NULL); } wait_for_completion(&loader_complete); up(&loader_mutex); if (!driver->bin_files[i].data) { WARNING("couldn't load binary file %s", driver->bin_files[i].name); EXIT1(return NULL); } } EXIT2(return &(driver->bin_files[i]));}/* called with loader_mutex down */static int add_bin_file(struct load_driver_file *driver_file){ struct wrap_driver *driver, *cur; struct wrap_bin_file *bin_file; int i = 0; driver = NULL; nt_list_for_each_entry(cur, &wrap_drivers, list) { for (i = 0; i < cur->num_bin_files; i++) if (!stricmp(cur->bin_files[i].name, driver_file->name)) { driver = cur; break; } if (driver) break; } if (!driver) { ERROR("couldn't find %s", driver_file->name); return -EINVAL; } bin_file = &driver->bin_files[i]; strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name)); bin_file->name[sizeof(bin_file->name)-1] = 0; bin_file->data = vmalloc(driver_file->size); if (!bin_file->data) { ERROR("couldn't allocate memory"); return -ENOMEM; } bin_file->size = driver_file->size; if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) { ERROR("couldn't copy data"); free_bin_file(bin_file); return -EFAULT; } return 0;}void free_bin_file(struct wrap_bin_file *bin_file){ TRACE2("unloading %s", bin_file->name); if (bin_file->data) vfree(bin_file->data); bin_file->data = NULL; bin_file->size = 0; EXIT2(return);}/* load firmware files from userspace */static int load_bin_files_info(struct wrap_driver *driver, struct load_driver *load_driver){ struct wrap_bin_file *bin_files; int i; ENTER1("loading bin files for driver %s", load_driver->name); bin_files = kmalloc(load_driver->nr_bin_files * sizeof(*bin_files), GFP_KERNEL); if (!bin_files) { ERROR("couldn't allocate memory"); EXIT1(return -ENOMEM); } memset(bin_files, 0, load_driver->nr_bin_files * sizeof(*bin_files)); for (i = 0; i < load_driver->nr_bin_files; i++) { strncpy(bin_files[i].name, load_driver->bin_files[i].name, sizeof(bin_files[i].name)); bin_files[i].name[sizeof(bin_files[i].name)-1] = 0; TRACE2("loaded bin file %s", bin_files[i].name); } driver->num_bin_files = load_driver->nr_bin_files; driver->bin_files = bin_files; EXIT1(return 0);}/* load settnigs for a device. called with loader_mutex down */static int load_settings(struct wrap_driver *wrap_driver, struct load_driver *load_driver){ int i, nr_settings; ENTER1("%p, %p", wrap_driver, load_driver); nr_settings = 0; for (i = 0; i < load_driver->nr_settings; i++) { struct load_device_setting *load_setting = &load_driver->settings[i]; struct wrap_device_setting *setting; ULONG data1; setting = kmalloc(sizeof(*setting), GFP_KERNEL); if (!setting) { ERROR("couldn't allocate memory"); break; } memset(setting, 0, sizeof(*setting)); strncpy(setting->name, load_setting->name, sizeof(setting->name)); setting->name[sizeof(setting->name)-1] = 0; strncpy(setting->value, load_setting->value, sizeof(setting->value)); setting->value[sizeof(setting->value)-1] = 0; TRACE2("%p: %s=%s", setting, setting->name, setting->value); if (strcmp(setting->name, "driver_version") == 0) { strncpy(wrap_driver->version, setting->value, sizeof(wrap_driver->version)); wrap_driver->version[sizeof(wrap_driver->version)-1] = 0; } else if (strcmp(setting->name, "class_guid") == 0 && sscanf(setting->value, "%x", &data1) == 1) { wrap_driver->dev_type = wrap_device_type(data1); if (wrap_driver->dev_type < 0) { WARNING("unknown guid: %x", data1); wrap_driver->dev_type = 0; } } InsertTailList(&wrap_driver->settings, &setting->list); nr_settings++; } /* it is not a fatal error if some settings couldn't be loaded */ if (nr_settings > 0) EXIT1(return 0); else EXIT1(return -EINVAL);}void unload_wrap_device(struct wrap_device *wd){ struct nt_list *cur; ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd, wd->vendor, wd->device, wd->subvendor, wd->subdevice, wd->driver_name); if (down_interruptible(&loader_mutex)) WARNING("couldn't obtain loader_mutex"); while ((cur = RemoveHeadList(&wd->settings))) { struct wrap_device_setting *setting; setting = container_of(cur, struct wrap_device_setting, list); kfree(setting); } RemoveEntryList(&wd->list); up(&loader_mutex); kfree(wd); EXIT1(return);}/* should be called with loader_mutex down */void unload_wrap_driver(struct wrap_driver *driver){ int i; struct driver_object *drv_obj; struct nt_list *cur, *next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -