X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fdrivers%2Fdriver_nl80211.c;h=9587eb4f2cf126669bfe5fe1fe25341e9874dbca;hb=4d584d8c2b08d851c2f46b144e54446445f8d1f8;hp=b4135cc542f65ecc70974465290c8d9a1b2c49a9;hpb=4d916ed6c502252107d0e6c5c10d66a2193e2c87;p=mech_eap.git diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b4135cc..9587eb4 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -200,6 +200,10 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv, static int i802_set_iface_flags(struct i802_bss *bss, int up); static int nl80211_set_param(void *priv, const char *param); +#ifdef CONFIG_MESH +static int nl80211_put_mesh_config(struct nl_msg *msg, + struct wpa_driver_mesh_bss_params *params); +#endif /* CONFIG_MESH */ /* Converts nl80211_chan_width to a common format */ @@ -445,6 +449,8 @@ static int nl_get_multicast_id(struct nl80211_global *global, void * nl80211_cmd(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg, int flags, uint8_t cmd) { + if (TEST_FAIL()) + return NULL; return genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, flags, cmd, 0); } @@ -2330,7 +2336,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, if (drv->hostapd || bss->static_ap) nlmode = NL80211_IFTYPE_AP; - else if (bss->if_dynamic) + else if (bss->if_dynamic || + nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT) nlmode = nl80211_get_ifmode(bss); else nlmode = NL80211_IFTYPE_STATION; @@ -2412,6 +2419,7 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) static void wpa_driver_nl80211_deinit(struct i802_bss *bss) { struct wpa_driver_nl80211_data *drv = bss->drv; + unsigned int i; wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d", bss->ifname, drv->disabled_11b_rates); @@ -2508,6 +2516,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) os_free(drv->extended_capa); os_free(drv->extended_capa_mask); + for (i = 0; i < drv->num_iface_ext_capa; i++) { + os_free(drv->iface_ext_capa[i].ext_capa); + os_free(drv->iface_ext_capa[i].ext_capa_mask); + } os_free(drv->first_bss); os_free(drv); } @@ -3461,6 +3473,48 @@ static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int) } +static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period) +{ + if (dtim_period > 0) { + wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period); + return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); + } + + return 0; +} + + +#ifdef CONFIG_MESH +static int nl80211_set_mesh_config(void *priv, + struct wpa_driver_mesh_bss_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG); + if (!msg) + return -1; + + ret = nl80211_put_mesh_config(msg, params); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Mesh config set failed: %d (%s)", + ret, strerror(-ret)); + return ret; + } + return 0; +} +#endif /* CONFIG_MESH */ + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -3474,6 +3528,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, int smps_mode; u32 suites[10], suite; u32 ver; +#ifdef CONFIG_MESH + struct wpa_driver_mesh_bss_params mesh_params; +#endif /* CONFIG_MESH */ beacon_set = params->reenable ? 0 : bss->beacon_set; @@ -3497,7 +3554,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail) || nl80211_put_beacon_int(msg, params->beacon_int) || - nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) || + nl80211_put_dtim_period(msg, params->dtim_period) || nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) goto fail; if (params->proberesp && params->proberesp_len) { @@ -3568,8 +3625,10 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA && - params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) && - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)) + (!params->pairwise_ciphers || + params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) && + (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) goto fail; wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", @@ -3688,7 +3747,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, "nl80211: Frequency set succeeded for ht2040 coex"); bss->bandwidth = params->freq->bandwidth; } - } else if (!beacon_set) { + } else if (!beacon_set && params->freq) { /* * cfg80211 updates the driver on frequence change in AP * mode only at the point when beaconing is started, so @@ -3697,6 +3756,18 @@ static int wpa_driver_nl80211_set_ap(void *priv, bss->bandwidth = params->freq->bandwidth; } } + +#ifdef CONFIG_MESH + if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) { + os_memset(&mesh_params, 0, sizeof(mesh_params)); + mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; + mesh_params.ht_opmode = params->ht_opmode; + ret = nl80211_set_mesh_config(priv, &mesh_params); + if (ret < 0) + return ret; + } +#endif /* CONFIG_MESH */ + return ret; fail: nlmsg_free(msg); @@ -3770,6 +3841,12 @@ static int nl80211_put_freq_params(struct nl_msg *msg, wpa_printf(MSG_DEBUG, " * channel_type=%d", ct); if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct)) return -ENOBUFS; + } else { + wpa_printf(MSG_DEBUG, " * channel_type=%d", + NL80211_CHAN_NO_HT); + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_NO_HT)) + return -ENOBUFS; } return 0; } @@ -3832,11 +3909,11 @@ static u32 sta_flags_nl80211(int flags) static u32 sta_plink_state_nl80211(enum mesh_plink_state state) { switch (state) { - case PLINK_LISTEN: + case PLINK_IDLE: return NL80211_PLINK_LISTEN; - case PLINK_OPEN_SENT: + case PLINK_OPN_SNT: return NL80211_PLINK_OPN_SNT; - case PLINK_OPEN_RCVD: + case PLINK_OPN_RCVD: return NL80211_PLINK_OPN_RCVD; case PLINK_CNF_RCVD: return NL80211_PLINK_CNF_RCVD; @@ -4025,6 +4102,15 @@ static int wpa_driver_nl80211_sta_add(void *priv, if (!(params->flags & WPA_STA_ASSOCIATED)) upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); } +#ifdef CONFIG_MESH + } else { + if (params->plink_state == PLINK_ESTAB && params->peer_aid) { + ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID, + params->peer_aid); + if (ret) + goto fail; + } +#endif /* CONFIG_MESH */ } wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x", @@ -4162,7 +4248,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx) } -static const char * nl80211_iftype_str(enum nl80211_iftype mode) +const char * nl80211_iftype_str(enum nl80211_iftype mode) { switch (mode) { case NL80211_IFTYPE_ADHOC: @@ -4870,6 +4956,14 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT)) return -1; + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA && + (params->pairwise_suite == WPA_CIPHER_NONE || + params->pairwise_suite == WPA_CIPHER_WEP104 || + params->pairwise_suite == WPA_CIPHER_WEP40) && + (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) + return -1; + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED && nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED)) return -1; @@ -5113,6 +5207,9 @@ static int wpa_driver_nl80211_set_mode_impl( int res; int mode_switch_res; + if (TEST_FAIL()) + return -1; + mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode); if (mode_switch_res && nlmode == nl80211_get_ifmode(bss)) mode_switch_res = 0; @@ -6920,6 +7017,12 @@ static int nl80211_set_param(void *priv, const char *param) drv->force_connect_cmd = 1; } + if (os_strstr(param, "force_bss_selection=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; + } + if (os_strstr(param, "no_offchannel_tx=1")) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -7696,7 +7799,7 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md, } -const u8 * wpa_driver_nl80211_get_macaddr(void *priv) +static const u8 * wpa_driver_nl80211_get_macaddr(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -8304,6 +8407,9 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr) struct wpa_driver_nl80211_data *drv = bss->drv; int new_addr = addr != NULL; + if (TEST_FAIL()) + return -1; + if (!addr) addr = drv->perm_addr; @@ -8364,6 +8470,46 @@ static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id, } +static int nl80211_put_mesh_config(struct nl_msg *msg, + struct wpa_driver_mesh_bss_params *params) +{ + struct nlattr *container; + + container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); + if (!container) + return -1; + + if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) && + nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, + params->auto_plinks)) || + ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) && + nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, + params->max_peer_links))) + return -1; + + /* + * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because + * the timer could disconnect stations even in that case. + */ + if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) && + nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, + params->peer_link_timeout)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT"); + return -1; + } + + if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) && + nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE"); + return -1; + } + + nla_nest_end(msg, container); + + return 0; +} + + static int nl80211_join_mesh(struct i802_bss *bss, struct wpa_driver_mesh_join_params *params) { @@ -8378,7 +8524,8 @@ static int nl80211_join_mesh(struct i802_bss *bss, nl80211_put_freq_params(msg, ¶ms->freq) || nl80211_put_basic_rates(msg, params->basic_rates) || nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) || - nl80211_put_beacon_int(msg, params->beacon_int)) + nl80211_put_beacon_int(msg, params->beacon_int) || + nl80211_put_dtim_period(msg, params->dtim_period)) goto fail; wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags); @@ -8407,29 +8554,11 @@ static int nl80211_join_mesh(struct i802_bss *bss, goto fail; nla_nest_end(msg, container); - container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); - if (!container) - goto fail; - - if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) && - nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0)) - goto fail; - if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) && - nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, - params->max_peer_links)) - goto fail; - - /* - * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because - * the timer could disconnect stations even in that case. - */ - if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, - params->conf.peer_link_timeout)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT"); + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS; + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT; + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS; + if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0) goto fail; - } - - nla_nest_end(msg, container); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; @@ -8439,7 +8568,7 @@ static int nl80211_join_mesh(struct i802_bss *bss, goto fail; } ret = 0; - bss->freq = params->freq.freq; + drv->assoc_freq = bss->freq = params->freq.freq; wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully"); fail: @@ -9105,6 +9234,89 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq) return 0; } + +static int nl80211_p2p_lo_start(void *priv, unsigned int freq, + unsigned int period, unsigned int interval, + unsigned int count, const u8 *device_types, + size_t dev_types_len, + const u8 *ies, size_t ies_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *container; + int ret; + + wpa_printf(MSG_DEBUG, + "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u", + freq, period, interval, count); + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) + return -1; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START)) + goto fail; + + container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!container) + goto fail; + + if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL, + freq) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD, + period) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL, + interval) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT, + count) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES, + dev_types_len, device_types) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE, + ies_len, ies)) + goto fail; + + nla_nest_end(msg, container); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to send P2P Listen offload vendor command"); + goto fail; + } + + return 0; + +fail: + nlmsg_free(msg); + return -1; +} + + +static int nl80211_p2p_lo_stop(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload"); + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) + return -1; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) { + nlmsg_free(msg); + return -1; + } + + return send_and_recv_msgs(drv, msg, NULL, NULL); +} + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -9199,6 +9411,39 @@ static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags) } +static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type, + const u8 **ext_capa, const u8 **ext_capa_mask, + unsigned int *ext_capa_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + enum nl80211_iftype nlmode; + unsigned int i; + + if (!ext_capa || !ext_capa_mask || !ext_capa_len) + return -1; + + nlmode = wpa_driver_nl80211_if_type(type); + + /* By default, use the per-radio values */ + *ext_capa = drv->extended_capa; + *ext_capa_mask = drv->extended_capa_mask; + *ext_capa_len = drv->extended_capa_len; + + /* Replace the default value if a per-interface type value exists */ + for (i = 0; i < drv->num_iface_ext_capa; i++) { + if (nlmode == drv->iface_ext_capa[i].iftype) { + *ext_capa = drv->iface_ext_capa[i].ext_capa; + *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask; + *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len; + break; + } + } + + return 0; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -9293,9 +9538,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .vendor_cmd = nl80211_vendor_cmd, .set_qos_map = nl80211_set_qos_map, .set_wowlan = nl80211_set_wowlan, -#ifdef CONFIG_DRIVER_NL80211_QCA - .roaming = nl80211_roaming, -#endif /* CONFIG_DRIVER_NL80211_QCA */ .set_mac_addr = nl80211_set_mac_addr, #ifdef CONFIG_MESH .init_mesh = wpa_driver_nl80211_init_mesh, @@ -9310,10 +9552,15 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .del_tx_ts = nl80211_del_ts, .get_ifindex = nl80211_get_ifindex, #ifdef CONFIG_DRIVER_NL80211_QCA + .roaming = nl80211_roaming, .do_acs = wpa_driver_do_acs, .set_band = nl80211_set_band, .get_pref_freq_list = nl80211_get_pref_freq_list, .set_prob_oper_freq = nl80211_set_prob_oper_freq, + .p2p_lo_start = nl80211_p2p_lo_start, + .p2p_lo_stop = nl80211_p2p_lo_stop, + .set_default_scan_ies = nl80211_set_default_scan_ies, #endif /* CONFIG_DRIVER_NL80211_QCA */ .configure_data_frame_filters = nl80211_configure_data_frame_filters, + .get_ext_capab = nl80211_get_ext_capab, };