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>
This commit is contained in:
Roy Marples 2016-01-09 01:39:43 +00:00 committed by Jouni Malinen
parent 4653ceb750
commit 449a31662d

View file

@ -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,