|
|
| version 1.1.2.1, 2010/10/27 13:10:40 | version 1.3, 2012/07/22 22:46:47 |
|---|---|
| Line 1 | Line 1 |
| /************************************************************************* | |
| * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> | |
| * by Michael Pounov <misho@aitbg.com> | |
| * | |
| * $Author$ | |
| * $Id$ | |
| * | |
| ************************************************************************* | |
| The ELWIX and AITNET software is distributed under the following | |
| terms: | |
| All of the documentation and software included in the ELWIX and AITNET | |
| Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> | |
| Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 | |
| by Michael Pounov <misho@elwix.org>. All rights reserved. | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| 1. Redistributions of source code must retain the above copyright | |
| notice, this list of conditions and the following disclaimer. | |
| 2. Redistributions in binary form must reproduce the above copyright | |
| notice, this list of conditions and the following disclaimer in the | |
| documentation and/or other materials provided with the distribution. | |
| 3. All advertising materials mentioning features or use of this software | |
| must display the following acknowledgement: | |
| This product includes software developed by Michael Pounov <misho@elwix.org> | |
| ELWIX - Embedded LightWeight unIX and its contributors. | |
| 4. Neither the name of AITNET nor the names of its contributors | |
| may be used to endorse or promote products derived from this software | |
| without specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND | |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| SUCH DAMAGE. | |
| */ | |
| #include "global.h" | #include "global.h" |
| #include "dwds.h" | #include "dwds.h" |
| cfg_root_t cfg; | |
| int Verbose, Kill, nif; | |
| char **ifs, szConfig[MAXPATHLEN] = DWDS_CONFIG; | |
| extern char compiled[], compiledby[], compilehost[]; | |
| static void | |
| Usage() | |
| { | |
| printf( "-= dWDS =- WiFi dynamic WDS service managment for VAP\n" | |
| "=== %s === %s@%s ===\n\n" | |
| " Syntax: dwds [options] <interface|any> [interface [ath0, ...]]\n" | |
| "\n" | |
| "\t-v\t\tVerbose ...\n" | |
| "\t-f\t\tForeground, not demonize process ...\n" | |
| "\t-c <config>\tConfig file [default=/etc/dwds.conf]\n" | |
| "\n", compiled, compiledby, compilehost); | |
| } | |
| static void | |
| sigHandler(int sig) | |
| { | |
| int stat; | |
| ait_val_t name; | |
| const char *v; | |
| switch (sig) { | |
| case SIGHUP: | |
| cfgUnloadConfig(&cfg); | |
| if (cfgLoadConfig(szConfig, &cfg)) { | |
| printf("Error:: can`t load config %s ...\n", szConfig); | |
| Kill++; | |
| } else { | |
| closelog(); | |
| cfg_loadAttribute(&cfg, "dwds", "name", &name, DWDS_NAME); | |
| openlog(AIT_GET_STR(&name), LOG_PID | LOG_CONS, LOG_DAEMON); | |
| AIT_FREE_VAL(&name); | |
| v = cfg_getAttribute(&cfg, "dwds", "syslog_upto"); | |
| setlogmask(v ? strtol(v, NULL, 0) : 0); | |
| } | |
| break; | |
| case SIGTERM: | |
| Kill++; | |
| break; | |
| case SIGCHLD: | |
| while (waitpid(-1, &stat, WNOHANG) > 0); | |
| break; | |
| } | |
| } | |
| static int | |
| RtMsg(struct dwds_if **wds, struct rt_msghdr *msg, size_t len) | |
| { | |
| struct if_announcemsghdr *ifan; | |
| const char *v; | |
| struct ether_addr bssid; | |
| ait_val_t Str, Ident; | |
| char szCmd[MAXPATHLEN] = { 0 }, szName[IFNAMSIZ] = { 0 }; | |
| int f, stat; | |
| assert(wds); | |
| assert(msg); | |
| if (msg->rtm_version != RTM_VERSION) { | |
| syslog(LOG_ERR, "Error:: routing message version %d not understood!\n", msg->rtm_version); | |
| return -1; | |
| } | |
| switch (msg->rtm_type) { | |
| case RTM_IFANNOUNCE: | |
| ifan = (struct if_announcemsghdr*) msg; | |
| switch (ifan->ifan_what) { | |
| case IFAN_ARRIVAL: | |
| VERB(1) syslog(LOG_INFO, "RTM_IFANNOUNCE: if# %d, what: arrival\n", | |
| ifan->ifan_index); | |
| break; | |
| case IFAN_DEPARTURE: | |
| VERB(1) syslog(LOG_INFO, "RTM_IFANNOUNCE: if# %d, what: departure\n", | |
| ifan->ifan_index); | |
| wifi_destroyWDS(ifan->ifan_name, wds); | |
| break; | |
| } | |
| break; | |
| case RTM_IEEE80211: | |
| #define V(type) ((struct type *)(&ifan[1])) | |
| ifan = (struct if_announcemsghdr*) msg; | |
| switch (ifan->ifan_what) { | |
| case RTM_IEEE80211_DISASSOC: | |
| v = cfg_getAttribute(&cfg, "dwds", "discover_on_join"); | |
| if (!v || !strtol(v, NULL, 0)) | |
| break; | |
| /* fall thru ... */ | |
| case RTM_IEEE80211_LEAVE: | |
| if (!wifi_chkIface(ifan->ifan_name, ifs, nif)) | |
| break; | |
| memcpy(&bssid, V(ieee80211_leave_event)->iev_addr, ETHER_ADDR_LEN); | |
| VERB(1) syslog(LOG_INFO, "BSSID:%s Station leave\n", ether_ntoa(&bssid)); | |
| if (!wifi_leaveWDS(bssid, wds, szName, IFNAMSIZ)) { | |
| cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME); | |
| /* delete state file ... */ | |
| v = cfg_getAttribute(&cfg, "dwds", "state_dir"); | |
| if (v) { | |
| memset(szCmd, 0, STRSIZ); | |
| snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", v, szName, | |
| ether_ntoa(&bssid), AIT_GET_STR(&Ident)); | |
| unlink(szCmd); | |
| VERB(2) syslog(LOG_DEBUG, "Debug:: delete session name %s\n", szCmd); | |
| } | |
| /* Launch script ... */ | |
| cfg_loadAttribute(&cfg, "dwds", "disassoc_event", &Str, NULL); | |
| if (!AIT_ISEMPTY(&Str)) { | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", AIT_GET_STR(&Str), | |
| szName, ether_ntoa(&bssid), AIT_GET_STR(&Ident)); | |
| VERB(3) syslog(LOG_DEBUG, "Debug:: Command line: %s\n", szCmd); | |
| if ((stat = system(szCmd))) | |
| syslog(LOG_ERR, "VAP down script %s exited " | |
| "with status %d\n", | |
| AIT_GET_STR(&Str), stat); | |
| AIT_FREE_VAL(&Str); | |
| } | |
| AIT_FREE_VAL(&Ident); | |
| } | |
| break; | |
| case RTM_IEEE80211_JOIN: | |
| case RTM_IEEE80211_REJOIN: | |
| case RTM_IEEE80211_ASSOC: | |
| case RTM_IEEE80211_REASSOC: | |
| v = cfg_getAttribute(&cfg, "dwds", "discover_on_join"); | |
| if (!v || !strtol(v, NULL, 0)) | |
| break; | |
| /* fall thru ... */ | |
| case RTM_IEEE80211_WDS: | |
| memcpy(&bssid, V(ieee80211_leave_event)->iev_addr, ETHER_ADDR_LEN); | |
| VERB(1) syslog(LOG_INFO, "BSSID:%s WDS discovery\n", ether_ntoa(&bssid)); | |
| if (!wifi_chkIface(ifan->ifan_name, ifs, nif)) | |
| break; | |
| if (!wifi_createWDS(ifan->ifan_name, bssid, wds)) { | |
| cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME); | |
| /* create state file ... */ | |
| v = cfg_getAttribute(&cfg, "dwds", "state_dir"); | |
| if (v) { | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", (char*) v, | |
| (*wds)->if_name, ether_ntoa(&bssid), | |
| AIT_GET_STR(&Ident)); | |
| f = open(szCmd, O_WRONLY | O_CREAT, 0644); | |
| if (f != -1) | |
| close(f); | |
| VERB(2) syslog(LOG_DEBUG, "Debug:: create session name %s\n", szCmd); | |
| } | |
| /* Launch script ... */ | |
| cfg_loadAttribute(&cfg, "dwds", "assoc_event", &Str, NULL); | |
| if (!AIT_ISEMPTY(&Str)) { | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", AIT_GET_STR(&Str), | |
| (*wds)->if_name, ether_ntoa(&bssid), | |
| AIT_GET_STR(&Ident)); | |
| VERB(3) syslog(LOG_DEBUG, "Debug:: Command line: %s\n", szCmd); | |
| if ((stat = system(szCmd))) | |
| syslog(LOG_ERR, "VAP up script %s exited " | |
| "with status %d\n", | |
| AIT_GET_STR(&Str), stat); | |
| AIT_FREE_VAL(&Str); | |
| } | |
| AIT_FREE_VAL(&Ident); | |
| } | |
| break; | |
| } | |
| #undef V | |
| break; | |
| } | |
| return 0; | |
| } | |
| int | int |
| main(int argc, char **argv) | main(int argc, char **argv) |
| { | { |
| char ch, fg = 0; | |
| ait_val_t Ident; | |
| const char *v, msg[2048]; | |
| int s; | |
| struct sigaction sa; | |
| size_t len; | |
| struct dwds_if *wds = NULL; | |
| while ((ch = getopt(argc, argv, "hvfc:")) != -1) | |
| switch (ch) { | |
| case 'v': | |
| Verbose++; | |
| break; | |
| case 'f': | |
| fg = 1; | |
| break; | |
| case 'c': | |
| strlcpy(szConfig, optarg, MAXPATHLEN); | |
| break; | |
| case 'h': | |
| default: | |
| Usage(); | |
| return 1; | |
| } | |
| argc -= optind; | |
| argv += optind; | |
| if (!argc) { | |
| printf("Error:: not specified interface for use ...\n"); | |
| Usage(); | |
| return 1; | |
| } else { | |
| nif = argc; | |
| ifs = argv; | |
| } | |
| if (cfgLoadConfig(szConfig, &cfg)) { | |
| printf("Error:: can`t load config %s ...\n", szConfig); | |
| return 1; | |
| } | |
| if (!fg) | |
| switch (fork()) { | |
| case -1: | |
| printf("Error:: when fork() #%d - %s\n", errno, strerror(errno)); | |
| cfgUnloadConfig(&cfg); | |
| return 2; | |
| case 0 : | |
| VERB(1) printf("Going to shadow land ...\n"); | |
| setsid(); | |
| memset(&sa, 0, sizeof sa); | |
| sa.sa_handler = sigHandler; | |
| sigemptyset(&sa.sa_mask); | |
| sigaction(SIGHUP, &sa, NULL); | |
| sigaction(SIGTERM, &sa, NULL); | |
| sigaction(SIGCHLD, &sa, NULL); | |
| break; | |
| default: | |
| goto end; | |
| } | |
| cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME); | |
| openlog(AIT_GET_STR(&Ident), LOG_PID | LOG_CONS, LOG_DAEMON); | |
| AIT_FREE_VAL(&Ident); | |
| v = cfg_getAttribute(&cfg, "dwds", "syslog_upto"); | |
| setlogmask(v ? strtol(v, NULL, 0) : 0); | |
| s = socket(PF_ROUTE, SOCK_RAW, 0); | |
| if (s == -1) { | |
| syslog(LOG_ERR, "Error:: socket() #%d - %s\n", errno, strerror(errno)); | |
| goto end; | |
| } | |
| if (!(wds = wifi_buildWDS(s, ifs, nif))) { | |
| syslog(LOG_ERR, "Error:: Go to dead ...\n"); | |
| goto end; | |
| } | |
| while (!Kill) { | |
| len = read(s, (void*) msg, sizeof msg); | |
| if (len == -1) { | |
| VERB(5) syslog(LOG_ERR, "Error:: read() #%d - %s\n", errno, strerror(errno)); | |
| Kill++; | |
| } else | |
| RtMsg(&wds, (struct rt_msghdr*) msg, len); | |
| } | |
| close(s); | |
| end: | |
| closelog(); | |
| cfgUnloadConfig(&cfg); | |
| return 0; | return 0; |
| } | } |