unsigned int pending_remain_on_chan:1;
unsigned int in_interface_list:1;
unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
}
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.client_poll.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
static int process_event(struct nl_msg *msg, void *arg)
{
struct wpa_driver_nl80211_data *drv = arg;
case NL80211_CMD_PMKSA_CANDIDATE:
nl80211_pmksa_candidate_event(drv, tb);
break;
+ case NL80211_CMD_PROBE_CLIENT:
+ nl80211_client_probe_event(drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
unsigned int error:1;
unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
};
case NL80211_CMD_START_SCHED_SCAN:
capa->sched_scan_supported = 1;
break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
}
}
}
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
drv->device_ap_sme = info.device_ap_sme;
+ drv->poll_command_supported = info.poll_command_supported;
return 0;
}
static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len)
+ size_t data_len, int noack)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
mgmt.u.deauth.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth));
+ sizeof(mgmt.u.deauth), 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));
+ sizeof(mgmt.u.disassoc), 0);
}
#endif /* HOSTAPD || CONFIG_AP */
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
if (is_ap_interface(drv->nlmode))
- ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+ ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+ 0);
else
ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
24 + data_len,
}
-static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
- int qos)
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+ const u8 *addr, int qos)
{
- struct i802_bss *bss = priv;
+ /* send data frame to poll STA and check whether
+ * this frame is ACKed */
struct {
struct ieee80211_hdr hdr;
u16 qos_ctl;
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)
+ if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame");
}
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+ int qos)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!drv->poll_command_supported) {
+ nl80211_send_null_frame(bss, own_addr, addr, qos);
+ return;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ send_and_recv_msgs(drv, msg, NULL, NULL);
+ return;
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+
#ifdef CONFIG_TDLS