[wpa-supplicant] Wireless-extension v19

Jouni Malinen jkmaline
Mon Sep 19 22:57:39 PDT 2005


On Mon, Sep 19, 2005 at 10:07:52AM -0700, Jean Tourrilhes wrote:

> 	Ok, that's a bug and that's fixable. I mananaged to do it in
> WT, so there must be a way. Let me think 2 sec about it.

Of course it can be fixed, it just means that all user space programs
using scan results or wireless extensions need to have support for
multiple formats..

> > I did not realize that WE-19 is changing kernel-user space interface in
> > a backwards incompatible way. If I had, I would have objected to it.
> 
> 	Let's not overreact. API changes happen all the time.

API changes in kernel are perfectly fine to me, but this sounds like a
kernel-userspace ABI change which is not okay without a good reason.
Fixing something that is broken on systems with 64-bit kernel and 32-bit
user space is a good reason, though.

> > Jean, have I misunderstood something or is this really changing the
> > event messages in a way that all user space programs need to be
> > recompiled or actually even worse, if they use IW_EV_POINT_LEN, modified
> > to support both old and new format and then recompiled? If that is the
> > case, was this change really needed?
> 
> 	Yes, I believe so. Having a pointer in there doesn't make the
> event format 32/64 bit clean, if you use a 32 bit userspace with a 64
> bit kernel you will end with potential trouble.

Is anything using that pointer in scan result or wireless event parsing?
Or is the 32/64 issue in just having an extra variable that has a
different length in kernel and user space? I haven't looked into details
of how this is done, so this is somewhat unclear to me.


On Mon, Sep 19, 2005 at 11:52:39AM -0700, Jean Tourrilhes wrote:

>       Attached is a revised patch. I took a slightly different
> approach this time, just to make things more interesting. This patch
> is not tested, not even compiled, but will give you some rough
> idea. It should work for both WE-19 and WE-18, and should compile with
> either WE-18 or WE-19.

Thanks! Being able to compile driver_wext.c with WE-18 is not needed, so
I removed that part. And I noticed that this was not compiled.. That
statement about should compile with either version is somewhat
optimistic ;-).

I ended up modifiying this a bit by not using memmove() separately on
the temporary buffer, but just changing the initial copying of the data
to copy stuff from the correct location. Anyway, the end result is
pretty much identical. This patch is attached.

I was about to commit this to CVS, but remembered that hostapd has the
exact same issue, so wireless_copy.h is not going to change before both
programs can be fixed at the same time. This is the part I don't like
about ABI changes.. ;-)

>       By the way, SIOCGIWRANGE also change and may break your code,
> I added code that should workaround those API changes.

Thanks!

-- 
Jouni Malinen                                            PGP id EFC895FA
-------------- next part --------------
Index: driver_wext.c
===================================================================
RCS file: /home/jm/cvsroot/hostap/wpa_supplicant/driver_wext.c,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 driver_wext.c
--- driver_wext.c	17 Sep 2005 05:36:33 -0000	1.41
+++ driver_wext.c	20 Sep 2005 05:34:54 -0000
@@ -42,6 +42,7 @@ struct wpa_driver_wext_data {
 	size_t assoc_resp_ies_len;
 	struct wpa_driver_capa capa;
 	int has_capability;
+	int we_version_compiled;
 };
 
 
@@ -380,11 +381,29 @@ static void wpa_driver_wext_event_wirele
 	while (pos + IW_EV_LCP_LEN <= end) {
 		/* Event data may be unaligned, so make a local, aligned copy
 		 * before processing. */
-		memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+		memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
 		wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
 			   iwe->cmd, iwe->len);
 		if (iwe->len <= IW_EV_LCP_LEN)
 			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version_compiled > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVCUSTOM ||
+		     iwe->cmd == IWEVASSOCREQIE ||
+		     iwe->cmd == IWEVASSOCRESPIE ||
+		     iwe->cmd == IWEVPMKIDCAND)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			memcpy(dpos, pos + IW_EV_LCP_LEN,
+			       sizeof(struct iw_event) - dlen);
+		} else {
+			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
 		switch (iwe->cmd) {
 		case SIOCGIWAP:
 			wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
@@ -410,11 +429,9 @@ static void wpa_driver_wext_event_wirele
 			break;
 		case IWEVMICHAELMICFAILURE:
 			wpa_driver_wext_event_wireless_michaelmicfailure(
-				drv, ctx, pos + IW_EV_POINT_LEN,
-				iwe->u.data.length);
+				drv, ctx, custom, iwe->u.data.length);
 			break;
 		case IWEVCUSTOM:
-			custom = pos + IW_EV_POINT_LEN;
 			if (custom + iwe->u.data.length > end)
 				return;
 			buf = malloc(iwe->u.data.length + 1);
@@ -432,18 +449,15 @@ static void wpa_driver_wext_event_wirele
 			break;
 		case IWEVASSOCREQIE:
 			wpa_driver_wext_event_wireless_assocreqie(
-				drv, ctx, pos + IW_EV_POINT_LEN,
-				iwe->u.data.length);
+				drv, ctx, custom, iwe->u.data.length);
 			break;
 		case IWEVASSOCRESPIE:
 			wpa_driver_wext_event_wireless_assocrespie(
-				drv, ctx, pos + IW_EV_POINT_LEN,
-				iwe->u.data.length);
+				drv, ctx, custom, iwe->u.data.length);
 			break;
 		case IWEVPMKIDCAND:
 			wpa_driver_wext_event_wireless_pmkidcand(
-				drv, ctx, pos + IW_EV_POINT_LEN,
-				iwe->u.data.length);
+				drv, ctx, custom, iwe->u.data.length);
 			break;
 		}
 
@@ -851,9 +865,26 @@ int wpa_driver_wext_get_scan_results(voi
 		int ssid_len;
 		/* Event data may be unaligned, so make a local, aligned copy
 		 * before processing. */
-		memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+		memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
 		if (iwe->len <= IW_EV_LCP_LEN)
 			break;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version_compiled > 18 &&
+		    (iwe->cmd == SIOCGIWESSID ||
+		     iwe->cmd == SIOCGIWENCODE ||
+		     iwe->cmd == IWEVGENIE ||
+		     iwe->cmd == IWEVCUSTOM)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			memcpy(dpos, pos + IW_EV_LCP_LEN,
+			       sizeof(struct iw_event) - dlen);
+		} else {
+			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
 		switch (iwe->cmd) {
 		case SIOCGIWAP:
 			if (!first)
@@ -875,7 +906,6 @@ int wpa_driver_wext_get_scan_results(voi
 			break;
 		case SIOCGIWESSID:
 			ssid_len = iwe->u.essid.length;
-			custom = pos + IW_EV_POINT_LEN;
 			if (custom + ssid_len > end)
 				break;
 			if (iwe->u.essid.flags &&
@@ -938,7 +968,7 @@ int wpa_driver_wext_get_scan_results(voi
 		case IWEVGENIE:
 			if (ap_num >= max_size)
 				break;
-			gpos = genie = pos + IW_EV_POINT_LEN;
+			gpos = genie = custom;
 			gend = genie + iwe->u.data.length;
 			if (gend > end) {
 				wpa_printf(MSG_INFO, "IWEVGENIE overflow");
@@ -971,7 +1001,6 @@ int wpa_driver_wext_get_scan_results(voi
 			}
 			break;
 		case IWEVCUSTOM:
-			custom = pos + IW_EV_POINT_LEN;
 			clen = iwe->u.data.length;
 			if (custom + clen > end)
 				break;
@@ -1039,42 +1068,49 @@ int wpa_driver_wext_get_scan_results(voi
 static int wpa_driver_wext_get_range(void *priv)
 {
 	struct wpa_driver_wext_data *drv = priv;
-	struct iw_range range;
+	char buffer[sizeof(struct iw_range) + 500];
+	struct iw_range *range = (struct iw_range *) buffer;
 	struct iwreq iwr;
 	int minlen;
 
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
 	memset(&iwr, 0, sizeof(iwr));
 	strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) ⦥
-	iwr.u.data.length = sizeof(range);
-	memset(&range, 0, sizeof(range));
+	iwr.u.data.pointer = (caddr_t) buffer;
+	iwr.u.data.length = sizeof(buffer);
+	memset(buffer, 0, sizeof(buffer));
 
-	minlen = ((char *) &range.enc_capa) - (char *) &range +
-		sizeof(range.enc_capa);
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
 		perror("ioctl[SIOCGIWRANGE]");
 		return -1;
 	} else if (iwr.u.data.length >= minlen &&
-		   range.we_version_compiled >= 18) {
+		   range->we_version_compiled >= 18) {
 		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
 			   "WE(source)=%d enc_capa=0x%x",
-			   range.we_version_compiled, range.we_version_source,
-			   range.enc_capa);
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
 		drv->has_capability = 1;
-		if (range.enc_capa & IW_ENC_CAPA_WPA) {
+		drv->we_version_compiled = range->we_version_compiled;
+		if (range->enc_capa & IW_ENC_CAPA_WPA) {
 			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 				WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
 		}
-		if (range.enc_capa & IW_ENC_CAPA_WPA2) {
+		if (range->enc_capa & IW_ENC_CAPA_WPA2) {
 			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
 				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
 		}
 		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
 			WPA_DRIVER_CAPA_ENC_WEP104;
-		if (range.enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
 			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-		if (range.enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
 			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
 		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x",
 			   drv->capa.key_mgmt, drv->capa.enc);



More information about the Hostap mailing list