[PATCH 4/6] driver_nl80211: work around libnl bug

Johannes Berg johannes
Thu Sep 16 06:03:14 PDT 2010


From: Johannes Berg <johannes.berg at intel.com>

libnl has a bug, when binding more than
two sockets and releasing one, it will
release the wrong address and then try
to reuse it, which fails. Therefore, we
need to reimplement the socket address
assignment logic locally for libnl 1.1.

Signed-off-by: Johannes Berg <johannes.berg at intel.com>
---
 src/drivers/driver_nl80211.c |   60 +++++++++++++++++++++++++++++++++++-------
 1 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index aa769e6..d9d5f8f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -39,8 +39,48 @@
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
 #define nl_handle nl_sock
-#define nl_handle_alloc_cb nl_socket_alloc_cb
-#define nl_handle_destroy nl_socket_free
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#else
+/*
+ * libnl 1.1 has a bug, it tries to allocate socket numbers densely
+ * but when you free a socket again it will mess up its bitmap and
+ * and use the wrong number the next time it needs a socket ID.
+ * Therefore, we wrap the handle alloc/destroy and add our own pid
+ * accounting.
+ */
+static uint32_t port_bitmap[32] = { 0 };
+
+static struct nl_handle *nl80211_handle_alloc(void *cb)
+{
+	struct nl_handle *handle;
+	uint32_t pid = getpid() & 0x3FFFFF;
+	int i;
+
+	handle = nl_handle_alloc_cb(cb);
+
+	for (i = 0; i < 1024; i++) {
+		if (port_bitmap[i/32] & (1 << (i % 32)))
+			continue;
+		port_bitmap[i/32] |= 1 << (i % 32);
+		pid += i << 22;
+		break;
+	}
+
+	nl_socket_set_local_port(handle, pid);
+
+	return handle;
+}
+
+static void nl80211_handle_destroy(struct nl_handle *handle)
+{
+	uint32_t port = nl_socket_get_local_port(handle);
+
+	port >>= 22;
+	port_bitmap[port/32] &= ~(1 << (port % 32));
+
+	nl_handle_destroy(handle);
+}
 #endif /* CONFIG_LIBNL20 */
 
 
@@ -1343,14 +1383,14 @@ static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
 		goto err1;
 	}
 
-	drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+	drv->nl_handle = nl80211_handle_alloc(drv->nl_cb);
 	if (drv->nl_handle == NULL) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
 			   "callbacks");
 		goto err2;
 	}
 
-	drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb);
+	drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb);
 	if (drv->nl_handle_event == NULL) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
 			   "callbacks (event)");
@@ -1433,9 +1473,9 @@ err4:
 err3b:
 	nl_cache_free(drv->nl_cache);
 err3:
-	nl_handle_destroy(drv->nl_handle_event);
+	nl80211_handle_destroy(drv->nl_handle_event);
 err2b:
-	nl_handle_destroy(drv->nl_handle);
+	nl80211_handle_destroy(drv->nl_handle);
 err2:
 	nl_cb_put(drv->nl_cb);
 err1:
@@ -1540,7 +1580,7 @@ failed:
 
 	genl_family_put(drv->nl80211);
 	nl_cache_free(drv->nl_cache);
-	nl_handle_destroy(drv->nl_handle);
+	nl80211_handle_destroy(drv->nl_handle);
 	nl_cb_put(drv->nl_cb);
 	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
 
@@ -1773,8 +1813,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
 	genl_family_put(drv->nl80211);
 	nl_cache_free(drv->nl_cache);
 	nl_cache_free(drv->nl_cache_event);
-	nl_handle_destroy(drv->nl_handle);
-	nl_handle_destroy(drv->nl_handle_event);
+	nl80211_handle_destroy(drv->nl_handle);
+	nl80211_handle_destroy(drv->nl_handle_event);
 	nl_cb_put(drv->nl_cb);
 
 	eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
@@ -5013,7 +5053,7 @@ failed:
 
 	genl_family_put(drv->nl80211);
 	nl_cache_free(drv->nl_cache);
-	nl_handle_destroy(drv->nl_handle);
+	nl80211_handle_destroy(drv->nl_handle);
 	nl_cb_put(drv->nl_cb);
 
 	os_free(drv);
-- 
1.7.1




More information about the Hostap mailing list