From ad1e68e6b5c4586d726ae357f1aa130d57deebea Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 16 Apr 2009 16:22:40 +0300 Subject: [PATCH] Clean up HT40 scan and share nl80211 scanning code Instead of adding a new driver_ops for fetching neighbor BSS data (that nl80211 driver interface had to scan during initialization), share the same scan operations that wpa_supplicant is using. This gets rid of duplicated scan code in driver_nl80211.c (and better yet, removes large part of old WEXT code). hostapd interface initialization is now completed in a callback, if needed, i.e., he_features channel/hw_mode selection can use as much time as needed. This can also help with radar detection in the future. --- hostapd/driver_i.h | 26 +- hostapd/drv_callbacks.c | 22 ++ hostapd/hostapd.c | 39 +- hostapd/hostapd.h | 4 +- hostapd/hw_features.c | 160 ++++++-- hostapd/hw_features.h | 7 + src/drivers/driver.h | 14 +- src/drivers/driver_ndis.c | 3 +- src/drivers/driver_nl80211.c | 708 ++++++++--------------------------- src/drivers/driver_privsep.c | 3 +- src/drivers/driver_test.c | 3 +- 11 files changed, 357 insertions(+), 632 deletions(-) diff --git a/hostapd/driver_i.h b/hostapd/driver_i.h index 921d1f1ec..1b6cd5e84 100644 --- a/hostapd/driver_i.h +++ b/hostapd/driver_i.h @@ -36,7 +36,6 @@ hostapd_driver_init(struct hostapd_data *hapd, const u8 *bssid) params.ssid_len = hapd->conf->ssid.ssid_len; params.test_socket = hapd->conf->test_socket; params.use_pae_group_addr = hapd->conf->use_pae_group_addr; - params.ht_40mhz_scan = hapd->iconf->secondary_channel != 0; params.num_bridge = hapd->iface->num_bss; params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *)); @@ -553,12 +552,27 @@ hostapd_set_wps_probe_resp_ie(struct hostapd_data *hapd, const u8 *ie, hapd->drv_priv, ie, len); } -static inline const struct hostapd_neighbor_bss * -hostapd_driver_get_neighbor_bss(struct hostapd_data *hapd, size_t *num) +static inline int hostapd_driver_set_mode(struct hostapd_data *hapd, int mode) { - if (hapd->driver == NULL || hapd->driver->get_neighbor_bss == NULL) - return NULL; - return hapd->driver->get_neighbor_bss(hapd->drv_priv, num); + if (hapd->driver == NULL || hapd->driver->set_mode == NULL) + return 0; + return hapd->driver->set_mode(hapd->drv_priv, mode); +} + +static inline int hostapd_driver_scan(struct hostapd_data *hapd, + struct wpa_driver_scan_params *params) +{ + if (hapd->driver && hapd->driver->scan2) + return hapd->driver->scan2(hapd->drv_priv, params); + return -1; +} + +static inline struct wpa_scan_results * hostapd_driver_get_scan_results( + struct hostapd_data *hapd) +{ + if (hapd->driver && hapd->driver->get_scan_results2) + return hapd->driver->get_scan_results2(hapd->drv_priv); + return NULL; } #endif /* DRIVER_I_H */ diff --git a/hostapd/drv_callbacks.c b/hostapd/drv_callbacks.c index 22058cc1c..1b884c767 100644 --- a/hostapd/drv_callbacks.c +++ b/hostapd/drv_callbacks.c @@ -294,3 +294,25 @@ struct hostapd_data * hostapd_sta_get_bss(struct hostapd_data *hapd, return NULL; } + + +#ifndef CONFIG_AP +void wpa_supplicant_event(void *ctx, wpa_event_type event, + union wpa_event_data *data) +{ + struct hostapd_data *hapd = ctx; + + switch (event) { + case EVENT_MICHAEL_MIC_FAILURE: + michael_mic_failure(hapd, data->michael_mic_failure.src, 1); + break; + case EVENT_SCAN_RESULTS: + if (hapd->iface->scan_cb) + hapd->iface->scan_cb(hapd->iface); + break; + default: + wpa_printf(MSG_DEBUG, "Unknown event %d", event); + break; + } +} +#endif /* CONFIG_AP */ diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c index 379e59c40..0d7eb65de 100644 --- a/hostapd/hostapd.c +++ b/hostapd/hostapd.c @@ -1314,9 +1314,6 @@ static int setup_interface(struct hostapd_iface *iface) size_t i; char country[4]; u8 *b = conf->bssid; - int freq; - size_t j; - u8 *prev_addr; /* * Initialize the driver interface and make sure that all BSSes get @@ -1337,6 +1334,11 @@ static int setup_interface(struct hostapd_iface *iface) iface->bss[i]->drv_priv = hapd->drv_priv; } + if (hostapd_driver_set_mode(hapd, IEEE80211_MODE_AP)) { + wpa_printf(MSG_ERROR, "Failed to set driver in AP mode"); + return -1; + } + if (hostapd_validate_bssid_configuration(iface)) return -1; @@ -1379,8 +1381,33 @@ static int setup_interface(struct hostapd_iface *iface) "channel. (%d)", ret); return -1; } + ret = hostapd_check_ht_capab(iface); + if (ret < 0) + return -1; + if (ret == 1) { + wpa_printf(MSG_DEBUG, "Interface initialization will " + "be completed in a callback"); + return 0; + } + } + return hostapd_setup_interface_complete(iface, 0); +} + + +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +{ + struct hostapd_data *hapd = iface->bss[0]; + int freq; + size_t j; + u8 *prev_addr; + + if (err) { + wpa_printf(MSG_ERROR, "Interface initialization failed"); + eloop_terminate(); + return -1; } + wpa_printf(MSG_DEBUG, "Completing interface initialization"); if (hapd->iconf->channel) { freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " @@ -1436,6 +1463,9 @@ static int setup_interface(struct hostapd_iface *iface) return -1; } + wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", + iface->bss[0]->conf->iface); + return 0; } @@ -1460,9 +1490,6 @@ int hostapd_setup_interface(struct hostapd_iface *iface) iface->bss[0]->conf->iface); eloop_terminate(); return -1; - } else if (!hostapd_drv_none(iface->bss[0])) { - wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", - iface->bss[0]->conf->iface); } return 0; diff --git a/hostapd/hostapd.h b/hostapd/hostapd.h index 03123f871..d45f46113 100644 --- a/hostapd/hostapd.h +++ b/hostapd/hostapd.h @@ -154,9 +154,8 @@ struct hostapd_iface { /* Overlapping BSS information */ int olbc_ht; -#ifdef CONFIG_IEEE80211N u16 ht_op_mode; -#endif /* CONFIG_IEEE80211N */ + void (*scan_cb)(struct hostapd_iface *iface); }; int hostapd_reload_config(struct hostapd_iface *iface); @@ -165,6 +164,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, struct hostapd_config *conf, struct hostapd_bss_config *bss); int hostapd_setup_interface(struct hostapd_iface *iface); +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); void hostapd_interface_deinit(struct hostapd_iface *iface); int handle_reload_iface(struct hostapd_iface *iface, void *ctx); int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx); diff --git a/hostapd/hw_features.c b/hostapd/hw_features.c index 79d785ff4..c29cd1938 100644 --- a/hostapd/hw_features.c +++ b/hostapd/hw_features.c @@ -18,6 +18,8 @@ #include "hostapd.h" #include "ieee802_11_defs.h" +#include "ieee802_11_common.h" +#include "eloop.h" #include "hw_features.h" #include "driver_i.h" #include "config.h" @@ -249,11 +251,37 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) } -static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface) +static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, + int *pri_chan, int *sec_chan) +{ + struct ieee80211_ht_operation *oper; + struct ieee802_11_elems elems; + + *pri_chan = *sec_chan = 0; + + ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); + if (elems.ht_operation && + elems.ht_operation_len >= sizeof(*oper)) { + oper = (struct ieee80211_ht_operation *) elems.ht_operation; + *pri_chan = oper->control_chan; + if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { + if (oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) + *sec_chan = *pri_chan + 4; + else if (oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) + *sec_chan = *pri_chan - 4; + } + } +} + + +static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, + struct wpa_scan_results *scan_res) { int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; - const struct hostapd_neighbor_bss *n; - size_t i, num; + int bss_pri_chan, bss_sec_chan; + size_t i; int match; pri_chan = iface->conf->channel; @@ -264,17 +292,16 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface) else sec_freq = pri_freq - 20; - n = hostapd_driver_get_neighbor_bss(iface->bss[0], &num); - /* * Switch PRI/SEC channels if Beacons were detected on selected SEC * channel, but not on selected PRI channel. */ pri_bss = sec_bss = 0; - for (i = 0; n && i < num; i++) { - if (n[i].freq == pri_freq) + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + if (bss->freq == pri_freq) pri_bss++; - else if (n[i].freq == sec_freq) + else if (bss->freq == sec_freq) sec_bss++; } if (sec_bss && !pri_bss) { @@ -290,21 +317,25 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface) * existing BSSes, use own preference). */ match = 0; - for (i = 0; n && i < num; i++) { - if (pri_chan == n[i].pri_chan && - sec_chan == n[i].sec_chan) { + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); + if (pri_chan == bss_pri_chan && + sec_chan == bss_sec_chan) { match = 1; break; } } if (!match) { - for (i = 0; n && i < num; i++) { - if (pri_chan == n[i].sec_chan && - sec_chan == n[i].pri_chan) { + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); + if (pri_chan == bss_sec_chan && + sec_chan == bss_pri_chan) { wpa_printf(MSG_INFO, "Switch own primary and " "secondary channel due to BSS " "overlap with " MACSTR, - MAC2STR(n[i].bssid)); + MAC2STR(bss->bssid)); ieee80211n_switch_pri_sec(iface); break; } @@ -315,12 +346,12 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface) } -static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface) +static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, + struct wpa_scan_results *scan_res) { int pri_freq, sec_freq; int affected_start, affected_end; - const struct hostapd_neighbor_bss *n; - size_t i, num; + size_t i; pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); if (iface->conf->secondary_channel > 0) @@ -331,12 +362,16 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface) affected_end = (pri_freq + sec_freq) / 2 + 25; wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", affected_start, affected_end); - n = hostapd_driver_get_neighbor_bss(iface->bss[0], &num); - for (i = 0; n && i < num; i++) { - int pri = n[i].freq; + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + int pri = bss->freq; int sec = pri; - if (n[i].sec_chan) { - if (n[i].sec_chan < n[i].pri_chan) + int sec_chan, pri_chan; + + ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); + + if (sec_chan) { + if (sec_chan < pri_chan) sec = pri - 20; else sec = pri + 20; @@ -346,13 +381,17 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface) (sec < affected_start || sec > affected_end)) continue; /* not within affected channel range */ - if (n[i].sec_chan) { + wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR + " freq=%d pri=%d sec=%d", + MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); + + if (sec_chan) { if (pri_freq != pri || sec_freq != sec) { wpa_printf(MSG_DEBUG, "40 MHz pri/sec " "mismatch with BSS " MACSTR " <%d,%d> (chan=%d%c) vs. <%d,%d>", - MAC2STR(n[i].bssid), - pri, sec, n[i].pri_chan, + MAC2STR(bss->bssid), + pri, sec, pri_chan, sec > pri ? '+' : '-', pri_freq, sec_freq); return 0; @@ -366,20 +405,27 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface) } -static void ieee80211n_check_40mhz(struct hostapd_iface *iface) +static void ieee80211n_check_scan(struct hostapd_iface *iface) { + struct wpa_scan_results *scan_res; int oper40; - if (!iface->conf->secondary_channel) - return; /* HT40 not used */ - /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */ + iface->scan_cb = NULL; + + scan_res = hostapd_driver_get_scan_results(iface->bss[0]); + if (scan_res == NULL) { + hostapd_setup_interface_complete(iface, 1); + return; + } + if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) - oper40 = ieee80211n_check_40mhz_5g(iface); + oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); else - oper40 = ieee80211n_check_40mhz_2g4(iface); + oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); + wpa_scan_results_free(scan_res); if (!oper40) { wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " @@ -390,6 +436,30 @@ static void ieee80211n_check_40mhz(struct hostapd_iface *iface) iface->conf->secondary_channel = 0; iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; } + + hostapd_setup_interface_complete(iface, 0); +} + + +static int ieee80211n_check_40mhz(struct hostapd_iface *iface) +{ + struct wpa_driver_scan_params params; + + if (!iface->conf->secondary_channel) + return 0; /* HT40 not used */ + + wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " + "40 MHz channel"); + os_memset(¶ms, 0, sizeof(params)); + /* TODO: scan only the needed frequency */ + if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { + wpa_printf(MSG_ERROR, "Failed to request a scan of " + "neighboring BSSes"); + return -1; + } + + iface->scan_cb = ieee80211n_check_scan; + return 1; } @@ -492,9 +562,27 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) return 1; } + #endif /* CONFIG_IEEE80211N */ +int hostapd_check_ht_capab(struct hostapd_iface *iface) +{ +#ifdef CONFIG_IEEE80211N + int ret; + ret = ieee80211n_check_40mhz(iface); + if (ret) + return ret; + if (!ieee80211n_allowed_ht40_channel_pair(iface)) + return -1; + if (!ieee80211n_supported_ht_capab(iface)) + return -1; +#endif /* CONFIG_IEEE80211N */ + + return 0; +} + + /** * hostapd_select_hw_mode - Select the hardware mode * @iface: Pointer to interface data. @@ -558,14 +646,6 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) return -1; } -#ifdef CONFIG_IEEE80211N - ieee80211n_check_40mhz(iface); - if (!ieee80211n_allowed_ht40_channel_pair(iface)) - return -1; - if (!ieee80211n_supported_ht_capab(iface)) - return -1; -#endif /* CONFIG_IEEE80211N */ - if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) { wpa_printf(MSG_ERROR, "Failed to prepare rates table."); hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, diff --git a/hostapd/hw_features.h b/hostapd/hw_features.h index 8a3f282f6..4449cbbcb 100644 --- a/hostapd/hw_features.h +++ b/hostapd/hw_features.h @@ -24,6 +24,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface); const char * hostapd_hw_mode_txt(int mode); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); +int hostapd_check_ht_capab(struct hostapd_iface *iface); #else /* NEED_MLME */ static inline void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, @@ -50,6 +51,12 @@ static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) { return -1; } + +static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) +{ + return 0; +} + #endif /* NEED_MLME */ #endif /* HW_FEATURES_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 05b856014..696294214 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -61,6 +61,7 @@ struct hostapd_hw_modes { #define IEEE80211_MODE_INFRA 0 #define IEEE80211_MODE_IBSS 1 +#define IEEE80211_MODE_AP 2 #define IEEE80211_CAP_ESS 0x0001 #define IEEE80211_CAP_IBSS 0x0002 @@ -494,14 +495,6 @@ enum hostapd_driver_if_type { HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS }; -struct hostapd_neighbor_bss { - u8 bssid[ETH_ALEN]; - int freq; /* MHz */ - unsigned int ht:1; - int pri_chan; - int sec_chan; /* 0 for 20 MHz channels */ -}; - struct wpa_init_params { const u8 *bssid; const char *ifname; @@ -509,7 +502,6 @@ struct wpa_init_params { size_t ssid_len; const char *test_socket; int use_pae_group_addr; - int ht_40mhz_scan; char **bridge; size_t num_bridge; }; @@ -1341,9 +1333,6 @@ struct wpa_driver_ops { const u8 *ie, size_t len); int (*set_wps_probe_resp_ie)(const char *ifname, void *priv, const u8 *ie, size_t len); - - const struct hostapd_neighbor_bss * - (*get_neighbor_bss)(void *priv, size_t *num); }; /** @@ -1589,6 +1578,7 @@ union wpa_event_data { */ struct michael_mic_failure { int unicast; + const u8 *src; } michael_mic_failure; /** diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 83122d290..7223ca133 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -3266,6 +3266,5 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = { NULL /* set_radius_acl_expire */, NULL /* set_ht_params */, NULL /* set_wps_beacon_ie */, - NULL /* set_wps_probe_resp_ie */, - NULL /* get_neighbor_bss */ + NULL /* set_wps_probe_resp_ie */ }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 75e9c73b8..127f38ac9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -110,6 +110,8 @@ struct wpa_driver_nl80211_data { int associated; u8 ssid[32]; size_t ssid_len; + int nlmode; + int ap_scan_as_station; #if defined(CONFIG_AP) || defined(HOSTAPD) int beacon_int; @@ -131,20 +133,16 @@ struct wpa_driver_nl80211_data { int num_if_indices; struct i802_bss bss; - unsigned int ht_40mhz_scan:1; int last_freq; int last_freq_ht; - struct hostapd_neighbor_bss *neighbors; - size_t num_neighbors; #endif /* HOSTAPD */ }; static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv, - int mode); +static int wpa_driver_nl80211_set_mode(void *priv, int mode); static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); @@ -740,11 +738,6 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv, static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, struct nlattr *tb[]) { -#ifdef HOSTAPD - if (tb[NL80211_ATTR_MAC]) - hostapd_michael_mic_failure(drv->hapd, - nla_data(tb[NL80211_ATTR_MAC])); -#else /* HOSTAPD */ union wpa_event_data data; wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); @@ -753,6 +746,7 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", nla_data(tb[NL80211_ATTR_MAC]), nla_len(tb[NL80211_ATTR_MAC])); + data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); } if (tb[NL80211_ATTR_KEY_SEQ]) { wpa_hexdump(MSG_DEBUG, "nl80211: TSC", @@ -774,7 +768,6 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, } wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -#endif /* HOSTAPD */ } @@ -797,8 +790,14 @@ static int process_event(struct nl_msg *msg, void *arg) } } + if (drv->ap_scan_as_station && + (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || + gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { + wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP); + drv->ap_scan_as_station = 0; + } + switch (gnlh->cmd) { -#ifndef HOSTAPD case NL80211_CMD_NEW_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "nl80211: New scan results available"); drv->scan_complete_events = 1; @@ -816,6 +815,7 @@ static int process_event(struct nl_msg *msg, void *arg) drv->ctx); wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); break; +#ifndef HOSTAPD case NL80211_CMD_AUTHENTICATE: case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: @@ -1174,7 +1174,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) { drv->ifindex = if_nametoindex(drv->ifname); - if (wpa_driver_nl80211_set_mode(drv, 0) < 0) { + if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " "use managed mode"); } @@ -1222,7 +1222,7 @@ static void wpa_driver_nl80211_deinit(void *priv) eloop_unregister_read_sock(drv->link_event_sock); hostapd_set_iface_flags(drv, drv->ifname, 0); - wpa_driver_nl80211_set_mode(drv, 0); + wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA); close(drv->link_event_sock); close(drv->ioctl_sock); @@ -1239,7 +1239,7 @@ static void wpa_driver_nl80211_deinit(void *priv) /** * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion - * @eloop_ctx: Unused + * @eloop_ctx: Driver private data * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() * * This function can be used as registered timeout when starting a scan to @@ -1247,16 +1247,19 @@ static void wpa_driver_nl80211_deinit(void *priv) */ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { + struct wpa_driver_nl80211_data *drv = eloop_ctx; + if (drv->ap_scan_as_station) { + wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP); + drv->ap_scan_as_station = 0; + } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -#ifndef HOSTAPD wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -#endif /* HOSTAPD */ } /** * wpa_driver_nl80211_scan - Request the driver to initiate scan - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() * @params: Scan parameters * Returns: 0 on success, -1 on failure */ @@ -1306,7 +1309,30 @@ static int wpa_driver_nl80211_scan(void *priv, if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); +#ifdef HOSTAPD + if (drv->nlmode == NL80211_IFTYPE_AP) { + /* + * mac80211 does not allow scan requests in AP mode, so + * try to do this in station mode. + */ + if (wpa_driver_nl80211_set_mode(drv, + IEEE80211_MODE_INFRA)) + goto nla_put_failure; + + if (wpa_driver_nl80211_scan(drv, params)) { + wpa_driver_nl80211_set_mode(drv, + IEEE80211_MODE_AP); + goto nla_put_failure; + } + + /* Restore AP mode when processing scan results */ + drv->ap_scan_as_station = 1; + ret = 0; + } else + goto nla_put_failure; +#else /* HOSTAPD */ goto nla_put_failure; +#endif /* HOSTAPD */ } /* Not all drivers generate "scan completed" wireless event, so try to @@ -2869,17 +2895,35 @@ nla_put_failure: } -/** - * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc) - * @drv: Pointer to private driver data from wpa_driver_nl80211_init() - * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS - * Returns: 0 on success, -1 on failure - */ -static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv, - int mode) +static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, + int ifindex, int mode) { - int ret = -1; struct nl_msg *msg; + int ret = -ENOBUFS; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + return 0; +nla_put_failure: + wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:" + " %d (%s)", ifindex, mode, ret, strerror(-ret)); + return ret; +} + + +static int wpa_driver_nl80211_set_mode(void *priv, int mode) +{ + struct wpa_driver_nl80211_data *drv = priv; + int ret = -1; int nlmode; switch (mode) { @@ -2896,52 +2940,28 @@ static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv, return -1; } - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (!ret) + if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { + drv->nlmode = nlmode; return 0; - else - goto try_again; + } -nla_put_failure: - wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)", - ret, strerror(-ret)); - return -1; + if (nlmode == drv->nlmode) + return 0; /* Already in the requested mode */ -try_again: /* mac80211 doesn't allow mode changes while the device is up, so * take the device down, try to set the mode again, and bring the * device back up. */ if (hostapd_set_iface_flags(drv, drv->ifname, 0) == 0) { /* Try to set the mode again while the interface is down */ - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode); - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - wpa_printf(MSG_ERROR, "Failed to set interface %s " - "mode(try_again): %d (%s)", - drv->ifname, ret, strerror(-ret)); - } - + ret = nl80211_set_mode(drv, drv->ifindex, nlmode); if (hostapd_set_iface_flags(drv, drv->ifname, 1)) ret = -1; } + if (!ret) + drv->nlmode = nlmode; + return ret; } @@ -3755,492 +3775,6 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) } -static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, const char *ifname, - int mode) -{ - struct nl_msg *msg; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(ifname)); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (!ret) - return 0; - nla_put_failure: - wpa_printf(MSG_ERROR, "Failed to set interface %s to master " - "mode.", ifname); - return ret; -} - - -#ifdef CONFIG_IEEE80211N -static void i802_add_neighbor(struct wpa_driver_nl80211_data *drv, u8 *bssid, - int freq, u8 *ie, size_t ie_len) -{ - struct ieee802_11_elems elems; - int ht, pri_chan = 0, sec_chan = 0; - struct ieee80211_ht_operation *oper; - struct hostapd_neighbor_bss *nnei; - - ieee802_11_parse_elems(ie, ie_len, &elems, 0); - ht = elems.ht_capabilities || elems.ht_operation; - if (elems.ht_operation && elems.ht_operation_len >= sizeof(*oper)) { - oper = (struct ieee80211_ht_operation *) elems.ht_operation; - pri_chan = oper->control_chan; - if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { - if (oper->ht_param & - HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) - sec_chan = pri_chan + 4; - else if (oper->ht_param & - HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) - sec_chan = pri_chan - 4; - } - } - - wpa_printf(MSG_DEBUG, "nl80211: Neighboring BSS - bssid=" MACSTR - " freq=%d MHz HT=%d pri_chan=%d sec_chan=%d", - MAC2STR(bssid), freq, ht, pri_chan, sec_chan); - - nnei = os_realloc(drv->neighbors, (drv->num_neighbors + 1) * - sizeof(struct hostapd_neighbor_bss)); - if (nnei == NULL) - return; - drv->neighbors = nnei; - nnei = &nnei[drv->num_neighbors]; - os_memcpy(nnei->bssid, bssid, ETH_ALEN); - nnei->freq = freq; - nnei->ht = !!ht; - nnei->pri_chan = pri_chan; - nnei->sec_chan = sec_chan; - drv->num_neighbors++; -} - - -static int i802_get_scan_freq(struct iw_event *iwe, int *freq) -{ - int divi = 1000000, i; - - if (iwe->u.freq.e == 0) { - /* - * Some drivers do not report frequency, but a channel. - * Try to map this to frequency by assuming they are using - * IEEE 802.11b/g. But don't overwrite a previously parsed - * frequency if the driver sends both frequency and channel, - * since the driver may be sending an A-band channel that we - * don't handle here. - */ - - if (*freq) - return 0; - - if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { - *freq = 2407 + 5 * iwe->u.freq.m; - return 0; - } else if (iwe->u.freq.m == 14) { - *freq = 2484; - return 0; - } - } - - if (iwe->u.freq.e > 6) { - wpa_printf(MSG_DEBUG, "Invalid freq in scan results: " - "m=%d e=%d", iwe->u.freq.m, iwe->u.freq.e); - return -1; - } - - for (i = 0; i < iwe->u.freq.e; i++) - divi /= 10; - *freq = iwe->u.freq.m / divi; - return 0; -} - - -static int i802_parse_scan(struct wpa_driver_nl80211_data *drv, u8 *res_buf, - size_t len) -{ - size_t ap_num = 0; - int first; - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom; - u8 bssid[ETH_ALEN]; - int freq = 0; - u8 *ie = NULL; - size_t ie_len = 0; - - ap_num = 0; - first = 1; - - pos = (char *) res_buf; - end = (char *) res_buf + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - if (iwe->len <= IW_EV_LCP_LEN) - break; - - custom = pos + IW_EV_POINT_LEN; - if (iwe->cmd == IWEVGENIE) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - os_memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case SIOCGIWAP: - if (!first) - i802_add_neighbor(drv, bssid, freq, ie, - ie_len); - first = 0; - os_memcpy(bssid, iwe->u.ap_addr.sa_data, ETH_ALEN); - freq = 0; - ie = NULL; - ie_len = 0; - break; - case SIOCGIWFREQ: - i802_get_scan_freq(iwe, &freq); - break; - case IWEVGENIE: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_ERROR, "IWEVGENIE overflow"); - return -1; - } - ie = (u8 *) custom; - ie_len = iwe->u.data.length; - break; - } - - pos += iwe->len; - } - - if (!first) - i802_add_neighbor(drv, bssid, freq, ie, ie_len); - - return 0; -} - - -static int i802_get_ht_scan_res(struct wpa_driver_nl80211_data *drv) -{ - struct iwreq iwr; - u8 *res_buf; - size_t res_buf_len; - int res; - - res_buf_len = IW_SCAN_MAX_DATA; - for (;;) { - res_buf = os_malloc(res_buf_len); - if (res_buf == NULL) - return -1; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = res_buf; - iwr.u.data.length = res_buf_len; - - if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) - break; - - if (errno == E2BIG && res_buf_len < 65535) { - os_free(res_buf); - res_buf = NULL; - res_buf_len *= 2; - if (res_buf_len > 65535) - res_buf_len = 65535; /* 16-bit length field */ - wpa_printf(MSG_DEBUG, "Scan results did not fit - " - "trying larger buffer (%lu bytes)", - (unsigned long) res_buf_len); - } else { - perror("ioctl[SIOCGIWSCAN]"); - os_free(res_buf); - return -1; - } - } - - if (iwr.u.data.length > res_buf_len) { - os_free(res_buf); - return -1; - } - - res = i802_parse_scan(drv, res_buf, iwr.u.data.length); - os_free(res_buf); - - return res; -} - - -static int i802_is_event_wireless_scan_complete(char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - if (iwe->cmd == SIOCGIWSCAN) - return 1; - - pos += iwe->len; - } - - return 0; -} - - -static int i802_is_rtm_scan_complete(int ifindex, struct nlmsghdr *h, int len) -{ - struct ifinfomsg *ifi; - int attrlen, _nlmsg_len, rta_len; - struct rtattr *attr; - - if (len < (int) sizeof(*ifi)) - return 0; - - ifi = NLMSG_DATA(h); - - if (ifindex != ifi->ifi_index) - return 0; /* event for foreign ifindex */ - - _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - _nlmsg_len; - if (attrlen < 0) - return 0; - - attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS && - i802_is_event_wireless_scan_complete( - ((char *) attr) + rta_len, - attr->rta_len - rta_len)) - return 1; - attr = RTA_NEXT(attr, attrlen); - } - - return 0; -} - - -static int i802_is_scan_complete(int s, int ifindex) -{ - char buf[1024]; - int left; - struct nlmsghdr *h; - - left = recv(s, buf, sizeof(buf), MSG_DONTWAIT); - if (left < 0) { - perror("recv(netlink)"); - return 0; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - if (i802_is_rtm_scan_complete(ifindex, h, plen)) - return 1; - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - return 0; -} - - -static int i802_ht_scan(struct wpa_driver_nl80211_data *drv) -{ - struct iwreq iwr; - int s, res, ifindex; - struct sockaddr_nl local; - time_t now, end; - fd_set rfds; - struct timeval tv; - - wpa_printf(MSG_DEBUG, "nl80211: Scanning overlapping BSSes before " - "starting HT 20/40 MHz BSS"); - - /* Request a new scan */ - /* TODO: would be enough to scan the selected band */ - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { - perror("ioctl[SIOCSIWSCAN]"); - return -1; - } - - ifindex = if_nametoindex(drv->ifname); - - /* Wait for scan completion event or timeout */ - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - time(&end); - end += 30; /* Wait at most 30 seconds for scan results */ - for (;;) { - time(&now); - tv.tv_sec = end > now ? end - now : 0; - tv.tv_usec = 0; - FD_ZERO(&rfds); - FD_SET(s, &rfds); - res = select(s + 1, &rfds, NULL, NULL, &tv); - if (res < 0) { - perror("select"); - /* Assume results are ready after 10 seconds wait */ - os_sleep(10, 0); - break; - } else if (res) { - if (i802_is_scan_complete(s, ifindex)) { - wpa_printf(MSG_DEBUG, "nl80211: Scan " - "completed"); - break; - } - } else { - wpa_printf(MSG_DEBUG, "nl80211: Scan timeout"); - /* Assume results are ready to be read now */ - break; - } - } - - close(s); - - return i802_get_ht_scan_res(drv); -} -#endif /* CONFIG_IEEE80211N */ - - -static int i802_init_sockets(struct wpa_driver_nl80211_data *drv, const u8 *bssid) -{ - struct ifreq ifr; - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - return -1; - } - - /* start listening for EAPOL on the default AP interface */ - add_ifidx(drv, if_nametoindex(drv->ifname)); - - if (hostapd_set_iface_flags(drv, drv->ifname, 0)) - return -1; - - if (bssid) { - os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ); - memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN); - ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { - perror("ioctl(SIOCSIFHWADDR)"); - return -1; - } - } - - if (wpa_driver_nl80211_init_nl(drv, drv->hapd)) - return -1; - -#ifdef CONFIG_IEEE80211N - if (drv->ht_40mhz_scan) { - if (nl80211_set_mode(drv, drv->ifname, NL80211_IFTYPE_STATION) - || hostapd_set_iface_flags(drv, drv->ifname, 1) || - i802_ht_scan(drv) || - hostapd_set_iface_flags(drv, drv->ifname, 0)) { - wpa_printf(MSG_ERROR, "Failed to scan channels for " - "HT 40 MHz operations"); - return -1; - } - } -#endif /* CONFIG_IEEE80211N */ - - /* Initialise a monitor interface */ - if (nl80211_create_monitor_interface(drv)) - return -1; - - if (nl80211_set_mode(drv, drv->ifname, NL80211_IFTYPE_AP)) - goto fail1; - - if (hostapd_set_iface_flags(drv, drv->ifname, 1)) - goto fail1; - - drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); - if (drv->eapol_sock < 0) { - perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); - goto fail1; - } - - if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) - { - printf("Could not register read socket for eapol\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - goto fail1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - goto fail1; - } - memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - return 0; - -fail1: - nl80211_remove_iface(drv, drv->monitor_ifidx); - return -1; -} - - static int i802_get_inact_sec(void *priv, const u8 *addr) { struct hostap_sta_driver_data data; @@ -4299,20 +3833,12 @@ static int i802_sta_disassoc(void *priv, const u8 *addr, int reason) } -static const struct hostapd_neighbor_bss * -i802_get_neighbor_bss(void *priv, size_t *num) -{ - struct wpa_driver_nl80211_data *drv = priv; - *num = drv->num_neighbors; - return drv->neighbors; -} - - static void *i802_init(struct hostapd_data *hapd, struct wpa_init_params *params) { struct wpa_driver_nl80211_data *drv; size_t i; + struct ifreq ifr; drv = os_zalloc(sizeof(struct wpa_driver_nl80211_data)); if (drv == NULL) { @@ -4321,6 +3847,7 @@ static void *i802_init(struct hostapd_data *hapd, } drv->hapd = hapd; + drv->ctx = hapd; memcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); drv->ifindex = if_nametoindex(drv->ifname); drv->bss.ifindex = drv->ifindex; @@ -4331,13 +3858,76 @@ static void *i802_init(struct hostapd_data *hapd, if (params->bridge[i]) add_ifidx(drv, if_nametoindex(params->bridge[i])); } - drv->ht_40mhz_scan = params->ht_40mhz_scan; - if (i802_init_sockets(drv, params->bssid)) + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); goto failed; + } + + /* start listening for EAPOL on the default AP interface */ + add_ifidx(drv, drv->ifindex); + + if (hostapd_set_iface_flags(drv, drv->ifname, 0)) + goto failed; + + if (params->bssid) { + os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ); + os_memcpy(ifr.ifr_hwaddr.sa_data, params->bssid, ETH_ALEN); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + + if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { + perror("ioctl(SIOCSIFHWADDR)"); + goto failed; + } + } + + if (wpa_driver_nl80211_init_nl(drv, drv->hapd)) + goto failed; + + /* Initialise a monitor interface */ + if (nl80211_create_monitor_interface(drv)) + goto failed; + + if (nl80211_set_mode(drv, drv->ifindex, NL80211_IFTYPE_AP)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " + "into AP mode", drv->ifname); + goto fail1; + } + + if (hostapd_set_iface_flags(drv, drv->ifname, 1)) + goto fail1; + + drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); + if (drv->eapol_sock < 0) { + perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); + goto fail1; + } + + if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) + { + printf("Could not register read socket for eapol\n"); + goto failed; + } + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { + perror("ioctl(SIOCGIFHWADDR)"); + goto fail1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + printf("Invalid HW-addr family 0x%04x\n", + ifr.ifr_hwaddr.sa_family); + goto fail1; + } + os_memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); return drv; +fail1: + nl80211_remove_iface(drv, drv->monitor_ifidx); failed: free(drv); return NULL; @@ -4384,8 +3974,6 @@ static void i802_deinit(void *priv) if (drv->if_indices != drv->default_if_indices) free(drv->if_indices); - os_free(drv->neighbors); - bss = drv->bss.next; while (bss) { prev = bss; @@ -4416,6 +4004,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_capa = wpa_driver_nl80211_get_capa, .set_operstate = wpa_driver_nl80211_set_operstate, .set_country = wpa_driver_nl80211_set_country, + .set_mode = wpa_driver_nl80211_set_mode, #ifdef CONFIG_AP .set_beacon = wpa_driver_nl80211_set_beacon, #endif /* CONFIG_AP */ @@ -4455,6 +4044,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .if_update = i802_if_update, .if_remove = i802_if_remove, .set_sta_vlan = i802_set_sta_vlan, - .get_neighbor_bss = i802_get_neighbor_bss, #endif /* HOSTAPD */ }; diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index 93427c1f0..7522527fc 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -862,8 +862,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = { NULL /* set_radius_acl_expire */, NULL /* set_ht_params */, NULL /* set_wps_beacon_ie */, - NULL /* set_wps_probe_resp_ie */, - NULL /* get_neighbor_bss */ + NULL /* set_wps_probe_resp_ie */ }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 9fdf010e7..640b33be6 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -2567,7 +2567,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = { NULL /* set_radius_acl_expire */, NULL /* set_ht_params */, NULL /* set_wps_beacon_ie */, - NULL /* set_wps_probe_resp_ie */, - NULL /* get_neighbor_bss */ + NULL /* set_wps_probe_resp_ie */ #endif /* HOSTAPD */ };