#endif /* CONFIG_LIBNL20 */
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+ return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+#endif /* ANDROID */
+
+
static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
{
struct nl_handle *handle;
}
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_handle **handle,
+ eloop_sock_handler handler,
+ void *eloop_data)
+{
+ nl_socket_set_nonblocking(*handle);
+ eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+ eloop_data, *handle);
+ *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+{
+ *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+ eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+ nl_destroy_handles(handle);
+}
+
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
#endif
struct nl80211_global {
struct dl_list interfaces;
int if_add_ifindex;
+ u64 if_add_wdevid;
+ int if_add_wdevid_set;
struct netlink_data *netlink;
struct nl_cb *nl_cb;
struct nl_handle *nl;
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;
+ unsigned int added_if:1;
u8 addr[ETH_ALEN];
int freq;
+ int if_dynamic;
void *ctx;
struct nl_handle *nl_preq, *nl_mgmt;
int operstate;
int scan_complete_events;
+ enum scan_states {
+ NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+ SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+ SCHED_SCAN_RESULTS
+ } scan_state;
struct nl_cb *nl_cb;
unsigned int retry_auth:1;
unsigned int use_monitor:1;
unsigned int ignore_next_local_disconnect:1;
+ unsigned int allow_p2p_device:1;
+ unsigned int hostapd:1;
+ unsigned int start_mode_ap:1;
+ unsigned int start_iface_up:1;
+ unsigned int channel_switch_supported:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
struct wpa_driver_scan_filter *filter_ssids;
size_t num_filter_ssids;
- struct i802_bss first_bss;
+ struct i802_bss *first_bss;
int eapol_tx_sock;
-#ifdef HOSTAPD
int eapol_sock; /* socket for EAPOL frames */
int default_if_indices[16];
int *if_indices;
int num_if_indices;
- int last_freq;
- int last_freq_ht;
-#endif /* HOSTAPD */
-
/* From failed authentication command */
int auth_freq;
u8 auth_bssid_[ETH_ALEN];
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
enum nl80211_iftype nlmode);
static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+ const u8 *set_addr, int first);
static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change);
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 nl80211_register_frame(struct i802_bss *bss,
+ struct nl_handle *hl_handle,
+ u16 type, const u8 *match, size_t match_len);
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 int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+ size_t buf_len);
#endif /* ANDROID */
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
-#ifdef HOSTAPD
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(struct i802_bss *bss,
enum wpa_driver_if_type type,
const char *ifname);
-#else /* HOSTAPD */
-static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
- return 0;
-}
-#endif /* HOSTAPD */
static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
struct hostapd_freq_params *freq);
static int wpa_driver_nl80211_authenticate_retry(
struct wpa_driver_nl80211_data *drv);
+static int i802_set_iface_flags(struct i802_bss *bss, int up);
+
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
}
+/* 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 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);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
valid_handler, valid_data);
- while (err > 0)
- nl_recvmsgs(nl_handle, cb);
+ while (err > 0) {
+ int res = nl_recvmsgs(nl_handle, cb);
+ if (res) {
+ wpa_printf(MSG_INFO,
+ "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
+ }
out:
nl_cb_put(cb);
nlmsg_free(msg);
};
+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;
struct wiphy_idx_data {
int wiphy_idx;
+ enum nl80211_iftype nlmode;
+ u8 *macaddr;
};
if (tb[NL80211_ATTR_WIPHY])
info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+ if (tb[NL80211_ATTR_IFTYPE])
+ info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+ if (tb[NL80211_ATTR_MAC] && info->macaddr)
+ os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+
return NL_SKIP;
}
struct nl_msg *msg;
struct wiphy_idx_data data = {
.wiphy_idx = -1,
+ .macaddr = NULL,
};
msg = nlmsg_alloc();
if (!msg)
- return -1;
+ return NL80211_IFTYPE_UNSPECIFIED;
nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
return data.wiphy_idx;
}
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .nlmode = NL80211_IFTYPE_UNSPECIFIED,
+ .macaddr = NULL,
+ };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
+
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ return data.nlmode;
+ msg = NULL;
+nla_put_failure:
+ nlmsg_free(msg);
+ return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .macaddr = bss->addr,
+ };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NL80211_IFTYPE_UNSPECIFIED;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
+
+ return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
struct nl80211_wiphy_data *w)
{
static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
{
struct nl80211_wiphy_data *w = eloop_ctx;
+ int res;
wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
- nl_recvmsgs(handle, w->nl_cb);
+ res = nl_recvmsgs(handle, w->nl_cb);
+ if (res) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
}
return NULL;
}
- eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
- nl80211_recv_beacons, w, w->nl_beacons);
+ nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
dl_list_add(&nl80211_wiphys, &w->list);
if (!dl_list_empty(&w->bsss))
return;
- eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+ nl80211_destroy_eloop_handle(&w->nl_beacons);
nl_cb_put(w->nl_cb);
- nl_destroy_handles(&w->nl_beacons);
dl_list_del(&w->list);
os_free(w);
}
event.interface_status.ifname,
del ? "removed" : "added");
- if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+ if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) ==
+ 0) {
if (del) {
if (drv->if_removed) {
wpa_printf(MSG_DEBUG, "nl80211: if_removed "
}
drv->if_removed = 1;
} else {
- if (if_nametoindex(drv->first_bss.ifname) == 0) {
+ if (if_nametoindex(drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
"does not exist - ignore "
"RTM_NEWLINK",
- drv->first_bss.ifname);
+ drv->first_bss->ifname);
return;
}
if (!drv->if_removed) {
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
- if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
- == 0)
+ if (os_strcmp(((char *) attr) + rta_len,
+ drv->first_bss->ifname) == 0)
return 1;
else
break;
return 1;
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
- drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
- wpa_driver_nl80211_finish_drv_init(drv);
+ wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
return 1;
}
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss.ifname) > 0) {
+ drv->first_bss->ifname) > 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
return;
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss.ifname) == 0) {
+ drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is down",
namebuf);
- } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+ } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s does not exist",
- drv->first_bss.ifname);
+ drv->first_bss->ifname);
} else if (drv->if_removed) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is marked "
- "removed", drv->first_bss.ifname);
+ "removed", drv->first_bss->ifname);
} else {
wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
"associated BSS from scan results: %u MHz",
arg.assoc_freq);
- return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+ if (arg.assoc_freq)
+ drv->assoc_freq = arg.assoc_freq;
+ return drv->assoc_freq;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
"(%s)", ret, strerror(-ret));
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *freq, struct nlattr *type)
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
{
+ struct i802_bss *bss;
union wpa_event_data data;
int ht_enabled = 1;
int chan_offset = 0;
+ int ifidx;
wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
- if (!freq || !type)
+ if (!freq)
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;
+ ifidx = nla_get_u32(ifindex);
+ for (bss = drv->first_bss; bss; bss = bss->next)
+ if (bss->ifindex == ifidx)
+ break;
+
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ 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;
+ }
}
+ os_memset(&data, 0, sizeof(data));
data.ch_switch.freq = nla_get_u32(freq);
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
+
+ bss->freq = data.ch_switch.freq;
wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
}
union wpa_event_data event;
u16 fc, stype;
int ssi_signal = 0;
+ int rx_freq = 0;
wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
mgmt = (const struct ieee80211_mgmt *) frame;
os_memset(&event, 0, sizeof(event));
if (freq) {
event.rx_action.freq = nla_get_u32(freq);
- drv->last_mgmt_freq = event.rx_action.freq;
+ rx_freq = drv->last_mgmt_freq = event.rx_action.freq;
}
+ wpa_printf(MSG_DEBUG,
+ "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u",
+ rx_freq, ssi_signal, stype, (unsigned int) len);
if (stype == WLAN_FC_STYPE_ACTION) {
event.rx_action.da = mgmt->da;
event.rx_action.sa = mgmt->sa;
if (type == EVENT_DISASSOC) {
event.disassoc_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
event.disassoc_info.addr = bssid;
event.disassoc_info.reason_code = reason_code;
if (frame + len > mgmt->u.disassoc.variable) {
}
} else {
event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
event.deauth_info.addr = bssid;
event.deauth_info.reason_code = reason_code;
if (frame + len > mgmt->u.deauth.variable) {
return;
}
os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
drv->associated = 1;
wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
MAC2STR(drv->bssid));
&info->ssids[info->num_ssids];
s->ssid = nla_data(nl);
s->ssid_len = nla_len(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
info->num_ssids++;
if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
break;
}
}
if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ char msg[200], *pos, *end;
+ int res;
+
+ pos = msg;
+ end = pos + sizeof(msg);
+ *pos = '\0';
+
nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
{
freqs[num_freqs] = nla_get_u32(nl);
+ res = os_snprintf(pos, end - pos, " %d",
+ freqs[num_freqs]);
+ if (res > 0 && end - pos > res)
+ pos += res;
num_freqs++;
if (num_freqs == MAX_REPORT_FREQS - 1)
break;
}
info->freqs = freqs;
info->num_freqs = num_freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+ msg);
}
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}
}
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
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]);
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
- wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
- data.dfs_event.freq);
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
switch (event_type) {
case NL80211_RADAR_DETECTED:
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data data;
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)) {
- wpa_driver_nl80211_set_mode(&drv->first_bss,
+ wpa_driver_nl80211_set_mode(drv->first_bss,
drv->ap_scan_as_station);
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+ drv->scan_state = SCAN_STARTED;
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
break;
case NL80211_CMD_START_SCHED_SCAN:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+ drv->scan_state = SCHED_SCAN_STARTED;
break;
case NL80211_CMD_SCHED_SCAN_STOPPED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+ drv->scan_state = SCHED_SCAN_STOPPED;
wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New scan results available");
+ drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
case NL80211_CMD_SCHED_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New sched scan results available");
+ drv->scan_state = SCHED_SCAN_RESULTS;
send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+ drv->scan_state = SCAN_ABORTED;
/*
* Need to indicate that scan results are available in order
* not to make wpa_supplicant stop its scanning.
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]);
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
break;
case NL80211_CMD_REG_CHANGE:
wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ break;
+ os_memset(&data, 0, sizeof(data));
+ switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+ nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+ break;
+ }
wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- NULL);
+ &data);
break;
case NL80211_CMD_REG_BEACON_HINT:
wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
case NL80211_CMD_RADAR_DETECT:
nl80211_radar_event(drv, tb);
break;
+ case NL80211_CMD_STOP_AP:
+ nl80211_stop_ap(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
- if (tb[NL80211_ATTR_IFINDEX])
+ if (tb[NL80211_ATTR_IFINDEX]) {
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;
+ 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);
}
- wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
- "interface (ifindex %d)", gnlh->cmd, ifidx);
-
return NL_SKIP;
}
struct wpa_driver_nl80211_data *drv, *tmp;
int ifidx = -1;
struct i802_bss *bss;
+ u64 wdev_id = 0;
+ 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) {
- for (bss = &drv->first_bss; bss; bss = bss->next) {
- if (ifidx == -1 || ifidx == bss->ifindex) {
+ 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;
}
void *handle)
{
struct nl_cb *cb = eloop_ctx;
+ int res;
wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
- nl_recvmsgs(handle, cb);
+ res = nl_recvmsgs(handle, cb);
+ if (res) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
}
}
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+ char *alpha2 = 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_REG_ALPHA2]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+ return NL_SKIP;
+ }
+ os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ alpha2[0] = '\0';
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+ if (!alpha2[0])
+ ret = -1;
+
+ return ret;
+}
+
+
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
u32 *feat = arg;
struct wpa_driver_nl80211_data *drv;
struct wpa_driver_capa *capa;
+ unsigned int num_multichan_concurrent;
+
unsigned int error:1;
unsigned int device_ap_sme:1;
unsigned int poll_command_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;
+ unsigned int channel_switch_supported:1;
+ unsigned int set_qos_map_supported:1;
};
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;
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;
+ info->num_multichan_concurrent =
+ nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
return 1;
}
case NL80211_CMD_PROBE_CLIENT:
info->poll_command_supported = 1;
break;
+ case NL80211_CMD_CHANNEL_SWITCH:
+ info->channel_switch_supported = 1;
+ break;
+ case NL80211_CMD_SET_QOS_MAP:
+ info->set_qos_map_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ int i, num;
+ u32 *ciphers;
+
+ if (tb == NULL)
+ return;
+
+ num = nla_len(tb) / sizeof(u32);
+ ciphers = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 c = ciphers[i];
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+ c >> 24, (c >> 16) & 0xff,
+ (c >> 8) & 0xff, c & 0xff);
+ switch (c) {
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+ break;
}
}
}
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_WIPHY_NAME])
+ os_strlcpy(drv->phyname,
+ nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
capa->max_scan_ssids =
nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
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]);
+ wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
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 (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+ goto nla_put_failure;
if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
return -1;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
}
- if (info->p2p_multichan_concurrent) {
+ if (info->num_multichan_concurrent > 1) {
wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
"concurrent (driver advertised support)");
- drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ drv->capa.num_multichan_concurrent =
+ info->num_multichan_concurrent;
}
/* default to 5000 since early versions of mac80211 don't set it */
return -1;
drv->has_capability = 1;
- /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP |
- WPA_DRIVER_CAPA_ENC_CCMP;
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
drv->device_ap_sme = info.device_ap_sme;
drv->poll_command_supported = info.poll_command_supported;
drv->data_tx_status = info.data_tx_status;
+ drv->channel_switch_supported = info.channel_switch_supported;
+ if (info.set_qos_map_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
/*
* If poll command and tx status are supported, mac80211 is new enough
nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
process_global_event, global);
- eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
- wpa_driver_nl80211_event_receive,
- global->nl_cb, global->nl_event);
+ nl80211_register_eloop_read(&global->nl_event,
+ wpa_driver_nl80211_event_receive,
+ global->nl_cb);
return 0;
{
struct wpa_driver_nl80211_data *drv = ctx;
wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
- if (linux_set_iface_flags(drv->global->ioctl_sock,
- drv->first_bss.ifname, 1)) {
+ if (i802_set_iface_flags(drv->first_bss, 1)) {
wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
"after rfkill unblock");
return;
}
-static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
-{
- /* Find phy (radio) to which this interface belongs */
- char buf[90], *pos;
- int f, rv;
-
- drv->phyname[0] = '\0';
- snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
- drv->first_bss.ifname);
- f = open(buf, O_RDONLY);
- if (f < 0) {
- wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
- buf, strerror(errno));
- return;
- }
-
- rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
- close(f);
- if (rv < 0) {
- wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
- buf, strerror(errno));
- return;
- }
-
- drv->phyname[rv] = '\0';
- pos = os_strchr(drv->phyname, '\n');
- if (pos)
- *pos = '\0';
- wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
- drv->first_bss.ifname, drv->phyname);
-}
-
-
static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
void *eloop_ctx,
void *handle)
}
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * @global_priv: private driver global data from global_init()
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
- void *global_priv)
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+ void *global_priv, int hostapd,
+ const u8 *set_addr)
{
struct wpa_driver_nl80211_data *drv;
struct rfkill_config *rcfg;
return NULL;
drv->global = global_priv;
drv->ctx = ctx;
- bss = &drv->first_bss;
- bss->drv = drv;
- bss->ctx = ctx;
+ drv->hostapd = !!hostapd;
+ drv->eapol_sock = -1;
+ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+ drv->if_indices = drv->default_if_indices;
- os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+ drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+ if (!drv->first_bss) {
+ os_free(drv);
+ return NULL;
+ }
+ 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;
drv->eapol_tx_sock = -1;
if (nl80211_init_bss(bss))
goto failed;
- nl80211_get_phy_name(drv);
-
rcfg = os_zalloc(sizeof(*rcfg));
if (rcfg == NULL)
goto failed;
os_free(rcfg);
}
- if (wpa_driver_nl80211_finish_drv_init(drv))
+ if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
+ drv->start_iface_up = 1;
+
+ if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
goto failed;
drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
}
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+ void *global_priv)
+{
+ return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+}
+
+
static int nl80211_register_frame(struct i802_bss *bss,
struct nl_handle *nl_handle,
u16 type, const u8 *match, size_t match_len)
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) < 0)
+ goto nla_put_failure;
+
NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
if (bss->nl_mgmt == NULL)
return -1;
- eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
- wpa_driver_nl80211_event_receive, bss->nl_cb,
- bss->nl_mgmt);
-
return 0;
}
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+ nl80211_register_eloop_read(&bss->nl_mgmt,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb);
+}
+
+
static int nl80211_register_action_frame(struct i802_bss *bss,
const u8 *match, size_t match_len)
{
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+ /* register for any AUTH message */
+ nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+ }
+
+#ifdef CONFIG_INTERWORKING
+ /* QoS Map Configure */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
+ return -1;
+#endif /* CONFIG_INTERWORKING */
#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
/* GAS Initial Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
return -1;
+ nl80211_mgmt_handle_register_eloop(bss);
+
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
"handle %p", bss->nl_mgmt);
- for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(stypes); i++) {
if (nl80211_register_frame(bss, bss->nl_mgmt,
(WLAN_FC_TYPE_MGMT << 2) |
(stypes[i] << 4),
if (nl80211_get_wiphy_data_ap(bss) == NULL)
goto out_err;
+ nl80211_mgmt_handle_register_eloop(bss);
return 0;
out_err:
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
nl_destroy_handles(&bss->nl_mgmt);
return -1;
}
NULL, 0) < 0)
goto out_err;
+ nl80211_mgmt_handle_register_eloop(bss);
return 0;
out_err:
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
nl_destroy_handles(&bss->nl_mgmt);
return -1;
}
return;
wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
"(%s)", bss->nl_mgmt, reason);
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
- nl_destroy_handles(&bss->nl_mgmt);
+ nl80211_destroy_eloop_handle(&bss->nl_mgmt);
nl80211_put_wiphy_data_ap(bss);
}
}
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+ NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+ bss->ifname, (long long unsigned int) bss->wdev_id,
+ strerror(-ret));
+
+nla_put_failure:
+ nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ if (start)
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+ else
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+ NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+ start ? "Start" : "Stop",
+ bss->ifname, (long long unsigned int) bss->wdev_id,
+ strerror(-ret));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+ enum nl80211_iftype nlmode;
+
+ nlmode = nl80211_get_ifmode(bss);
+ if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+ bss->ifname, up);
+ }
+
+ /* P2P Device has start/stop which is equivalent */
+ return nl80211_set_p2pdev(bss, up);
+}
+
+
static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+ const u8 *set_addr, int first)
{
- struct i802_bss *bss = &drv->first_bss;
+ struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
+ enum nl80211_iftype nlmode;
drv->ifindex = if_nametoindex(bss->ifname);
- drv->first_bss.ifindex = drv->ifindex;
+ bss->ifindex = drv->ifindex;
+ bss->wdev_id = drv->global->if_add_wdevid;
+ bss->wdev_id_set = drv->global->if_add_wdevid_set;
-#ifndef HOSTAPD
- /*
- * Make sure the interface starts up in station mode unless this is a
- * dynamically added interface (e.g., P2P) that was already configured
- * with proper iftype.
- */
- if (drv->ifindex != drv->global->if_add_ifindex &&
- wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
- "use managed mode");
+ bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
+ bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
+ drv->global->if_add_wdevid_set = 0;
+
+ if (wpa_driver_nl80211_capa(drv))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+ bss->ifname, drv->phyname);
+
+ if (set_addr &&
+ (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+ linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ set_addr)))
return -1;
+
+ if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+ drv->start_mode_ap = 1;
+
+ if (drv->hostapd)
+ nlmode = NL80211_IFTYPE_AP;
+ else if (bss->if_dynamic)
+ nlmode = nl80211_get_ifmode(bss);
+ else
+ nlmode = NL80211_IFTYPE_STATION;
+
+ if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
+ return -1;
+ }
+
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ int ret = nl80211_set_p2pdev(bss, 1);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+ nl80211_get_macaddr(bss);
+ return ret;
}
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
}
}
- netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
- 1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
-
- if (wpa_driver_nl80211_capa(drv))
- return -1;
+ if (!drv->hostapd)
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
bss->addr))
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+ drv->ifindex);
nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (is_ap_interface(drv->nlmode))
wpa_driver_nl80211_del_beacon(drv);
-#ifdef HOSTAPD
- if (drv->last_freq_ht) {
- /* Clear HT flags from the driver */
- struct hostapd_freq_params freq;
- os_memset(&freq, 0, sizeof(freq));
- freq.freq = drv->last_freq;
- wpa_driver_nl80211_set_freq(bss, &freq);
- }
-
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
close(drv->eapol_sock);
if (drv->if_indices != drv->default_if_indices)
os_free(drv->if_indices);
-#endif /* HOSTAPD */
if (drv->disabled_11b_rates)
nl80211_disable_11b_rates(drv, drv->ifindex, 0);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
- wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
- nl80211_mgmt_unsubscribe(bss, "deinit");
-
+ if (!drv->start_iface_up)
+ (void) i802_set_iface_flags(bss, 0);
+ if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ if (!drv->hostapd || !drv->start_mode_ap)
+ wpa_driver_nl80211_set_mode(bss,
+ NL80211_IFTYPE_STATION);
+ nl80211_mgmt_unsubscribe(bss, "deinit");
+ } else {
+ nl80211_mgmt_unsubscribe(bss, "deinit");
+ nl80211_del_p2pdev(bss);
+ }
nl_cb_put(drv->nl_cb);
- nl80211_destroy_bss(&drv->first_bss);
+ nl80211_destroy_bss(drv->first_bss);
os_free(drv->filter_ssids);
os_free(drv->extended_capa);
os_free(drv->extended_capa_mask);
+ os_free(drv->first_bss);
os_free(drv);
}
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
- wpa_driver_nl80211_set_mode(&drv->first_bss,
+ wpa_driver_nl80211_set_mode(drv->first_bss,
drv->ap_scan_as_station);
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
static struct nl_msg *
nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
- struct wpa_driver_scan_params *params)
+ struct wpa_driver_scan_params *params, u64 *wdev_id)
{
struct nl_msg *msg;
size_t i;
nl80211_cmd(drv, msg, 0, cmd);
- if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
- goto fail;
+ 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;
return msg;
fail:
+nla_put_failure:
nlmsg_free(msg);
return 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);
+ msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+ bss->wdev_id_set ? &bss->wdev_id : NULL);
if (!msg)
return -1;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
"(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
- if (is_ap_interface(drv->nlmode)) {
+ if (drv->hostapd && is_ap_interface(drv->nlmode)) {
/*
* mac80211 does not allow scan requests in AP mode, so
* try to do this in station mode.
ret = 0;
} else
goto nla_put_failure;
-#else /* HOSTAPD */
- goto nla_put_failure;
-#endif /* HOSTAPD */
}
+ drv->scan_state = SCAN_REQUESTED;
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
timeout = 10;
return android_pno_start(bss, params);
#endif /* ANDROID */
- msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+ 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;
goto nla_put_failure;
nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+ goto nla_put_failure;
arg.drv = drv;
arg.res = res;
const u8 *key, size_t key_len)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ifindex = if_nametoindex(ifname);
+ int ifindex;
struct nl_msg *msg;
int ret;
+ int tdls = 0;
+
+ /* Ignore for P2P Device */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+ ifindex = if_nametoindex(ifname);
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, ifname, alg, addr, key_idx, set_tx,
(unsigned long) seq_len, (unsigned long) key_len);
#ifdef CONFIG_TDLS
- if (key_idx == -1)
+ if (key_idx == -1) {
key_idx = 0;
+ tdls = 1;
+ }
#endif /* CONFIG_TDLS */
msg = nlmsg_alloc();
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_GCMP);
break;
+ case WPA_ALG_CCMP_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_CCMP_256);
+ break;
+ case WPA_ALG_GCMP_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_GCMP_256);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
break;
+ case WPA_ALG_BIP_GMAC_128:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_GMAC_128);
+ break;
+ case WPA_ALG_BIP_GMAC_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_GMAC_256);
+ break;
+ case WPA_ALG_BIP_CMAC_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_CMAC_256);
+ break;
case WPA_ALG_SMS4:
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_SMS4);
* If we failed or don't need to set the default TX key (below),
* we're done here.
*/
- if (ret || !set_tx || alg == WPA_ALG_NONE)
+ if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
return ret;
if (is_ap_interface(drv->nlmode) && addr &&
!is_broadcast_ether_addr(addr))
case WPA_ALG_GCMP:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
break;
+ case WPA_ALG_CCMP_256:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_CCMP_256);
+ break;
+ case WPA_ALG_GCMP_256:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_GCMP_256);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
break;
+ case WPA_ALG_BIP_GMAC_128:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_GMAC_128);
+ break;
+ case WPA_ALG_BIP_GMAC_256:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_GMAC_256);
+ break;
+ case WPA_ALG_BIP_CMAC_256:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_BIP_CMAC_256);
+ break;
default:
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
"algorithm %d", __func__, alg);
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
int reason_code)
{
+ int ret;
+
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);
+ ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+ reason_code, 0);
+ /*
+ * For locally generated disconnect, supplicant already generates a
+ * DEAUTH event, so ignore the event from NL80211.
+ */
+ drv->ignore_next_local_disconnect = ret == 0;
+
+ return ret;
}
struct wpa_driver_nl80211_data *drv)
{
struct wpa_driver_auth_params params;
- struct i802_bss *bss = &drv->first_bss;
+ struct i802_bss *bss = drv->first_bss;
int i;
wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
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_NO_IR])
+ chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | 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]);
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_PASSIVE_SCAN] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .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 },
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;
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+ HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+ /*
+ * Unsupported VHT MCS stream is defined as value 3, so the VHT
+ * MCS RX/TX map must be initialized with 0xffff to mark all 8
+ * possible streams as unsupported. This will be overridden if
+ * driver advertises VHT support.
+ */
+ mode->vht_mcs_set[0] = 0xff;
+ mode->vht_mcs_set[1] = 0xff;
+ mode->vht_mcs_set[4] = 0xff;
+ mode->vht_mcs_set[5] = 0xff;
+
*(phy_info->num_modes) += 1;
phy_info->last_mode = nl_band->nla_type;
phy_info->last_chan_idx = 0;
}
+static void nl80211_reg_rule_max_eirp(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_eirp;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm",
+ start, end, max_eirp);
+
+ for (m = 0; m < *results->num_modes; m++) {
+ int c;
+ struct hostapd_hw_modes *mode = &results->modes[m];
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if ((u32) chan->freq - 10 >= start &&
+ (u32) chan->freq + 10 <= end)
+ chan->max_tx_power = max_eirp;
+ }
+ }
+}
+
+
static void nl80211_reg_rule_ht40(struct nlattr *tb[],
struct phy_info_arg *results)
{
}
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+ if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+ if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+ if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+ }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ /* TODO: use a real VHT support indication */
+ if (!results->modes[m].vht_capab)
+ continue;
+
+ nl80211_set_vht_mode(&results->modes[m], start, end);
+ }
+}
+
+
static int nl80211_get_reg(struct nl_msg *msg, void *arg)
{
struct phy_info_arg *results = arg;
nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
nla_data(nl_rule), nla_len(nl_rule), reg_policy);
nl80211_reg_rule_ht40(tb_rule, results);
+ nl80211_reg_rule_max_eirp(tb_rule, results);
}
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
nl80211_reg_rule_sec(tb_rule, results);
}
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_vht(tb_rule, results);
+ }
+
return NL_SKIP;
}
-static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
- struct phy_info_arg *results)
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+ struct phy_info_arg *results)
{
struct nl_msg *msg;
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);
+ nl80211_set_regulatory_flags(drv, &result);
return wpa_driver_nl80211_postprocess_modes(result.modes,
num_modes);
}
{
struct wpa_driver_nl80211_data *drv = bss->drv;
u64 cookie;
+ int res;
- if (freq == 0)
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
+ bss->freq);
freq = bss->freq;
+ }
- if (drv->use_monitor)
+ if (drv->use_monitor) {
+ wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+ freq, bss->freq);
return wpa_driver_nl80211_send_mntr(drv, data, len,
encrypt, noack);
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
+ res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+ &cookie, no_cck, noack, offchanok);
+ if (res == 0 && !noack) {
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ mgmt = (const struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
+ (long long unsigned int)
+ drv->send_action_cookie,
+ (long long unsigned int) cookie);
+ drv->send_action_cookie = cookie;
+ }
+ }
- return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
- &cookie, no_cck, noack, offchanok);
+ return res;
}
mgmt = (struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
+ noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
- if (is_sta_interface(drv->nlmode) &&
+ if ((is_sta_interface(drv->nlmode) ||
+ drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
/*
* but it works due to the single-threaded nature
* of wpa_supplicant.
*/
- if (freq == 0)
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
+ drv->last_mgmt_freq);
freq = drv->last_mgmt_freq;
+ }
return nl80211_send_frame_cmd(bss, freq, 0,
data, data_len, NULL, 1, noack,
1);
}
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
- if (freq == 0)
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
+ bss->freq);
freq = bss->freq;
+ }
return nl80211_send_frame_cmd(bss, freq,
(int) freq == bss->freq ? 0 :
wait_time,
encrypt = 0;
}
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
noack, freq, no_cck, offchanok,
wait_time);
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
num_suites = 0;
+ if (params->pairwise_ciphers & WPA_CIPHER_CCMP_256)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+ if (params->pairwise_ciphers & WPA_CIPHER_GCMP_256)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
params->group_cipher);
switch (params->group_cipher) {
+ case WPA_CIPHER_CCMP_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_CCMP_256);
+ break;
+ case WPA_CIPHER_GCMP_256:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_GCMP_256);
+ break;
case WPA_CIPHER_CCMP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_CCMP);
}
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
- struct hostapd_freq_params *freq)
+static int nl80211_put_freq_params(struct nl_msg *msg,
+ 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, 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->freq);
if (freq->vht_enabled) {
switch (freq->bandwidth) {
NL80211_CHAN_WIDTH_160);
break;
default:
- return -1;
+ return -EINVAL;
}
NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
if (freq->center_freq2)
break;
}
}
+ return 0;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
- if (ret == 0) {
- bss->freq = freq->freq;
- return 0;
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+ 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, 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);
+ if (nl80211_put_freq_params(msg, freq) < 0)
+ goto nla_put_failure;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret == 0) {
+ bss->freq = freq->freq;
+ return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
"%d (%s)", freq->freq, ret, strerror(-ret));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
+ " --> %d (%s)",
+ bss->ifname, MAC2STR(addr), ret, strerror(-ret));
if (ret == -ENOENT)
return 0;
return ret;
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;
int ifidx;
return -1;
nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+ goto nla_put_failure;
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
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)
+ 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 use_existing)
{
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)) {
+ if (use_existing) {
+ wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+ ifname);
+ return -ENFILE;
+ }
wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
/* Try to remove the interface that was already there. */
/* 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;
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+ strerror(errno));
return;
}
if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
- printf("received invalid radiotap frame\n");
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
return;
}
if (ret == -ENOENT)
break;
if (ret) {
- printf("received invalid radiotap frame (%d)\n", ret);
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+ ret);
return;
}
switch (iter.this_arg_index) {
};
static struct sock_fprog msock_filter = {
- .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+ .len = ARRAY_SIZE(msock_filter_insns),
.filter = msock_filter_insns,
};
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
&msock_filter, sizeof(msock_filter))) {
- perror("SO_ATTACH_FILTER");
+ wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
return -1;
}
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv)
{
- drv->monitor_refcount--;
+ if (drv->monitor_refcount > 0)
+ drv->monitor_refcount--;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+ drv->monitor_refcount);
if (drv->monitor_refcount > 0)
return;
if (drv->monitor_ifidx >= 0) {
drv->monitor_refcount++;
+ wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+ drv->monitor_refcount);
return 0;
}
- if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+ if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
/*
* P2P interface name is of the format p2p-%s-%d. For monitor
* interface name corresponding to P2P GO, replace "p2p-" with
* "mon-" to retain the same interface name length and to
* indicate that it is a monitor interface.
*/
- snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
} else {
/* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
}
buf[IFNAMSIZ - 1] = '\0';
drv->monitor_ifidx =
nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0);
+ 0, NULL, NULL, 0);
if (drv->monitor_ifidx == -EOPNOTSUPP) {
/*
ll.sll_ifindex = drv->monitor_ifidx;
drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (drv->monitor_sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+ strerror(errno));
goto error;
}
}
if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
- perror("monitor socket bind");
+ wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+ strerror(errno));
goto error;
}
optval = 20;
if (setsockopt
(drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
- perror("Failed to set socket priority");
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+ strerror(errno));
goto error;
}
if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
drv, NULL)) {
- printf("Could not register monitor read socket\n");
+ wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
goto error;
}
+ drv->monitor_refcount++;
return 0;
error:
nl80211_remove_monitor_interface(drv);
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
- "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
/*
* Disable Probe Request reporting unless we need it in this way for
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
if (drv->device_ap_sme) {
wpa_driver_nl80211_probe_req_report(bss, 0);
if (!drv->use_monitor)
data_len;
hdr = os_zalloc(len);
if (hdr == NULL) {
- printf("malloc() failed for i802_send_data(len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+ (unsigned long) len);
return -1;
}
nlmode = NL80211_IFTYPE_AP;
old_mode = drv->nlmode;
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, 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 (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
if (old_mode != nlmode)
- wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+ wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
return -1;
}
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
nla_put_failure:
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
+ NL80211_IFTYPE_STATION)) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+ "station mode");
+ }
+
nlmsg_free(msg);
return ret;
}
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
NL80211_IFTYPE_ADHOC)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
- }
+ drv->assoc_freq = params->freq;
+ } else
+ drv->assoc_freq = 0;
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
case CIPHER_GCMP:
cipher = WLAN_CIPHER_SUITE_GCMP;
break;
+ case CIPHER_CCMP_256:
+ cipher = WLAN_CIPHER_SUITE_CCMP_256;
+ break;
+ case CIPHER_GCMP_256:
+ cipher = WLAN_CIPHER_SUITE_GCMP_256;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
case CIPHER_GCMP:
cipher = WLAN_CIPHER_SUITE_GCMP;
break;
+ case CIPHER_CCMP_256:
+ cipher = WLAN_CIPHER_SUITE_CCMP_256;
+ break;
+ case CIPHER_GCMP_256:
+ cipher = WLAN_CIPHER_SUITE_GCMP_256;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
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;
case CIPHER_GCMP:
cipher = WLAN_CIPHER_SUITE_GCMP;
break;
+ case CIPHER_CCMP_256:
+ cipher = WLAN_CIPHER_SUITE_CCMP_256;
+ break;
+ case CIPHER_GCMP_256:
+ cipher = WLAN_CIPHER_SUITE_GCMP_256;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
case CIPHER_GCMP:
cipher = WLAN_CIPHER_SUITE_GCMP;
break;
+ case CIPHER_CCMP_256:
+ cipher = WLAN_CIPHER_SUITE_CCMP_256;
+ break;
+ case CIPHER_GCMP_256:
+ cipher = WLAN_CIPHER_SUITE_GCMP_256;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+ goto nla_put_failure;
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
int res;
res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (res && nlmode == nl80211_get_ifmode(bss))
+ res = 0;
+
if (res == 0) {
drv->nlmode = nlmode;
ret = 0;
wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
"interface down");
for (i = 0; i < 10; i++) {
- res = linux_set_iface_flags(drv->global->ioctl_sock,
- bss->ifname, 0);
+ res = i802_set_iface_flags(bss, 0);
if (res == -EACCES || res == -ENODEV)
break;
if (res == 0) {
ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
if (ret == -EACCES)
break;
- res = linux_set_iface_flags(drv->global->ioctl_sock,
- bss->ifname, 1);
+ res = i802_set_iface_flags(bss, 1);
if (res && !ret)
ret = -1;
else if (ret != -EBUSY)
return ret;
}
- if (is_p2p_interface(nlmode))
+ 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);
capa->extended_capa_mask = drv->extended_capa_mask;
capa->extended_capa_len = drv->extended_capa_len;
}
+
+ if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ !drv->allow_p2p_device) {
+ wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+ capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+ }
+
return 0;
}
}
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
static inline int min_int(int a, int b)
{
if (a < b)
if (!msg)
return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
+ bss->ifname);
nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
/*
return -ENOBUFS;
}
-#endif /* HOSTAPD || CONFIG_AP */
-
static int get_sta_handler(struct nl_msg *msg, void *arg)
{
}
-#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)
{
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+ ", ifname=%s[%d], vlan_id=%d)",
+ bss->ifname, if_nametoindex(bss->ifname),
+ MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
0);
}
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
{
static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
- const char *bridge_ifname)
+ const char *bridge_ifname, char *ifname_wds)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
char name[IFNAMSIZ + 1];
os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ if (ifname_wds)
+ os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
+
wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
" aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
if (val) {
if (!if_nametoindex(name)) {
if (nl80211_create_iface(drv, name,
NL80211_IFTYPE_AP_VLAN,
- bss->addr, 1) < 0)
+ bss->addr, 1, NULL, NULL, 0) <
+ 0)
return -1;
if (bridge_ifname &&
linux_br_add_if(drv->global->ioctl_sock,
len = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&lladdr, &fromlen);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+ strerror(errno));
return;
}
int ifindex, br_ifindex;
int br_added = 0;
- bss = wpa_driver_nl80211_init(hapd, params->ifname,
- params->global_priv);
+ bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+ params->global_priv, 1,
+ params->bssid);
if (bss == NULL)
return NULL;
drv = bss->drv;
- drv->nlmode = NL80211_IFTYPE_AP;
- drv->eapol_sock = -1;
if (linux_br_get(brname, params->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
br_ifindex = 0;
}
- drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
- drv->if_indices = drv->default_if_indices;
for (i = 0; i < params->num_bridge; i++) {
if (params->bridge[i]) {
ifindex = if_nametoindex(params->bridge[i]);
/* start listening for EAPOL on the default AP interface */
add_ifidx(drv, drv->ifindex);
- if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
- goto failed;
-
- if (params->bssid) {
- if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
- params->bssid))
- goto failed;
- }
-
- if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
- "into AP mode", bss->ifname);
- goto failed;
- }
-
if (params->num_bridge && params->bridge[0] &&
i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
goto failed;
- if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
- goto failed;
-
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
if (drv->eapol_sock < 0) {
- perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+ strerror(errno));
goto failed;
}
if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
{
- printf("Could not register read socket for eapol\n");
+ wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
goto failed;
}
wpa_driver_nl80211_deinit(bss);
}
-#endif /* HOSTAPD */
-
static enum nl80211_iftype wpa_driver_nl80211_if_type(
enum wpa_driver_if_type type)
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;
}
struct wpa_driver_nl80211_data *drv;
dl_list_for_each(drv, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+ if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
return 1;
}
return 0;
if (!drv->global)
return -1;
- os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+ os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
for (idx = 0; idx < 64; idx++) {
- new_addr[0] = drv->first_bss.addr[0] | 0x02;
+ new_addr[0] = drv->first_bss->addr[0] | 0x02;
new_addr[0] ^= idx << 2;
if (!nl80211_addr_in_use(drv->global, new_addr))
break;
#endif /* CONFIG_P2P */
+struct wdev_info {
+ u64 wdev_id;
+ int wdev_id_set;
+ u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wdev_info *wi = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_WDEV]) {
+ wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wi->wdev_id_set = 1;
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+
+ return NL_SKIP;
+}
+
+
static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr,
void *bss_ctx, void **drv_priv,
char *force_ifname, u8 *if_addr,
- const char *bridge)
+ const char *bridge, int use_existing)
{
+ enum nl80211_iftype nlmode;
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifidx;
-#ifdef HOSTAPD
- struct i802_bss *new_bss = NULL;
-
- if (type == WPA_IF_AP_BSS) {
- new_bss = os_zalloc(sizeof(*new_bss));
- if (new_bss == NULL)
- return -1;
- }
-#endif /* HOSTAPD */
+ int added = 1;
if (addr)
os_memcpy(if_addr, addr, ETH_ALEN);
- ifidx = nl80211_create_iface(drv, ifname,
- wpa_driver_nl80211_if_type(type), addr,
- 0);
- if (ifidx < 0) {
-#ifdef HOSTAPD
- os_free(new_bss);
-#endif /* HOSTAPD */
- return -1;
+ nlmode = wpa_driver_nl80211_if_type(type);
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ struct wdev_info p2pdev_info;
+
+ os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+ ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+ 0, nl80211_wdev_handler,
+ &p2pdev_info, use_existing);
+ if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+ ifname);
+ return -1;
+ }
+
+ drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+ drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+ if (!is_zero_ether_addr(p2pdev_info.macaddr))
+ os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+ ifname,
+ (long long unsigned int) p2pdev_info.wdev_id);
+ } else {
+ ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+ 0, NULL, NULL, use_existing);
+ if (use_existing && ifidx == -ENFILE) {
+ added = 0;
+ ifidx = if_nametoindex(ifname);
+ } else if (ifidx < 0) {
+ return -1;
+ }
}
- if (!addr &&
- linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
- if_addr) < 0) {
- nl80211_remove_iface(drv, ifidx);
- return -1;
+ if (!addr) {
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ os_memcpy(if_addr, bss->addr, ETH_ALEN);
+ else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+ bss->ifname, if_addr) < 0) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
}
#ifdef CONFIG_P2P
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
type == WPA_IF_P2P_GO)) {
/* Enforce unique P2P Interface Address */
- u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+ u8 new_addr[ETH_ALEN];
- if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
- own_addr) < 0 ||
- linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
new_addr) < 0) {
nl80211_remove_iface(drv, ifidx);
return -1;
}
- if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+ if (nl80211_addr_in_use(drv->global, new_addr)) {
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
"for P2P group interface");
if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
}
#endif /* CONFIG_P2P */
-#ifdef HOSTAPD
- if (bridge &&
- i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
- "interface %s to a bridge %s", ifname, bridge);
- nl80211_remove_iface(drv, ifidx);
- os_free(new_bss);
- return -1;
- }
-
if (type == WPA_IF_AP_BSS) {
+ struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+ if (new_bss == NULL) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+
+ if (bridge &&
+ i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+ "interface %s to a bridge %s",
+ ifname, bridge);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ os_free(new_bss);
+ return -1;
+ }
+
if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
{
nl80211_remove_iface(drv, ifidx);
os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
new_bss->ifindex = ifidx;
new_bss->drv = drv;
- new_bss->next = drv->first_bss.next;
- new_bss->freq = drv->first_bss.freq;
+ 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;
+ new_bss->added_if = added;
+ drv->first_bss->next = new_bss;
if (drv_priv)
*drv_priv = new_bss;
nl80211_init_bss(new_bss);
if (nl80211_setup_ap(new_bss))
return -1;
}
-#endif /* HOSTAPD */
if (drv->global)
drv->global->if_add_ifindex = ifidx;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
- wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
- __func__, type, ifname, ifindex);
- if (ifindex <= 0)
- return -1;
-
- nl80211_remove_iface(drv, ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+ __func__, type, ifname, ifindex, bss->added_if);
+ if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
+ nl80211_remove_iface(drv, ifindex);
-#ifdef HOSTAPD
if (type != WPA_IF_AP_BSS)
return 0;
bss->brname, strerror(errno));
}
- if (bss != &drv->first_bss) {
+ if (bss != drv->first_bss) {
struct i802_bss *tbss;
- for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+ wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+ for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
if (tbss->next == bss) {
tbss->next = bss->next;
/* Unsubscribe management frames */
if (bss)
wpa_printf(MSG_INFO, "nl80211: %s - could not find "
"BSS %p in the list", __func__, bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+ nl80211_teardown_ap(bss);
+ if (!bss->added_if && !drv->first_bss->next)
+ wpa_driver_nl80211_del_beacon(drv);
+ nl80211_destroy_bss(bss);
+ if (!bss->added_if)
+ i802_set_iface_flags(bss, 0);
+ if (drv->first_bss->next) {
+ drv->first_bss = drv->first_bss->next;
+ drv->ctx = drv->first_bss->ctx;
+ os_free(bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+ }
}
-#endif /* HOSTAPD */
return 0;
}
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);
+ wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
+ if (freq)
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
if (wait)
NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
- if (is_ap_interface(drv->nlmode))
+ if (is_ap_interface(drv->nlmode) &&
+ (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+ (int) freq == bss->freq || drv->device_ap_sme ||
+ !drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
0, freq, no_cck, 1,
wait_time);
(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);
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
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) < 0)
+ 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) < 0)
+ 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);
} else if (bss->nl_preq) {
wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
"reporting nl_preq=%p", bss->nl_preq);
- eloop_unregister_read_sock(
- nl_socket_get_fd(bss->nl_preq));
- nl_destroy_handles(&bss->nl_preq);
+ nl80211_destroy_eloop_handle(&bss->nl_preq);
}
return 0;
}
NULL, 0) < 0)
goto out_err;
- eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
- wpa_driver_nl80211_event_receive, bss->nl_cb,
- bss->nl_preq);
+ nl80211_register_eloop_read(&bss->nl_preq,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb);
return 0;
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(drv);
+
+ /*
+ * If the P2P GO interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
+ return 0;
+
return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
}
struct wpa_driver_nl80211_data *drv = bss->drv;
if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
return -1;
+
+ /*
+ * If the P2P Client interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (bss->if_dynamic)
+ return 0;
+
return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
}
static void wpa_driver_nl80211_resume(void *priv)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
- "resume event");
- }
+
+ if (i802_set_iface_flags(bss, 1))
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
}
}
-/* 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];
wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
MACSTR,
- driver->phyname, driver->first_bss.ifname,
- MAC2STR(driver->first_bss.addr));
+ driver->phyname, driver->first_bss->ifname,
+ MAC2STR(driver->first_bss->addr));
if (is_ap_interface(driver->nlmode))
- freq = driver->first_bss.freq;
+ freq = driver->first_bss->freq;
else
freq = nl80211_get_assoc_freq(driver);
wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
}
+
+ if (os_strstr(param, "p2p_device=1")) {
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ drv->allow_p2p_device = 1;
+ }
#endif /* CONFIG_P2P */
return 0;
global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (global->ioctl_sock < 0) {
- perror("socket(PF_INET,SOCK_DGRAM)");
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+ strerror(errno));
goto err;
}
nl_destroy_handles(&global->nl);
- if (global->nl_event) {
- eloop_unregister_read_sock(
- nl_socket_get_fd(global->nl_event));
- nl_destroy_handles(&global->nl_event);
- }
+ if (global->nl_event)
+ nl80211_destroy_eloop_handle(&global->nl_event);
nl_cb_put(global->nl_cb);
}
+static void clean_survey_results(struct survey_results *survey_results)
+{
+ struct freq_survey *survey, *tmp;
+
+ if (dl_list_empty(&survey_results->survey_list))
+ return;
+
+ dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+ struct freq_survey, list) {
+ dl_list_del(&survey->list);
+ os_free(survey);
+ }
+}
+
+
+static void add_survey(struct nlattr **sinfo, u32 ifidx,
+ struct dl_list *survey_list)
+{
+ struct freq_survey *survey;
+
+ survey = os_zalloc(sizeof(struct freq_survey));
+ if (!survey)
+ return;
+
+ survey->ifidx = ifidx;
+ survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ survey->filled = 0;
+
+ if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
+ survey->nf = (int8_t)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ survey->filled |= SURVEY_HAS_NF;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
+ survey->channel_time =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
+ survey->channel_time_busy =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
+ survey->channel_time_rx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
+ survey->channel_time_tx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
+ survey->freq,
+ survey->nf,
+ (unsigned long int) survey->channel_time,
+ (unsigned long int) survey->channel_time_busy,
+ (unsigned long int) survey->channel_time_tx,
+ (unsigned long int) survey->channel_time_rx,
+ survey->filled);
+
+ dl_list_add_tail(survey_list, &survey->list);
+}
+
+
+static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
+ unsigned int freq_filter)
+{
+ if (!freq_filter)
+ return 1;
+
+ return freq_filter == surveyed_freq;
+}
+
+
+static int survey_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ struct survey_results *survey_results;
+ u32 surveyed_freq = 0;
+ u32 ifidx;
+
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+
+ survey_results = (struct survey_results *) arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO])
+ return NL_SKIP;
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy))
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
+ wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
+ return NL_SKIP;
+ }
+
+ surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+
+ if (!check_survey_ok(sinfo, surveyed_freq,
+ survey_results->freq_filter))
+ return NL_SKIP;
+
+ if (survey_results->freq_filter &&
+ survey_results->freq_filter != surveyed_freq) {
+ wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
+ surveyed_freq);
+ return NL_SKIP;
+ }
+
+ add_survey(sinfo, ifidx, &survey_results->survey_list);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int err = -ENOBUFS;
+ union wpa_event_data data;
+ struct survey_results *survey_results;
+
+ os_memset(&data, 0, sizeof(data));
+ survey_results = &data.survey_results;
+
+ dl_list_init(&survey_results->survey_list);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (freq)
+ data.survey_results.freq_filter = freq;
+
+ do {
+ wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
+ err = send_and_recv_msgs(drv, msg, survey_handler,
+ survey_results);
+ } while (err > 0);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
+ goto out_clean;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
+
+out_clean:
+ clean_survey_results(survey_results);
+nla_put_failure:
+ return err;
+}
+
+
static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
const u8 *replay_ctr)
{
wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
"opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
- if (opp_ps != -1 || ctwindow != -1)
+ if (opp_ps != -1 || ctwindow != -1) {
+#ifdef ANDROID_P2P
+ wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
+#else /* ANDROID_P2P */
return -1; /* Not yet supported */
+#endif /* ANDROID_P2P */
+ }
if (legacy_ps == -1)
return 0;
}
-static int nl80211_start_radar_detection(void *priv, int freq)
+static int nl80211_start_radar_detection(void *priv,
+ struct hostapd_freq_params *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)");
+ wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (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);
+
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
"detection");
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);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
- /* only HT20 is supported at this point */
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+ 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);
+ break;
+ case 1:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT40PLUS);
+ break;
+ default:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT20);
+ break;
+ }
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret == 0)
memset(&ifr, 0, sizeof(ifr));
memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
priv_cmd.buf = buf;
priv_cmd.used_len = bp;
}
-#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,
}
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ return NULL;
+
+ return bss->addr;
+}
+
+
+static const char * scan_state_str(enum scan_states scan_state)
+{
+ switch (scan_state) {
+ case NO_SCAN:
+ return "NO_SCAN";
+ case SCAN_REQUESTED:
+ return "SCAN_REQUESTED";
+ case SCAN_STARTED:
+ return "SCAN_STARTED";
+ case SCAN_COMPLETED:
+ return "SCAN_COMPLETED";
+ case SCAN_ABORTED:
+ return "SCAN_ABORTED";
+ case SCHED_SCAN_STARTED:
+ return "SCHED_SCAN_STARTED";
+ case SCHED_SCAN_STOPPED:
+ return "SCHED_SCAN_STOPPED";
+ case SCHED_SCAN_RESULTS:
+ return "SCHED_SCAN_RESULTS";
+ }
+
+ return "??";
+}
+
+
+static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "brname=%s\n"
+ "addr=" MACSTR "\n"
+ "freq=%d\n"
+ "%s%s%s%s%s",
+ bss->ifindex,
+ bss->ifname,
+ bss->brname,
+ MAC2STR(bss->addr),
+ bss->freq,
+ bss->beacon_set ? "beacon_set=1\n" : "",
+ bss->added_if_into_bridge ?
+ "added_if_into_bridge=1\n" : "",
+ bss->added_bridge ? "added_bridge=1\n" : "",
+ bss->in_deinit ? "in_deinit=1\n" : "",
+ bss->if_dynamic ? "if_dynamic=1\n" : "");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+
+ if (bss->wdev_id_set) {
+ res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
+ (unsigned long long) bss->wdev_id);
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+
+ res = os_snprintf(pos, end - pos,
+ "phyname=%s\n"
+ "drv_ifindex=%d\n"
+ "operstate=%d\n"
+ "scan_state=%s\n"
+ "auth_bssid=" MACSTR "\n"
+ "auth_attempt_bssid=" MACSTR "\n"
+ "bssid=" MACSTR "\n"
+ "prev_bssid=" MACSTR "\n"
+ "associated=%d\n"
+ "assoc_freq=%u\n"
+ "monitor_sock=%d\n"
+ "monitor_ifidx=%d\n"
+ "monitor_refcount=%d\n"
+ "last_mgmt_freq=%u\n"
+ "eapol_tx_sock=%d\n"
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ drv->phyname,
+ drv->ifindex,
+ drv->operstate,
+ scan_state_str(drv->scan_state),
+ MAC2STR(drv->auth_bssid),
+ MAC2STR(drv->auth_attempt_bssid),
+ MAC2STR(drv->bssid),
+ MAC2STR(drv->prev_bssid),
+ drv->associated,
+ drv->assoc_freq,
+ drv->monitor_sock,
+ drv->monitor_ifidx,
+ drv->monitor_refcount,
+ drv->last_mgmt_freq,
+ drv->eapol_tx_sock,
+ drv->ignore_if_down_event ?
+ "ignore_if_down_event=1\n" : "",
+ drv->scan_complete_events ?
+ "scan_complete_events=1\n" : "",
+ drv->disabled_11b_rates ?
+ "disabled_11b_rates=1\n" : "",
+ drv->pending_remain_on_chan ?
+ "pending_remain_on_chan=1\n" : "",
+ drv->in_interface_list ? "in_interface_list=1\n" : "",
+ drv->device_ap_sme ? "device_ap_sme=1\n" : "",
+ drv->poll_command_supported ?
+ "poll_command_supported=1\n" : "",
+ drv->data_tx_status ? "data_tx_status=1\n" : "",
+ drv->scan_for_auth ? "scan_for_auth=1\n" : "",
+ drv->retry_auth ? "retry_auth=1\n" : "",
+ drv->use_monitor ? "use_monitor=1\n" : "",
+ drv->ignore_next_local_disconnect ?
+ "ignore_next_local_disconnect=1\n" : "",
+ drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+
+ if (drv->has_capability) {
+ res = os_snprintf(pos, end - pos,
+ "capa.key_mgmt=0x%x\n"
+ "capa.enc=0x%x\n"
+ "capa.auth=0x%x\n"
+ "capa.flags=0x%x\n"
+ "capa.max_scan_ssids=%d\n"
+ "capa.max_sched_scan_ssids=%d\n"
+ "capa.sched_scan_supported=%d\n"
+ "capa.max_match_sets=%d\n"
+ "capa.max_remain_on_chan=%u\n"
+ "capa.max_stations=%u\n"
+ "capa.probe_resp_offloads=0x%x\n"
+ "capa.max_acl_mac_addrs=%u\n"
+ "capa.num_multichan_concurrent=%u\n",
+ drv->capa.key_mgmt,
+ drv->capa.enc,
+ drv->capa.auth,
+ drv->capa.flags,
+ drv->capa.max_scan_ssids,
+ drv->capa.max_sched_scan_ssids,
+ drv->capa.sched_scan_supported,
+ drv->capa.max_match_sets,
+ drv->capa.max_remain_on_chan,
+ drv->capa.max_stations,
+ drv->capa.probe_resp_offloads,
+ drv->capa.max_acl_mac_addrs,
+ drv->capa.num_multichan_concurrent);
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+
+ return pos - buf;
+}
+
+
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+ if (settings->head)
+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
+ settings->head_len, settings->head);
+
+ if (settings->tail)
+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
+ settings->tail_len, settings->tail);
+
+ if (settings->beacon_ies)
+ NLA_PUT(msg, NL80211_ATTR_IE,
+ settings->beacon_ies_len, settings->beacon_ies);
+
+ if (settings->proberesp_ies)
+ NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+ settings->proberesp_ies_len, settings->proberesp_ies);
+
+ if (settings->assocresp_ies)
+ NLA_PUT(msg,
+ NL80211_ATTR_IE_ASSOC_RESP,
+ settings->assocresp_ies_len, settings->assocresp_ies);
+
+ if (settings->probe_resp)
+ NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
+ settings->probe_resp_len, settings->probe_resp);
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *beacon_csa;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
+ settings->cs_count, settings->block_tx,
+ settings->freq_params.freq, settings->freq_params.bandwidth,
+ settings->freq_params.center_freq1,
+ settings->freq_params.center_freq2);
+
+ if (!drv->channel_switch_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+ return -EOPNOTSUPP;
+ }
+
+ if ((drv->nlmode != NL80211_IFTYPE_AP) &&
+ (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+ return -EOPNOTSUPP;
+
+ /* check settings validity */
+ if (!settings->beacon_csa.tail ||
+ ((settings->beacon_csa.tail_len <=
+ settings->counter_offset_beacon) ||
+ (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
+ settings->cs_count)))
+ return -EINVAL;
+
+ if (settings->beacon_csa.probe_resp &&
+ ((settings->beacon_csa.probe_resp_len <=
+ settings->counter_offset_presp) ||
+ (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
+ settings->cs_count)))
+ return -EINVAL;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
+ ret = nl80211_put_freq_params(msg, &settings->freq_params);
+ if (ret)
+ goto error;
+
+ if (settings->block_tx)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+ /* beacon_after params */
+ ret = set_beacon_data(msg, &settings->beacon_after);
+ if (ret)
+ goto error;
+
+ /* beacon_csa params */
+ beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+ if (!beacon_csa)
+ goto nla_put_failure;
+
+ ret = set_beacon_data(msg, &settings->beacon_csa);
+ if (ret)
+ goto error;
+
+ NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+ settings->counter_offset_beacon);
+
+ if (settings->beacon_csa.probe_resp)
+ NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+ settings->counter_offset_presp);
+
+ nla_nest_end(msg, beacon_csa);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+
+nla_put_failure:
+ ret = -ENOBUFS;
+error:
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+ return ret;
+}
+
+
+static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
+ u8 qos_map_set_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+ qos_map_set, qos_map_set_len);
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
+
+ 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",
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
+ .get_country = wpa_driver_nl80211_get_country,
.set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
.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
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
.set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
.get_inact_sec = i802_get_inact_sec,
.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 = driver_nl80211_send_action,
.tdls_oper = nl80211_tdls_oper,
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+ .get_mac_addr = wpa_driver_nl80211_get_macaddr,
+ .get_survey = wpa_driver_nl80211_get_survey,
+ .status = wpa_driver_nl80211_status,
+ .switch_channel = nl80211_switch_channel,
+#ifdef ANDROID_P2P
+ .set_noa = wpa_driver_set_p2p_noa,
+ .get_noa = wpa_driver_get_p2p_noa,
+ .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+#endif /* ANDROID_P2P */
+#ifdef ANDROID
+ .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* ANDROID */
+ .set_qos_map = nl80211_set_qos_map,
};