diff --git a/wifiloader/Android.mk b/wifiloader/Android.mk index 15c9dc2b..72c1c494 100644 --- a/wifiloader/Android.mk +++ b/wifiloader/Android.mk @@ -9,6 +9,14 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ liblog libutils +ifneq ($(WIFI_DRIVER_MODULE_NAME),) +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME=\"$(WIFI_DRIVER_MODULE_NAME)\" +endif + +ifneq ($(WIFI_DRIVER_MODULE_PATH),) +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\" +endif + LOCAL_MODULE := wifiloader LOCAL_MODULE_TAGS := optional diff --git a/wifiloader/wifiloader.c b/wifiloader/wifiloader.c index 54afdaf2..6c296601 100644 --- a/wifiloader/wifiloader.c +++ b/wifiloader/wifiloader.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015 Andreas Schneider + * Copyright (c) 2017 Christopher N. Hesse * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +19,86 @@ #define LOG_NDEBUG 0 #include +#include #include +#include #include #include +#include +#include -#define DEFERRED_INITCALLS "/proc/deferred_initcalls" +#define DEFERRED_INITCALLS "/proc/deferred_initcalls" + +#ifndef WIFI_DRIVER_MODULE_NAME +#define WIFI_DRIVER_MODULE_NAME "wlan" +#endif + +#ifndef WIFI_DRIVER_MODULE_PATH +#define WIFI_DRIVER_MODULE_PATH "/system/lib/modules/" WIFI_DRIVER_MODULE_NAME ".ko" +#endif + +#define finit_module(fd, params, flags) syscall(__NR_finit_module, fd, params, flags) + + +static int check_module_loaded(char const *tag) +{ + FILE *proc; + char line[126]; + + if ((proc = fopen("/proc/modules", "r")) == NULL) { + ALOGW("Could not open %s: %s", "/proc/modules", strerror(errno)); + return -errno; + } + + while ((fgets(line, sizeof(line), proc)) != NULL) { + if (strncmp(line, tag, strlen(tag)) == 0) { + fclose(proc); + return 1; + } + } + + fclose(proc); + return 0; +} + +static int load_module(char const *path) +{ + int fd; + + if (check_module_loaded(WIFI_DRIVER_MODULE_NAME) > 0) { + ALOGE("Driver: %s already loaded", path); + return -1; + } + + fd = open(path, O_RDONLY); + if (fd == -1) { + ALOGE("Failed to open %s - error: %s", path, strerror(errno)); + return -errno; + } + + // load the .ko image + if (finit_module(fd, "", 0) != 0) { + ALOGE("Failed to load module %s - error: %s", path, strerror(errno)); + close(fd); + return -errno; + } + + close(fd); + return 0; +} int main(void) { char buf[8] = { '\0' }; FILE *fp; size_t r; + int fd; + struct stat st; + + if (stat(WIFI_DRIVER_MODULE_PATH, &st) == 0) { + ALOGD("Loading WiFi kernel module: %s", WIFI_DRIVER_MODULE_PATH); + load_module(WIFI_DRIVER_MODULE_PATH); + } ALOGD("Trigger initcall of deferred modules\n");