1: /*************************************************************************
2: * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
6: * $Id: dwds.c,v 1.3.4.1 2014/01/30 01:03:23 misho Exp $
7: *
8: *************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2014
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "dwds.h"
48:
49:
50: cfg_root_t cfg;
51: int Verbose, Kill, nif;
52: char **ifs, szConfig[MAXPATHLEN] = DWDS_CONFIG;
53: extern char compiled[], compiledby[], compilehost[];
54:
55:
56: static void
57: Usage()
58: {
59: printf( "-= dWDS =- WiFi dynamic WDS service managment for VAP\n"
60: "=== %s === %s@%s ===\n\n"
61: " Syntax: dwds [options] <interface|any> [interface [ath0, ...]]\n"
62: "\n"
63: "\t-v\t\tVerbose ...\n"
64: "\t-f\t\tForeground, not demonize process ...\n"
65: "\t-c <config>\tConfig file [default=/etc/dwds.conf]\n"
66: "\n", compiled, compiledby, compilehost);
67: }
68:
69: static void
70: sigHandler(int sig)
71: {
72: int stat;
73: ait_val_t name;
74: const char *v;
75:
76: switch (sig) {
77: case SIGHUP:
78: cfgUnloadConfig(&cfg);
79: if (cfgLoadConfig(szConfig, &cfg)) {
80: printf("Error:: can`t load config %s ...\n", szConfig);
81: Kill++;
82: } else {
83: closelog();
84:
85: cfg_loadAttribute(&cfg, "dwds", "name", &name, DWDS_NAME);
86: openlog(AIT_GET_STR(&name), LOG_PID | LOG_CONS, LOG_DAEMON);
87: AIT_FREE_VAL(&name);
88: v = cfg_getAttribute(&cfg, "dwds", "syslog_upto");
89: setlogmask(v ? strtol(v, NULL, 0) : 0);
90: }
91: break;
92: case SIGTERM:
93: Kill++;
94: break;
95: case SIGCHLD:
96: while (waitpid(-1, &stat, WNOHANG) > 0);
97: break;
98: }
99: }
100:
101: static int
102: RtMsg(struct dwds_if **wds, struct rt_msghdr *msg, size_t len)
103: {
104: struct if_announcemsghdr *ifan;
105: const char *v;
106: struct ether_addr bssid;
107: ait_val_t Str, Ident;
108: char szCmd[MAXPATHLEN] = { 0 }, szName[IFNAMSIZ] = { 0 };
109: int f, stat;
110:
111: assert(wds);
112: assert(msg);
113:
114: if (msg->rtm_version != RTM_VERSION) {
115: syslog(LOG_ERR, "Error:: routing message version %d not understood!\n", msg->rtm_version);
116: return -1;
117: }
118:
119: switch (msg->rtm_type) {
120: case RTM_IFANNOUNCE:
121: ifan = (struct if_announcemsghdr*) msg;
122: switch (ifan->ifan_what) {
123: case IFAN_ARRIVAL:
124: VERB(1) syslog(LOG_INFO, "RTM_IFANNOUNCE: if# %d, what: arrival\n",
125: ifan->ifan_index);
126: break;
127: case IFAN_DEPARTURE:
128: VERB(1) syslog(LOG_INFO, "RTM_IFANNOUNCE: if# %d, what: departure\n",
129: ifan->ifan_index);
130: wifi_destroyWDS(ifan->ifan_name, wds);
131: break;
132: }
133: break;
134: case RTM_IEEE80211:
135: #define V(type) ((struct type *)(&ifan[1]))
136: ifan = (struct if_announcemsghdr*) msg;
137: switch (ifan->ifan_what) {
138: case RTM_IEEE80211_DISASSOC:
139: v = cfg_getAttribute(&cfg, "dwds", "discover_on_join");
140: if (!v || !strtol(v, NULL, 0))
141: break;
142: /* fall thru ... */
143: case RTM_IEEE80211_LEAVE:
144: if (!wifi_chkIface(ifan->ifan_name, ifs, nif))
145: break;
146: memcpy(&bssid, V(ieee80211_leave_event)->iev_addr, ETHER_ADDR_LEN);
147: VERB(1) syslog(LOG_INFO, "BSSID:%s Station leave\n", ether_ntoa(&bssid));
148: if (!wifi_leaveWDS(bssid, wds, szName, IFNAMSIZ)) {
149: cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME);
150: /* delete state file ... */
151: v = cfg_getAttribute(&cfg, "dwds", "state_dir");
152: if (v) {
153: memset(szCmd, 0, STRSIZ);
154: snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", v, szName,
155: ether_ntoa(&bssid), AIT_GET_STR(&Ident));
156: unlink(szCmd);
157: VERB(2) syslog(LOG_DEBUG, "Debug:: delete session name %s\n", szCmd);
158: }
159:
160: /* Launch script ... */
161: cfg_loadAttribute(&cfg, "dwds", "disassoc_event", &Str, NULL);
162: if (!AIT_ISEMPTY(&Str)) {
163: memset(szCmd, 0, MAXPATHLEN);
164: snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", AIT_GET_STR(&Str),
165: szName, ether_ntoa(&bssid), AIT_GET_STR(&Ident));
166: VERB(3) syslog(LOG_DEBUG, "Debug:: Command line: %s\n", szCmd);
167:
168: if ((stat = system(szCmd)))
169: syslog(LOG_ERR, "VAP down script %s exited "
170: "with status %d\n",
171: AIT_GET_STR(&Str), stat);
172: AIT_FREE_VAL(&Str);
173: }
174: AIT_FREE_VAL(&Ident);
175: }
176: break;
177:
178: case RTM_IEEE80211_JOIN:
179: case RTM_IEEE80211_REJOIN:
180: case RTM_IEEE80211_ASSOC:
181: case RTM_IEEE80211_REASSOC:
182: v = cfg_getAttribute(&cfg, "dwds", "discover_on_join");
183: if (!v || !strtol(v, NULL, 0))
184: break;
185: /* fall thru ... */
186: case RTM_IEEE80211_WDS:
187: memcpy(&bssid, V(ieee80211_leave_event)->iev_addr, ETHER_ADDR_LEN);
188: VERB(1) syslog(LOG_INFO, "BSSID:%s WDS discovery\n", ether_ntoa(&bssid));
189: if (!wifi_chkIface(ifan->ifan_name, ifs, nif))
190: break;
191: if (!wifi_createWDS(ifan->ifan_name, bssid, wds)) {
192: cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME);
193: /* create state file ... */
194: v = cfg_getAttribute(&cfg, "dwds", "state_dir");
195: if (v) {
196: memset(szCmd, 0, MAXPATHLEN);
197: snprintf(szCmd, MAXPATHLEN, "%s/%s-%s-%s", (char*) v,
198: (*wds)->if_name, ether_ntoa(&bssid),
199: AIT_GET_STR(&Ident));
200: f = open(szCmd, O_WRONLY | O_CREAT, 0644);
201: if (f != -1)
202: close(f);
203: VERB(2) syslog(LOG_DEBUG, "Debug:: create session name %s\n", szCmd);
204: }
205:
206: /* Launch script ... */
207: cfg_loadAttribute(&cfg, "dwds", "assoc_event", &Str, NULL);
208: if (!AIT_ISEMPTY(&Str)) {
209: memset(szCmd, 0, MAXPATHLEN);
210: snprintf(szCmd, MAXPATHLEN, "%s %s %s %s", AIT_GET_STR(&Str),
211: (*wds)->if_name, ether_ntoa(&bssid),
212: AIT_GET_STR(&Ident));
213: VERB(3) syslog(LOG_DEBUG, "Debug:: Command line: %s\n", szCmd);
214:
215: if ((stat = system(szCmd)))
216: syslog(LOG_ERR, "VAP up script %s exited "
217: "with status %d\n",
218: AIT_GET_STR(&Str), stat);
219: AIT_FREE_VAL(&Str);
220: }
221: AIT_FREE_VAL(&Ident);
222: }
223: break;
224: }
225: #undef V
226: break;
227: }
228:
229: return 0;
230: }
231:
232:
233: int
234: main(int argc, char **argv)
235: {
236: char ch, fg = 0;
237: ait_val_t Ident;
238: const char *v, msg[2048];
239: int s;
240: struct sigaction sa;
241: size_t len;
242: struct dwds_if *wds = NULL;
243:
244: while ((ch = getopt(argc, argv, "hvfc:")) != -1)
245: switch (ch) {
246: case 'v':
247: Verbose++;
248: break;
249: case 'f':
250: fg = 1;
251: break;
252: case 'c':
253: strlcpy(szConfig, optarg, MAXPATHLEN);
254: break;
255: case 'h':
256: default:
257: Usage();
258: return 1;
259: }
260: argc -= optind;
261: argv += optind;
262: if (!argc) {
263: printf("Error:: not specified interface for use ...\n");
264: Usage();
265: return 1;
266: } else {
267: nif = argc;
268: ifs = argv;
269: }
270: if (cfgLoadConfig(szConfig, &cfg)) {
271: printf("Error:: can`t load config %s ...\n", szConfig);
272: return 1;
273: }
274:
275: if (!fg)
276: switch (fork()) {
277: case -1:
278: printf("Error:: when fork() #%d - %s\n", errno, strerror(errno));
279: cfgUnloadConfig(&cfg);
280: return 2;
281: case 0 :
282: VERB(1) printf("Going to shadow land ...\n");
283:
284: setsid();
285:
286: memset(&sa, 0, sizeof sa);
287: sa.sa_handler = sigHandler;
288: sigemptyset(&sa.sa_mask);
289: sigaction(SIGHUP, &sa, NULL);
290: sigaction(SIGTERM, &sa, NULL);
291: sigaction(SIGCHLD, &sa, NULL);
292: break;
293: default:
294: goto end;
295: }
296:
297: cfg_loadAttribute(&cfg, "dwds", "name", &Ident, DWDS_NAME);
298: openlog(AIT_GET_STR(&Ident), LOG_PID | LOG_CONS, LOG_DAEMON);
299: AIT_FREE_VAL(&Ident);
300: v = cfg_getAttribute(&cfg, "dwds", "syslog_upto");
301: setlogmask(v ? strtol(v, NULL, 0) : 0);
302:
303: s = socket(PF_ROUTE, SOCK_RAW, 0);
304: if (s == -1) {
305: syslog(LOG_ERR, "Error:: socket() #%d - %s\n", errno, strerror(errno));
306: goto end;
307: }
308:
309: if (!(wds = wifi_buildWDS(s, ifs, nif))) {
310: syslog(LOG_ERR, "Error:: Go to dead ...\n");
311: goto end;
312: }
313:
314: while (!Kill) {
315: len = read(s, (void*) msg, sizeof msg);
316: if (len == -1) {
317: VERB(5) syslog(LOG_ERR, "Error:: read() #%d - %s\n", errno, strerror(errno));
318: Kill++;
319: } else
320: RtMsg(&wds, (struct rt_msghdr*) msg, len);
321: }
322:
323: close(s);
324: end:
325: closelog();
326: cfgUnloadConfig(&cfg);
327: return 0;
328: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>