From 2ae1e2cae4b568dd68ee4dd07435a2da0ffa3332 Mon Sep 17 00:00:00 2001
From: Patrick Martin <patrick.martin.r@gmail.com>
Date: Mon, 23 Jan 2017 15:18:58 -0800
Subject: [PATCH] Added ability to load backends from external modules.

---
 iwinfo_external_wrapper.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 297 insertions(+)
 create mode 100644 iwinfo_external_wrapper.c

diff --git a/iwinfo_external_wrapper.c b/iwinfo_external_wrapper.c
new file mode 100644
index 0000000..a257de1
--- /dev/null
+++ b/iwinfo_external_wrapper.c
@@ -0,0 +1,297 @@
+/*
+ * iwinfo - Wireless Information Library - External Backend
+ *
+ *   Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The iwinfo library 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.
+ *
+ * The iwinfo library 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 the iwinfo library. If not, see http://www.gnu.org/licenses/.
+ *
+ * The signal handling code is derived from the official madwifi tools,
+ * wlanconfig.c in particular. The encryption property handling was
+ * inspired by the hostapd madwifi driver.
+ */
+
+#include "iwinfo_wext.h"
+#include <string.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+#define MAX_MODULES_TO_LOAD 128
+#define MAX_BACKENDS_TO_ADD 512
+
+
+#define BFLAG_NONE 0x00
+#define BFLAG_OPS_PROVIDED_BY_MODULE 0x01
+	/* RESERVED FLAGS */
+#define BFLAG_ALL 0xFF
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+typedef void* ModuleHandle;
+typedef struct {
+	iwinfo_ops * backend;
+	unsigned char flags;
+	ModuleHandle parent_module;
+	unsigned int backend_index;
+} BackendEntry;
+
+extern static struct iwinfo_ops ** backends;
+extern static struct iwinfo_ops * backends_template[];
+
+iwinfo_ops * default_ops_list = NULL;
+iwinfo_ops * default_ops_list_without_external = NULL;
+
+unsigned int external_module_count = 0;
+void ** external_modules = NULL;
+
+unsigned int custom_backend_max_index = 0;
+BackendEntry custom_backend_list[MAX_BACKENDS_TO_ADD] = {0};
+
+static int external_placeholder_probe(const char * ifname){
+	return 0;
+}
+static int external_module_search(const char * ifname){
+	static char modulepath[4096];
+	int probe_result = 0;
+	if (default_ops_list == NULL){
+		default_ops_list = backends;
+		default_ops_list_without_external = backends+2;
+	}
+	if (external_modules == NULL){
+		external_module_count = 0;
+		unsigned int external_module_file_count = 0;
+		char ** external_module_files = NULL;
+		DIR * d;
+		struct dirent * ent;
+		d = opendir("/usr/lib/iwinfo")
+		if(d){
+			while((dir=readdir(d)) != NULL)
+			{
+				char * ext;
+				ext = strchr(dir->d_name,'.')
+				if(ext == dir->d_name)
+					ext = strchr(dir->d_name+1,'.')
+				if(strcmp(ext,".so") == 0){
+					char * str = malloc(strlen(dir->d_name));
+					strcpy(str,dir->d_name);
+					external_module_files = (char**)(external_module_file_count == 0?malloc(sizeof(char*)):realloc(external_module_files,(external_module_file_count+1)*sizeof(char*)))
+					external_module_files[external_module_file_count++] = str;
+				}
+			}
+		}
+		for(unsigned int i=0;i < external_module_file_count; i++){
+			if (external_module_count>=MAX_MODULES_TO_LOAD)
+				break;
+			strcpy(modulename,"/usr/lib/iwinfo/");
+			strcat(modulename,external_module_files[i])
+			ModuleHandle module = dlopen(modulename,RTLD_NOW)
+			if (module == NULL)
+				continue;
+			int (*setOpsList)(void*) = (int (*)(void*,size_t))dlsym(module,"setOpsList");
+			if (setOpsList==NULL){
+				dlclose(module);
+				continue;
+			}
+			int next = 0;
+			for (unsigned int i = 0; i < external_module_count; i++){
+				if(module == external_modules[i]){
+					next = 1;
+					break;
+				}
+			}
+			if (next){
+				dlclose(module);
+				continue;
+			}
+			setOpsList((void*)default_ops_list_without_external,ARRAY_SIZE(default_ops_list)-2)
+			external_modules = (ModuleHandle*)(external_module_count == 0?malloc(sizeof(ModuleHandle)):realloc(external_modules,(external_module_count+1)*sizeof(ModuleHandle)));
+			external_modules[external_module_count++] = module;
+		}
+		if(external_module_files_list != NULL){
+			for(unsigned int i=0; i < external_module_file_count; i++){
+				free(external_module_files[i]);
+			}
+			free(external_module_files);
+		}
+	}
+	for(unsigned int i=0;i< external_module_count && i < MAX_MODULES_TO_LOAD ;i++){
+		int (*probe)(const char*) = (int (*)(const char*))dlsym(module,"probe");
+		
+		if(probe(ifname)){
+			probe_result = 1;
+			iwinfo_ops * (*getops) () = (iwinfo_ops * (*) (const char * ))dlsym(module,"getOps")
+			iwinfo_ops* custom_ops;
+			int ops_were_provided_by_module = 0;
+			if(getops == NULL){
+				custom_ops = (iwinfo_ops*)malloc(sizeof(iwinfo_ops));
+				custom_ops.name = (const char*)dlsym(module,"name")
+				custom_ops.channel = (int (*)(const char *, int *))dlsym(module,"channel");
+				custom_ops.frequency = (int (*)(const char *, int *))dlsym(module,"frequency");
+				custom_ops.frequency_offset = (int (*)(const char *, int *))dlsym(module,"frequency_offset");
+				custom_ops.txpower = (int (*)(const char *, int *))dlsym(module,"txpower");
+				custom_ops.txpower_offset = (int (*)(const char *, int *))dlsym(module,"txpower_offset");
+				custom_ops.bitrate = (int (*)(const char *, int *))dlsym(module,"bitrate");
+				custom_ops.signal = (int (*)(const char *, int *))dlsym(module,"signal");
+				custom_ops.noise = (int (*)(const char *, int *))dlsym(module,"noise");
+				custom_ops.quality = (int (*)(const char *, int *))dlsym(module,"quality");
+				custom_ops.quality_max = (int (*)(const char *, int *))dlsym(module,"quality_max");
+				custom_ops.mbssid_support = (int (*)(const char *, int *))dlsym(module,"mbssid_support");
+				custom_ops.hwmodelist = (int (*) (const char *, int *))dlsym(module,"hwmodelist");
+				custom_ops.htmodelist = (int (*) (const char *, int *))dlsym(module,"htmodelist");
+				custom_ops.ssid = (int (*) (const char *, char *))dlsym(module,"ssid");
+				custom_ops.bssid = (int (*) (const char *, char *))dlsym(module,"bssid");
+				custom_ops.country = (int (*) (const char *, char *))dlsym(module,"country");
+				custom_ops.hardware_id = (int (*) (const char *, char *))dlsym(module,"hardware_id");
+				custom_ops.hardware_name = (int (*) (const char *, char *))dlsym(module,"hardware_name");
+				custom_ops.encryption = (int (*) (const char *, char *))dlsym(module,"encryption");
+				custom_ops.phyname = (int (*) (const char *, char *))dlsym(module,"phyname");
+				custom_ops.assoclist = (int (*) (const char *, char *, int *))dlsym(module,"assoclist");
+				custom_ops.txpwrlist = (int (*) (const char *, char *, int *))dlsym(module,"txpwrlist");
+				custom_ops.scanlist = (int (*) (const char *, char *, int *))dlsym(module,"scanlist");
+				custom_ops.freqlist = (int (*) (const char *, char *, int *))dlsym(module,"freqlist");
+				custom_ops.countrylist = (int (*) (const char *, char *, int *))dlsym(module,"countrylist");
+				custom_ops.lookup_phy = (int (*) (const char *, char *))dlsym(module,"lookup_phy");
+				custom_ops.close = (int (*)(void))dlsym(module,"close");
+			}else{
+				ops_were_provided_by_module = 1;
+				custom_ops = getops();
+			}
+			static int first_backend_entry = 1;
+			if (first_backend_entry) {
+				custom_backend_list[0].backend = custom_ops;
+				custom_backend_list[0].flags = (unsigned char)(ops_were_provided_by_module?BFLAG_OPS_PROVIDED_BY_MODULE:BFLAG_NONE);
+				custom_backend_list[0].parent_module = module;
+				custom_backend_list[0].backend_index = 0;
+				first_backend_entry = 0;
+			}else{
+				custom_backend_list[++custom_backend_max_index].backend = custom_ops;
+				custom_backend_list[custom_backend_max_index].flags = (unsigned char)(ops_were_provided_by_module?BFLAG_OPS_PROVIDED_BY_MODULE:BFLAG_NONE);
+				custom_backend_list[custom_backend_max_index].parent_module = module;
+				custom_backend_list[custom_backend_max_index].backend_index = 0;
+			}
+			static iwinfo_ops ** old_backends = NULL;
+			if(old_backends != NULL) free(old_backends);
+			new_backends = malloc(sizeof(backends_template)+((custom_backend_max_index+1)*sizeof(iwinfo_ops*)));
+			memcpy(new_backends+1,backends,sizeof(backends_template)+(custom_backend_max_index*sizeof(iwinfo_ops*)));
+			backends[1] = custom_ops;
+			old_backends = backends;
+			new_backends[0] = external_ops;
+			new_backends[1] = external_placeholder_ops;
+			new_backends[2] = custom_ops;
+			backends = new_backends;
+		}
+	}
+	
+}
+static int external_getzero(const char * ifname,int* zero){
+	*zero = 0;
+	return -1;
+}
+
+static int external_getemptystring(const char * ifname,char * str){
+	strcpy(str,"")
+	return -1;
+}
+static int external_gettwozerostring(const char * ifname,char * str){
+	strcpy(str,"00")
+	return -1;
+}
+static int external_getnochange(const char * ifname,char * buf){
+	return -1;
+}
+
+static int external_getemptylist(const char * ifname,char * buf, int* len){
+	*len = 0;
+	return -1;
+}
+
+static void external_close(void){
+	backends = default_ops_list;
+	for(unsigned int i=0; i<=custom_backend_max_index;i++){
+		custom_backend_list[i].backend->close();
+		if(!(custom_backend_list[i].flags & BFLAG_OPS_PROVIDED_BY_MODULE))free(custom_backend_list[i].backend);
+	}
+	backends[2] = &external_placeholder_ops;
+	for(unsigned int i=external_modules_max_index;i>=0;i--){
+		dlclose(external_modules[i])
+	}
+	free(external_modules);
+}
+static void external_nop(void){
+	//NOP
+}
+
+const struct iwinfo_ops external_ops = {
+	.name             = "External Backend Wrapper",
+	.probe            = external_module_search,
+	.channel          = external_getzero,
+	.frequency        = external_getzero,
+	.frequency_offset = external_getzero,
+	.txpower          = external_getzero,
+	.txpower_offset   = external_getzero,
+	.bitrate          = external_getzero,
+	.signal           = external_getzero,
+	.noise            = external_getzero,
+	.quality          = external_getzero,
+	.quality_max      = external_getzero,
+	.mbssid_support   = external_getzero,
+	.hwmodelist       = external_getzero,
+	.htmodelist       = external_getzero,
+	.mode             = external_getzero,
+	.ssid             = external_getemptystring,
+	.bssid            = external_getemptystring,
+	.country          = external_gettwozerostring,
+	.hardware_id      = external_getemptystring,
+	.hardware_name    = external_getemptystring,
+	.encryption       = external_getnochange,
+	.phyname          = external_getemptystring,
+	.assoclist        = external_getemptylist,
+	.txpwrlist        = external_getemptylist,
+	.scanlist         = external_getemptylist,
+	.freqlist         = external_getemptylist,
+	.countrylist      = external_getemptylist,
+	.close            = external_close
+};
+
+const struct iwinfo_ops external_placeholder_ops = {
+	.name             = "Placeholder Backend",
+	.probe            = external_placeholder_probe,
+	.channel          = external_getzero,
+	.frequency        = external_getzero,
+	.frequency_offset = external_getzero,
+	.txpower          = external_getzero,
+	.txpower_offset   = external_getzero,
+	.bitrate          = external_getzero,
+	.signal           = external_getzero,
+	.noise            = external_getzero,
+	.quality          = external_getzero,
+	.quality_max      = external_getzero,
+	.mbssid_support   = external_getzero,
+	.hwmodelist       = external_getzero,
+	.htmodelist       = external_getzero,
+	.mode             = external_getzero,
+	.ssid             = external_getemptystring,
+	.bssid            = external_getemptystring,
+	.country          = external_gettwozerostring,
+	.hardware_id      = external_getemptystring,
+	.hardware_name    = external_getemptystring,
+	.encryption       = external_getnochange,
+	.phyname          = external_getemptystring,
+	.assoclist        = external_getemptylist,
+	.txpwrlist        = external_getemptylist,
+	.scanlist         = external_getemptylist,
+	.freqlist         = external_getemptylist,
+	.countrylist      = external_getemptylist,
+	.close            = external_nop
+};
-- 
2.11.0.windows.3

