#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 [...]]\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 };
int 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) < 0)
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)) {
/* Launch script ... */
cfg_LoadAttribute(&cfg, CFG("dwds"), CFG("disassoc_event"),
CFG(szStr), STRSIZ, NULL);
if (*szStr) {
snprintf(szCmd, MAXPATHLEN, "%s %s %s", szStr,
ifan->ifan_name, ether_ntoa(&bssid));
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) < 0)
break;
if (!wifi_createWDS(ifan->ifan_name, bssid, wds)) {
/* Launch script ... */
cfg_LoadAttribute(&cfg, CFG("dwds"), CFG("assoc_event"),
CFG(szStr), STRSIZ, NULL);
if (*szStr) {
snprintf(szCmd, MAXPATHLEN, "%s %s %s", szStr,
ifan->ifan_name, ether_ntoa(&bssid));
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) {
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;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>