};
static void nl80211_global_deinit(void *priv);
-static void wpa_driver_nl80211_deinit(void *priv);
struct i802_bss {
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
int ifindex;
+ u64 wdev_id;
char ifname[IFNAMSIZ + 1];
char brname[IFNAMSIZ];
unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
unsigned int added_bridge:1;
unsigned int in_deinit:1;
+ unsigned int wdev_id_set:1;
u8 addr[ETH_ALEN];
int freq;
+ void *ctx;
struct nl_handle *nl_preq, *nl_mgmt;
struct nl_cb *nl_cb;
int ignore_if_down_event;
struct rfkill_data *rfkill;
struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
int has_capability;
int operstate;
struct nl_cb *nl_cb;
u8 auth_bssid[ETH_ALEN];
+ u8 auth_attempt_bssid[ETH_ALEN];
u8 bssid[ETH_ALEN];
+ u8 prev_bssid[ETH_ALEN];
int associated;
u8 ssid[32];
size_t ssid_len;
unsigned int scan_for_auth:1;
unsigned int retry_auth:1;
unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
};
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
void *timeout_ctx);
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, u64 *cookie,
int no_cck, int no_ack, int offchanok);
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
+ int report);
#ifdef ANDROID
static int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
enum wpa_driver_if_type type,
const char *ifname);
#else /* HOSTAPD */
}
#endif /* HOSTAPD */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+ struct hostapd_freq_params *freq);
static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
struct wpa_driver_nl80211_data *drv);
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+#undef C2S
+}
+
+
static int is_ap_interface(enum nl80211_iftype nlmode)
{
return (nlmode == NL80211_IFTYPE_AP ||
}
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
{
return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
nlmode == NL80211_IFTYPE_P2P_GO);
}
+static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->associated)
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ drv->associated = 0;
+ os_memset(drv->bssid, 0, ETH_ALEN);
+}
+
+
struct nl80211_bss_info_arg {
struct wpa_driver_nl80211_data *drv;
struct wpa_scan_results *res;
};
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+ if (bss->wdev_id_set)
+ NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+
static int family_handler(struct nl_msg *msg, void *arg)
{
struct family_data *res = arg;
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
}
os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
os_memset(&event, 0, sizeof(event));
os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
if (len > 24 + sizeof(mgmt->u.auth)) {
event.auth.ies = mgmt->u.auth.variable;
union wpa_event_data event;
u16 status;
+ wpa_printf(MSG_DEBUG, "nl80211: Associate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
drv->associated = 1;
os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+ os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
os_memset(&event, 0, sizeof(event));
if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
return;
}
+ if (cmd == NL80211_CMD_CONNECT)
+ wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+ else if (cmd == NL80211_CMD_ROAM)
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
os_memset(&event, 0, sizeof(event));
if (cmd == NL80211_CMD_CONNECT &&
nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
}
drv->associated = 1;
- if (addr)
+ if (addr) {
os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ }
if (req_ie) {
event.assoc_info.req_ies = nla_data(req_ie);
struct nlattr *by_ap)
{
union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
/*
return;
}
- drv->associated = 0;
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event triggered during reassociation");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+ "disconnect but got another disconnect "
+ "event first");
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+ nl80211_mark_disconnected(drv);
os_memset(&data, 0, sizeof(data));
if (reason)
data.deauth_info.reason_code = nla_get_u16(reason);
}
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *freq, struct nlattr *type)
+{
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq || !type)
+ return;
+
+ switch (nla_get_u32(type)) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+
+ wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *addr)
{
u16 fc, stype;
int ssi_signal = 0;
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24) {
wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
const struct ieee80211_hdr *hdr;
u16 fc;
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
if (!is_ap_interface(drv->nlmode)) {
u64 cookie_val;
const u8 *bssid = NULL;
u16 reason_code = 0;
+ if (type == EVENT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
mgmt = (const struct ieee80211_mgmt *) frame;
if (len >= 24) {
bssid = mgmt->bssid;
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ !drv->associated &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
if (drv->associated != 0 &&
os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
}
}
- drv->associated = 0;
+ nl80211_mark_disconnected(drv);
os_memset(&event, 0, sizeof(event));
/* Note: Same offset for Reason Code in both frame subtypes */
union wpa_event_data event;
u16 reason_code = 0;
+ if (type == EVENT_UNPROT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
if (len < 24)
return;
}
-static void mlme_event(struct wpa_driver_nl80211_data *drv,
+static void mlme_event(struct i802_bss *bss,
enum nl80211_commands cmd, struct nlattr *frame,
struct nlattr *addr, struct nlattr *timed_out,
struct nlattr *freq, struct nlattr *ack,
struct nlattr *cookie, struct nlattr *sig)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const u8 *data;
+ size_t len;
+
if (timed_out && addr) {
mlme_timeout_event(drv, cmd, addr);
return;
}
if (frame == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
- "data", cmd);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLME event %d (%s) without frame data",
+ cmd, nl80211_command_to_string(cmd));
return;
}
- wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+ data = nla_data(frame);
+ len = nla_len(frame);
+ if (len < 4 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+ MACSTR ") - too short",
+ cmd, nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr));
+ return;
+ }
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+ ") A1=" MACSTR " A2=" MACSTR, cmd,
+ nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(data + 4),
+ MAC2STR(data + 4 + ETH_ALEN));
+ if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+ "for foreign address", bss->ifname);
+ return;
+ }
wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
nla_data(frame), nla_len(frame));
}
-static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
struct nlattr *tb[])
{
union wpa_event_data data;
wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
}
- wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
}
}
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (tb[NL80211_ATTR_IE]) {
+ data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+
+ if (tb[NL80211_ATTR_IE_RIC]) {
+ data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+ data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(data.ft_ies.target_ap,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+ MAC2STR(data.ft_ies.target_ap));
+
+ wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
struct nlattr *tb[])
{
struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
};
struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
sig_change->current_signal =
(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
+ if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+ sig_change->avg_signal =
+ (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+ else
+ sig_change->avg_signal = 0;
+
if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
sinfo[NL80211_STA_INFO_TX_BITRATE],
};
union wpa_event_data data;
+ wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
return;
if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
{
union wpa_event_data data;
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
return;
}
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+ case NL80211_TDLS_SETUP:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_SETUP;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+ "event");
+ return;
+ }
+ if (tb[NL80211_ATTR_REASON_CODE]) {
+ data.tdls.reason_code =
+ nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ u32 reason;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.connect_failed_reason.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+ switch (reason) {
+ case NL80211_CONN_FAIL_MAX_CLIENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+ data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+ break;
+ case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+ wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+ " tried to connect",
+ MAC2STR(data.connect_failed_reason.addr));
+ data.connect_failed_reason.code = BLOCKED_CLIENT;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+ "%u", reason);
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ enum nl80211_radar_event event_type;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+ data.dfs_event.freq);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+ "received", event_type);
+ break;
+ }
+}
+
+
static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
int wds)
{
}
-static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
- int cmd, struct nlattr **tb)
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ struct nlattr **tb)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+ cmd, nl80211_command_to_string(cmd), bss->ifname);
+
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
cmd == NL80211_CMD_SCAN_ABORTED)) {
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
- wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
break;
case NL80211_CMD_START_SCHED_SCAN:
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
break;
case NL80211_CMD_SCHED_SCAN_STOPPED:
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
- wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New scan results available");
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCHED_SCAN_RESULTS:
- wpa_printf(MSG_DEBUG,
- "nl80211: New sched scan results available");
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New sched scan results available");
send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCAN_ABORTED:
- wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
/*
* Need to indicate that scan results are available in order
* not to make wpa_supplicant stop its scanning.
case NL80211_CMD_FRAME_TX_STATUS:
case NL80211_CMD_UNPROT_DEAUTHENTICATE:
case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
+ mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE]);
break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
tb[NL80211_ATTR_MAC],
tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
break;
case NL80211_CMD_MICHAEL_MIC_FAILURE:
- mlme_event_michael_mic_failure(drv, tb);
+ mlme_event_michael_mic_failure(bss, tb);
break;
case NL80211_CMD_JOIN_IBSS:
mlme_event_join_ibss(drv, tb);
case NL80211_CMD_PROBE_CLIENT:
nl80211_client_probe_event(drv, tb);
break;
+ case NL80211_CMD_TDLS_OPER:
+ nl80211_tdls_oper_event(drv, tb);
+ break;
+ case NL80211_CMD_CONN_FAILED:
+ nl80211_connect_failed_event(drv, tb);
+ break;
+ case NL80211_CMD_FT_EVENT:
+ mlme_event_ft_event(drv, tb);
+ break;
+ case NL80211_CMD_RADAR_DETECT:
+ nl80211_radar_event(drv, tb);
+ break;
default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", cmd);
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
break;
}
}
struct wpa_driver_nl80211_data *drv = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct i802_bss *bss;
+ int ifidx = -1;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb[NL80211_ATTR_IFINDEX]) {
- int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
- " for foreign interface (ifindex %d)",
- gnlh->cmd, ifindex);
- return NL_SKIP;
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+ for (bss = &drv->first_bss; bss; bss = bss->next)
+ if (ifidx == -1 || ifidx == bss->ifindex) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+ gnlh->cmd, ifidx);
+ } else if (tb[NL80211_ATTR_WDEV]) {
+ u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+ for (bss = &drv->first_bss; bss; bss = bss->next) {
+ if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
}
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+ gnlh->cmd, (long long unsigned int) wdev_id);
}
- do_process_drv_event(drv, gnlh->cmd, tb);
return NL_SKIP;
}
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct wpa_driver_nl80211_data *drv, *tmp;
int ifidx = -1;
+ struct i802_bss *bss;
+ u64 wdev_id;
+ int wdev_id_set = 0;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb[NL80211_ATTR_IFINDEX])
ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ else if (tb[NL80211_ATTR_WDEV]) {
+ wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wdev_id_set = 1;
+ }
dl_list_for_each_safe(drv, tmp, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (ifidx == -1 || ifidx == drv->ifindex ||
- have_ifidx(drv, ifidx))
- do_process_drv_event(drv, gnlh->cmd, tb);
+ for (bss = &drv->first_bss; bss; bss = bss->next) {
+ if ((ifidx == -1 && !wdev_id_set) ||
+ ifidx == bss->ifindex ||
+ (wdev_id_set && bss->wdev_id_set &&
+ wdev_id == bss->wdev_id)) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
+ }
}
return NL_SKIP;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+ gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+ bss->ifname);
+
switch (gnlh->cmd) {
case NL80211_CMD_FRAME:
case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
{
struct nl_cb *cb = eloop_ctx;
- wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+ wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
nl_recvmsgs(handle, cb);
}
}
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+ u32 *feat = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+ *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+ u32 feat = 0;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ return feat;
+
+ msg = NULL;
+nla_put_failure:
+ nlmsg_free(msg);
+ return 0;
+}
+
+
struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
struct wpa_driver_capa *capa;
unsigned int error:1;
unsigned int poll_command_supported:1;
unsigned int data_tx_status:1;
unsigned int monitor_supported:1;
+ unsigned int auth_supported:1;
+ unsigned int connect_supported:1;
+ unsigned int p2p_go_supported:1;
+ unsigned int p2p_client_supported:1;
+ unsigned int p2p_concurrent:1;
+ unsigned int p2p_multichan_concurrent:1;
};
}
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+ struct nlattr *tb)
{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct wiphy_info_data *info = arg;
- int p2p_go_supported = 0, p2p_client_supported = 0;
- int p2p_concurrent = 0;
- int auth_supported = 0, connect_supported = 0;
- struct wpa_driver_capa *capa = info->capa;
+ struct nlattr *nl_mode;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_mode, tb, i) {
+ switch (nla_type(nl_mode)) {
+ case NL80211_IFTYPE_AP:
+ info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ info->capa->flags |=
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ info->p2p_go_supported = 1;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ info->p2p_client_supported = 1;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ info->monitor_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+ struct nlattr *nl_combi)
+{
+ struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+ struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+ struct nlattr *nl_limit, *nl_mode;
+ int err, rem_limit, rem_mode;
+ int combination_has_p2p = 0, combination_has_mgd = 0;
static struct nla_policy
iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
[NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
[NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
},
iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
};
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
- capa->max_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+ err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+ nl_combi, iface_combination_policy);
+ if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+ !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+ !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+ return 0; /* broken combination */
- if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
- capa->max_sched_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+ if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+ info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
- if (tb[NL80211_ATTR_MAX_MATCH_SETS])
- capa->max_match_sets =
- nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+ nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+ rem_limit) {
+ err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+ nl_limit, iface_limit_policy);
+ if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+ return 0; /* broken combination */
- if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
- struct nlattr *nl_mode;
- int i;
nla_for_each_nested(nl_mode,
- tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
- switch (nla_type(nl_mode)) {
- case NL80211_IFTYPE_AP:
- capa->flags |= WPA_DRIVER_FLAGS_AP;
- break;
- case NL80211_IFTYPE_P2P_GO:
- p2p_go_supported = 1;
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- p2p_client_supported = 1;
- break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
- }
+ tb_limit[NL80211_IFACE_LIMIT_TYPES],
+ rem_mode) {
+ int ift = nla_type(nl_mode);
+ if (ift == NL80211_IFTYPE_P2P_GO ||
+ ift == NL80211_IFTYPE_P2P_CLIENT)
+ combination_has_p2p = 1;
+ if (ift == NL80211_IFTYPE_STATION)
+ combination_has_mgd = 1;
}
+ if (combination_has_p2p && combination_has_mgd)
+ break;
}
- if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
- struct nlattr *nl_combi;
- int rem_combi;
-
- nla_for_each_nested(nl_combi,
- tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
- rem_combi) {
- struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
- struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
- struct nlattr *nl_limit, *nl_mode;
- int err, rem_limit, rem_mode;
- int combination_has_p2p = 0, combination_has_mgd = 0;
-
- err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
- nl_combi,
- iface_combination_policy);
- if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
- !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
- !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
- goto broken_combination;
-
- nla_for_each_nested(nl_limit,
- tb_comb[NL80211_IFACE_COMB_LIMITS],
- rem_limit) {
- err = nla_parse_nested(tb_limit,
- MAX_NL80211_IFACE_LIMIT,
- nl_limit,
- iface_limit_policy);
- if (err ||
- !tb_limit[NL80211_IFACE_LIMIT_TYPES])
- goto broken_combination;
-
- nla_for_each_nested(
- nl_mode,
- tb_limit[NL80211_IFACE_LIMIT_TYPES],
- rem_mode) {
- int ift = nla_type(nl_mode);
- if (ift == NL80211_IFTYPE_P2P_GO ||
- ift == NL80211_IFTYPE_P2P_CLIENT)
- combination_has_p2p = 1;
- if (ift == NL80211_IFTYPE_STATION)
- combination_has_mgd = 1;
- }
- if (combination_has_p2p && combination_has_mgd)
- break;
- }
+ if (combination_has_p2p && combination_has_mgd) {
+ info->p2p_concurrent = 1;
+ if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+ info->p2p_multichan_concurrent = 1;
+ return 1;
+ }
- if (combination_has_p2p && combination_has_mgd) {
- p2p_concurrent = 1;
- break;
- }
+ return 0;
+}
-broken_combination:
- ;
- }
- }
- if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
- struct nlattr *nl_cmd;
- int i;
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_combi;
+ int rem_combi;
- nla_for_each_nested(nl_cmd,
- tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
- switch (nla_get_u32(nl_cmd)) {
- case NL80211_CMD_AUTHENTICATE:
- auth_supported = 1;
- break;
- case NL80211_CMD_CONNECT:
- connect_supported = 1;
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- capa->sched_scan_supported = 1;
- break;
- case NL80211_CMD_PROBE_CLIENT:
- info->poll_command_supported = 1;
- break;
- }
- }
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_combi, tb, rem_combi) {
+ if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+ break;
}
+}
- if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_cmd;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_cmd, tb, i) {
+ switch (nla_get_u32(nl_cmd)) {
+ case NL80211_CMD_AUTHENTICATE:
+ info->auth_supported = 1;
+ break;
+ case NL80211_CMD_CONNECT:
+ info->connect_supported = 1;
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ info->capa->sched_scan_supported = 1;
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ if (tb)
+ capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+ struct nlattr *ext_setup)
+{
+ if (tdls == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+ if (ext_setup) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+ }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ u32 flags;
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ flags = nla_get_u32(tb);
+
+ if (flags & NL80211_FEATURE_SK_TX_STATUS)
+ info->data_tx_status = 1;
+
+ if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+ capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+ if (flags & NL80211_FEATURE_SAE)
+ capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+ if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+ capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ u32 protocols;
+
+ if (tb == NULL)
+ return;
+
+ protocols = nla_get_u32(tb);
+ wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+ "mode");
+ capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+ capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_info_data *info = arg;
+ struct wpa_driver_capa *capa = info->capa;
+ struct wpa_driver_nl80211_data *drv = info->drv;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+ capa->max_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+ capa->max_sched_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+ if (tb[NL80211_ATTR_MAC_ACL_MAX])
+ capa->max_acl_mac_addrs =
+ nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
+ wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+ wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+ wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
"off-channel TX");
capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
}
capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
}
- /* default to 5000 since early versions of mac80211 don't set it */
- capa->max_remain_on_chan = 5000;
+ wiphy_info_max_roc(capa,
+ tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
- if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
- capa->max_remain_on_chan =
- nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
- if (auth_supported)
- capa->flags |= WPA_DRIVER_FLAGS_SME;
- else if (!connect_supported) {
- wpa_printf(MSG_INFO, "nl80211: Driver does not support "
- "authentication/association or connect commands");
- info->error = 1;
- }
-
- if (p2p_go_supported && p2p_client_supported)
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- if (p2p_concurrent) {
- wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
- "interface (driver advertised support)");
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
- }
-
- if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
- if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
- capa->flags |=
- WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
- }
- }
+ wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+ tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
if (tb[NL80211_ATTR_DEVICE_AP_SME])
info->device_ap_sme = 1;
- if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
- u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
-
- if (flags & NL80211_FEATURE_SK_TX_STATUS)
- info->data_tx_status = 1;
-
- if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
- capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
- }
-
- if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
- int protocols =
- nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
- wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
- "offload in AP mode");
- capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
- capa->probe_resp_offloads =
- probe_resp_offload_support(protocols);
+ wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_probe_resp_offload(capa,
+ tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+ if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+ drv->extended_capa == NULL) {
+ drv->extended_capa =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa) {
+ os_memcpy(drv->extended_capa,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ drv->extended_capa_len =
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ }
+ drv->extended_capa_mask =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa_mask) {
+ os_memcpy(drv->extended_capa_mask,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ } else {
+ os_free(drv->extended_capa);
+ drv->extended_capa = NULL;
+ drv->extended_capa_len = 0;
+ }
}
return NL_SKIP;
static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
struct wiphy_info_data *info)
{
+ u32 feat;
struct nl_msg *msg;
os_memset(info, 0, sizeof(*info));
info->capa = &drv->capa;
+ info->drv = drv;
msg = nlmsg_alloc();
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+ else
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
- return 0;
- msg = NULL;
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ return -1;
+
+ if (info->auth_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+ else if (!info->connect_supported) {
+ wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+ "authentication/association or connect commands");
+ info->error = 1;
+ }
+
+ if (info->p2p_go_supported && info->p2p_client_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ if (info->p2p_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+ if (info->p2p_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ }
+
+ /* default to 5000 since early versions of mac80211 don't set it */
+ if (!drv->capa.max_remain_on_chan)
+ drv->capa.max_remain_on_chan = 5000;
+
+ return 0;
nla_put_failure:
nlmsg_free(msg);
return -1;
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
- if (!info.device_ap_sme)
+ if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
drv->device_ap_sme = info.device_ap_sme;
drv->poll_command_supported = info.poll_command_supported;
drv->data_tx_status = info.data_tx_status;
/*
- * If poll command is supported mac80211 is new enough to
- * have everything we need to not need monitor interfaces.
+ * If poll command and tx status are supported, mac80211 is new enough
+ * to have everything we need to not need monitor interfaces.
*/
- drv->use_monitor = !info.poll_command_supported;
+ drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
if (drv->device_ap_sme && drv->use_monitor) {
/*
u8 data[2048];
struct msghdr msg;
struct iovec entry;
- struct {
- struct cmsghdr cm;
- char control[512];
- } control;
+ u8 control[512];
struct cmsghdr *cmsg;
int res, found_ee = 0, found_wifi = 0, acked = 0;
union wpa_event_data event;
drv->ctx = ctx;
bss = &drv->first_bss;
bss->drv = drv;
+ bss->ctx = ctx;
+
os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
drv->monitor_ifidx = -1;
drv->monitor_sock = -1;
nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ if (nl80211_set_iface_id(msg, bss))
+ goto nla_put_failure;
+
NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
/* WNM - BSS Transition Management Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
return -1;
+ /* WNM-Sleep Mode Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
+ return -1;
return 0;
}
/**
* wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
*
* Shut down driver interface and processing of driver events. Free
* private data buffer if one was allocated in wpa_driver_nl80211_init().
*/
-static void wpa_driver_nl80211_deinit(void *priv)
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
bss->in_deinit = 1;
struct hostapd_freq_params freq;
os_memset(&freq, 0, sizeof(freq));
freq.freq = drv->last_freq;
- i802_set_freq(priv, &freq);
+ wpa_driver_nl80211_set_freq(bss, &freq);
}
if (drv->eapol_sock >= 0) {
if (drv->in_interface_list)
dl_list_del(&drv->list);
+ os_free(drv->extended_capa);
+ os_free(drv->extended_capa_mask);
os_free(drv);
}
}
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(void *priv,
- struct wpa_driver_scan_params *params)
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+ struct wpa_driver_scan_params *params, u64 *wdev_id)
{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0, timeout;
- struct nl_msg *msg, *ssids, *freqs, *rates;
+ struct nl_msg *msg;
size_t i;
- drv->scan_for_auth = 0;
-
msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- rates = nlmsg_alloc();
- if (!msg || !ssids || !freqs || !rates) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- nlmsg_free(rates);
- return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
+ if (!msg)
+ return NULL;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ nl80211_cmd(drv, msg, 0, cmd);
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
+ if (!wdev_id)
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ else
+ NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
+
+ if (params->num_ssids) {
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid) < 0)
+ goto fail;
+ }
+ nla_nest_end(msg, ssids);
}
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
if (params->extra_ies) {
wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies) < 0)
+ goto fail;
}
if (params->freqs) {
+ struct nlattr *freqs;
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+ if (freqs == NULL)
+ goto fail;
for (i = 0; params->freqs[i]; i++) {
wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
"MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
+ goto fail;
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+ nla_nest_end(msg, freqs);
}
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ return msg;
+
+fail:
+nla_put_failure:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, timeout;
+ struct nl_msg *msg = NULL;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+ drv->scan_for_auth = 0;
+
+ msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+ bss->wdev_id_set ? &bss->wdev_id : NULL);
+ if (!msg)
+ return -1;
+
if (params->p2p_probe) {
+ struct nlattr *rates;
+
wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+ rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+ if (rates == NULL)
+ goto nla_put_failure;
+
/*
* Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
* by masking out everything else apart from the OFDM rates 6,
* 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
* rates are left enabled.
*/
- NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+ NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
"\x0c\x12\x18\x24\x30\x48\x60\x6c");
- nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+ nla_nest_end(msg, rates);
NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
}
bss, NL80211_IFTYPE_STATION))
goto nla_put_failure;
- if (wpa_driver_nl80211_scan(drv, params)) {
+ if (wpa_driver_nl80211_scan(bss, params)) {
wpa_driver_nl80211_set_mode(bss, drv->nlmode);
goto nla_put_failure;
}
drv, drv->ctx);
nla_put_failure:
- nlmsg_free(ssids);
nlmsg_free(msg);
- nlmsg_free(freqs);
- nlmsg_free(rates);
return ret;
}
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0;
- struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+ int ret = -1;
+ struct nl_msg *msg;
size_t i;
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
#ifdef ANDROID
if (!drv->capa.sched_scan_supported)
return android_pno_start(bss, params);
#endif /* ANDROID */
- msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- if (!msg || !ssids || !freqs) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+ bss->wdev_id_set ? &bss->wdev_id : NULL);
+ if (!msg)
+ goto nla_put_failure;
NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
- if (drv->num_filter_ssids &&
- (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
- match_sets = nlmsg_alloc();
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
+ struct nlattr *match_sets;
+ match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+ if (match_sets == NULL)
+ goto nla_put_failure;
for (i = 0; i < drv->num_filter_ssids; i++) {
+ struct nlattr *match_set_ssid;
wpa_hexdump_ascii(MSG_MSGDUMP,
"nl80211: Sched scan filter SSID",
drv->filter_ssids[i].ssid,
drv->filter_ssids[i].ssid_len);
- match_set_ssid = nlmsg_alloc();
- nla_put(match_set_ssid,
- NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ match_set_ssid = nla_nest_start(msg, i + 1);
+ if (match_set_ssid == NULL)
+ goto nla_put_failure;
+ NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
drv->filter_ssids[i].ssid_len,
drv->filter_ssids[i].ssid);
- nla_put_nested(match_sets, i + 1, match_set_ssid);
-
- nlmsg_free(match_set_ssid);
+ nla_nest_end(msg, match_set_ssid);
}
- nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
- match_sets);
- nlmsg_free(match_sets);
- }
-
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
- }
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
- if (params->extra_ies) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
- }
-
- if (params->freqs) {
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ if (params->filter_rssi) {
+ struct nlattr *match_set_rssi;
+ match_set_rssi = nla_nest_start(msg, 0);
+ if (match_set_rssi == NULL)
+ goto nla_put_failure;
+ NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ nla_nest_end(msg, match_set_rssi);
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+ nla_nest_end(msg, match_sets);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
"scan interval %d msec", ret, interval);
nla_put_failure:
- nlmsg_free(ssids);
nlmsg_free(msg);
- nlmsg_free(freqs);
return ret;
}
return NL_SKIP;
}
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return NL_SKIP;
}
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
int ret;
- wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+ wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
"set_tx=%d seq_len=%lu key_len=%lu",
- __func__, ifindex, alg, addr, key_idx, set_tx,
+ __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
(unsigned long) seq_len, (unsigned long) key_len);
#ifdef CONFIG_TDLS
if (key_idx == -1)
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
break;
+ case WPA_ALG_SMS4:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_SMS4);
+ break;
+ case WPA_ALG_KRK:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_KRK);
+ break;
default:
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
"algorithm %d", __func__, alg);
NL80211_KEYTYPE_GROUP);
}
} else if (addr && is_broadcast_ether_addr(addr)) {
- struct nl_msg *types;
- int err;
+ struct nlattr *types;
+
wpa_printf(MSG_DEBUG, " broadcast key");
- types = nlmsg_alloc();
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ nla_nest_end(msg, types);
}
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
else
NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
if (addr && is_broadcast_ether_addr(addr)) {
- struct nl_msg *types;
- int err;
- types = nlmsg_alloc();
+ struct nlattr *types;
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ nla_nest_end(msg, types);
} else if (addr) {
- struct nl_msg *types;
- int err;
- types = nlmsg_alloc();
+ struct nlattr *types;
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+ nla_nest_end(msg, types);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
case WPA_ALG_CCMP:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
if (local_state_change)
NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int reason_code)
+ int reason_code)
{
- wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
- __func__, MAC2STR(addr), reason_code);
- drv->associated = 0;
- return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+ wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
+ nl80211_mark_disconnected(drv);
+ drv->ignore_next_local_disconnect = 0;
+ /* Disconnect command doesn't need BSSID - it uses cached value */
+ return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
reason_code, 0);
}
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+ const u8 *addr, int reason_code)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+ return wpa_driver_nl80211_disconnect(drv, reason_code);
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
- drv->associated = 0;
+ nl80211_mark_disconnected(drv);
if (drv->nlmode == NL80211_IFTYPE_ADHOC)
return nl80211_leave_ibss(drv);
return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
}
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
- wpa_printf(MSG_DEBUG, "%s", __func__);
- drv->associated = 0;
- return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
- reason_code, 0);
-}
-
-
static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_auth_params *params)
{
static int wpa_driver_nl80211_authenticate(
- void *priv, struct wpa_driver_auth_params *params)
+ struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, i;
struct nl_msg *msg;
is_retry = drv->retry_auth;
drv->retry_auth = 0;
- drv->associated = 0;
+ nl80211_mark_disconnected(drv);
os_memset(drv->auth_bssid, 0, ETH_ALEN);
+ if (params->bssid)
+ os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+ else
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
/* FIX: IBSS mode */
nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
if (drv->nlmode != nlmode &&
- wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+ wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
return -1;
retry:
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+ wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
NULL, i,
i == params->wep_tx_keyidx, NULL, 0,
params->wep_key[i],
wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
if (params->ie)
NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+ if (params->sae_data) {
+ wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
+ params->sae_data_len);
+ NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+ params->sae_data);
+ }
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
type = NL80211_AUTHTYPE_OPEN_SYSTEM;
else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
type = NL80211_AUTHTYPE_NETWORK_EAP;
else if (params->auth_alg & WPA_AUTH_ALG_FT)
type = NL80211_AUTHTYPE_FT;
+ else if (params->auth_alg & WPA_AUTH_ALG_SAE)
+ type = NL80211_AUTHTYPE_SAE;
else
goto nla_put_failure;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
struct phy_info_arg {
u16 *num_modes;
struct hostapd_hw_modes *modes;
+ int last_mode, last_chan_idx;
};
-static int phy_info_handler(struct nl_msg *msg, void *arg)
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+ struct nlattr *ampdu_factor,
+ struct nlattr *ampdu_density,
+ struct nlattr *mcs_set)
{
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct phy_info_arg *phy_info = arg;
+ if (capa)
+ mode->ht_capab = nla_get_u16(capa);
- struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ if (ampdu_factor)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
- struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ if (ampdu_density)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+ if (mcs_set && nla_len(mcs_set) >= 16) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *capa,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->vht_capab = nla_get_u32(capa);
+
+ if (mcs_set && nla_len(mcs_set) >= 8) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->vht_mcs_set, mcs, 8);
+ }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+ struct hostapd_channel_data *chan,
+ struct nlattr *tb_freq[])
+{
+ u8 channel;
+ chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ chan->flag = 0;
+ if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+ chan->chan = channel;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->flag |= HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ chan->flag |= HOSTAPD_CHAN_RADAR;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+ !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->max_tx_power = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+ enum nl80211_dfs_state state =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+ switch (state) {
+ case NL80211_DFS_USABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+ break;
+ case NL80211_DFS_AVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+ break;
+ case NL80211_DFS_UNAVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+ break;
+ }
+ }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+ struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
};
-
- struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
- static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
- [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
- [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
- };
-
- struct nlattr *nl_band;
+ int new_channels = 0;
+ struct hostapd_channel_data *channel;
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
struct nlattr *nl_freq;
- struct nlattr *nl_rate;
- int rem_band, rem_freq, rem_rate;
- struct hostapd_hw_modes *mode;
- int idx, mode_is_set;
+ int rem_freq, idx;
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb == NULL)
+ return NL_OK;
- if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ new_channels++;
+ }
+
+ channel = os_realloc_array(mode->channels,
+ mode->num_channels + new_channels,
+ sizeof(struct hostapd_channel_data));
+ if (!channel)
return NL_SKIP;
- nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
- mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
- if (!mode)
- return NL_SKIP;
- phy_info->modes = mode;
+ mode->channels = channel;
+ mode->num_channels += new_channels;
- mode_is_set = 0;
+ idx = phy_info->last_chan_idx;
- mode = &phy_info->modes[*(phy_info->num_modes)];
- memset(mode, 0, sizeof(*mode));
- mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
- *(phy_info->num_modes) += 1;
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ phy_info_freq(mode, &mode->channels[idx], tb_freq);
+ idx++;
+ }
+ phy_info->last_chan_idx = idx;
- nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
- nla_len(nl_band), NULL);
+ return NL_OK;
+}
- if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
- mode->ht_capab = nla_get_u16(
- tb_band[NL80211_BAND_ATTR_HT_CAPA]);
- }
- if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
- mode->a_mpdu_params |= nla_get_u8(
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
- 0x03;
- }
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ struct nlattr *nl_rate;
+ int rem_rate, idx;
- if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
- mode->a_mpdu_params |= nla_get_u8(
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
- 2;
- }
+ if (tb == NULL)
+ return NL_OK;
- if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
- nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
- u8 *mcs;
- mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
- os_memcpy(mode->mcs_set, mcs, 16);
- }
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
- nla_len(nl_freq), freq_policy);
- if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
- mode->num_channels++;
- }
+ mode->rates = os_calloc(mode->num_rates, sizeof(int));
+ if (!mode->rates)
+ return NL_SKIP;
- mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
- if (!mode->channels)
- return NL_SKIP;
+ idx = 0;
- idx = 0;
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx] = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+ idx++;
+ }
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
- nla_len(nl_freq), freq_policy);
- if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
+ return NL_OK;
+}
- mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
- mode->channels[idx].flag = 0;
- if (!mode_is_set) {
- /* crude heuristic */
- if (mode->channels[idx].freq < 4000)
- mode->mode = HOSTAPD_MODE_IEEE80211B;
- else
- mode->mode = HOSTAPD_MODE_IEEE80211A;
- mode_is_set = 1;
- }
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ struct hostapd_hw_modes *mode;
+ int ret;
- /* crude heuristic */
- if (mode->channels[idx].freq < 4000)
- if (mode->channels[idx].freq == 2484)
- mode->channels[idx].chan = 14;
- else
- mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
- else
- mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_DISABLED;
- if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_PASSIVE_SCAN;
- if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_NO_IBSS;
- if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_RADAR;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
- !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- mode->channels[idx].max_tx_power =
- nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
-
- idx++;
- }
+ if (phy_info->last_mode != nl_band->nla_type) {
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
- nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
- nla_len(nl_rate), rate_policy);
- if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
- continue;
- mode->num_rates++;
- }
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ mode->mode = NUM_HOSTAPD_MODES;
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
+ *(phy_info->num_modes) += 1;
+ phy_info->last_mode = nl_band->nla_type;
+ phy_info->last_chan_idx = 0;
+ } else
+ mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+ tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+ tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ if (ret != NL_OK)
+ return ret;
+ ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+ if (ret != NL_OK)
+ return ret;
- mode->rates = os_zalloc(mode->num_rates * sizeof(int));
- if (!mode->rates)
- return NL_SKIP;
+ return NL_OK;
+}
- idx = 0;
- nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
- nla_len(nl_rate), rate_policy);
- if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
- continue;
- mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+ struct nlattr *nl_band;
+ int rem_band;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
- /* crude heuristic */
- if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
- mode->rates[idx] > 200)
- mode->mode = HOSTAPD_MODE_IEEE80211G;
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
- idx++;
- }
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+ {
+ int res = phy_info_band(phy_info, nl_band);
+ if (res != NL_OK)
+ return res;
}
return NL_SKIP;
}
+
static struct hostapd_hw_modes *
-wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+ u16 *num_modes)
{
u16 m;
struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
int i, mode11g_idx = -1;
+ /* heuristic to set up modes */
+ for (m = 0; m < *num_modes; m++) {
+ if (!modes[m].num_channels)
+ continue;
+ if (modes[m].channels[0].freq < 4000) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+ for (i = 0; i < modes[m].num_rates; i++) {
+ if (modes[m].rates[i] > 200) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+ break;
+ }
+ }
+ } else if (modes[m].channels[0].freq > 50000)
+ modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
/* If only 802.11g mode is included, use it to construct matching
* 802.11b mode data. */
if (mode11g_idx < 0)
return modes; /* 2.4 GHz band not supported at all */
- nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+ nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
if (nmodes == NULL)
return modes; /* Could not add 802.11b mode */
static struct hostapd_hw_modes *
wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
{
+ u32 feat;
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct phy_info_arg result = {
.num_modes = num_modes,
.modes = NULL,
+ .last_mode = -1,
};
*num_modes = 0;
if (!msg)
return NULL;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+ else
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
nl80211_set_ht40_flags(drv, &result);
- return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+ return wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
}
msg = NULL;
nla_put_failure:
if (noack)
txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
- *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+ WPA_PUT_LE16(&rtap_hdr[12], txflags);
res = sendmsg(drv->monitor_sock, &msg, 0);
if (res < 0) {
}
-static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
- const u8 *data,
- size_t data_len, int noack,
- unsigned int freq, int no_cck,
- int offchanok,
- unsigned int wait_time)
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+ size_t data_len, int noack,
+ unsigned int freq, int no_cck,
+ int offchanok,
+ unsigned int wait_time)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
}
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
-{
- struct i802_bss *bss = priv;
- return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
- 0, 0, 0, 0);
-}
-
-
static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
int slot, int ht_opmode, int ap_isolate,
int *basic_rates)
}
+static int wpa_driver_nl80211_set_acl(void *priv,
+ struct hostapd_acl_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *acl;
+ unsigned int i;
+ int ret = 0;
+
+ if (!(drv->capa.max_acl_mac_addrs))
+ return -ENOTSUP;
+
+ if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+ return -ENOTSUP;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+ params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+ acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+ if (acl == NULL)
+ goto nla_put_failure;
+
+ for (i = 0; i < params->num_mac_acl; i++)
+ NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+ nla_nest_end(msg, acl);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
cmd = NL80211_CMD_SET_BEACON;
nl80211_cmd(drv, msg, 0, cmd);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
+ params->head, params->head_len);
NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
+ params->tail, params->tail_len);
NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
+ wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+ wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+ wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
+ params->ssid, params->ssid_len);
NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid);
- if (params->proberesp && params->proberesp_len)
+ if (params->proberesp && params->proberesp_len) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
+ params->proberesp, params->proberesp_len);
NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
params->proberesp);
+ }
switch (params->hide_ssid) {
case NO_SSID_HIDING:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
NL80211_HIDDEN_SSID_NOT_IN_USE);
break;
case HIDDEN_SSID_ZERO_LEN:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
NL80211_HIDDEN_SSID_ZERO_LEN);
break;
case HIDDEN_SSID_ZERO_CONTENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
NL80211_HIDDEN_SSID_ZERO_CONTENTS);
break;
}
+ wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
if (params->privacy)
NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
(WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
/* Leave out the attribute */
NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
NL80211_AUTHTYPE_OPEN_SYSTEM);
+ wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
ver = 0;
if (params->wpa_version & WPA_PROTO_WPA)
ver |= NL80211_WPA_VERSION_1;
if (ver)
NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+ params->key_mgmt_suites);
num_suites = 0;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
suites[num_suites++] = WLAN_AKM_SUITE_8021X;
params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+ wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+ params->pairwise_ciphers);
num_suites = 0;
if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
num_suites * sizeof(u32), suites);
}
+ wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+ params->group_cipher);
switch (params->group_cipher) {
case WPA_CIPHER_CCMP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_CIPHER_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_CIPHER_TKIP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_TKIP);
}
if (params->beacon_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
+ params->beacon_ies);
NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
wpabuf_head(params->beacon_ies));
}
if (params->proberesp_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
+ params->proberesp_ies);
NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
wpabuf_len(params->proberesp_ies),
wpabuf_head(params->proberesp_ies));
}
if (params->assocresp_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
+ params->assocresp_ies);
NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
wpabuf_len(params->assocresp_ies),
wpabuf_head(params->assocresp_ies));
}
if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
+ wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
+ params->ap_max_inactivity);
NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
params->ap_max_inactivity);
}
static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
- int freq, int ht_enabled,
- int sec_channel_offset)
+ struct hostapd_freq_params *freq)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
- "sec_channel_offset=%d)",
- freq, ht_enabled, sec_channel_offset);
+ wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
+ " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled,
+ freq->bandwidth, freq->center_freq1, freq->center_freq2);
msg = nlmsg_alloc();
if (!msg)
return -1;
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- if (ht_enabled) {
- switch (sec_channel_offset) {
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+ if (freq->vht_enabled) {
+ switch (freq->bandwidth) {
+ case 20:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_20);
+ break;
+ case 40:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_40);
+ break;
+ case 80:
+ if (freq->center_freq2)
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_80P80);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_80);
+ break;
+ case 160:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_160);
+ break;
+ default:
+ return -1;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
+ if (freq->center_freq2)
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
+ freq->center_freq2);
+ } else if (freq->ht_enabled) {
+ switch (freq->sec_channel_offset) {
case -1:
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
NL80211_CHAN_HT40MINUS);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret == 0) {
- bss->freq = freq;
+ bss->freq = freq->freq;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
- "%d (%s)", freq, ret, strerror(-ret));
+ "%d (%s)", freq->freq, ret, strerror(-ret));
nla_put_failure:
nlmsg_free(msg);
return -1;
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *wme = NULL;
+ struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
int ret = -ENOBUFS;
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
+ params->set ? "Set" : "Add", MAC2STR(params->addr));
nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
NL80211_CMD_NEW_STATION);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
params->supp_rates);
+ wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
+ params->supp_rates_len);
if (!params->set) {
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ if (params->aid) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ } else {
+ /*
+ * cfg80211 validates that AID is non-zero, so we have
+ * to make this a non-zero value for the TDLS case where
+ * a dummy STA entry is used for now.
+ */
+ wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)");
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ }
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
params->listen_interval);
+ } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+ wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
+ NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
}
if (params->ht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
+ (u8 *) params->ht_capabilities,
+ sizeof(*params->ht_capabilities));
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
sizeof(*params->ht_capabilities),
params->ht_capabilities);
}
+ if (params->vht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
+ (u8 *) params->vht_capabilities,
+ sizeof(*params->vht_capabilities));
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
+ sizeof(*params->vht_capabilities),
+ params->vht_capabilities);
+ }
+
+ wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+
+ if (params->ext_capab) {
+ wpa_hexdump(MSG_DEBUG, " * ext_capab",
+ params->ext_capab, params->ext_capab_len);
+ NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+ params->ext_capab_len, params->ext_capab);
+ }
+
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(params->flags);
upd.set = upd.mask;
+ wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
+ upd.set, upd.mask);
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
if (params->flags & WPA_STA_WMM) {
- wme = nlmsg_alloc();
+ struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
if (!wme)
goto nla_put_failure;
- NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+ wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
+ NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
- NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
- (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+ NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
- nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+ nla_nest_end(msg, wme);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret == -EEXIST)
ret = 0;
nla_put_failure:
- nlmsg_free(wme);
nlmsg_free(msg);
return ret;
}
-static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
return "STATION";
case NL80211_IFTYPE_AP:
return "AP";
+ case NL80211_IFTYPE_AP_VLAN:
+ return "AP_VLAN";
+ case NL80211_IFTYPE_WDS:
+ return "WDS";
case NL80211_IFTYPE_MONITOR:
return "MONITOR";
+ case NL80211_IFTYPE_MESH_POINT:
+ return "MESH_POINT";
case NL80211_IFTYPE_P2P_CLIENT:
return "P2P_CLIENT";
case NL80211_IFTYPE_P2P_GO:
return "P2P_GO";
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return "P2P_DEVICE";
default:
return "unknown";
}
static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
const char *ifname,
enum nl80211_iftype iftype,
- const u8 *addr, int wds)
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg)
{
- struct nl_msg *msg, *flags = NULL;
+ struct nl_msg *msg;
int ifidx;
int ret = -ENOBUFS;
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
if (iftype == NL80211_IFTYPE_MONITOR) {
- int err;
+ struct nlattr *flags;
- flags = nlmsg_alloc();
+ flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
if (!flags)
goto nla_put_failure;
- NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+ NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
- err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
- nlmsg_free(flags);
-
- if (err)
- goto nla_put_failure;
+ nla_nest_end(msg, flags);
} else if (wds) {
NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, handler, arg);
msg = NULL;
if (ret) {
nla_put_failure:
return ret;
}
+ if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: New P2P Device interface %s created",
+ ifname);
+ return 0;
+ }
+
ifidx = if_nametoindex(ifname);
wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
ifname, ifidx);
static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
- const u8 *addr, int wds)
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg)
{
int ret;
- ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+ arg);
/* if error occurred and interface exists already */
if (ret == -ENFILE && if_nametoindex(ifname)) {
/* Try to create the interface again */
ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
- wds);
+ wds, handler, arg);
}
- if (ret >= 0 && is_p2p_interface(iftype))
+ if (ret >= 0 && is_p2p_net_interface(iftype))
nl80211_disable_11b_rates(drv, ret, 1);
return ret;
drv->monitor_ifidx =
nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0);
+ 0, NULL, NULL);
if (drv->monitor_ifidx == -EOPNOTSUPP) {
/*
pos = (u8 *) (hdr + 1);
if (qos) {
- /* add an empty QoS header if needed */
- pos[0] = 0;
+ /* Set highest priority in QoS header */
+ pos[0] = 7;
pos[1] = 0;
pos += 2;
}
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *flags = NULL;
+ struct nl_msg *msg;
+ struct nlattr *flags;
struct nl80211_sta_flag_update upd;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- flags = nlmsg_alloc();
- if (!flags) {
- nlmsg_free(msg);
- return -ENOMEM;
- }
-
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
* Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
* can be removed eventually.
*/
+ flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+ if (!flags)
+ goto nla_put_failure;
if (total_flags & WPA_STA_AUTHORIZED)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
if (total_flags & WPA_STA_WMM)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
if (total_flags & WPA_STA_SHORT_PREAMBLE)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
if (total_flags & WPA_STA_MFP)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
if (total_flags & WPA_STA_TDLS_PEER)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
- if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
- goto nla_put_failure;
+ nla_nest_end(msg, flags);
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
upd.set = sta_flags_nl80211(flags_or);
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
- nlmsg_free(flags);
-
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
nlmsg_free(msg);
- nlmsg_free(flags);
return -ENOBUFS;
}
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
- enum nl80211_iftype nlmode;
+ enum nl80211_iftype nlmode, old_mode;
+ struct hostapd_freq_params freq = {
+ .freq = params->freq,
+ };
if (params->p2p) {
wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
} else
nlmode = NL80211_IFTYPE_AP;
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
- wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
+ old_mode = drv->nlmode;
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+ }
+
+ if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+ if (old_mode != nlmode)
+ wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
return -1;
}
goto nla_put_failure;
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
- u8 *bssid)
-{
- struct nl_msg *msg;
- int ret;
- struct nl80211_bss_info_arg arg;
-
- os_memset(&arg, 0, sizeof(arg));
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- arg.drv = drv;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
- msg = NULL;
- if (ret == 0) {
- if (is_zero_ether_addr(arg.assoc_bssid))
- return -ENOTCONN;
- os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
- return 0;
- }
- wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
- "(%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
- return drv->assoc_freq;
-}
-
-
-static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- const u8 *bssid)
-{
- u8 addr[ETH_ALEN];
-
- if (bssid == NULL) {
- int res = nl80211_get_assoc_bssid(drv, addr);
- if (res)
- return res;
- bssid = addr;
- }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
- return wpa_driver_nl80211_disconnect(drv, bssid,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
}
-static int wpa_driver_nl80211_connect(
+static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
int cipher;
switch (params->pairwise_suite) {
+ case CIPHER_SMS4:
+ cipher = WLAN_CIPHER_SUITE_SMS4;
+ break;
case CIPHER_WEP40:
cipher = WLAN_CIPHER_SUITE_WEP40;
break;
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
int cipher;
switch (params->group_suite) {
+ case CIPHER_SMS4:
+ cipher = WLAN_CIPHER_SUITE_SMS4;
+ break;
case CIPHER_WEP40:
cipher = WLAN_CIPHER_SUITE_WEP40;
break;
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
}
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
- params->key_mgmt_suite == KEY_MGMT_PSK) {
+ params->key_mgmt_suite == KEY_MGMT_PSK ||
+ params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
+ params->key_mgmt_suite == KEY_MGMT_CCKM) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
+ case KEY_MGMT_CCKM:
+ mgmt = WLAN_AKM_SUITE_CCKM;
+ break;
case KEY_MGMT_802_1X:
mgmt = WLAN_AKM_SUITE_8021X;
break;
+ case KEY_MGMT_FT_802_1X:
+ mgmt = WLAN_AKM_SUITE_FT_8021X;
+ break;
+ case KEY_MGMT_FT_PSK:
+ mgmt = WLAN_AKM_SUITE_FT_PSK;
+ break;
case KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
}
+#ifdef CONFIG_IEEE80211W
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+ NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
if (params->disable_ht)
NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
params->htcaps_mask);
}
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask);
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
ret = nl80211_set_conn_keys(params, msg);
if (ret)
goto nla_put_failure;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
- /*
- * cfg80211 does not currently accept new connection if we are
- * already connected. As a workaround, force disconnection and
- * try again once the driver indicates it completed
- * disconnection.
- */
- if (ret == -EALREADY)
- nl80211_disconnect(drv, params->bssid);
goto nla_put_failure;
}
ret = 0;
}
+static int wpa_driver_nl80211_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret = wpa_driver_nl80211_try_connect(drv, params);
+ if (ret == -EALREADY) {
+ /*
+ * cfg80211 does not currently accept new connections if
+ * we are already connected. As a workaround, force
+ * disconnection and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+ "disconnecting before reassociation "
+ "attempt");
+ if (wpa_driver_nl80211_disconnect(
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+ return -1;
+ /* Ignore the next local disconnect message. */
+ drv->ignore_next_local_disconnect = 1;
+ ret = wpa_driver_nl80211_try_connect(drv, params);
+ }
+ return ret;
+}
+
+
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
return wpa_driver_nl80211_connect(drv, params);
}
- drv->associated = 0;
+ nl80211_mark_disconnected(drv);
msg = nlmsg_alloc();
if (!msg)
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
params->htcaps_mask);
}
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask);
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
if (params->p2p)
wpa_printf(MSG_DEBUG, " * P2P group");
return ret;
}
+ if (is_p2p_net_interface(nlmode))
+ nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+ else if (drv->disabled_11b_rates)
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
/* Setup additional AP mode functionality if needed */
if (!drv->has_capability)
return -1;
os_memcpy(capa, &drv->capa, sizeof(*capa));
+ if (drv->extended_capa && drv->extended_capa_mask) {
+ capa->extended_capa = drv->extended_capa;
+ capa->extended_capa_mask = drv->extended_capa_mask;
+ capa->extended_capa_len = drv->extended_capa_len;
+ }
return 0;
}
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
+ wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+ MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
- freq->sec_channel_offset);
+ return wpa_driver_nl80211_set_freq(bss, freq);
}
return -ENOBUFS;
}
+#endif /* HOSTAPD || CONFIG_AP */
+
static int get_sta_handler(struct nl_msg *msg, void *arg)
{
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
};
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
if (stats[NL80211_STA_INFO_TX_PACKETS])
data->tx_packets =
nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+ if (stats[NL80211_STA_INFO_TX_FAILED])
+ data->tx_retry_failed =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
return NL_SKIP;
}
-static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+static int i802_read_sta_data(struct i802_bss *bss,
+ struct hostap_sta_driver_data *data,
const u8 *addr)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
}
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+
static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
}
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
+static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
const char *ifname, int vlan_id)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -ENOBUFS;
mgmt.u.deauth.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0);
+ sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+ 0);
}
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0);
+ sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+ 0);
}
#endif /* HOSTAPD || CONFIG_AP */
else
old = NULL;
- drv->if_indices = os_realloc(old,
- sizeof(int) * (drv->num_if_indices + 1));
+ drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+ sizeof(int));
if (!drv->if_indices) {
if (!old)
drv->if_indices = drv->default_if_indices;
if (!if_nametoindex(name)) {
if (nl80211_create_iface(drv, name,
NL80211_IFTYPE_AP_VLAN,
- NULL, 1) < 0)
+ bss->addr, 1, NULL, NULL) < 0)
return -1;
if (bridge_ifname &&
linux_br_add_if(drv->global->ioctl_sock,
bridge_ifname, name) < 0)
return -1;
}
- linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+ if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+ "interface %s up", name);
+ }
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
+ if (bridge_ifname)
+ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+ name);
+
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
name);
static void i802_deinit(void *priv)
{
- wpa_driver_nl80211_deinit(priv);
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
}
#endif /* HOSTAPD */
return NL80211_IFTYPE_AP;
case WPA_IF_P2P_GO:
return NL80211_IFTYPE_P2P_GO;
+ case WPA_IF_P2P_DEVICE:
+ return NL80211_IFTYPE_P2P_DEVICE;
}
return -1;
}
os_memcpy(if_addr, addr, ETH_ALEN);
ifidx = nl80211_create_iface(drv, ifname,
wpa_driver_nl80211_if_type(type), addr,
- 0);
+ 0, NULL, NULL);
if (ifidx < 0) {
#ifdef HOSTAPD
os_free(new_bss);
new_bss->drv = drv;
new_bss->next = drv->first_bss.next;
new_bss->freq = drv->first_bss.freq;
+ new_bss->ctx = bss_ctx;
drv->first_bss.next = new_bss;
if (drv_priv)
*drv_priv = new_bss;
}
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
enum wpa_driver_if_type type,
const char *ifname)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
if (ifindex <= 0)
return -1;
+ nl80211_remove_iface(drv, ifindex);
+
#ifdef HOSTAPD
+ if (type != WPA_IF_AP_BSS)
+ return 0;
+
if (bss->added_if_into_bridge) {
if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
bss->ifname) < 0)
"bridge %s: %s",
bss->brname, strerror(errno));
}
-#endif /* HOSTAPD */
-
- nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
- if (type != WPA_IF_AP_BSS)
- return 0;
if (bss != &drv->first_bss) {
struct i802_bss *tbss;
if (!msg)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+ wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
"no_ack=%d offchanok=%d",
freq, wait, no_cck, no_ack, offchanok);
nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ if (nl80211_set_iface_id(msg, bss))
+ goto nla_put_failure;
+
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
if (wait)
NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
freq, wait);
goto nla_put_failure;
}
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
"cookie 0x%llx", no_ack ? " (no ACK)" : "",
(long long unsigned int) cookie);
}
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+ unsigned int freq,
unsigned int wait_time,
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len,
int no_cck)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
u8 *buf;
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
if (is_ap_interface(drv->nlmode))
- ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
- 24 + data_len,
- 0, freq, no_cck, 1,
- wait_time);
+ ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
+ 0, freq, no_cck, 1,
+ wait_time);
else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len,
if (!msg)
return;
+ wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
+ (long long unsigned int) drv->send_action_cookie);
nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nl80211_set_iface_id(msg, bss))
+ goto nla_put_failure;
+
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nl80211_set_iface_id(msg, bss))
+ goto nla_put_failure;
+
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
}
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!report) {
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
- }
+ } else
+ drv->disabled_11b_rates = disabled;
return ret;
}
+static int wpa_driver_nl80211_stop_ap(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!is_ap_interface(drv->nlmode))
+ return -1;
+ wpa_driver_nl80211_del_beacon(drv);
+ bss->beacon_set = 0;
+ return 0;
+}
+
+
static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
{
struct i802_bss *bss = priv;
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *cqm = NULL;
+ struct nl_msg *msg;
+ struct nlattr *cqm;
+ int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
"hysteresis=%d", threshold, hysteresis);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- cqm = nlmsg_alloc();
+ cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
if (cqm == NULL)
- return -1;
+ goto nla_put_failure;
- NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
- NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
- nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+ NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+ NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+ nla_nest_end(msg, cqm);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
- return 0;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
nla_put_failure:
- nlmsg_free(cqm);
nlmsg_free(msg);
- return -1;
+ return ret;
+}
+
+
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return CHAN_WIDTH_20_NOHT;
+ case NL80211_CHAN_WIDTH_20:
+ return CHAN_WIDTH_20;
+ case NL80211_CHAN_WIDTH_40:
+ return CHAN_WIDTH_40;
+ case NL80211_CHAN_WIDTH_80:
+ return CHAN_WIDTH_80;
+ case NL80211_CHAN_WIDTH_80P80:
+ return CHAN_WIDTH_80P80;
+ case NL80211_CHAN_WIDTH_160:
+ return CHAN_WIDTH_160;
+ }
+ return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_signal_info *sig_change = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ sig_change->center_frq1 = -1;
+ sig_change->center_frq2 = -1;
+ sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+ sig_change->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ sig_change->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ sig_change->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
}
if (res != 0)
return res;
+ res = nl80211_get_channel_width(drv, si);
+ if (res != 0)
+ return res;
+
return nl80211_get_link_noise(drv, si);
}
os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+ if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+ 0, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame");
}
}
+static int nl80211_start_radar_detection(void *priv, int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+ "detection");
+ return -1;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+ /* only HT20 is supported at this point */
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+ "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
#ifdef CONFIG_TDLS
static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
#endif /* ANDROID */
+static int driver_nl80211_set_key(const char *ifname, void *priv,
+ enum wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
+ set_tx, seq, seq_len, key, key_len);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+ struct wpa_driver_scan_params *params)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+ struct wpa_driver_auth_params *params)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len, int noack)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+ 0, 0, 0, 0);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_sta_remove(bss, addr);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_bss *bss = priv;
+ return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+ unsigned int wait_time,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ int no_cck)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+ bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
+static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
+ const u8 *ies, size_t ies_len)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 mdid = WPA_GET_LE16(md);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+ NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
+ "err=%d (%s)", ret, strerror(-ret));
+ }
+
+ return ret;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
- .set_key = wpa_driver_nl80211_set_key,
- .scan2 = wpa_driver_nl80211_scan,
+ .set_key = driver_nl80211_set_key,
+ .scan2 = driver_nl80211_scan2,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
- .deauthenticate = wpa_driver_nl80211_deauthenticate,
- .disassociate = wpa_driver_nl80211_disassociate,
- .authenticate = wpa_driver_nl80211_authenticate,
+ .deauthenticate = driver_nl80211_deauthenticate,
+ .authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
.init2 = wpa_driver_nl80211_init,
- .deinit = wpa_driver_nl80211_deinit,
+ .deinit = driver_nl80211_deinit,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
.set_ap = wpa_driver_nl80211_set_ap,
+ .set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
- .if_remove = wpa_driver_nl80211_if_remove,
- .send_mlme = wpa_driver_nl80211_send_mlme,
+ .if_remove = driver_nl80211_if_remove,
+ .send_mlme = driver_nl80211_send_mlme,
.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
- .sta_remove = wpa_driver_nl80211_sta_remove,
+ .sta_remove = driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
#ifdef HOSTAPD
#if defined(HOSTAPD) || defined(CONFIG_AP)
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
- .read_sta_data = i802_read_sta_data,
.get_inact_sec = i802_get_inact_sec,
.sta_clear_stats = i802_sta_clear_stats,
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
.set_tx_queue_params = i802_set_tx_queue_params,
- .set_sta_vlan = i802_set_sta_vlan,
+ .set_sta_vlan = driver_nl80211_set_sta_vlan,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
+ .read_sta_data = driver_nl80211_read_sta_data,
.set_freq = i802_set_freq,
- .send_action = wpa_driver_nl80211_send_action,
+ .send_action = driver_nl80211_send_action,
.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
- .probe_req_report = wpa_driver_nl80211_probe_req_report,
+ .probe_req_report = driver_nl80211_probe_req_report,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
.set_rekey_info = nl80211_set_rekey_info,
.poll_client = nl80211_poll_client,
.set_p2p_powersave = nl80211_set_p2p_powersave,
+ .start_dfs_cac = nl80211_start_radar_detection,
+ .stop_ap = wpa_driver_nl80211_stop_ap,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
#endif /* CONFIG_TDLS */
+ .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
};