openbsd: reassociation in hostap mode

Andreas Koepsel <[email protected]> Fri, 30 Aug 2002 15:44:27 +0200 (CEST)
Newsgroups gmane.network.wireless.bsd.general
Message-ID <Pine.LNX.4.33.0208301507350.14801-200000@polarstern.bln.acticom.de>
I apologize if this issue was known before ...

I was trying to integrate an access point based on the latest
openbsd-3.1 version in a wireless network. After some tests with a
DLink-DWL650 PCMCIA (firmware 0.8.3, station 1.3.4) card I realized,
that I was unable to roam between a Cisco AP350 and the openbsd system
(Linux-wlan-ng driver and Windows-2K drivers).

I checked the code for association/reassociation in if_wi_hostap.c where
all incoming re-/association messages are processed. According
to IEEE802.11-1999.pdf (7.2.3.4)  an association request must contain the
following fields (in this order):

1. Capability information
2. Listen interval
3. SSID
4. Supported rates

Beyond these fields a reassociation request must contain the CurrentAP
information field (IEEE-802.11-1999.pdf 7.2.3.6) following the Listen
interval information:

1. Capability information
2. Listen interval
3. CurrentAP
4. SSID
5. Supported rates

In if_wi_hostap.c the function 'wihap_assoc_req' handles all incoming
association and reassociation messages. Association requests are handled
properly, the function fails when parsing reassociation requests due to
the additional CurrentAP field, that is assumed in the last position, not
the third one.

In addition the type of the management frame that is sent to the mobile device
as a response must be corrected for reassociation requests,
WI_STYPE_MGMT_ASRESP must be replaced by WI_STYPE_MGMT_REASRESP in case
of a reassociation event.


-----------------------------------------------------------------snip


--- if_wi_hostap.c.orig Fri Aug 30 16:55:39 2002
+++ if_wi_hostap.c      Fri Aug 30 17:22:11 2002
@@ -611,6 +611,8 @@
        struct ieee80211_nwid   ssid;
        u_int16_t               status;
        u_int16_t               asid = 0;
+       struct ether_addr currentAP;
+       int i;

        if (len < 8)
                return;
@@ -618,6 +620,24 @@
        /* Pull out request parameters. */
        capinfo = take_hword(&pkt, &len);
        lstintvl = take_hword(&pkt, &len);
+       if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
+        htole16(WI_STYPE_MGMT_REASREQ)) {
+
+        for (i = 0; i<6; i++) {
+            currentAP.ether_addr_octet[i] = *((u_int8_t*)pkt)++;
+        }
+        len -= 6;
+
+        if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+            printf("wihap_assoc_req: reassociation request current AP field "
+                    "(%0.2x:%0.2x:%0.2x:%0.2x:%0.2x:%0.2x)\n",
+                    currentAP.ether_addr_octet[0],
+                    currentAP.ether_addr_octet[1],
+                    currentAP.ether_addr_octet[2],
+                    currentAP.ether_addr_octet[3],
+                    currentAP.ether_addr_octet[4],
+                    currentAP.ether_addr_octet[5]);
+       }
        if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
            ssid.i_nwid, sizeof(ssid)))<0)
                return;
@@ -711,7 +731,12 @@
        /* Send response. */
        resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
        bzero(resp_hdr, sizeof(struct wi_80211_hdr));
-       resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
+       if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
+        htole16(WI_STYPE_MGMT_REASREQ)) {
+               resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_REASRESP);
+       } else {
+               resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
+       }
        pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr);

        bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);


---------------------------------------------------------------------snip


I tested these changes and all worked fine with the DLink and a Cisco
PCMCIA card (Linux and W2k). Maybe someone with other card models/types
can confirm the correctness of the patch?

Thanks,
  Andreas




------------------------------------------------------
Andreas Koepsel
acticom GmbH R&D
Am Borsigturm 42
13507 Berlin
Germany

    WWW:    www.acticom.de
  EMail:    [email protected]
Telefon:    ++49-30-4303 2510
Telefax:    ++49-30-4303 2519
------------------------------------------------------
openbsd-3.1-patch-if_wi_hostap.c (text/plain, 1.9 KB)
--- if_wi_hostap.c.orig	Fri Aug 30 16:55:39 2002
+++ if_wi_hostap.c	Fri Aug 30 17:22:11 2002
@@ -611,6 +611,8 @@
 	struct ieee80211_nwid	ssid;
 	u_int16_t		status;
 	u_int16_t		asid = 0;
+	struct ether_addr currentAP;
+    	int i;
 
 	if (len < 8)
 		return;
@@ -618,6 +620,24 @@
 	/* Pull out request parameters. */
 	capinfo = take_hword(&pkt, &len);
 	lstintvl = take_hword(&pkt, &len);
+	if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
+        htole16(WI_STYPE_MGMT_REASREQ)) {
+
+        for (i = 0; i<6; i++) {
+            currentAP.ether_addr_octet[i] = *((u_int8_t*)pkt)++;
+        }
+        len -= 6;
+
+        if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+            printf("wihap_assoc_req: reassociation request current AP field "
+                    "(%0.2x:%0.2x:%0.2x:%0.2x:%0.2x:%0.2x)\n",
+                    currentAP.ether_addr_octet[0],
+                    currentAP.ether_addr_octet[1],
+                    currentAP.ether_addr_octet[2],
+                    currentAP.ether_addr_octet[3],
+                    currentAP.ether_addr_octet[4],
+                    currentAP.ether_addr_octet[5]);
+    	}
 	if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
 	    ssid.i_nwid, sizeof(ssid)))<0)
 		return;
@@ -711,7 +731,12 @@
 	/* Send response. */
 	resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
 	bzero(resp_hdr, sizeof(struct wi_80211_hdr));
-	resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
+	if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
+        htole16(WI_STYPE_MGMT_REASREQ)) {
+        	resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_REASRESP);
+    	} else {
+        	resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
+    	}
 	pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr);
 
 	bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);