Discussion:
detecting loss of access point (link status monitoring fix?)
(too old to reply)
Eric Naud
2010-04-06 17:58:38 UTC
Permalink
Hello,

While working with the rum and ral driver I noticed that these drivers
don't detect the loss of their access point. Situations such as moving
out of range or powering down the AP is not noticed by the driver and as
a result the network status remains active and no efforts are made to
scan for a new channel.

Here's a quick test case:
1. Boot into netBSD5.0.2
2. Insert rum or ral device
3. ifconfig rum0 ssid "TESTNETWORK" -nwkey (no keys, keep it simple)
4. ifconfig rum0 up
5. Wait until network status = active and run ifconfig rum0, note the
bssid.
6. Unplug the access point associated with that bssid.
7. Wait. Run ifconfig and notice the 'status: active' is always
displayed instead of 'status: no network'

Are there other mechanisms available to detect the loss of access point
or network status without manually initiating a channel scan?

The change below uses the ieee80211_beacon_miss() function in a periodic
callout to determine if two or more consecutive beacons were missed, if
beacons were missed the driver state changes in order to initiate a
scan.

Any feedback?

Regards,
Eric

Index: if_rum.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.23
diff -r1.23 if_rum.c
25d24
<
205a205
Static void rum_linkmon(void *);
362a363
usb_callout_init(sc->sc_link_mon);
493a495
usb_uncallout(sc->sc_link_mon, rum_linkmon, sc);
747a750
usb_callout(sc->sc_link_mon, hz*3, rum_linkmon,
sc);
761a765
usb_uncallout(sc->sc_link_mon, , NULL);
2288a2293,2301
void rum_linkmon(void *arg)
{
struct rum_softc *sc = arg;
ieee80211_beacon_miss(&sc->sc_ic);
if (ic->ic_state == IEEE80211_S_RUN) {
usb_callout(sc->sc_link_mon, hz*3, rum_linkmon,
sc);
}
}
Index: if_rumvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rumvar.h,v
retrieving revision 1.4
diff -r1.4 if_rumvar.h
112a113
usb_callout_t sc_link_mon;
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Eric Naud
2010-04-06 18:53:02 UTC
Permalink
Here's the unified diff, it should be easier to look at.

Regards,
Eric

Index: if_rum.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.23
diff -u -r1.23 if_rum.c
--- if_rum.c 21 Oct 2008 12:21:46 -0000 1.23
+++ if_rum.c 6 Apr 2010 18:50:59 -0000
@@ -203,6 +203,7 @@
Static void rum_amrr_timeout(void *);
Static void rum_amrr_update(usbd_xfer_handle,
usbd_private_handle,
usbd_status status);
+Static void rum_linkmon(void *);

/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -360,6 +361,7 @@
sc->amrr.amrr_min_success_threshold = 1;
sc->amrr.amrr_max_success_threshold = 10;
usb_callout_init(sc->sc_amrr_ch);
+ usb_callout_init(sc->sc_link_mon);

/* retrieve RT2573 rev. no */
for (ntries = 0; ntries < 1000; ntries++) {
@@ -491,6 +493,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, rum_linkmon, sc);

if (sc->amrr_xfer != NULL) {
usbd_free_xfer(sc->amrr_xfer);
@@ -745,6 +748,7 @@
rum_amrr_start(sc, ni);
}

+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
break;
}

@@ -759,6 +763,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, , NULL);

/* do it in a process context */
sc->sc_state = nstate;
@@ -2286,3 +2291,12 @@

return 0;
}
+
+void rum_linkmon(void *arg)
+{
+ struct rum_softc *sc = arg;
+ ieee80211_beacon_miss(&sc->sc_ic);
+ if (sc->sc_ic.ic_state == IEEE80211_S_RUN) {
+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
+ }
+}
Index: if_rumvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rumvar.h,v
retrieving revision 1.4
diff -u -r1.4 if_rumvar.h
--- if_rumvar.h 25 Nov 2007 09:30:10 -0000 1.4
+++ if_rumvar.h 6 Apr 2010 18:50:59 -0000
@@ -110,6 +110,7 @@

usb_callout_t sc_scan_ch;
usb_callout_t sc_amrr_ch;
+ usb_callout_t sc_link_mon;

int sc_tx_timer;


Regards,
Eric

-----Original Message-----
From: Eric Naud
Sent: April 6, 2010 1:59 PM
To: 'tech-***@netbsd.org'
Subject: detecting loss of access point (link status monitoring fix?)

Hello,

While working with the rum and ral driver I noticed that these drivers
don't detect the loss of their access point. Situations such as moving
out of range or powering down the AP is not noticed by the driver and as
a result the network status remains active and no efforts are made to
scan for a new channel.

Here's a quick test case:
1. Boot into netBSD5.0.2
2. Insert rum or ral device
3. ifconfig rum0 ssid "TESTNETWORK" -nwkey (no keys, keep it simple)
4. ifconfig rum0 up
5. Wait until network status = active and run ifconfig rum0, note the
bssid.
6. Unplug the access point associated with that bssid.
7. Wait. Run ifconfig and notice the 'status: active' is always
displayed instead of 'status: no network'

Are there other mechanisms available to detect the loss of access point
or network status without manually initiating a channel scan?

The change below uses the ieee80211_beacon_miss() function in a periodic
callout to determine if two or more consecutive beacons were missed, if
beacons were missed the driver state changes in order to initiate a
scan.

Any feedback?

Regards,
Eric

Index: if_rum.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.23
diff -r1.23 if_rum.c
25d24
<
205a205
Static void rum_linkmon(void *);
362a363
usb_callout_init(sc->sc_link_mon);
493a495
usb_uncallout(sc->sc_link_mon, rum_linkmon, sc);
747a750
usb_callout(sc->sc_link_mon, hz*3, rum_linkmon,
sc);
761a765
usb_uncallout(sc->sc_link_mon, , NULL);
2288a2293,2301
void rum_linkmon(void *arg)
{
struct rum_softc *sc = arg;
ieee80211_beacon_miss(&sc->sc_ic);
if (ic->ic_state == IEEE80211_S_RUN) {
usb_callout(sc->sc_link_mon, hz*3, rum_linkmon,
sc);
}
}
Index: if_rumvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rumvar.h,v
retrieving revision 1.4
diff -r1.4 if_rumvar.h
112a113
usb_callout_t sc_link_mon;
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Young
2010-04-09 21:04:05 UTC
Permalink
Post by Eric Naud
The change below uses the ieee80211_beacon_miss() function in a periodic
callout to determine if two or more consecutive beacons were missed, if
beacons were missed the driver state changes in order to initiate a
scan.
It looks to me like the change may work a little differently than
you say: you indicate a beacon miss to net80211 every three seconds,
regardless of whether any beacon was missed. If ic_bmiss_max is 2 (the
default), then on the first miss, net80211 sends a probe request to the
access point (iirc, a probe response resets the beacon-miss count), and
on the second miss, net80211 starts a scan.

Can ral(4) and rum(4) indicate a beacon miss with an interrupt? Other
NICs can.

Dave
--
David Young OJC Technologies
***@ojctech.com Urbana, IL * (217) 278-3933

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Eric Naud
2010-04-19 20:15:39 UTC
Permalink
Post by Eric Naud
-----Original Message-----
Behalf Of David Young
Sent: April 9, 2010 5:04 PM
Subject: Re: detecting loss of access point (link status monitoring
fix?)
Post by Eric Naud
Post by Eric Naud
The change below uses the ieee80211_beacon_miss() function in a periodic
callout to determine if two or more consecutive beacons were missed, if
beacons were missed the driver state changes in order to initiate a
scan.
It looks to me like the change may work a little differently than
you say: you indicate a beacon miss to net80211 every three seconds,
regardless of whether any beacon was missed. If ic_bmiss_max is 2 (the
default), then on the first miss, net80211 sends a probe request to the
access point (iirc, a probe response resets the beacon-miss count), and
on the second miss, net80211 starts a scan.
Can ral(4) and rum(4) indicate a beacon miss with an interrupt? Other
NICs can.
Dave
Hello Dave,

Thank you for your reply. As far as I can tell from reading the
Rum/RT2501 (RT2571/RT2561) specs the only interrupt we could use to
detect missed beacons is the TBTT interrupt which fires once every
beacon interval, in typical cases this would involve an interrupt every
100ms which seems excessive for the task at hand. I also get the feeling
this is mostly used for IBSS mode. I don't have the specs for the run
driver but there's no indication in if_runreg.h of a missed beacon
interrupt in this newer device.

Seeing that the hardware capability isn't present like it is in other
devices I would like to propose a new, slightly modified change taking
into account your comments. Indeed, ieee80211_beacon_miss should only be
called once beacons appear to be stalled or missing, not every single
time the monitor runs.

The change still includes a periodic callback (every three seconds when
in the IEEE80211_S_RUN state). This callback looks at the
ic->ic_stats.is_rx_beacon data structure element to determine if the
received beacon count has stalled. On first detecting the beacon count
isn't moving we call ieee80211_beacon_miss to send a probe request to
the AP. Next time the link monitor runs, three seconds later, if the
beacon count still hasn't moved, we assume the AP is gone and
ieee80211_beacon_miss will be called again to initiate a channel scan.

Because of the generic nature of the change, with only one function
dependency on the ieee80211 stack, this change can apply to the rum(4),
ral(4) and run(4) drivers which all currently appear to lack the
hardware and software ability to detect the loss of an access point.

Regards,
Eric


Index: if_rum.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.23
diff -u -r1.23 if_rum.c
--- if_rum.c 21 Oct 2008 12:21:46 -0000 1.23
+++ if_rum.c 19 Apr 2010 15:28:05 -0000
@@ -203,6 +203,7 @@
Static void rum_amrr_timeout(void *);
Static void rum_amrr_update(usbd_xfer_handle,
usbd_private_handle,
usbd_status status);
+Static void rum_linkmon(void *);

/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -360,6 +361,7 @@
sc->amrr.amrr_min_success_threshold = 1;
sc->amrr.amrr_max_success_threshold = 10;
usb_callout_init(sc->sc_amrr_ch);
+ usb_callout_init(sc->sc_link_mon);

/* retrieve RT2573 rev. no */
for (ntries = 0; ntries < 1000; ntries++) {
@@ -491,6 +493,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, rum_linkmon, sc);

if (sc->amrr_xfer != NULL) {
usbd_free_xfer(sc->amrr_xfer);
@@ -745,6 +748,7 @@
rum_amrr_start(sc, ni);
}

+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
break;
}

@@ -759,6 +763,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, rum_linkmon, NULL);

/* do it in a process context */
sc->sc_state = nstate;
@@ -2286,3 +2291,24 @@

return 0;
}
+
+static int beacon_count = 0;
+static int bcnt_initialized = 0;
+void rum_linkmon(void *arg)
+{
+ struct rum_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ if (bcnt_initialized == 0) {
+ beacon_count = ic->ic_stats.is_rx_beacon;
+ bcnt_initialized = 1;
+ } else if (beacon_count == ic->ic_stats.is_rx_beacon) {
+ ieee80211_beacon_miss(ic);
+ } else {
+ beacon_count = ic->ic_stats.is_rx_beacon;
+ }
+
+ if (sc->sc_ic.ic_state == IEEE80211_S_RUN) {
+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
+ }
+}
Index: if_rumvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rumvar.h,v
retrieving revision 1.4
diff -u -r1.4 if_rumvar.h
--- if_rumvar.h 25 Nov 2007 09:30:10 -0000 1.4
+++ if_rumvar.h 19 Apr 2010 15:28:05 -0000
@@ -110,6 +110,7 @@

usb_callout_t sc_scan_ch;
usb_callout_t sc_amrr_ch;
+ usb_callout_t sc_link_mon;

int sc_tx_timer




--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Young
2010-04-20 02:58:48 UTC
Permalink
Post by Eric Naud
The change still includes a periodic callback (every three seconds when
in the IEEE80211_S_RUN state). This callback looks at the
ic->ic_stats.is_rx_beacon data structure element to determine if the
received beacon count has stalled. On first detecting the beacon count
isn't moving we call ieee80211_beacon_miss to send a probe request to
the AP. Next time the link monitor runs, three seconds later, if the
beacon count still hasn't moved, we assume the AP is gone and
ieee80211_beacon_miss will be called again to initiate a channel scan.
That sounds like it will work. The idea of a driver using the net80211
stats in that way doesn't sit well, but I cannot think of a better
solution that is also as parsimonious.

Dave
--
David Young OJC Technologies
***@ojctech.com Urbana, IL * (217) 278-3933

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Eric Naud
2010-04-27 18:20:40 UTC
Permalink
Post by David Young
That sounds like it will work. The idea of a driver using the
net80211
Post by David Young
stats in that way doesn't sit well, but I cannot think of a better
solution that is also as parsimonious.
Dave
--
David Young OJC Technologies
Hello Dave,

I agree, using the stats in such was way didn't seem right, so I came up
with another approach to detecting an AP disconnect. Now I pass in a
timestamp to the ieee80211_input function via the currently unused
rstamp parameter. This in turn populates the ni_rstamp iee80211node
structure member with the last received timestamp.

In the link monitor, if this timestamp isn't updated, as it should with
every incoming packet, and the timestamp is the same as it was last time
the link monitor ran the connection is considered stale and a scan is
initiated.

The change is below. This seems like an improvement over using the stats
counter, any thoughts?


Regards,
Eric

Index: if_rum.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.23
diff -u -r1.23 if_rum.c
--- if_rum.c 21 Oct 2008 12:21:46 -0000 1.23
+++ if_rum.c 27 Apr 2010 17:53:42 -0000
@@ -38,6 +38,7 @@
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/device.h>
+#include <sys/time.h>

#include <sys/bus.h>
#include <machine/endian.h>
@@ -203,6 +204,7 @@
Static void rum_amrr_timeout(void *);
Static void rum_amrr_update(usbd_xfer_handle,
usbd_private_handle,
usbd_status status);
+Static void rum_linkmon(void *);

/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -360,6 +362,7 @@
sc->amrr.amrr_min_success_threshold = 1;
sc->amrr.amrr_max_success_threshold = 10;
usb_callout_init(sc->sc_amrr_ch);
+ usb_callout_init(sc->sc_link_mon);

/* retrieve RT2573 rev. no */
for (ntries = 0; ntries < 1000; ntries++) {
@@ -491,6 +494,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, rum_linkmon, sc);

if (sc->amrr_xfer != NULL) {
usbd_free_xfer(sc->amrr_xfer);
@@ -745,6 +749,7 @@
rum_amrr_start(sc, ni);
}

+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
break;
}

@@ -759,6 +764,7 @@
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_uncallout(sc->sc_scan_ch, rum_next_scan, sc);
usb_uncallout(sc->sc_amrr_ch, rum_amrr_timeout, sc);
+ usb_uncallout(sc->sc_link_mon, rum_linkmon, NULL);

/* do it in a process context */
sc->sc_state = nstate;
@@ -823,6 +829,7 @@
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct mbuf *mnew, *m;
+ struct timeval tstamp;
int s, len;

if (status != USBD_NORMAL_COMPLETION) {
@@ -902,7 +909,8 @@
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min
*)wh);

/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, desc->rssi, 0);
+ microtime(&tstamp);
+ ieee80211_input(ic, m, ni, desc->rssi, tstamp.tv_sec);

/* node is no longer needed */
ieee80211_free_node(ni);
@@ -2286,3 +2294,23 @@

return 0;
}
+
+static int last_rx_tstamp = 0;
+static int rx_tstamp_init = 0;
+void rum_linkmon(void *arg)
+{
+ struct rum_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ if ((rx_tstamp_init) && (ic->ic_bss->ni_rstamp ==
last_rx_tstamp)) {
+ DPRINTF(("Current AP stale: initiating scan\n"));
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ }
+
+ rx_tstamp_init = 1;
+ last_rx_tstamp = ic->ic_bss->ni_rstamp;
+
+ if (sc->sc_ic.ic_state == IEEE80211_S_RUN) {
+ usb_callout(sc->sc_link_mon, hz*3, rum_linkmon, sc);
+ }
+}
Index: if_rumvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_rumvar.h,v
retrieving revision 1.4
diff -u -r1.4 if_rumvar.h
--- if_rumvar.h 25 Nov 2007 09:30:10 -0000 1.4
+++ if_rumvar.h 27 Apr 2010 17:53:42 -0000
@@ -110,6 +110,7 @@

usb_callout_t sc_scan_ch;
usb_callout_t sc_amrr_ch;
+ usb_callout_t sc_link_mon;

int sc_tx_timer;


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Young
2010-04-30 17:57:00 UTC
Permalink
Post by David Young
Post by David Young
That sounds like it will work. The idea of a driver using the
net80211
Post by David Young
stats in that way doesn't sit well, but I cannot think of a better
solution that is also as parsimonious.
Dave
--
David Young OJC Technologies
Hello Dave,
I agree, using the stats in such was way didn't seem right, so I came up
with another approach to detecting an AP disconnect. Now I pass in a
timestamp to the ieee80211_input function via the currently unused
rstamp parameter. This in turn populates the ni_rstamp iee80211node
structure member with the last received timestamp.
That looks better. It's too bad that the NIC does not provide an Rx
timestamp like other WLAN NICs do!

You can extract a timestamp from the beacons, btw. It might (or might
not) be less costly than a microtime(9) call.

Dave
--
David Young OJC Technologies
***@ojctech.com Urbana, IL * (217) 278-3933

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Loading...