#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;
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;
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);
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);
}
+/* 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 ||
}
-#ifndef HOSTAPD
static int nl80211_get_macaddr(struct i802_bss *bss)
{
struct nl_msg *msg;
nlmsg_free(msg);
return NL80211_IFTYPE_UNSPECIFIED;
}
-#endif /* HOSTAPD */
static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
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;
}
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);
}
&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 enum chan_width convert2width(int width);
-
static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
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);
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");
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");
unsigned int p2p_go_supported:1;
unsigned int p2p_client_supported:1;
unsigned int p2p_concurrent:1;
+ unsigned int channel_switch_supported:1;
+ unsigned int set_qos_map_supported: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;
}
}
}
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 "
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
}
-/**
- * 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;
+ 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;
drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
if (!drv->first_bss) {
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)
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)
{
-#ifndef HOSTAPD
- enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
-#endif /* HOSTAPD */
struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
+ enum nl80211_iftype nlmode;
drv->ifindex = if_nametoindex(bss->ifname);
bss->ifindex = drv->ifindex;
wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
bss->ifname, drv->phyname);
-#ifndef HOSTAPD
- if (bss->if_dynamic)
+ 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;
- /*
- * 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 (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
+ wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
return -1;
}
- drv->nlmode = nlmode;
if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
int ret = nl80211_set_p2pdev(bss, 1);
}
}
- netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
- 1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
+ 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 (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) i802_set_iface_flags(bss, 0);
+ if (!drv->start_iface_up)
+ (void) i802_set_iface_flags(bss, 0);
if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
- wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+ 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");
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;
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);
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);
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;
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 },
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;
+
+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;
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;
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 defined(HOSTAPD) || defined(CONFIG_AP)
-
static inline int min_int(int a, int b)
{
if (a < b)
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)
{
0);
}
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
{
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) {
wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
wpa_driver_nl80211_deinit(bss);
}
-#endif /* HOSTAPD */
-
static enum nl80211_iftype wpa_driver_nl80211_if_type(
enum wpa_driver_if_type type)
}
#endif /* CONFIG_P2P */
-#ifdef HOSTAPD
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
if (new_bss == NULL) {
if (nl80211_setup_ap(new_bss))
return -1;
}
-#endif /* HOSTAPD */
if (drv->global)
drv->global->if_add_ifindex = ifidx;
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)
+ if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
nl80211_remove_iface(drv, ifindex);
-#ifdef HOSTAPD
if (type != WPA_IF_AP_BSS)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
}
}
-#endif /* HOSTAPD */
return 0;
}
}
-/* 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: 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;
}
-#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,
}
+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",
.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,
.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,
};