Modify

Opened 11 years ago

Closed 11 years ago

#164 closed enhancement (fixed)

Better WDS watchdog

Reported by: pjf@… Owned by: nbd
Priority: normal Milestone:
Component: packages Version: 1.0
Keywords: wds Cc:

Description

Hi,

I made a few changes to wificonf's WDS watchdog to make it more reliable.

--- openwrt/branches/whiterussian/openwrt/package/wificonf/wificonf.c        2005-12-13 19:58:32.000000000 +0100
+++ pointwrt/package/wificonf-pointwrt/wificonf.c        2005-12-28 17:47:18.000000000 +0100
@@ -21,6 +21,24 @@
 #include <shutils.h>
 #include <wlioctl.h>
 #include <signal.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+#define WC_NVRAM_BUF_SIZE 8192
+#define WC_WATCHDOG_SLEEP 5
+
+/* the counter loops after 59 */
+#define WC_WATCHDOG_WDS_TIMEOUT 50
+
+/* if idle time on flag 0x40 is less than this value, start detecting 0x40 loop */
+#define WC_WATCHDOG_WDS_0x40_LOOP_DETECT 9
+
+/* time to wait after restarting of WDS connections */
+#define WC_WATCHDOG_WDS_RESTART_WAIT 60
+
+#if (WC_WATCHDOG_WDS_0x40_LOOP_DETECT >= WC_WATCHDOG_WDS_TIMEOUT)
+#error "WC_WATCHDOG_WDS_0x40_LOOP_DETECT should be smaller than WC_WATCHDOG_WDS_TIMEOUT"
+#endif

 /*------------------------------------------------------------------*/
 /*
@@ -82,6 +100,7 @@
 static char *prefix;
 static char buffer[128];
 static int wpa_enc = 0;
+static int debug = 0;

 static char *wl_var(char *name)
 {
@@ -120,6 +139,17 @@
  */
 #define QDBM_TABLE_HIGH_BOUND 64938

+static void dbg(const char *msg, ...)
+{
+       if (!debug) return;
+
+       va_list va;
+
+       va_start(va, msg);
+       vsyslog(LOG_DEBUG, msg, va);
+       va_end(va);
+}
+
 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
 /* qdBm:        +0             +1              +2              +3              +4              +5              +6              +7      */
 /* 153: */      6683,  7079,   7499,   7943,   8414,   8913,   9441,   10000,
@@ -178,7 +208,7 @@

 static int bcom_set_val(int skfd, char *ifname, char *var, void *val, int len)
 {
-       char buf[8192];
+       char buf[WC_NVRAM_BUF_SIZE];
        int ret;

        if (strlen(var) + 1 > sizeof(buf) || len > sizeof(buf))
@@ -226,7 +256,7 @@

 static int setup_bcom_wds(int skfd, char *ifname)
 {
-       char buf[8192];
+       char buf[WC_NVRAM_BUF_SIZE];
        char wbuf[80];
        char *v;
        int wds_enabled = 0;
@@ -236,7 +266,7 @@
                struct ether_addr *addr = wdslist->ea;
                char *next;

-               memset(buf, 0, 8192);
+               memset(buf, 0, WC_NVRAM_BUF_SIZE);
                foreach(wbuf, v, next) {
                        if (ether_atoe(wbuf, addr->ether_addr_octet)) {
                                wdslist->count++;
@@ -252,7 +282,8 @@
 void start_watchdog(int skfd, char *ifname)
 {
        FILE *f;
-       unsigned char buf[8192], buf2[8192], wbuf[80], *v, *p, *next, *tmp;
+       unsigned char buf[WC_NVRAM_BUF_SIZE], wds_links[WC_NVRAM_BUF_SIZE], wbuf[80], *v, *p, *next, *tmp;
+       int wds_0x40_timer[WC_NVRAM_BUF_SIZE / 6]; /* max nvram var length / size (B) of MAC address */
        int wds = 0, i, j, restart_wds;
        wlc_ssid_t ssid;

@@ -263,13 +294,14 @@
        f = fopen("/var/run/wifi.pid", "w");
        fprintf(f, "%d\n", getpid());
        fclose(f);
-
+
        v = nvram_safe_get(wl_var("wds"));
-       memset(buf2, 0, 8192);
-       p = buf2;
+       memset(wds_links, 0, WC_NVRAM_BUF_SIZE);
+       p = wds_links;
        foreach(wbuf, v, next) {
                if (ether_atoe(wbuf, p)) {
                        p += 6;
+                       wds_0x40_timer[wds] = 0;
                        wds++;
                }
        }
@@ -278,7 +310,7 @@
        strncpy(ssid.SSID, v, 32);

        for (;;) {
-               sleep(5);
+               sleep(WC_WATCHDOG_SLEEP);

                /* client mode */
                bcom_ioctl(skfd, ifname, WLC_GET_AP, &i, sizeof(i));
@@ -290,10 +322,10 @@
                        if (memcmp(buf, buf + 6, 6) == 0)
                                i = 1;

-                       memset(buf, 0, 8192);
+                       memset(buf, 0, WC_NVRAM_BUF_SIZE);
                        strcpy(buf, "sta_info");
                        bcom_ioctl(skfd, ifname, WLC_GET_BSSID, buf + strlen(buf) + 1, 6);
-                       if (bcom_ioctl(skfd, ifname, WLC_GET_VAR, buf, 8192) < 0) {
+                       if (bcom_ioctl(skfd, ifname, WLC_GET_VAR, buf, WC_NVRAM_BUF_SIZE) < 0) {
                                i = 1;
                        } else {
                                sta_info_t *sta = (sta_info_t *) (buf + 4);
@@ -309,32 +341,61 @@


                /* wds */
-               p = buf2;
+               p = wds_links;
                restart_wds = 0;
-               for (i = 0; i < wds; i++) {
-                       memset(buf, 0, 8192);
+               for (i = 0; i < wds && !restart_wds; i++, p += 6) {
+                       /* fetch info about peer */
+                       memset(buf, 0, WC_NVRAM_BUF_SIZE);
                        strcpy(buf, "sta_info");
                        memcpy(buf + strlen(buf) + 1, p, 6);
-                       if (bcom_ioctl(skfd, ifname, WLC_GET_VAR, buf, 8192) < 0) {
-                       } else {
-                               sta_info_t *sta = (sta_info_t *) (buf + 4);
-                               if (!(sta->flags & 0x40)) {
-                               } else {
-                                       if (sta->idle > 120)
-                                               restart_wds = 1;
+                       if (bcom_ioctl(skfd, ifname, WLC_GET_VAR, buf, WC_NVRAM_BUF_SIZE) < 0) {
+                               syslog(LOG_ERR, "can't fetch sta_info for wds peer #%d", i + 1);
+                               continue;
+                       }
+
+                       sta_info_t *sta = (sta_info_t *) (buf + 4);
+                       dbg("wds peer #%d: flags=0x%x, idle=%d, 0x40_timer=%d",
+                            i + 1, sta->flags, sta->idle, wds_0x40_timer[i]);
+
+                       if (sta->flags & WL_STA_AUTHO) { /* authorized */
+                               dbg("wds peer #%d: authorized", i + 1);
+                               wds_0x40_timer[i] = 0;
+
+                               if (sta->idle > WC_WATCHDOG_WDS_TIMEOUT) {
+                                       syslog(LOG_NOTICE, "wds peer #%d: authorized but dead, restarting wds", i + 1);
+                                       restart_wds = 1;
                                }
                        }
-                       p += 6;
+                       else if (sta->idle < WC_WATCHDOG_WDS_0x40_LOOP_DETECT) {
+                               wds_0x40_timer[i] += WC_WATCHDOG_SLEEP;
+
+                               if (wds_0x40_timer[i] >= WC_WATCHDOG_WDS_0x40_LOOP_DETECT &&
+                                               wds_0x40_timer[i] < (WC_WATCHDOG_WDS_0x40_LOOP_DETECT + WC_WATCHDOG_SLEEP))
+                                       syslog(LOG_INFO, "wds peer #%d: loop detection triggered", i + 1);
+
+                               if (wds_0x40_timer[i] > WC_WATCHDOG_WDS_TIMEOUT) {
+                                       syslog(LOG_NOTICE, "wds peer #%d: not authorized (0x40) but dead, restarting wds", i + 1);
+                                       restart_wds = 1;
+                               }
+                       }
+                       else { /* probably just turned off */
+                               dbg("wds peer #%d: turned off / simply dead, ignoring", i + 1);
+                               wds_0x40_timer[i] = 0;
+                       }
                }
-               if (restart_wds)
+
+               if (restart_wds) {
                        setup_bcom_wds(skfd, ifname);
+                       for (i = 0; i < wds; i++) wds_0x40_timer[i] = 0;
+                       sleep(WC_WATCHDOG_WDS_RESTART_WAIT);
+               }
        }
 }

 static void setup_bcom(int skfd, char *ifname)
 {
        int val = 0, ap;
-       char buf[8192];
+       char buf[WC_NVRAM_BUF_SIZE];
        char wbuf[80];
        char *v;
        int wds_enabled = 0;
@@ -409,7 +470,7 @@
                struct ether_addr *addr;
                char *next;

-               memset(buf, 0, 8192);
+               memset(buf, 0, WC_NVRAM_BUF_SIZE);
                mac_list = (struct maclist *) buf;
                addr = mac_list->ea;

@@ -669,8 +730,15 @@
                exit(-1);
        }

+       openlog("wifi", 0, LOG_USER);
+
+       if (argc > 1) {
+               if (!strncmp(argv[1], "debug", 5)) debug = 1;
+               /* todo: other commands */
+       }
+
        prefix = strdup("wl0_");
        iw_enum_devices(skfd, &setup_interfaces, NULL, 0);
-
+
        return 0;
 }

Pawel Foremski

Attachments (0)

Change History (2)

comment:1 Changed 11 years ago by nbd

  • Owner changed from developers to nbd
  • Status changed from new to assigned

comment:2 Changed 11 years ago by nbd

  • Resolution set to fixed
  • Status changed from assigned to closed

WDS watchdog is improved in [2956]

Add Comment

Modify Ticket

Action
as closed .
The resolution will be deleted. Next status will be 'reopened'.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.