tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Possible fix for wpa_supplicant(8) WPA re-key lossage



Hi,

Since the last import back in January, wpa_supplicant(8) in 
NetBSD-current has been unable to maintain a WPA session with a 
wireless AP due to lossage during re-keying. The work-around thus far 
has been to keep a wpa_cli(8) instance running for the duration of the 
session.

After some playing around this evening, I believe I have tracked down 
the cause of the bug to lossage within bpf(4)'s bpf_poll() function. 
The bottom line is that wpa_supplicant(8) does not receive the re-key 
packet from the AP because the select(2) call in 
dist/wpa/src/utils/eloop.c does not report the event promptly. The 
wpa_cli(8) hack works because it sends a PING request over 
wpa_supplicant's control socket once per second, resulting in the 
select(2) call returning each time. The next call to select(2) returns 
a bpf(2) readable status, so re-keying proceeds normally albeit delayed 
slightly.

The attached patch to sys/net/bpf.c contains two changes lifted from 
FreeBSD's bpf.c:
 - A "fix" for bpf_poll() to address the above problem (but see below).
 - A fix for catchpacket() which delays calling bpf_wakeup() until
   the state has been updated.

I'd like someone with more bpf(4) clue to look over the first fix, as 
I'm somewhat perplexed as to why it fixes the problem. (Maybe it's the 
beer, maybe I need to spend more time staring at it, or maybe I'm just 
getting too old ;-)

In anycase, if you have been experiencing this wpa_supplicant(8) 
problem, please try the patch and report back.

Cheers, Steve
Index: bpf.c
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.c,v
retrieving revision 1.137
diff -u -p -r1.137 bpf.c
--- bpf.c       26 Mar 2008 02:21:52 -0000      1.137
+++ bpf.c       18 Apr 2008 20:31:05 -0000
@@ -1084,14 +1084,10 @@ bpf_poll(struct file *fp, int events)
                /*
                 * An imitation of the FIONREAD ioctl code.
                 */
-               if ((d->bd_hlen != 0) ||
-                   (d->bd_immediate && d->bd_slen != 0)) {
+               if (d->bd_hlen != 0 ||
+                   ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
+                    d->bd_slen != 0)) {
                        revents |= events & (POLLIN | POLLRDNORM);
-               } else if (d->bd_state == BPF_TIMED_OUT) {
-                       if (d->bd_slen != 0)
-                               revents |= events & (POLLIN | POLLRDNORM);
-                       else
-                               revents |= events & POLLIN;
                } else {
                        selrecord(curlwp, &d->bd_sel);
                        /* Start the read timeout if necessary */
@@ -1416,6 +1412,7 @@ catchpacket(struct bpf_d *d, u_char *pkt
        struct bpf_hdr *hp;
        int totlen, curlen;
        int hdrlen = d->bd_bif->bif_hdrlen;
+       int do_wakeup = 0;
 
        ++d->bd_ccount;
        ++bpf_gstats.bs_capt;
@@ -1449,8 +1446,15 @@ catchpacket(struct bpf_d *d, u_char *pkt
                        return;
                }
                ROTATE_BUFFERS(d);
-               bpf_wakeup(d);
+               do_wakeup = 1;
                curlen = 0;
+       } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) {
+               /*
+                * Immediate mode is set, or the read timeout has
+                * already expired during a select call.  A packet
+                * arrived, so the reader should be woken up.
+                */
+               do_wakeup = 1;
        }
 
        /*
@@ -1470,12 +1474,7 @@ catchpacket(struct bpf_d *d, u_char *pkt
         * Call bpf_wakeup after bd_slen has been updated so that kevent(2)
         * will cause filt_bpfread() to be called with it adjusted.
         */
-       if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT)
-               /*
-                * Immediate mode is set, or the read timeout has
-                * already expired during a select call.  A packet
-                * arrived, so the reader should be woken up.
-                */
+       if (do_wakeup)
                bpf_wakeup(d);
 }
 


Home | Main Index | Thread Index | Old Index