Просмотр исходного кода

ncd: add net.backend.rfkill module

ambrop7 15 лет назад
Родитель
Сommit
af4d47d91a

+ 1 - 0
blog_channels.txt

@@ -16,6 +16,7 @@ ncd_run 4
 ncd_net_backend_physical 4
 ncd_net_backend_waitdevice 4
 ncd_net_backend_badvpn 4
+ncd_net_backend_rfkill 4
 ncd_net_dns 4
 ncd_net_iptables 4
 ncd_net_ipv4_addr 4

+ 4 - 0
generated/blog_channel_ncd_net_backend_rfkill.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_net_backend_rfkill

+ 34 - 33
generated/blog_channels_defines.h

@@ -16,36 +16,37 @@
 #define BLOG_CHANNEL_ncd_net_backend_physical 15
 #define BLOG_CHANNEL_ncd_net_backend_waitdevice 16
 #define BLOG_CHANNEL_ncd_net_backend_badvpn 17
-#define BLOG_CHANNEL_ncd_net_dns 18
-#define BLOG_CHANNEL_ncd_net_iptables 19
-#define BLOG_CHANNEL_ncd_net_ipv4_addr 20
-#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 21
-#define BLOG_CHANNEL_ncd_net_ipv4_route 22
-#define BLOG_CHANNEL_StreamPeerIO 23
-#define BLOG_CHANNEL_DatagramPeerIO 24
-#define BLOG_CHANNEL_BReactor 25
-#define BLOG_CHANNEL_BSignal 26
-#define BLOG_CHANNEL_FragmentProtoAssembler 27
-#define BLOG_CHANNEL_BPredicate 28
-#define BLOG_CHANNEL_ServerConnection 29
-#define BLOG_CHANNEL_Listener 30
-#define BLOG_CHANNEL_DataProto 31
-#define BLOG_CHANNEL_FrameDecider 32
-#define BLOG_CHANNEL_BSocksClient 33
-#define BLOG_CHANNEL_BDHCPClientCore 34
-#define BLOG_CHANNEL_BDHCPClient 35
-#define BLOG_CHANNEL_NCDIfConfig 36
-#define BLOG_CHANNEL_BUnixSignal 37
-#define BLOG_CHANNEL_BProcess 38
-#define BLOG_CHANNEL_StreamSocketSink 39
-#define BLOG_CHANNEL_StreamSocketSource 40
-#define BLOG_CHANNEL_DatagramSocketSink 41
-#define BLOG_CHANNEL_DatagramSocketSource 42
-#define BLOG_CHANNEL_PRStreamSink 43
-#define BLOG_CHANNEL_PRStreamSource 44
-#define BLOG_CHANNEL_BSocketPRFileDesc 45
-#define BLOG_CHANNEL_PacketProtoDecoder 46
-#define BLOG_CHANNEL_DPRelay 47
-#define BLOG_CHANNEL_BThreadWork 48
-#define BLOG_CHANNEL_DPReceive 49
-#define BLOG_NUM_CHANNELS 50
+#define BLOG_CHANNEL_ncd_net_backend_rfkill 18
+#define BLOG_CHANNEL_ncd_net_dns 19
+#define BLOG_CHANNEL_ncd_net_iptables 20
+#define BLOG_CHANNEL_ncd_net_ipv4_addr 21
+#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 22
+#define BLOG_CHANNEL_ncd_net_ipv4_route 23
+#define BLOG_CHANNEL_StreamPeerIO 24
+#define BLOG_CHANNEL_DatagramPeerIO 25
+#define BLOG_CHANNEL_BReactor 26
+#define BLOG_CHANNEL_BSignal 27
+#define BLOG_CHANNEL_FragmentProtoAssembler 28
+#define BLOG_CHANNEL_BPredicate 29
+#define BLOG_CHANNEL_ServerConnection 30
+#define BLOG_CHANNEL_Listener 31
+#define BLOG_CHANNEL_DataProto 32
+#define BLOG_CHANNEL_FrameDecider 33
+#define BLOG_CHANNEL_BSocksClient 34
+#define BLOG_CHANNEL_BDHCPClientCore 35
+#define BLOG_CHANNEL_BDHCPClient 36
+#define BLOG_CHANNEL_NCDIfConfig 37
+#define BLOG_CHANNEL_BUnixSignal 38
+#define BLOG_CHANNEL_BProcess 39
+#define BLOG_CHANNEL_StreamSocketSink 40
+#define BLOG_CHANNEL_StreamSocketSource 41
+#define BLOG_CHANNEL_DatagramSocketSink 42
+#define BLOG_CHANNEL_DatagramSocketSource 43
+#define BLOG_CHANNEL_PRStreamSink 44
+#define BLOG_CHANNEL_PRStreamSource 45
+#define BLOG_CHANNEL_BSocketPRFileDesc 46
+#define BLOG_CHANNEL_PacketProtoDecoder 47
+#define BLOG_CHANNEL_DPRelay 48
+#define BLOG_CHANNEL_BThreadWork 49
+#define BLOG_CHANNEL_DPReceive 50
+#define BLOG_NUM_CHANNELS 51

+ 1 - 0
generated/blog_channels_list.h

@@ -16,6 +16,7 @@
 {.name = "ncd_net_backend_physical", .loglevel = 4},
 {.name = "ncd_net_backend_waitdevice", .loglevel = 4},
 {.name = "ncd_net_backend_badvpn", .loglevel = 4},
+{.name = "ncd_net_backend_rfkill", .loglevel = 4},
 {.name = "ncd_net_dns", .loglevel = 4},
 {.name = "ncd_net_iptables", .loglevel = 4},
 {.name = "ncd_net_ipv4_addr", .loglevel = 4},

+ 2 - 0
ncd/CMakeLists.txt

@@ -4,6 +4,7 @@ add_executable(badvpn-ncd
     NCDModule.c
     NCDIfConfig.c
     NCDInterfaceMonitor.c
+    NCDRfkillMonitor.c
     modules/command_template.c
     modules/var.c
     modules/list.c
@@ -18,6 +19,7 @@ add_executable(badvpn-ncd
     modules/net_backend_physical.c
     modules/net_backend_waitdevice.c
     modules/net_backend_badvpn.c
+    modules/net_backend_rfkill.c
     modules/net_dns.c
     modules/net_iptables.c
     modules/net_ipv4_addr.c

+ 103 - 0
ncd/NCDRfkillMonitor.c

@@ -0,0 +1,103 @@
+/**
+ * @file NCDRfkillMonitor.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN 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.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <misc/debug.h>
+#include <misc/nonblocking.h>
+
+#include <ncd/NCDRfkillMonitor.h>
+
+#define RFKILL_DEVICE_NODE "/dev/rfkill"
+
+static void rfkill_fd_handler (NCDRfkillMonitor *o, int events);
+
+void rfkill_fd_handler (NCDRfkillMonitor *o, int events)
+{
+    DebugObject_Access(&o->d_obj);
+    
+    // read from netlink fd
+    struct rfkill_event event;
+    int len = read(o->rfkill_fd, &event, sizeof(event));
+    if (len < 0) {
+        DEBUG("read failed");
+        return;
+    }
+    if (len != sizeof(event)) {
+        DEBUG("read returned wrong length");
+        return;
+    }
+    
+    // call handler
+    o->handler(o->user, event);
+    return;
+}
+
+int NCDRfkillMonitor_Init (NCDRfkillMonitor *o, BReactor *reactor, NCDRfkillMonitor_handler handler, void *user)
+{
+    // init arguments
+    o->reactor = reactor;
+    o->handler = handler;
+    o->user = user;
+    
+    // open rfkill
+    if ((o->rfkill_fd = open(RFKILL_DEVICE_NODE, O_RDONLY)) < 0) {
+        DEBUG("open failed");
+        goto fail0;
+    }
+    
+    // set fd non-blocking
+    if (!badvpn_set_nonblocking(o->rfkill_fd)) {
+        DEBUG("badvpn_set_nonblocking failed");
+        goto fail1;
+    }
+    
+    // init BFileDescriptor
+    BFileDescriptor_Init(&o->bfd, o->rfkill_fd, (BFileDescriptor_handler)rfkill_fd_handler, o);
+    if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
+        DEBUG("BReactor_AddFileDescriptor failed");
+        goto fail1;
+    }
+    BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, BREACTOR_READ);
+    
+    DebugObject_Init(&o->d_obj);
+    return 1;
+    
+fail1:
+    ASSERT_FORCE(close(o->rfkill_fd) == 0)
+fail0:
+    return 0;
+}
+
+void NCDRfkillMonitor_Free (NCDRfkillMonitor *o)
+{
+    DebugObject_Free(&o->d_obj);
+    
+    // free BFileDescriptor
+    BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
+    
+    // close rfkill
+    ASSERT_FORCE(close(o->rfkill_fd) == 0)
+}

+ 46 - 0
ncd/NCDRfkillMonitor.h

@@ -0,0 +1,46 @@
+/**
+ * @file NCDRfkillMonitor.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN 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.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BADVPN_NCD_NCDRFKILLMONITOR_H
+#define BADVPN_NCD_NCDRFKILLMONITOR_H
+
+#include <linux/rfkill.h>
+
+#include <misc/debug.h>
+#include <system/DebugObject.h>
+#include <system/BReactor.h>
+
+typedef void (*NCDRfkillMonitor_handler) (void *user, struct rfkill_event event);
+
+typedef struct {
+    BReactor *reactor;
+    NCDRfkillMonitor_handler handler;
+    void *user;
+    int rfkill_fd;
+    BFileDescriptor bfd;
+    DebugObject d_obj;
+} NCDRfkillMonitor;
+
+int NCDRfkillMonitor_Init (NCDRfkillMonitor *o, BReactor *reactor, NCDRfkillMonitor_handler handler, void *user) WARN_UNUSED;
+void NCDRfkillMonitor_Free (NCDRfkillMonitor *o);
+
+#endif

+ 2 - 0
ncd/modules/modules.h

@@ -40,6 +40,7 @@ extern const struct NCDModuleGroup ncdmodule_run;
 extern const struct NCDModuleGroup ncdmodule_net_backend_physical;
 extern const struct NCDModuleGroup ncdmodule_net_backend_waitdevice;
 extern const struct NCDModuleGroup ncdmodule_net_backend_badvpn;
+extern const struct NCDModuleGroup ncdmodule_net_backend_rfkill;
 extern const struct NCDModuleGroup ncdmodule_net_dns;
 extern const struct NCDModuleGroup ncdmodule_net_iptables;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_addr;
@@ -60,6 +61,7 @@ static const struct NCDModuleGroup *ncd_modules[] = {
     &ncdmodule_net_backend_physical,
     &ncdmodule_net_backend_waitdevice,
     &ncdmodule_net_backend_badvpn,
+    &ncdmodule_net_backend_rfkill,
     &ncdmodule_net_dns,
     &ncdmodule_net_iptables,
     &ncdmodule_net_ipv4_addr,

+ 209 - 0
ncd/modules/net_backend_rfkill.c

@@ -0,0 +1,209 @@
+/**
+ * @file net_backend_rfkill.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN 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.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Rfkill monitoring module.
+ * 
+ * Synopsis: net.backend.rfkill(string type, string name)
+ * Arguments:
+ *   type - method of determining the index of the rfkill device. "index" for
+ *     rfkill device index, "wlan" for wireless device. Be aware that, for
+ *     the wireless device method, the index is resloved at initialization,
+ *     and no attempt is made to refresh it if the device goes away. In other
+ *     words, you should probably put a "net.backend.waitdevice" statement
+ *     in front of the rfkill statement.
+ *   name - rfkill index or wireless device name
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <misc/string_begins_with.h>
+#include <ncd/NCDModule.h>
+#include <ncd/NCDRfkillMonitor.h>
+
+#include <generated/blog_channel_ncd_net_backend_rfkill.h>
+
+#define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+
+struct instance {
+    NCDModuleInst *i;
+    uint32_t index;
+    NCDRfkillMonitor monitor;
+    int up;
+};
+
+static int find_wlan_rfill (const char *ifname, uint32_t *out_index)
+{
+    char ieee_path[100];
+    snprintf(ieee_path, sizeof(ieee_path), "/sys/class/net/%s/../../ieee80211", ifname);
+    
+    int res = 0;
+    
+    DIR *d = opendir(ieee_path);
+    if (!d) {
+        goto fail0;
+    }
+    
+    struct dirent *e;
+    while (e = readdir(d)) {
+        if (!string_begins_with(e->d_name, "phy")) {
+            continue;
+        }
+        
+        char phy_path[150];
+        snprintf(phy_path, sizeof(phy_path), "%s/%s", ieee_path, e->d_name);
+        
+        DIR *d2 = opendir(phy_path);
+        if (!d2) {
+            continue;
+        }
+        
+        struct dirent *e2;
+        while (e2 = readdir(d2)) {
+            int index_pos;
+            if (!(index_pos = string_begins_with(e2->d_name, "rfkill"))) {
+                continue;
+            }
+            
+            uint32_t index;
+            if (sscanf(e2->d_name + index_pos, "%"SCNu32, &index) != 1) {
+                continue;
+            }
+            
+            res = 1;
+            *out_index = index;
+        }
+        
+        closedir(d2);
+    }
+    
+    closedir(d);
+fail0:
+    return res;
+}
+
+static void monitor_handler (struct instance *o, struct rfkill_event event)
+{
+    if (event.idx != o->index) {
+        return;
+    }
+    
+    int was_up = o->up;
+    o->up = (event.op != RFKILL_OP_DEL && !event.soft && !event.hard);
+    
+    if (o->up && !was_up) {
+        NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+    }
+    else if (!o->up && was_up) {
+        NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_DOWN);
+    }
+}
+
+static void * func_new (NCDModuleInst *i)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    
+    // init arguments
+    o->i = i;
+    
+    // check arguments
+    NCDValue *type_arg;
+    NCDValue *name_arg;
+    if (!NCDValue_ListRead(i->args, 2, &type_arg, &name_arg)) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(type_arg) != NCDVALUE_STRING || NCDValue_Type(name_arg) != NCDVALUE_STRING) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    char *type = NCDValue_StringValue(type_arg);
+    char *name = NCDValue_StringValue(name_arg);
+    
+    if (!strcmp(type, "index")) {
+        if (sscanf(name, "%"SCNu32, &o->index) != 1) {
+            ModuleLog(o->i, BLOG_ERROR, "wrong index argument");
+            goto fail1;
+        }
+    }
+    else if (!strcmp(type, "wlan")) {
+        if (!find_wlan_rfill(name, &o->index)) {
+            ModuleLog(o->i, BLOG_ERROR, "failed to find rfkill for wlan interface");
+            goto fail1;
+        }
+    }
+    else {
+        ModuleLog(o->i, BLOG_ERROR, "unknown type argument");
+        goto fail1;
+    }
+    
+    // init monitor
+    if (!NCDRfkillMonitor_Init(&o->monitor, o->i->reactor, (NCDRfkillMonitor_handler)monitor_handler, o)) {
+        ModuleLog(o->i, BLOG_ERROR, "monitor failed");
+        goto fail1;
+    }
+    
+    // set not up
+    o->up = 0;
+    
+    return o;
+    
+fail1:
+    free(o);
+fail0:
+    return NULL;
+}
+
+static void func_free (void *vo)
+{
+    struct instance *o = vo;
+    
+    // free monitor
+    NCDRfkillMonitor_Free(&o->monitor);
+    
+    // free instance
+    free(o);
+}
+
+static const struct NCDModule modules[] = {
+    {
+        .type = "net.backend.rfkill",
+        .func_new = func_new,
+        .func_free = func_free
+    }, {
+        .type = NULL
+    }
+};
+
+const struct NCDModuleGroup ncdmodule_net_backend_rfkill = {
+    .modules = modules
+};