2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
21 /* Get BSSID of given interface */
22 static int iw_get_bssid(int iwfd
, const char *ifname
, char *bssid
)
26 if( iw_ioctl(iwfd
, ifname
, SIOCGIWAP
, &iwrq
) >= 0 )
28 unsigned char *addr
= (unsigned char *)iwrq
.u
.ap_addr
.sa_data
;
30 sprintf(bssid
, "%02X:%02X:%02X:%02X:%02X:%02X",
31 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
39 /* Get channel of given interface */
40 static int iw_get_channel(int iwfd
, const char *ifname
, int *channel
)
43 char buffer
[sizeof(struct iw_range
)];
44 double cur_freq
, cmp_freq
;
46 struct iw_range
*range
;
48 memset(buffer
, 0, sizeof(buffer
));
50 iwrq
.u
.data
.pointer
= (char *)buffer
;
51 iwrq
.u
.data
.length
= sizeof(buffer
);
52 iwrq
.u
.data
.flags
= 0;
54 if( iw_ioctl(iwfd
, ifname
, SIOCGIWRANGE
, &iwrq
) < 0)
60 range
= (struct iw_range
*)buffer
;
62 if( iw_ioctl(iwfd
, ifname
, SIOCGIWFREQ
, &iwrq
) >= 0 )
64 cur_freq
= ((double)iwrq
.u
.freq
.m
) * pow(10, iwrq
.u
.freq
.e
);
65 if( cur_freq
< 1000.00 )
67 *channel
= (int)cur_freq
;
71 for(i
= 0; i
< range
->num_frequency
; i
++)
73 cmp_freq
= ((double)range
->freq
[i
].m
) * pow(10, range
->freq
[i
].e
);
74 if( cmp_freq
== cur_freq
)
76 *channel
= (int)range
->freq
[i
].i
;
86 /* Get the (first) pid of given process name */
87 static int find_process(const char *name
)
96 if( (dir
= opendir("/proc")) != NULL
)
98 snprintf(cmpname
, sizeof(cmpname
), "Name:\t%s\n", name
);
100 while( (entry
= readdir(dir
)) != NULL
)
102 if( !strcmp(entry
->d_name
, "..") || !isdigit(*entry
->d_name
) )
105 sprintf(buffer
, "/proc/%s/status", entry
->d_name
);
106 if( (file
= open(buffer
, O_RDONLY
)) > -1 )
108 read(file
, buffer
, sizeof(buffer
));
111 if( strstr(buffer
, cmpname
) == buffer
)
113 pid
= atoi(entry
->d_name
);
115 /* Skip myself ... */
116 if( pid
== getpid() )
128 syslog(LOG_CRIT
, "Unable to open /proc: %s",
134 /* Check if given uci file was updated */
135 static int check_uci_update(const char *config
, time_t *mtime
)
140 snprintf(path
, sizeof(path
), "/etc/config/%s", config
);
141 if( stat(path
, &s
) > -1 )
143 if( (*mtime
== 0) || (s
.st_mtime
> *mtime
) )
150 snprintf(path
, sizeof(path
), "/var/state/%s", config
);
151 if( stat(path
, &s
) > -1 )
153 if( (*mtime
== 0) || (s
.st_mtime
> *mtime
) )
168 static void load_wifi_uci_add_iface(const char *section
, struct uci_itr_ctx
*itr
)
174 if( (t
= (wifi_tuple_t
*)malloc(sizeof(wifi_tuple_t
))) != NULL
)
176 ucitmp
= ucix_get_option(itr
->ctx
, "wireless", section
, "ifname");
179 strncpy(t
->ifname
, ucitmp
, sizeof(t
->ifname
));
183 ucitmp
= ucix_get_option(itr
->ctx
, "wireless", section
, "bssid");
186 strncpy(t
->bssid
, ucitmp
, sizeof(t
->bssid
));
190 ucitmp
= ucix_get_option(itr
->ctx
, "wireless", section
, "device");
193 ucitmp
= ucix_get_option(itr
->ctx
, "wireless", ucitmp
, "channel");
196 t
->channel
= atoi(ucitmp
);
203 syslog(LOG_INFO
, "Monitoring %s: bssid=%s channel=%d",
204 t
->ifname
, t
->bssid
, t
->channel
);
217 static wifi_tuple_t
* load_wifi_uci(wifi_tuple_t
*ifs
, time_t *modtime
)
219 struct uci_context
*ctx
;
220 struct uci_itr_ctx itr
;
221 wifi_tuple_t
*cur
, *next
;
223 if( check_uci_update("wireless", modtime
) )
225 syslog(LOG_INFO
, "Config changed, reloading");
227 if( (ctx
= ucix_init("wireless")) != NULL
)
231 for(cur
= ifs
; cur
; cur
= next
)
241 ucix_for_each_section_type(ctx
, "wireless", "wifi-iface",
242 (void *)load_wifi_uci_add_iface
, &itr
);
251 /* Daemon implementation */
252 static int do_daemon(void)
258 wifi_tuple_t
*ifs
= NULL
, *curif
;
261 int restart_wifi
= 0;
262 int restart_cron
= 0;
264 openlog(SYSLOG_IDENT
, 0, LOG_DAEMON
);
267 if( (iwfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1 )
269 perror("Can not open wireless control socket");
275 if( (ifs
= load_wifi_uci(ifs
, &modtime
)) == NULL
)
277 printf("Can not load wireless uci. File corrupt?\n");
282 if( find_process("crond") < 0 )
284 syslog(LOG_WARNING
, "The crond process died, restarting");
288 /* Check wireless interfaces */
289 for( curif
= ifs
; curif
; curif
= curif
->next
)
291 /* Get current channel and bssid */
292 if( (iw_get_bssid(iwfd
, curif
->ifname
, bssid
) == 0) &&
293 (iw_get_channel(iwfd
, curif
->ifname
, &channel
) == 0) )
296 if( strcasecmp(bssid
, curif
->bssid
) != 0 )
298 syslog(LOG_WARNING
, "BSSID mismatch on %s: current=%s wanted=%s",
299 curif
->ifname
, bssid
, curif
->bssid
);
305 if( channel
!= curif
->channel
)
307 syslog(LOG_WARNING
, "Channel mismatch on %s: current=%d wanted=%d",
308 curif
->ifname
, channel
, curif
->channel
);
315 syslog(LOG_WARNING
, "Requested interface %s not present", curif
->ifname
);
320 /* Wifi restart required? */
321 if( restart_wifi
>= HYSTERESIS
)
324 syslog(LOG_WARNING
, "Restarting wireless");
328 /* Cron restart required? */
329 if( restart_cron
>= HYSTERESIS
)
332 syslog(LOG_WARNING
, "Restarting crond process");
344 int main(int argc
, char *argv
[])
346 /* Check if watchdog is running ... */
347 if( (argc
> 1) && (strcmp(argv
[1], "running") == 0) )
349 return (find_process(BINARY
) == -1);