|
|
| version 1.1, 2010/10/27 13:10:40 | version 1.2, 2011/06/08 12:45:41 |
|---|---|
| Line 0 | Line 1 |
| #include "global.h" | |
| #include "dwds.h" | |
| sl_config 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; | |
| const u_char *v; | |
| char szStr[STRSIZ]; | |
| switch (sig) { | |
| case SIGHUP: | |
| UnloadConfig(&cfg); | |
| if (LoadConfig(szConfig, &cfg)) { | |
| printf("Error:: can`t load config %s ...\n", szConfig); | |
| Kill++; | |
| } else { | |
| closelog(); | |
| cfg_LoadAttribute(&cfg, CFG("dwds"), CFG("name"), CFG(szStr), STRSIZ, DWDS_NAME); | |
| openlog(szStr, LOG_PID | LOG_CONS, LOG_DAEMON); | |
| v = cfg_GetAttribute(&cfg, CFG("dwds"), CFG("syslog_upto")); | |
| setlogmask(v ? strtol((char*) 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 u_char *v; | |
| struct ether_addr bssid; | |
| char szStr[STRSIZ] = { 0 }, szCmd[MAXPATHLEN] = { 0 }, szIdent[STRSIZ] = { 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, CFG("dwds"), CFG("discover_on_join")); | |
| if (!v || !strtol((char*) 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, CFG("dwds"), CFG("name"), | |
| CFG(szIdent), STRSIZ, DWDS_NAME); | |
| /* delete state file ... */ | |
| v = cfg_GetAttribute(&cfg, CFG("dwds"), CFG("state_dir")); | |
| if (v) { | |
| memset(szCmd, 0, STRSIZ); | |
| snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", (char*) v, | |
| szName, ether_ntoa(&bssid), szIdent); | |
| unlink(szCmd); | |
| VERB(2) syslog(LOG_DEBUG, "Debug:: delete session name %s\n", szCmd); | |
| } | |
| /* Launch script ... */ | |
| cfg_LoadAttribute(&cfg, CFG("dwds"), CFG("disassoc_event"), | |
| CFG(szStr), STRSIZ, NULL); | |
| if (*szStr) { | |
| cfg_LoadAttribute(&cfg, CFG("dwds"), CFG("name"), | |
| CFG(szIdent), STRSIZ, DWDS_NAME); | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", szStr, | |
| szName, ether_ntoa(&bssid), szIdent); | |
| 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", szStr, stat); | |
| } | |
| } | |
| break; | |
| case RTM_IEEE80211_JOIN: | |
| case RTM_IEEE80211_REJOIN: | |
| case RTM_IEEE80211_ASSOC: | |
| case RTM_IEEE80211_REASSOC: | |
| v = cfg_GetAttribute(&cfg, CFG("dwds"), CFG("discover_on_join")); | |
| if (!v || !strtol((char*) 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, CFG("dwds"), CFG("name"), | |
| CFG(szIdent), STRSIZ, DWDS_NAME); | |
| /* create state file ... */ | |
| v = cfg_GetAttribute(&cfg, CFG("dwds"), CFG("state_dir")); | |
| if (v) { | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", (char*) v, | |
| (*wds)->if_name, ether_ntoa(&bssid), szIdent); | |
| 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, CFG("dwds"), CFG("assoc_event"), | |
| CFG(szStr), STRSIZ, NULL); | |
| if (*szStr) { | |
| memset(szCmd, 0, MAXPATHLEN); | |
| snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", szStr, | |
| (*wds)->if_name, ether_ntoa(&bssid), szIdent); | |
| 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", szStr, stat); | |
| } | |
| } | |
| break; | |
| } | |
| #undef V | |
| break; | |
| } | |
| return 0; | |
| } | |
| // --------------------------------------------------------------- | |
| int | |
| main(int argc, char **argv) | |
| { | |
| char ch, szStr[STRSIZ], fg = 0; | |
| const u_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 (LoadConfig(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)); | |
| UnloadConfig(&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, CFG("dwds"), CFG("name"), CFG(szStr), STRSIZ, DWDS_NAME); | |
| openlog(szStr, LOG_PID | LOG_CONS, LOG_DAEMON); | |
| v = cfg_GetAttribute(&cfg, CFG("dwds"), CFG("syslog_upto")); | |
| setlogmask(v ? strtol((char*) 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(); | |
| UnloadConfig(&cfg); | |
| return 0; | |
| } |