diff options
Diffstat (limited to 'contrib/wpa/src/drivers/driver_bsd.c')
-rw-r--r-- | contrib/wpa/src/drivers/driver_bsd.c | 659 |
1 files changed, 316 insertions, 343 deletions
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c index 96cf066a7a46..16502b945212 100644 --- a/contrib/wpa/src/drivers/driver_bsd.c +++ b/contrib/wpa/src/drivers/driver_bsd.c @@ -9,7 +9,6 @@ #include "includes.h" #include <sys/ioctl.h> -#include <sys/sysctl.h> #include "common.h" #include "driver.h" @@ -17,7 +16,9 @@ #include "common/ieee802_11_defs.h" #include "common/wpa_common.h" +#include <ifaddrs.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/if_media.h> #ifdef __NetBSD__ @@ -51,22 +52,19 @@ struct bsd_driver_global { void *ctx; 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 */ + void *ctx; struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ char ifname[IFNAMSIZ+1]; /* interface name */ int flags; unsigned int ifindex; /* interface index */ int if_removed; /* has the interface been removed? */ - void *ctx; struct wpa_driver_capa capa; /* driver capability */ int is_ap; /* Access point mode */ int prev_roaming; /* roaming state to restore on deinit */ @@ -76,6 +74,7 @@ struct bsd_driver_data { }; /* Generic functions for hostapd and wpa_supplicant */ + static struct bsd_driver_data * bsd_get_drvindex(void *priv, unsigned int ifindex) { @@ -89,7 +88,6 @@ bsd_get_drvindex(void *priv, unsigned int ifindex) return NULL; } -#ifndef HOSTAPD static struct bsd_driver_data * bsd_get_drvname(void *priv, const char *ifname) { @@ -102,7 +100,6 @@ bsd_get_drvname(void *priv, const char *ifname) } return NULL; } -#endif /* HOSTAPD */ static int bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) @@ -142,7 +139,9 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, ireq->i_data = arg; if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, " + int level = drv->if_removed ? MSG_DEBUG : MSG_ERROR; + + wpa_printf(level, "ioctl[SIOCG80211, op=%u, " "arg_len=%u]: %s", op, arg_len, strerror(errno)); return -1; } @@ -294,9 +293,8 @@ bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) } static int -bsd_ctrl_iface(void *priv, int enable) +bsd_get_iface_flags(struct bsd_driver_data *drv) { - struct bsd_driver_data *drv = priv; struct ifreq ifr; os_memset(&ifr, 0, sizeof(ifr)); @@ -308,36 +306,24 @@ bsd_ctrl_iface(void *priv, int enable) return -1; } drv->flags = ifr.ifr_flags; - - if (enable) { - if (ifr.ifr_flags & IFF_UP) - return 0; - ifr.ifr_flags |= IFF_UP; - } else { - if (!(ifr.ifr_flags & IFF_UP)) - return 0; - ifr.ifr_flags &= ~IFF_UP; - } - - if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", - strerror(errno)); - return -1; - } - - drv->flags = ifr.ifr_flags; return 0; } static int -bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) +bsd_set_key(void *priv, struct wpa_driver_set_key_params *params) { struct ieee80211req_key wk; #ifdef IEEE80211_KEY_NOREPLAY struct bsd_driver_data *drv = priv; #endif /* IEEE80211_KEY_NOREPLAY */ + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *seq = params->seq; + size_t seq_len = params->seq_len; + const u8 *key = params->key; + size_t key_len = params->key_len; wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, @@ -539,7 +525,7 @@ bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) __func__); return -1; } - return bsd_ctrl_iface(priv, 1); + return 0; } static void @@ -594,17 +580,13 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq) if (channel < 14) { mode = -#ifdef CONFIG_IEEE80211N freq->ht_enabled ? IFM_IEEE80211_11NG : -#endif /* CONFIG_IEEE80211N */ - IFM_IEEE80211_11G; + IFM_IEEE80211_11G; } else if (channel == 14) { mode = IFM_IEEE80211_11B; } else { mode = -#ifdef CONFIG_IEEE80211N freq->ht_enabled ? IFM_IEEE80211_11NA : -#endif /* CONFIG_IEEE80211N */ IFM_IEEE80211_11A; } if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { @@ -635,20 +617,262 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) return 0; } -static size_t -rtbuf_len(void) +#ifdef SO_RERROR +static void +bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global) { - size_t len; + char event_buf[2048]; /* max size of a single route(4) msg */ + int n; + struct ifaddrs *ifaddrs, *ifa; + struct bsd_driver_data *drv; + struct sockaddr_dl *sdl; + union wpa_event_data event; - int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; + /* We need to match the system state, so drain the route + * socket to avoid stale messages. */ + do { + n = read(sock, event_buf, sizeof(event_buf)); + } while (n != -1 || errno == ENOBUFS); - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - wpa_printf(MSG_WARNING, "%s failed: %s", __func__, - strerror(errno)); - len = 2048; + if (getifaddrs(&ifaddrs) == -1) { + wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s", + __func__, strerror(errno)); + return; + } + + /* add or update existing interfaces */ + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_LINK) + continue; + sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr; + drv = bsd_get_drvname(global, ifa->ifa_name); + if (drv != NULL && + (drv->ifindex != sdl->sdl_index || drv->if_removed)) { + wpa_printf(MSG_DEBUG, + "RTM_IFANNOUNCE: Interface '%s' added", + drv->ifname); + drv->ifindex = sdl->sdl_index; + drv->if_removed = 0; + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + os_strlcpy(event.interface_status.ifname, ifa->ifa_name, + sizeof(event.interface_status.ifname)); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + } + if (!drv && + (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) { + /* Driver name is invalid */ + wpa_printf(MSG_DEBUG, + "RTM_IFANNOUNCE: Interface '%s' removed", + drv->ifname); + drv->if_removed = 1; + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + os_strlcpy(event.interface_status.ifname, drv->ifname, + sizeof(event.interface_status.ifname)); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + } + } + + /* punt missing interfaces and update flags */ + dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) { + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_LINK) + continue; + sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr; + if (os_strcmp(drv->ifname, ifa->ifa_name) == 0) + break; + } + if (ifa == NULL && !drv->if_removed) { + wpa_printf(MSG_DEBUG, + "RTM_IFANNOUNCE: Interface '%s' removed", + drv->ifname); + drv->if_removed = 1; + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + os_strlcpy(event.interface_status.ifname, drv->ifname, + sizeof(event.interface_status.ifname)); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + } + if (!ifa) + continue; + + if ((ifa->ifa_flags & IFF_UP) == 0 && + (drv->flags & IFF_UP) != 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, + NULL); + } else if ((ifa->ifa_flags & IFF_UP) != 0 && + (drv->flags & IFF_UP) == 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } + drv->flags = ifa->ifa_flags; } - return (len == 0) ? 2048 : len; + freeifaddrs(ifaddrs); +} +#endif /* SO_RERROR */ + +static void +bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) +{ + char event_buf[2048]; /* max size of a single route(4) msg */ + 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; + struct ieee80211_leave_event *leave; + struct ieee80211_join_event *join; + int n; + + n = read(sock, event_buf, sizeof(event_buf)); + if (n < 0) { + if (errno != EINTR && errno != EAGAIN) + wpa_printf(MSG_ERROR, "%s read() failed: %s", + __func__, strerror(errno)); +#ifdef SO_RERROR + if (errno == ENOBUFS) + bsd_route_overflow(sock, ctx, sock_ctx); +#endif /* SO_RERROR */ + return; + } + + rtm = (struct rt_msghdr *) event_buf; + if (rtm->rtm_version != RTM_VERSION) { + wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", + rtm->rtm_version); + return; + } + os_memset(&event, 0, sizeof(event)); + switch (rtm->rtm_type) { + case RTM_IEEE80211: + ifan = (struct if_announcemsghdr *) rtm; + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv == NULL) + return; + switch (ifan->ifan_what) { + case RTM_IEEE80211_ASSOC: + case RTM_IEEE80211_REASSOC: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); + break; + case RTM_IEEE80211_DISASSOC: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); + break; + case RTM_IEEE80211_SCAN: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, + NULL); + break; + case RTM_IEEE80211_LEAVE: + leave = (struct ieee80211_leave_event *) &ifan[1]; + drv_event_disassoc(drv->ctx, leave->iev_addr); + break; + case RTM_IEEE80211_JOIN: +#ifdef RTM_IEEE80211_REJOIN + case RTM_IEEE80211_REJOIN: +#endif + join = (struct ieee80211_join_event *) &ifan[1]; + bsd_new_sta(drv, drv->ctx, join->iev_addr); + break; + case RTM_IEEE80211_REPLAY: + /* ignore */ + break; + case RTM_IEEE80211_MICHAEL: + mic = (struct ieee80211_michael_event *) &ifan[1]; + wpa_printf(MSG_DEBUG, + "Michael MIC failure wireless event: " + "keyix=%u src_addr=" MACSTR, mic->iev_keyix, + MAC2STR(mic->iev_src)); + os_memset(&event, 0, sizeof(event)); + event.michael_mic_failure.unicast = + !IEEE80211_IS_MULTICAST(mic->iev_dst); + event.michael_mic_failure.src = mic->iev_src; + wpa_supplicant_event(drv->ctx, + EVENT_MICHAEL_MIC_FAILURE, &event); + break; + } + break; + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *) rtm; + switch (ifan->ifan_what) { + case IFAN_DEPARTURE: + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv) + drv->if_removed = 1; + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + break; + case IFAN_ARRIVAL: + drv = bsd_get_drvname(global, ifan->ifan_name); + if (drv) { + drv->ifindex = ifan->ifan_index; + drv->if_removed = 0; + } + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + break; + default: + wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action"); + return; + } + wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", + ifan->ifan_name, + ifan->ifan_what == IFAN_DEPARTURE ? + "removed" : "added"); + os_strlcpy(event.interface_status.ifname, ifan->ifan_name, + sizeof(event.interface_status.ifname)); + if (drv) { + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + /* + * Set ifindex to zero after sending the event as the + * event might query the driver to ensure a match. + */ + if (ifan->ifan_what == IFAN_DEPARTURE) + drv->ifindex = 0; + } else { + wpa_supplicant_event_global(global->ctx, + EVENT_INTERFACE_STATUS, + &event); + } + break; + case RTM_IFINFO: + ifm = (struct if_msghdr *) rtm; + drv = bsd_get_drvindex(global, ifm->ifm_index); + if (drv == NULL) + return; + if (((ifm->ifm_flags & IFF_UP) == 0 || + (ifm->ifm_flags & IFF_RUNNING) == 0) && + (drv->flags & IFF_UP) != 0 && + (drv->flags & IFF_RUNNING) != 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, + NULL); + } else if ((ifm->ifm_flags & IFF_UP) != 0 && + (ifm->ifm_flags & IFF_RUNNING) != 0 && + ((drv->flags & IFF_UP) == 0 || + (drv->flags & IFF_RUNNING) == 0)) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } + drv->flags = ifm->ifm_flags; + break; + } } #ifdef HOSTAPD @@ -769,80 +993,10 @@ 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_global *global = sock_ctx; - struct bsd_driver_data *drv; - struct if_announcemsghdr *ifan; - struct rt_msghdr *rtm; - struct ieee80211_michael_event *mic; - struct ieee80211_join_event *join; - struct ieee80211_leave_event *leave; - int n; - union wpa_event_data data; - - 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", - __func__, strerror(errno)); - return; - } - - 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; - } - switch (rtm->rtm_type) { - case RTM_IEEE80211: - ifan = (struct if_announcemsghdr *) rtm; - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv == NULL) - return; - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - case RTM_IEEE80211_DISASSOC: - case RTM_IEEE80211_SCAN: - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(drv->hapd, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, drv->hapd, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = mic->iev_src; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - break; - } - break; - } -} - -static void handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct bsd_driver_data *drv = ctx; - drv_event_eapol_rx(drv->hapd, src_addr, buf, len); + drv_event_eapol_rx(drv->ctx, src_addr, buf, len); } static void * @@ -863,7 +1017,8 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) goto bad; } - drv->hapd = hapd; + drv->ctx = hapd; + drv->is_ap = 1; drv->global = params->global_priv; os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); @@ -874,8 +1029,7 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) goto bad; - /* mark down during setup */ - if (bsd_ctrl_iface(drv, 0) < 0) + if (bsd_get_iface_flags(drv) < 0) goto bad; if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { @@ -900,8 +1054,6 @@ bsd_deinit(void *priv) { struct bsd_driver_data *drv = priv; - if (drv->ifindex != 0) - bsd_ctrl_iface(drv, 0); if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); os_free(drv); @@ -909,13 +1061,6 @@ bsd_deinit(void *priv) static int -bsd_commit(void *priv) -{ - return bsd_ctrl_iface(priv, 1); -} - - -static int bsd_set_sta_authorized(void *priv, const u8 *addr, unsigned int total_flags, unsigned int flags_or, unsigned int flags_and) @@ -1079,14 +1224,7 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) mode = 0 /* STA */; break; case IEEE80211_MODE_IBSS: - /* - * Ref bin/203086 - FreeBSD's net80211 currently uses - * IFM_IEEE80211_ADHOC. - */ -#if 0 mode = IFM_IEEE80211_IBSS; -#endif - mode = IFM_IEEE80211_ADHOC; break; case IEEE80211_MODE_AP: mode = IFM_IEEE80211_HOSTAP; @@ -1133,13 +1271,6 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) return -1; - /* - * NB: interface must be marked UP for association - * or scanning (ap_scan=2) - */ - if (bsd_ctrl_iface(drv, 1) < 0) - return -1; - os_memset(&mlme, 0, sizeof(mlme)); mlme.im_op = IEEE80211_MLME_ASSOC; if (params->ssid != NULL) @@ -1182,8 +1313,11 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) } /* NB: interface must be marked UP to do a scan */ - if (bsd_ctrl_iface(drv, 1) < 0) + if (!(drv->flags & IFF_UP)) { + wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan", + __func__); return -1; + } #ifdef IEEE80211_IOC_SCAN_MAX_SSID os_memset(&sr, 0, sizeof(sr)); @@ -1221,166 +1355,6 @@ 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_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; - struct ieee80211_leave_event *leave; - struct ieee80211_join_event *join; - int n; - - /* - * CID 1394785: Memory - illegal access (STRING_NULL): - * Though global->event_buf is a char *, it actually contains - * a struct rt_msghdr *. See below. - */ - 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", - __func__, strerror(errno)); - return; - } - - /* - * CID 1394785: global->event_buf is assigned here to a - * struct rt_msghdr *. - */ - 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; - } - os_memset(&event, 0, sizeof(event)); - switch (rtm->rtm_type) { - case RTM_IFANNOUNCE: - ifan = (struct if_announcemsghdr *) rtm; - switch (ifan->ifan_what) { - case IFAN_DEPARTURE: - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv) - drv->if_removed = 1; - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - break; - case IFAN_ARRIVAL: - drv = bsd_get_drvname(global, ifan->ifan_name); - if (drv) { - drv->ifindex = ifan->ifan_index; - drv->if_removed = 0; - } - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - break; - default: - wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action"); - return; - } - wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", - ifan->ifan_name, - ifan->ifan_what == IFAN_DEPARTURE ? - "removed" : "added"); - os_strlcpy(event.interface_status.ifname, ifan->ifan_name, - sizeof(event.interface_status.ifname)); - if (drv) { - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, - &event); - /* - * Set ifindex to zero after sending the event as the - * event might query the driver to ensure a match. - */ - if (ifan->ifan_what == IFAN_DEPARTURE) - drv->ifindex = 0; - } else { - wpa_supplicant_event_global(global->ctx, - EVENT_INTERFACE_STATUS, - &event); - } - break; - case RTM_IEEE80211: - ifan = (struct if_announcemsghdr *) rtm; - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv == NULL) - return; - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); - break; - case RTM_IEEE80211_DISASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - break; - case RTM_IEEE80211_SCAN: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, - NULL); - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(drv->ctx, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, drv->ctx, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - - os_memset(&event, 0, sizeof(event)); - event.michael_mic_failure.unicast = - !IEEE80211_IS_MULTICAST(mic->iev_dst); - wpa_supplicant_event(drv->ctx, - EVENT_MICHAEL_MIC_FAILURE, &event); - break; - } - break; - case RTM_IFINFO: - ifm = (struct if_msghdr *) rtm; - drv = bsd_get_drvindex(global, ifm->ifm_index); - if (drv == NULL) - return; - if (((ifm->ifm_flags & IFF_UP) == 0 || - (ifm->ifm_flags & IFF_RUNNING) == 0) && - (drv->flags & IFF_UP) != 0 && - (drv->flags & IFF_RUNNING) != 0) { - wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", - drv->ifname); - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, - NULL); - } else if ((ifm->ifm_flags & IFF_UP) != 0 && - (ifm->ifm_flags & IFF_RUNNING) != 0 && - ((drv->flags & IFF_UP) == 0 || - (drv->flags & IFF_RUNNING) == 0)) { - wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", - drv->ifname); - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, - NULL); - } - drv->flags = ifm->ifm_flags; - break; - } -} - -static void wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, struct ieee80211req_scan_result *sr) { @@ -1516,17 +1490,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -#ifdef __FreeBSD__ - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | - WPA_DRIVER_CAPA_ENC_CCMP; -#else - /* - * XXX - * FreeBSD exports hardware cryptocaps. These have no meaning for wpa - * since net80211 performs software crypto. - */ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104; @@ -1534,7 +1497,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; -#endif if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) drv->capa.flags |= WPA_DRIVER_FLAGS_AP; @@ -1587,8 +1549,6 @@ get80211opmode(struct bsd_driver_data *drv) } if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) return IEEE80211_M_HOSTAP; - if (ifmr.ifm_current & IFM_IEEE80211_IBSS) - return IEEE80211_M_IBSS; if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) return IEEE80211_M_MONITOR; #ifdef IEEE80211_M_MBSS @@ -1605,17 +1565,12 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) #define GETPARAM(drv, param, v) \ (((v) = get80211param(drv, param)) != -1) struct bsd_driver_data *drv; + int i; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) return NULL; - /* - * NB: We require the interface name be mappable to an index. - * This implies we do not support having wpa_supplicant - * wait for an interface to appear. This seems ok; that - * doesn't belong here; it's really the job of devd. - */ drv->ifindex = if_nametoindex(ifname); if (drv->ifindex == 0) { wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", @@ -1627,6 +1582,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) drv->global = priv; os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); + /* Set the interface as removed until proven to work. */ + drv->if_removed = 1; + if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", __func__, strerror(errno)); @@ -1646,10 +1604,17 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) if (wpa_driver_bsd_capa(drv)) goto fail; + /* Update per interface supported AKMs */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + /* Down interface during setup. */ - if (bsd_ctrl_iface(drv, 0) < 0) + if (bsd_get_iface_flags(drv) < 0) goto fail; + /* Proven to work, lets go! */ + drv->if_removed = 0; + drv->opmode = get80211opmode(drv); dl_list_add(&drv->global->ifaces, &drv->list); @@ -1668,9 +1633,6 @@ wpa_driver_bsd_deinit(void *priv) if (drv->ifindex != 0 && !drv->if_removed) { wpa_driver_bsd_set_wpa(drv, 0); - /* NB: mark interface down */ - bsd_ctrl_iface(drv, 0); - wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); @@ -1701,6 +1663,15 @@ static void * bsd_global_init(void *ctx) { struct bsd_driver_global *global; +#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER) + unsigned char msgfilter[] = { + RTM_IEEE80211, + RTM_IFINFO, RTM_IFANNOUNCE, + }; +#endif +#ifdef ROUTE_MSGFILTER + unsigned int i, msgfilter_mask; +#endif global = os_zalloc(sizeof(*global)); if (global == NULL) @@ -1709,36 +1680,39 @@ bsd_global_init(void *ctx) global->ctx = ctx; dl_list_init(&global->ifaces); - global->sock = socket(PF_INET, SOCK_DGRAM, 0); + global->sock = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 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); + global->route = socket(PF_ROUTE, + SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 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; - } +#if defined(RO_MSGFILTER) + if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER, + &msgfilter, sizeof(msgfilter)) < 0) + wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s", + strerror(errno)); +#elif defined(ROUTE_MSGFILTER) + msgfilter_mask = 0; + for (i = 0; i < (sizeof(msgfilter) / sizeof(msgfilter[0])); i++) + msgfilter_mask |= ROUTE_FILTER(msgfilter[i]); + if (setsockopt(global->route, PF_ROUTE, ROUTE_MSGFILTER, + &msgfilter_mask, sizeof(msgfilter_mask)) < 0) + wpa_printf(MSG_ERROR, "socket[PF_ROUTE,ROUTE_MSGFILTER]: %s", + strerror(errno)); +#endif -#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: @@ -1775,7 +1749,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { .sta_disassoc = bsd_sta_disassoc, .sta_deauth = bsd_sta_deauth, .sta_set_flags = bsd_set_sta_authorized, - .commit = bsd_commit, #else /* HOSTAPD */ .init2 = wpa_driver_bsd_init, .deinit = wpa_driver_bsd_deinit, |