[PATCH v2 6/6] nl80211: Use global netlink objects.

greearb at candelatech.com greearb
Thu Oct 20 13:21:24 PDT 2011


From: Ben Greear <greearb at candelatech.com>

Netlink sockets can be shared among all driver instances,
saving lots of sockets, spurious log messages, memory,
and CPU usage when using multiple interfaces in a single
process.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
:100644 100644 971db78... 271cca5... M	src/drivers/driver_nl80211.c
 src/drivers/driver_nl80211.c |  509 ++++++++++++++++++++++--------------------
 1 files changed, 263 insertions(+), 246 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 971db78..271cca5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -104,8 +104,10 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 #define IF_OPER_UP 6
 #endif
 
-#define DRVNL nl80211
-#define DRVPREQ nl_handle_preq
+#define DRVNL global->nl80211
+#define DRVPREQ global->nl_handle_preq
+static void nl80211_global_deinit(void *priv);
+static void wpa_driver_nl80211_deinit(void *priv);
 
 /* TODO:  Move this somewhere central and put struct_ids
  * in all structs that are passed around as void* so that
@@ -156,7 +158,6 @@ struct wpa_driver_nl80211_data {
 	u8 addr[ETH_ALEN];
 	char phyname[32];
 	void *ctx;
-	struct netlink_data *netlink;
 	int ioctl_sock; /* socket for ioctl() use */
 	int ifindex;
 	int if_removed;
@@ -170,18 +171,10 @@ struct wpa_driver_nl80211_data {
 
 	int scan_complete_events;
 
-	struct nl_handle *nl_handle;
-	struct nl_handle *nl_handle_event;
-	struct nl_handle *nl_handle_preq;
-	struct nl_cache *nl_cache;
-	struct nl_cache *nl_cache_event;
-	struct nl_cache *nl_cache_preq;
-	struct nl_cb *nl_cb;
-	struct genl_family *nl80211;
-
 	u8 auth_bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	int associated;
+	int probe_req_report; /* registered for this report or not? */
 	u8 ssid[32];
 	size_t ssid_len;
 	enum nl80211_iftype nlmode;
@@ -314,7 +307,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
 }
 
 
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv(struct nl80211_global *global,
 			 struct nl_handle *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
 			 void *valid_data)
@@ -322,7 +315,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
 	struct nl_cb *cb;
 	int err = -ENOMEM;
 
-	cb = nl_cb_clone(drv->nl_cb);
+	cb = nl_cb_clone(global->nl_cb);
 	if (!cb)
 		goto out;
 
@@ -349,12 +342,21 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int send_and_recv_msgs_g(struct nl80211_global *global,
+				struct nl_msg *msg,
+				int (*valid_handler)(struct nl_msg *, void *),
+				void *valid_data)
+{
+	return send_and_recv(global, global->nl_handle, msg, valid_handler,
+			     valid_data);
+}
+
 static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 			      struct nl_msg *msg,
 			      int (*valid_handler)(struct nl_msg *, void *),
 			      void *valid_data)
 {
-	return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
+	return send_and_recv(drv->global, drv->global->nl_handle, msg, valid_handler,
 			     valid_data);
 }
 
@@ -396,7 +398,7 @@ static int family_handler(struct nl_msg *msg, void *arg)
 }
 
 
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
 			       const char *family, const char *group)
 {
 	struct nl_msg *msg;
@@ -406,11 +408,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
-	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl_handle, "nlctrl"),
 		    0, 0, CTRL_CMD_GETFAMILY, 0);
 	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
 
-	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+	ret = send_and_recv_msgs_g(global, msg, family_handler, &res);
 	msg = NULL;
 	if (ret == 0)
 		ret = res.id;
@@ -533,13 +535,15 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
+	struct wpa_driver_nl80211_data *drv;
+
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 
-	if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-	    !have_ifidx(drv, ifi->ifi_index)) {
+	if (!drv) {
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
 			   "ifindex %d", ifi->ifi_index);
 		return;
@@ -581,7 +585,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 	if (drv->operstate == 1 &&
 	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
 	    !(ifi->ifi_flags & IFF_RUNNING))
-		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 				       -1, IF_OPER_UP);
 
 	attrlen = len;
@@ -615,10 +619,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
+	struct wpa_driver_nl80211_data *drv;
+
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+
+	if (!drv) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for"
+			   " foreign ifindex %d", ifi->ifi_index);
+		return;
+	}
 
 	attrlen = len;
 	attr = (struct rtattr *) buf;
@@ -1550,25 +1563,11 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int process_event(struct nl_msg *msg, void *arg)
+static void do_process_event(struct nl_msg *msg,
+			     struct wpa_driver_nl80211_data *drv,
+			     struct genlmsghdr *gnlh,
+			     struct nlattr *tb[])
 {
-	struct wpa_driver_nl80211_data *drv = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb[NL80211_ATTR_IFINDEX]) {
-		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-				   " for foreign interface (ifindex %d)",
-				   gnlh->cmd, ifindex);
-			return NL_SKIP;
-		}
-	}
-
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
 	    (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
 	     gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -1677,7 +1676,29 @@ static int process_event(struct nl_msg *msg, void *arg)
 			   "(cmd=%d)", gnlh->cmd);
 		break;
 	}
+}
+
+static int process_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_global *global = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct wpa_driver_nl80211_data *drv = NULL;
+	int ifindex = -1;
 
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX]) {
+		ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+	}
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if ((ifindex == -1) ||
+		    (ifindex == drv->ifindex || have_ifidx(drv, ifindex))) {
+			do_process_event(msg, drv, gnlh, tb);
+		}
+	}
 	return NL_SKIP;
 }
 
@@ -1686,15 +1707,15 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 					     void *handle)
 {
 	struct nl_cb *cb;
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct nl80211_global *global = eloop_ctx;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+	wpa_msg(NULL, MSG_DEBUG, "nl80211: Event message available");
 
-	cb = nl_cb_clone(drv->nl_cb);
+	cb = nl_cb_clone(global->nl_cb);
 	if (!cb)
 		return;
 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, global);
 	nl_recvmsgs(handle, cb);
 	nl_cb_put(cb);
 }
@@ -1985,130 +2006,6 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 }
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
-{
-	int ret;
-
-	/* Initialize generic netlink and nl80211 */
-
-	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (drv->nl_cb == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks");
-		goto err1;
-	}
-
-	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 = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks (event)");
-		goto err2b;
-	}
-
-	if (genl_connect(drv->nl_handle)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink");
-		goto err3;
-	}
-
-	if (genl_connect(drv->nl_handle_event)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink (event)");
-		goto err3;
-	}
-
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
-	    0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
-	if (drv->nl_cache == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
-	if (drv->nl_cache_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	drv->DRVNL = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
-	if (drv->DRVNL == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
-			   "found");
-		goto err4;
-	}
-
-	ret = nl_get_multicast_id(drv, "nl80211", "scan");
-	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
-			   "membership for scan events: %d (%s)",
-			   ret, strerror(-ret));
-		goto err4;
-	}
-
-	ret = nl_get_multicast_id(drv, "nl80211", "mlme");
-	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
-			   "membership for mlme events: %d (%s)",
-			   ret, strerror(-ret));
-		goto err4;
-	}
-
-	ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
-	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
-			   "membership for regulatory events: %d (%s)",
-			   ret, strerror(-ret));
-		/* Continue without regulatory events */
-	}
-
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
-				 wpa_driver_nl80211_event_receive, drv,
-				 drv->nl_handle_event);
-
-	return 0;
-
-err4:
-	nl_cache_free(drv->nl_cache_event);
-err3b:
-	nl_cache_free(drv->nl_cache);
-err3:
-	nl80211_handle_destroy(drv->nl_handle_event);
-err2b:
-	nl80211_handle_destroy(drv->nl_handle);
-err2:
-	nl_cb_put(drv->nl_cb);
-err1:
-	return -1;
-}
-
-
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -2187,7 +2084,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 				      void *global_priv)
 {
 	struct wpa_driver_nl80211_data *drv;
-	struct netlink_config *cfg;
 	struct rfkill_config *rcfg;
 	struct i802_bss *bss;
 
@@ -2206,11 +2102,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 	drv->ioctl_sock = -1;
 	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
-	if (wpa_driver_nl80211_init_nl(drv)) {
-		os_free(drv);
-		return NULL;
-	}
-
 	nl80211_get_phy_name(drv);
 
 	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
@@ -2219,18 +2110,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 		goto failed;
 	}
 
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		goto failed;
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		goto failed;
-	}
-
 	rcfg = os_zalloc(sizeof(*rcfg));
 	if (rcfg == NULL)
 		goto failed;
@@ -2258,18 +2137,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 	return bss;
 
 failed:
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->DRVNL);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
@@ -2292,7 +2160,7 @@ static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
 	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
 	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
-	ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
+	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2313,7 +2181,7 @@ static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
 					 const u8 *match, size_t match_len)
 {
 	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
-	return nl80211_register_frame(drv, drv->nl_handle_event,
+	return nl80211_register_frame(drv, drv->global->nl_handle_event,
 				      type, match, match_len);
 }
 
@@ -2409,7 +2277,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 		}
 	}
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 			       1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
@@ -2473,8 +2341,9 @@ static void wpa_driver_nl80211_deinit(void *priv)
 		l2_packet_deinit(drv->l2);
 #endif /* CONFIG_AP */
 
-	if (drv->DRVPREQ)
+	if (drv->probe_req_report)
 		wpa_driver_nl80211_probe_req_report(bss, 0);
+
 	if (bss->added_if_into_bridge) {
 		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
 		    < 0)
@@ -2515,9 +2384,9 @@ static void wpa_driver_nl80211_deinit(void *priv)
 	if (drv->disable_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-	netlink_deinit(drv->netlink);
-	rfkill_deinit(drv->rfkill);
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, IF_OPER_UP);
+	if (drv->rfkill)
+		rfkill_deinit(drv->rfkill);
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
@@ -2527,14 +2396,6 @@ static void wpa_driver_nl80211_deinit(void *priv)
 	if (drv->ioctl_sock >= 0)
 		close(drv->ioctl_sock);
 
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-	genl_family_put(drv->DRVNL);
-	nl_cache_free(drv->nl_cache);
-	nl_cache_free(drv->nl_cache_event);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl80211_handle_destroy(drv->nl_handle_event);
-	nl_cb_put(drv->nl_cb);
-
 	os_free(drv->filter_ssids);
 
 	if (drv->global)
@@ -5828,7 +5689,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
 	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
 		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
 	drv->operstate = state;
-	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
 				      state ? IF_OPER_UP : IF_OPER_DORMANT);
 }
 
@@ -6456,7 +6317,9 @@ static void *i802_init(struct hostapd_data *hapd,
 	int ifindex, br_ifindex;
 	int br_added = 0;
 
-	bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL);
+	struct nl80211_global *global = nl80211_global_init();
+
+	bss = wpa_driver_nl80211_init(hapd, params->ifname, global);
 	if (bss == NULL)
 		return NULL;
 
@@ -6529,19 +6392,7 @@ static void *i802_init(struct hostapd_data *hapd,
 	return bss;
 
 failed:
-	nl80211_remove_monitor_interface(drv);
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->DRVNL);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
@@ -6969,6 +6820,17 @@ nla_put_failure:
 	return -1;
 }
 
+static void nl80211_global_deinit_handle_preq(struct nl80211_global *global) {
+	if (global->nl_handle_preq)
+		eloop_unregister_read_sock(
+			nl_socket_get_fd(global->nl_handle_preq));
+	if (global->nl_cache_preq)
+		nl_cache_free(global->nl_cache_preq);
+	if (global->nl_handle_preq)
+		nl80211_handle_destroy(global->nl_handle_preq);
+	global->nl_handle_preq = NULL;
+	global->nl_cache_preq = NULL;
+}
 
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 {
@@ -6976,24 +6838,26 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
 	if (!report) {
-		if (drv->DRVPREQ) {
-			eloop_unregister_read_sock(
-				nl_socket_get_fd(drv->DRVPREQ));
-			nl_cache_free(drv->nl_cache_preq);
-			nl80211_handle_destroy(drv->DRVPREQ);
-			drv->DRVPREQ = NULL;
+		if (!drv->probe_req_report)
+			return 0;
+		if (--drv->global->nl_handle_preq_refcnt <= 0) {
+			if (drv->global->nl_handle_preq_refcnt < 0) {
+				wpa_msg(NULL, MSG_ERROR,
+					"ERROR:  preq_refcnt is negative: %i in driver_nl80211.c.\n",
+					drv->global->nl_handle_preq_refcnt);
+				drv->global->nl_handle_preq_refcnt = 0;
+			}
+			nl80211_global_deinit_handle_preq(drv->global);
 		}
+		drv->probe_req_report = 0;
 		return 0;
 	}
 
-	if (drv->DRVPREQ) {
-		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
-			   "already on!");
+	if (drv->probe_req_report)
 		return 0;
-	}
 
-	{ /* get ready for global pre-req */
-		drv->DRVPREQ = nl80211_handle_alloc(drv->nl_cb);
+	if (! drv->DRVPREQ) {
+		drv->DRVPREQ = nl80211_handle_alloc(drv->global->nl_cb);
 		if (drv->DRVPREQ == NULL) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate "
 				   "netlink callbacks (preq)");
@@ -7009,14 +6873,14 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 
 #ifdef CONFIG_LIBNL20
 		if (genl_ctrl_alloc_cache(drv->DRVPREQ,
-					  &drv->nl_cache_preq) < 0) {
+					  &drv->global->nl_cache_preq) < 0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
 				   "netlink cache (preq)");
 			goto out_err2;
 		}
 #else /* CONFIG_LIBNL20 */
-		drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->DRVPREQ);
-		if (drv->nl_cache_preq == NULL) {
+		drv->global->nl_cache_preq = genl_ctrl_alloc_cache(drv->DRVPREQ);
+		if (drv->global->nl_cache_preq == NULL) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
 				   "netlink cache (preq)");
 			goto out_err2;
@@ -7031,14 +6895,17 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 		}
 
 		eloop_register_read_sock(nl_socket_get_fd(drv->DRVPREQ),
-					 wpa_driver_nl80211_event_receive, drv,
+					 wpa_driver_nl80211_event_receive, drv->global,
 					 drv->DRVPREQ);
 	}
 
+	drv->global->nl_handle_preq_refcnt++;
+	drv->probe_req_report = 1;
 	return 0;
 
  out_err3:
-	nl_cache_free(drv->nl_cache_preq);
+	nl_cache_free(drv->global->nl_cache_preq);
+	drv->global->nl_cache_preq = NULL;
  out_err2:
 	nl80211_handle_destroy(drv->DRVPREQ);
 	drv->DRVPREQ = NULL;
@@ -7263,13 +7130,141 @@ static int nl80211_set_param(void *priv, const char *param)
 static void * nl80211_global_init(void)
 {
 	struct nl80211_global *global;
+	struct netlink_config *cfg;
+	int ret;
+
+	/* already initailized? */
+	if (global_ptr)
+		return global_ptr;
+
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
 		return NULL;
 	global->struct_id = HAP_DRV_NL80211_GLOBAL;
 	dl_list_init(&global->interfaces);
 	global->if_add_ifindex = -1;
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		goto err;
+
+	cfg->ctx = global;
+	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+	global->netlink = netlink_init(cfg);
+	if (global->netlink == NULL) {
+		os_free(cfg);
+		goto err;
+	}
+
+	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (global->nl_cb == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate netlink "
+			"callbacks");
+		goto err;
+	}
+
+	global->nl_handle = nl80211_handle_alloc(global->nl_cb);
+	if (global->nl_handle == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate netlink "
+			"callbacks (nl_handle)");
+		goto err;
+	}
+
+	global->nl_handle_event = nl80211_handle_alloc(global->nl_cb);
+	if (global->nl_handle_event == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate netlink "
+			"callbacks (event)");
+		goto err;
+	}
+
+	if (genl_connect(global->nl_handle)) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to connect to generic "
+			"netlink");
+		goto err;
+	}
+
+	if (genl_connect(global->nl_handle_event)) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to connect to generic "
+			"netlink (event)");
+		goto err;
+	}
+
+#ifdef CONFIG_LIBNL20
+	if (genl_ctrl_alloc_cache(global->nl_handle, &global->nl_cache) < 0) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate generic "
+			"netlink cache");
+		goto err;
+	}
+	if (genl_ctrl_alloc_cache(global->nl_handle_event, &global->nl_cache_event) <
+	    0) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate generic "
+			"netlink cache (event)");
+		goto err;
+	}
+#else /* CONFIG_LIBNL20 */
+	global->nl_cache = genl_ctrl_alloc_cache(global->nl_handle);
+	if (global->nl_cache == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate generic "
+			"netlink cache");
+		goto err;
+	}
+	global->nl_cache_event = genl_ctrl_alloc_cache(global->nl_handle_event);
+	if (global->nl_cache_event == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Failed to allocate generic "
+			"netlink cache (event)");
+		goto err;
+	}
+#endif /* CONFIG_LIBNL20 */
+
+	global->nl80211 = genl_ctrl_search_by_name(global->nl_cache, "nl80211");
+	if (global->nl80211 == NULL) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+			"found");
+		goto err;
+	}
+
+	ret = nl_get_multicast_id(global, "nl80211", "scan");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_handle_event, ret);
+	if (ret < 0) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Could not add multicast "
+			"membership for scan events: %d (%s)",
+			ret, strerror(-ret));
+		goto err;
+	}
+
+	ret = nl_get_multicast_id(global, "nl80211", "mlme");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_handle_event, ret);
+	if (ret < 0) {
+		wpa_msg(NULL, MSG_ERROR, "nl80211: Could not add multicast "
+			"membership for mlme events: %d (%s)",
+			ret, strerror(-ret));
+		goto err;
+	}
+
+	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_handle_event, ret);
+	if (ret < 0) {
+		wpa_msg(NULL, MSG_DEBUG, "nl80211: Could not add multicast "
+			"membership for regulatory events: %d (%s)",
+			ret, strerror(-ret));
+		/* Continue without regulatory events */
+	}
+
+	eloop_register_read_sock(nl_socket_get_fd(global->nl_handle_event),
+				 wpa_driver_nl80211_event_receive, global,
+				 global->nl_handle_event);
+
+	global_ptr = global;
+
 	return global;
+
+err:
+	nl80211_global_deinit(global);
+	return NULL;
 }
 
 
@@ -7283,6 +7278,28 @@ static void nl80211_global_deinit(void *priv)
 			   "nl80211_global_deinit",
 			   dl_list_len(&global->interfaces));
 	}
+
+	nl80211_global_deinit_handle_preq(global);
+
+	if (global->netlink)
+		netlink_deinit(global->netlink);
+
+	if (global->nl_cache_event)
+		nl_cache_free(global->nl_cache_event);
+	if (global->nl_cache)
+		nl_cache_free(global->nl_cache);
+	if (global->nl_handle_event)
+		nl80211_handle_destroy(global->nl_handle_event);
+	if (global->nl_handle)
+		nl80211_handle_destroy(global->nl_handle);
+	if (global->nl_cb)
+		nl_cb_put(global->nl_cb);
+	if (global->nl80211)
+		genl_family_put(global->nl80211);
+
+	if (global == global_ptr)
+		global_ptr = NULL;
+
 	os_free(global);
 }
 
-- 
1.7.3.4




More information about the Hostap mailing list