Browse Source

bsd: Optimize socket use

Create global init to handle socket calls and route messages.
Register each interface inside the global driver so that
routing messages can find the interface based on rtm_ifindex.

Signed-off-by: Roy Marples <roy@marples.name>
Roy Marples 9 years ago
parent
commit
449a31662d
1 changed files with 129 additions and 89 deletions
  1. 129 89
      src/drivers/driver_bsd.c

+ 129 - 89
src/drivers/driver_bsd.c

@@ -47,12 +47,20 @@
 
 #include "l2_packet/l2_packet.h"
 
+struct bsd_driver_global {
+	int		sock;			/* socket for 802.11 ioctls */
+	int		route;			/* routing socket for events */
+	char		*event_buf;
+	size_t		event_buf_len;
+	struct dl_list	ifaces;			/* list of interfaces */
+};
+
 struct bsd_driver_data {
+	struct dl_list	list;
+	struct bsd_driver_global *global;
 	struct hostapd_data *hapd;	/* back pointer */
 
-	int	sock;			/* open socket for 802.11 ioctls */
 	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
-	int	route;			/* routing socket for events */
 	char	ifname[IFNAMSIZ+1];	/* interface name */
 	unsigned int ifindex;		/* interface index */
 	void	*ctx;
@@ -62,12 +70,23 @@ struct bsd_driver_data {
 	int	prev_privacy;	/* privacy state to restore on deinit */
 	int	prev_wpa;	/* wpa state to restore on deinit */
 	enum ieee80211_opmode opmode;	/* operation mode */
-	char	*event_buf;
-	size_t	event_buf_len;
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
 
+static struct bsd_driver_data *
+bsd_get_drvindex(void *priv, unsigned int ifindex)
+{
+	struct bsd_driver_global *global = priv;
+	struct bsd_driver_data *drv;
+
+	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+		if (drv->ifindex == ifindex)
+			return drv;
+	}
+	return NULL;
+}
+
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
@@ -81,7 +100,7 @@ bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 	ireq.i_data = (void *) arg;
 	ireq.i_len = arg_len;
 
-	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+	if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
 			   "arg_len=%u]: %s", op, val, arg_len,
 			   strerror(errno));
@@ -102,7 +121,7 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
 	ireq->i_len = arg_len;
 	ireq->i_data = arg;
 
-	if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
+	if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
 			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
 		return -1;
@@ -143,7 +162,7 @@ bsd_get_ssid(void *priv, u8 *ssid, int len)
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_data = (void *)&nwid;
-	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+	if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 ||
 	    nwid.i_len > IEEE80211_NWID_LEN)
 		return -1;
 	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
@@ -166,7 +185,7 @@ bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_data = (void *)&nwid;
-	return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+	return ioctl(drv->global->sock, SIOCS80211NWID, &ifr);
 #else
 	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
 #endif
@@ -181,7 +200,7 @@ bsd_get_if_media(void *priv)
 	os_memset(&ifmr, 0, sizeof(ifmr));
 	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-	if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+	if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) {
 		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
 			   strerror(errno));
 		return -1;
@@ -200,7 +219,7 @@ bsd_set_if_media(void *priv, int media)
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	ifr.ifr_media = media;
 
-	if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
 			   strerror(errno));
 		return -1;
@@ -263,7 +282,7 @@ bsd_ctrl_iface(void *priv, int enable)
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 
-	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
 			   strerror(errno));
 		return -1;
@@ -279,7 +298,7 @@ bsd_ctrl_iface(void *priv, int enable)
 		ifr.ifr_flags &= ~IFF_UP;
 	}
 
-	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+	if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
 			   strerror(errno));
 		return -1;
@@ -576,7 +595,7 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
 	os_memset(&creq, 0, sizeof(creq));
 	os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
 	creq.i_channel = (u_int16_t)channel;
-	return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
+	return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq);
 #else /* SIOCS80211CHANNEL */
 	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
 #endif /* SIOCS80211CHANNEL */
@@ -730,7 +749,8 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 static void
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
-	struct bsd_driver_data *drv = ctx;
+	struct bsd_driver_global *global = sock_ctx;
+	struct bsd_driver_data *drv;
 	struct if_announcemsghdr *ifan;
 	struct rt_msghdr *rtm;
 	struct ieee80211_michael_event *mic;
@@ -739,7 +759,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 	int n;
 	union wpa_event_data data;
 
-	n = read(sock, drv->event_buf, drv->event_buf_len);
+	n = read(sock, global->event_buf, global->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -747,15 +767,18 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) drv->event_buf;
+	rtm = (struct rt_msghdr *) global->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
 		return;
 	}
-	ifan = (struct if_announcemsghdr *) rtm;
+	drv = bsd_get_drvindex(global, rtm->rtm_index);
+	if (drv == NULL)
+		return;
 	switch (rtm->rtm_type) {
 	case RTM_IEEE80211:
+		ifan = (struct if_announcemsghdr *) rtm;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
@@ -811,21 +834,15 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
 		return NULL;
 	}
 
-	drv->event_buf_len = rtbuf_len();
-
-	drv->event_buf = os_malloc(drv->event_buf_len);
-	if (drv->event_buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+	drv->ifindex = if_nametoindex(params->ifname);
+	if (drv->ifindex == 0) {
+		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+			   __func__, params->ifname);
 		goto bad;
 	}
 
 	drv->hapd = hapd;
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
-			   strerror(errno));
-		goto bad;
-	}
+	drv->global = params->global_priv;
 	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
 
 	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
@@ -839,28 +856,18 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
 	if (bsd_ctrl_iface(drv, 0) < 0)
 		goto bad;
 
-	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-	if (drv->route < 0) {
-		wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
-			   strerror(errno));
-		goto bad;
-	}
-	eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
-				 NULL);
-
 	if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
 		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
 			   __func__);
 		goto bad;
 	}
 
+	dl_list_add(&drv->global->ifaces, &drv->list);
+
 	return drv;
 bad:
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock >= 0)
-		close(drv->sock);
-	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 }
@@ -871,16 +878,9 @@ bsd_deinit(void *priv)
 {
 	struct bsd_driver_data *drv = priv;
 
-	if (drv->route >= 0) {
-		eloop_unregister_read_sock(drv->route);
-		close(drv->route);
-	}
 	bsd_ctrl_iface(drv, 0);
-	if (drv->sock >= 0)
-		close(drv->sock);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	os_free(drv->event_buf);
 	os_free(drv);
 }
 
@@ -932,7 +932,7 @@ wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
 	struct ieee80211_bssid bs;
 
 	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
-	if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+	if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0)
 		return -1;
 	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
 	return 0;
@@ -1186,9 +1186,9 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
 static void
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
-	struct bsd_driver_data *drv = sock_ctx;
+	struct bsd_driver_global *global = sock_ctx;
+	struct bsd_driver_data *drv;
 	struct if_announcemsghdr *ifan;
-	struct if_msghdr *ifm;
 	struct rt_msghdr *rtm;
 	union wpa_event_data event;
 	struct ieee80211_michael_event *mic;
@@ -1196,7 +1196,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 	struct ieee80211_join_event *join;
 	int n;
 
-	n = read(sock, drv->event_buf, drv->event_buf_len);
+	n = read(sock, global->event_buf, global->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -1204,18 +1204,20 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) drv->event_buf;
+	rtm = (struct rt_msghdr *) global->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
 		return;
 	}
+	drv = bsd_get_drvindex(global, rtm->rtm_index);
+	if (drv == NULL)
+		return;
+	ctx = drv->ctx;
 	os_memset(&event, 0, sizeof(event));
 	switch (rtm->rtm_type) {
 	case RTM_IFANNOUNCE:
 		ifan = (struct if_announcemsghdr *) rtm;
-		if (ifan->ifan_index != drv->ifindex)
-			break;
 		os_strlcpy(event.interface_status.ifname, drv->ifname,
 			   sizeof(event.interface_status.ifname));
 		switch (ifan->ifan_what) {
@@ -1232,8 +1234,6 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 		break;
 	case RTM_IEEE80211:
 		ifan = (struct if_announcemsghdr *) rtm;
-		if (ifan->ifan_index != drv->ifindex)
-			break;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
@@ -1281,9 +1281,6 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 		}
 		break;
 	case RTM_IFINFO:
-		ifm = (struct if_msghdr *) rtm;
-		if (ifm->ifm_index != drv->ifindex)
-			break;
 		if ((rtm->rtm_flags & RTF_UP) == 0) {
 			os_strlcpy(event.interface_status.ifname, drv->ifname,
 				   sizeof(event.interface_status.ifname));
@@ -1477,7 +1474,7 @@ get80211opmode(struct bsd_driver_data *drv)
 	(void) memset(&ifmr, 0, sizeof(ifmr));
 	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+	if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
 			if (ifmr.ifm_current & IFM_FLAG0)
 				return IEEE80211_M_AHDEMO;
@@ -1497,7 +1494,7 @@ get80211opmode(struct bsd_driver_data *drv)
 }
 
 static void *
-wpa_driver_bsd_init(void *ctx, const char *ifname)
+wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
 {
 #define	GETPARAM(drv, param, v) \
 	(((v) = get80211param(drv, param)) != -1)
@@ -1507,14 +1504,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
 	if (drv == NULL)
 		return NULL;
 
-	drv->event_buf_len = rtbuf_len();
-
-	drv->event_buf = os_malloc(drv->event_buf_len);
-	if (drv->event_buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
-		goto fail1;
-	}
-
 	/*
 	 * NB: We require the interface name be mappable to an index.
 	 *     This implies we do not support having wpa_supplicant
@@ -1525,25 +1514,17 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
 	if (drv->ifindex == 0) {
 		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
 			   __func__, ifname);
-		goto fail1;
+		goto fail;
 	}
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail1;
+
+	drv->ctx = ctx;
+	drv->global = priv;
 
 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
 	/* Down interface during setup. */
 	if (bsd_ctrl_iface(drv, 0) < 0)
 		goto fail;
 
-	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-	if (drv->route < 0)
-		goto fail;
-	eloop_register_read_sock(drv->route,
-		wpa_driver_bsd_event_receive, ctx, drv);
-
-	drv->ctx = ctx;
-
 	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
 		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
 			__func__, strerror(errno));
@@ -1564,12 +1545,10 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
 		goto fail;
 
 	drv->opmode = get80211opmode(drv);
+	dl_list_add(&drv->global->ifaces, &drv->list);
 
 	return drv;
 fail:
-	close(drv->sock);
-fail1:
-	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 #undef GETPARAM
@@ -1581,21 +1560,19 @@ wpa_driver_bsd_deinit(void *priv)
 	struct bsd_driver_data *drv = priv;
 
 	wpa_driver_bsd_set_wpa(drv, 0);
-	eloop_unregister_read_sock(drv->route);
 
 	/* NB: mark interface down */
 	bsd_ctrl_iface(drv, 0);
 
 	wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
+
 	if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
 		wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
 			__func__);
 
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
-	(void) close(drv->route);		/* ioctl socket */
-	(void) close(drv->sock);		/* event socket */
-	os_free(drv->event_buf);
+	dl_list_del(&drv->list);
 	os_free(drv);
 }
 
@@ -1609,10 +1586,73 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
 }
 #endif /* HOSTAPD */
 
+static void *
+bsd_global_init(void)
+{
+	struct bsd_driver_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	dl_list_init(&global->ifaces);
+
+	global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (global->sock < 0) {
+		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
+		goto fail1;
+	}
+
+	global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (global->route < 0) {
+		wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
+			   strerror(errno));
+		goto fail;
+	}
+
+	global->event_buf_len = rtbuf_len();
+	global->event_buf = os_malloc(global->event_buf_len);
+	if (global->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+		goto fail;
+	}
+
+#ifdef HOSTAPD
+	eloop_register_read_sock(global->route, bsd_wireless_event_receive,
+				 NULL, global);
+
+#else /* HOSTAPD */
+	eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
+				 NULL, global);
+#endif /* HOSTAPD */
+
+	return global;
+
+fail:
+	close(global->sock);
+fail1:
+	os_free(global);
+	return NULL;
+}
+
+static void
+bsd_global_deinit(void *priv)
+{
+	struct bsd_driver_global *global = priv;
+
+	eloop_unregister_read_sock(global->route);
+	(void) close(global->route);
+	(void) close(global->sock);
+	os_free(global);
+}
+
 
 const struct wpa_driver_ops wpa_driver_bsd_ops = {
 	.name			= "bsd",
 	.desc			= "BSD 802.11 support",
+	.global_init		= bsd_global_init,
+	.global_deinit		= bsd_global_deinit,
 #ifdef HOSTAPD
 	.hapd_init		= bsd_init,
 	.hapd_deinit		= bsd_deinit,
@@ -1625,7 +1665,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
 	.sta_set_flags		= bsd_set_sta_authorized,
 	.commit			= bsd_commit,
 #else /* HOSTAPD */
-	.init			= wpa_driver_bsd_init,
+	.init2			= wpa_driver_bsd_init,
 	.deinit			= wpa_driver_bsd_deinit,
 	.get_bssid		= wpa_driver_bsd_get_bssid,
 	.get_ssid		= wpa_driver_bsd_get_ssid,