From faa52d8e105f0df4dea63ac4d090c46a35dea23c Mon Sep 17 00:00:00 2001
From: Paul Kocialkowski <contact@paulk.fr>
Date: Mon, 11 Nov 2013 22:25:48 +0100
Subject: Properly handle missing firmwares

Change-Id: I33e9f2fd201834ebe5a0cd0255913aaf463e01d4
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
---
 wifi/wifi.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

diff --git a/wifi/wifi.c b/wifi/wifi.c
index 90b7632..58d4572 100644
--- a/wifi/wifi.c
+++ b/wifi/wifi.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <string.h>
 #include <dirent.h>
+#include <libgen.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include <poll.h>
@@ -283,8 +284,143 @@ int is_wifi_driver_loaded() {
 #endif
 }
 
+int wifi_check_fw_path(const char *fw_path)
+{
+    char *fw_path_string = NULL;
+    char *fw_dirname;
+    char *fw_basename;
+    size_t fw_basename_length;
+    size_t length;
+    int rc;
+
+    DIR *fw_dir = NULL;
+    struct dirent *entry;
+
+    if (fw_path == NULL)
+        return -1;
+
+    fw_path_string = strdup(fw_path);
+    fw_basename = basename(fw_path_string);
+    fw_dirname = dirname(fw_path_string);
+
+    fw_basename_length = strlen(fw_basename);
+    if (fw_basename_length == 0)
+        goto error;
+
+    fw_dir = opendir(fw_dirname);
+    if (fw_dir == NULL)
+            goto error;
+
+    while ((entry = readdir(fw_dir)) != NULL) {
+        length = strlen(entry->d_name);
+        if (length >= fw_basename_length && strncmp(fw_basename, entry->d_name, fw_basename_length) == 0) {
+            rc = 1;
+            goto complete;
+        }
+    }
+
+    rc = 0;
+    goto complete;
+
+error:
+    rc = 0;
+
+complete:
+    if (fw_path_string != NULL)
+        free(fw_path_string);
+
+    if (fw_dir != NULL)
+        closedir(fw_dir);
+
+    return rc;
+}
+
+int wifi_check_fw_args(const char *args, const char **keys, unsigned int keys_count)
+{
+    char format[256] = { 0 };
+    char fw_path[PATH_MAX] = { 0 };
+    size_t args_length;
+    size_t key_length;
+    unsigned int i, j;
+    int rc;
+
+    if (args == NULL || keys == NULL || keys_count == 0)
+        return 0;
+
+    args_length = strlen(args);
+
+    for (i = 0; i < keys_count; i++) {
+        key_length = strlen(keys[i]);
+
+        for (j = 0; j < args_length; j++) {
+            if (strncmp(&args[j], keys[i], key_length) == 0) {
+                snprintf((char *) &format, sizeof(format), "%s=%256[^ ]", keys[i]);
+
+                rc = sscanf(&args[j], format, &fw_path);
+                if (rc == 1) {
+                    rc = wifi_check_fw_path(fw_path);
+                    if (!rc)
+                        return rc;
+                    else
+                        break;
+                }
+            }
+        }
+    }
+
+    return 1;
+}
+
+int wifi_check_fw_paths(void)
+{
+    const char *keys[] = {
+        "firmware_path",
+        "nvram_path"
+    };
+    unsigned int keys_count = sizeof(keys) / sizeof(const char *);
+    int rc;
+
+    if (WIFI_DRIVER_FW_PATH_STA != NULL && wifi_mode != 1) {
+        rc = wifi_check_fw_path(WIFI_DRIVER_FW_PATH_STA);
+        if (!rc)
+            return rc;
+    } else if (WIFI_DRIVER_FW_PATH_AP && wifi_mode == 1) {
+        rc = wifi_check_fw_path(WIFI_DRIVER_FW_PATH_AP);
+        if (!rc)
+            return rc;
+    }
+
+    if (WIFI_DRIVER_FW_PATH_P2P != NULL) {
+        rc = wifi_check_fw_path(WIFI_DRIVER_FW_PATH_P2P);
+        if (!rc)
+            return rc;
+    }
+
+    if (WIFI_DRIVER_MODULE_ARG != NULL) {
+        rc = wifi_check_fw_args(WIFI_DRIVER_MODULE_ARG, (const char **) &keys, keys_count);
+        if (!rc)
+            return rc;
+    }
+
+    if (WIFI_DRIVER_MODULE_AP_ARG != NULL && wifi_mode == 1) {
+        rc = wifi_check_fw_args(WIFI_DRIVER_MODULE_AP_ARG, (const char **) &keys, keys_count);
+        if (!rc)
+            return rc;
+    }
+
+    return 1;
+}
+
 int wifi_load_driver()
 {
+    int rc;
+
+    rc = wifi_check_fw_paths();
+    if (!rc) {
+        property_set(DRIVER_PROP_NAME, "unloaded");
+        return -1;
+    }
+
 #ifdef WIFI_DRIVER_MODULE_PATH
     char driver_status[PROPERTY_VALUE_MAX];
     int count = 100; /* wait at most 20 seconds for completion */
-- 
cgit v1.1