Преглед изворни кода

ncd: modules: net_backend_wpa_supplicant: add bssid and ssid variables

ambrop7 пре 14 година
родитељ
комит
66b8298e50
1 измењених фајлова са 209 додато и 5 уклоњено
  1. 209 5
      ncd/modules/net_backend_wpa_supplicant.c

+ 209 - 5
ncd/modules/net_backend_wpa_supplicant.c

@@ -29,13 +29,24 @@
  * statement in front of the wpa_supplicant statement.
  * 
  * Synopsis: net.backend.wpa_supplicant(string ifname, string conf, string exec, list(string) args)
+ * Variables:
+ *   bssid - BSSID of the wireless network we connected to.
+ *           Consists of 6 capital, two-character hexadecimal numbers, separated with colons.
+ *           Example: "01:B2:C3:04:E5:F6"
+ *   ssid - SSID of the wireless network we connected to. Note that this is after what
+ *          wpa_supplicant does to it before it prints it. In particular, it replaces all bytes
+ *          outside [32, 126] with underscores.
  */
 
 #include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
 
 #include <misc/cmdline.h>
 #include <misc/string_begins_with.h>
 #include <misc/stdbuf_cmdline.h>
+#include <misc/balloc.h>
 #include <flow/LineBuffer.h>
 #include <system/BInputProcess.h>
 #include <ncd/NCDModule.h>
@@ -60,14 +71,100 @@ struct instance {
     int have_pipe;
     LineBuffer pipe_buffer;
     PacketPassInterface pipe_input;
+    int have_info;
+    uint8_t info_bssid[6];
+    char *info_ssid;
 };
 
+static int parse_hex_digit (uint8_t d, uint8_t *out);
+static int parse_trying (uint8_t *data, int data_len, uint8_t *out_bssid, uint8_t **out_ssid, int *out_ssid_len);
 static int build_cmdline (struct instance *o, CmdLine *c);
+static int init_info (struct instance *o, const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len);
+static void free_info (struct instance *o);
+static void process_error (struct instance *o);
 static void process_handler_terminated (struct instance *o, int normally, uint8_t normally_exit_status);
 static void process_handler_closed (struct instance *o, int is_error);
 static void process_pipe_handler_send (struct instance *o, uint8_t *data, int data_len);
 static void instance_free (struct instance *o);
 
+int parse_hex_digit (uint8_t d, uint8_t *out)
+{
+    switch (d) {
+        case '0': *out = 0; return 1;
+        case '1': *out = 1; return 1;
+        case '2': *out = 2; return 1;
+        case '3': *out = 3; return 1;
+        case '4': *out = 4; return 1;
+        case '5': *out = 5; return 1;
+        case '6': *out = 6; return 1;
+        case '7': *out = 7; return 1;
+        case '8': *out = 8; return 1;
+        case '9': *out = 9; return 1;
+        case 'A': case 'a': *out = 10; return 1;
+        case 'B': case 'b': *out = 11; return 1;
+        case 'C': case 'c': *out = 12; return 1;
+        case 'D': case 'd': *out = 13; return 1;
+        case 'E': case 'e': *out = 14; return 1;
+        case 'F': case 'f': *out = 15; return 1;
+    }
+    
+    return 0;
+}
+
+int parse_trying (uint8_t *data, int data_len, uint8_t *out_bssid, uint8_t **out_ssid, int *out_ssid_len)
+{
+    // Trying to associate with AB:CD:EF:01:23:45 (SSID='Some SSID' freq=2462 MHz)
+    
+    int p;
+    if (!(p = data_begins_with(data, data_len, "Trying to associate with "))) {
+        return 0;
+    }
+    data += p;
+    data_len -= p;
+    
+    for (int i = 0; i < 6; i++) {
+        uint8_t d1;
+        uint8_t d2;
+        if (data_len < 2 || !parse_hex_digit(data[0], &d1) || !parse_hex_digit(data[1], &d2)) {
+            return 0;
+        }
+        data += 2;
+        data_len -= 2;
+        out_bssid[i] = ((d1 << 4) | d2);
+        
+        if (i != 5) {
+            if (data_len < 1 || data[0] != ':') {
+                return 0;
+            }
+            data += 1;
+            data_len -= 1;
+        }
+    }
+    
+    if (!(p = data_begins_with(data, data_len, " (SSID='"))) {
+        return 0;
+    }
+    data += p;
+    data_len -= p;
+    
+    // find last '
+    uint8_t *q = NULL;
+    for (int i = data_len; i > 0; i--) {
+        if (data[i - 1] == '\'') {
+            q = &data[i - 1];
+            break;
+        }
+    }
+    if (!q) {
+        return 0;
+    }
+    
+    *out_ssid = data;
+    *out_ssid_len = q - data;
+    
+    return 1;
+}
+
 int build_cmdline (struct instance *o, CmdLine *c)
 {
     // init cmdline
@@ -119,6 +216,43 @@ fail0:
     return 0;
 }
 
+int init_info (struct instance *o, const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len)
+{
+    ASSERT(!o->have_info)
+    
+    // set bssid
+    memcpy(o->info_bssid, bssid, 6);
+    
+    // set ssid
+    if (!(o->info_ssid = BAllocSize(bsize_add(bsize_fromsize(ssid_len), bsize_fromsize(1))))) {
+        ModuleLog(o->i, BLOG_ERROR, "BAllocSize failed");
+        return 0;
+    }
+    memcpy(o->info_ssid, ssid, ssid_len);
+    o->info_ssid[ssid_len] = '\0';
+    
+    // set have info
+    o->have_info = 1;
+    
+    return 1;
+}
+
+void free_info (struct instance *o)
+{
+    ASSERT(o->have_info)
+    
+    // free ssid
+    BFree(o->info_ssid);
+    
+    // set not have info
+    o->have_info = 0;
+}
+
+void process_error (struct instance *o)
+{
+    BInputProcess_Terminate(&o->process);
+}
+
 void process_handler_terminated (struct instance *o, int normally, uint8_t normally_exit_status)
 {
     ModuleLog(o->i, (o->dying ? BLOG_INFO : BLOG_ERROR), "process terminated");
@@ -164,17 +298,47 @@ void process_pipe_handler_send (struct instance *o, uint8_t *data, int data_len)
         return;
     }
     
-    if (data_begins_with((char *)data, data_len, EVENT_STRING_CONNECTED)) {
+    uint8_t bssid[6];
+    uint8_t *ssid;
+    int ssid_len;
+    if (parse_trying(data, data_len, bssid, &ssid, &ssid_len)) {
+        ModuleLog(o->i, BLOG_INFO, "trying event");
+        
+        if (o->up) {
+            ModuleLog(o->i, BLOG_ERROR, "trying unexpected!");
+            process_error(o);
+            return;
+        }
+        
+        if (o->have_info) {
+            free_info(o);
+        }
+        
+        if (!init_info(o, bssid, ssid, ssid_len)) {
+            ModuleLog(o->i, BLOG_ERROR, "init_info failed");
+            process_error(o);
+            return;
+        }
+    }
+    else if (data_begins_with((char *)data, data_len, EVENT_STRING_CONNECTED)) {
         ModuleLog(o->i, BLOG_INFO, "connected event");
         
-        if (!o->up) {
-            o->up = 1;
-            NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+        if (o->up || !o->have_info) {
+            ModuleLog(o->i, BLOG_ERROR, "connected unexpected!");
+            process_error(o);
+            return;
         }
+        
+        o->up = 1;
+        NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
     }
     else if (data_begins_with((char *)data, data_len, EVENT_STRING_DISCONNECTED)) {
         ModuleLog(o->i, BLOG_INFO, "disconnected event");
         
+        if (o->have_info) {
+            free_info(o);
+        }
+        
         if (o->up) {
             o->up = 0;
             NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_DOWN);
@@ -254,6 +418,9 @@ static void func_new (NCDModuleInst *i)
         goto fail4;
     }
     
+    // set not have info
+    o->have_info = 0;
+    
     CmdLine_Free(&c);
     
     return;
@@ -276,6 +443,11 @@ void instance_free (struct instance *o)
 {
     NCDModuleInst *i = o->i;
     
+    // free info
+    if (o->have_info) {
+        free_info(o);
+    }
+    
     if (o->have_pipe) {
         // free buffer
         LineBuffer_Free(&o->pipe_buffer);
@@ -305,11 +477,43 @@ static void func_die (void *vo)
     o->dying = 1;
 }
 
+static int func_getvar (void *vo, const char *name, NCDValue *out)
+{
+    struct instance *o = vo;
+    ASSERT(o->up)
+    ASSERT(o->have_info)
+    
+    if (!strcmp(name, "bssid")) {
+        uint8_t *bssid = o->info_bssid;
+        char str[18];
+        sprintf(str, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+        
+        if (!NCDValue_InitString(out, str)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
+            return 0;
+        }
+        
+        return 1;
+    }
+    
+    if (!strcmp(name, "ssid")) {
+        if (!NCDValue_InitString(out, o->info_ssid)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
+            return 0;
+        }
+        
+        return 1;
+    }
+    
+    return 0;
+}
+
 static const struct NCDModule modules[] = {
     {
         .type = "net.backend.wpa_supplicant",
         .func_new = func_new,
-        .func_die = func_die
+        .func_die = func_die,
+        .func_getvar = func_getvar
     }, {
         .type = NULL
     }