|
@@ -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
|
|
|
};
|
|
|
|
|
|
|
|
|
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
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
@@ -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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
* 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ drv->ap_scan_as_station = 1;
|
|
|
+ ret = 0;
|
|
|
+ } else
|
|
|
+ goto nla_put_failure;
|
|
|
+#else
|
|
|
goto nla_put_failure;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
|
|
@@ -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;
|
|
|
|
|
|
-try_again:
|
|
|
|
|
|
* 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) {
|
|
|
|
|
|
- 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) {
|
|
|
-
|
|
|
- * 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) {
|
|
|
-
|
|
|
- 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;
|
|
|
- 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) {
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
- _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");
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- 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);
|
|
|
-
|
|
|
-
|
|
|
- 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;
|
|
|
- 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");
|
|
|
-
|
|
|
- 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");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- close(s);
|
|
|
-
|
|
|
- return i802_get_ht_scan_res(drv);
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-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;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- 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
|
|
|
-
|
|
|
-
|
|
|
- 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+
|
|
|
+ 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
|
|
@@ -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
|
|
|
};
|