X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fdrivers%2Fdriver_nl80211.c;h=f27b1496bdd2c30931d18545916de8e78a398378;hb=a1431ef8df30eb7ede9a0a95693f17c45ca5fd39;hp=b93721c69a023e9bf86d4b7521459a731e943f15;hpb=29eddc3d8cf824e058cccade7ffacf0cea109697;p=mech_eap.git diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b93721c..f27b149 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -445,6 +445,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); } @@ -763,6 +765,15 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss) } +static unsigned int nl80211_get_ifindex(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + return drv->ifindex; +} + + static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) { struct i802_bss *bss = priv; @@ -786,11 +797,12 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) static void wpa_driver_nl80211_event_newlink( - struct wpa_driver_nl80211_data *drv, const char *ifname) + struct nl80211_global *global, struct wpa_driver_nl80211_data *drv, + int ifindex, const char *ifname) { union wpa_event_data event; - if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (drv && os_strcmp(drv->first_bss->ifname, 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); @@ -804,19 +816,25 @@ static void wpa_driver_nl80211_event_newlink( } os_memset(&event, 0, sizeof(event)); + event.interface_status.ifindex = ifindex; os_strlcpy(event.interface_status.ifname, ifname, sizeof(event.interface_status.ifname)); event.interface_status.ievent = EVENT_INTERFACE_ADDED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); + if (drv) + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); + else + wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS, + &event); } static void wpa_driver_nl80211_event_dellink( - struct wpa_driver_nl80211_data *drv, const char *ifname) + struct nl80211_global *global, struct wpa_driver_nl80211_data *drv, + int ifindex, const char *ifname) { union wpa_event_data event; - if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) { if (drv->if_removed) { wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s", ifname); @@ -831,10 +849,15 @@ static void wpa_driver_nl80211_event_dellink( } os_memset(&event, 0, sizeof(event)); + event.interface_status.ifindex = ifindex; os_strlcpy(event.interface_status.ifname, ifname, sizeof(event.interface_status.ifname)); event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); + if (drv) + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); + else + wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS, + &event); } @@ -908,13 +931,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, char ifname[IFNAMSIZ + 1]; char extra[100], *pos, *end; - drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); - if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d", - ifi->ifi_index); - return; - } - extra[0] = '\0'; pos = extra; end = pos + sizeof(extra); @@ -958,6 +974,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) + goto event_newlink; + if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { namebuf[0] = '\0'; if (if_indextoname(ifi->ifi_index, namebuf) && @@ -1052,10 +1072,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, -1, IF_OPER_UP); } +event_newlink: if (ifname[0]) - wpa_driver_nl80211_event_newlink(drv, ifname); + wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index, + ifname); - if (ifi->ifi_family == AF_BRIDGE && brid) { + if (ifi->ifi_family == AF_BRIDGE && brid && drv) { struct i802_bss *bss; /* device has been added to bridge */ @@ -1091,13 +1113,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, char ifname[IFNAMSIZ + 1]; char extra[100], *pos, *end; - drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); - if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d", - ifi->ifi_index); - return; - } - extra[0] = '\0'; pos = extra; end = pos + sizeof(extra); @@ -1138,10 +1153,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); - if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid)) - wpa_driver_nl80211_event_dellink(drv, ifname); + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); - if (ifi->ifi_family == AF_BRIDGE && brid) { + if (ifi->ifi_family == AF_BRIDGE && brid && drv) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; @@ -1156,6 +1170,10 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, } del_ifidx(drv, brid, ifi->ifi_index); } + + if (ifi->ifi_family != AF_BRIDGE || !brid) + wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index, + ifname); } @@ -1973,6 +1991,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0) ret = -1; + /* Radio Measurement - Radio Measurement Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0) + ret = -1; + /* Radio Measurement - Link Measurement Request */ if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) && (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0)) @@ -2034,6 +2056,49 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss) } +static int nl80211_action_subscribe_ap(struct i802_bss *bss) +{ + int ret = 0; + + /* Public Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0) + ret = -1; + /* RRM Measurement Report */ + if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0) + ret = -1; + /* RRM Neighbor Report Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0) + ret = -1; + /* FT Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) + ret = -1; +#ifdef CONFIG_IEEE80211W + /* SA Query */ + if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0) + ret = -1; +#endif /* CONFIG_IEEE80211W */ + /* Protected Dual of Public Action */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0) + ret = -1; + /* WNM */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0) + ret = -1; + /* WMM */ + if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0) + ret = -1; +#ifdef CONFIG_FST + /* FST Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0) + ret = -1; +#endif /* CONFIG_FST */ + /* Vendor-specific */ + if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0) + ret = -1; + + return ret; +} + + static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) { static const int stypes[] = { @@ -2042,7 +2107,6 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) WLAN_FC_STYPE_REASSOC_REQ, WLAN_FC_STYPE_DISASSOC, WLAN_FC_STYPE_DEAUTH, - WLAN_FC_STYPE_ACTION, WLAN_FC_STYPE_PROBE_REQ, /* Beacon doesn't work as mac80211 doesn't currently allow * it, but it wouldn't really be the right thing anyway as @@ -2067,6 +2131,9 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) } } + if (nl80211_action_subscribe_ap(bss)) + goto out_err; + if (nl80211_register_spurious_class3(bss)) goto out_err; @@ -2089,10 +2156,7 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " "handle %p (device SME)", bss->nl_mgmt); - if (nl80211_register_frame(bss, bss->nl_mgmt, - (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_ACTION << 4), - NULL, 0) < 0) + if (nl80211_action_subscribe_ap(bss)) goto out_err; nl80211_mgmt_handle_register_eloop(bss); @@ -2268,7 +2332,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; @@ -2350,6 +2415,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); @@ -2446,6 +2512,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); } @@ -3399,6 +3469,17 @@ 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; +} + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -3435,7 +3516,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) { @@ -3506,8 +3587,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", @@ -3626,7 +3709,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 @@ -3708,6 +3791,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; } @@ -3770,11 +3859,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; @@ -3861,6 +3950,13 @@ static int wpa_driver_nl80211_sta_add(void *priv, params->ext_capab_len, params->ext_capab)) goto fail; } + + if (is_ap_interface(drv->nlmode) && + nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS, + params->support_p2p_ps ? + NL80211_P2P_PS_SUPPORTED : + NL80211_P2P_PS_UNSUPPORTED)) + goto fail; } if (!params->set) { if (params->aid) { @@ -3956,6 +4052,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", @@ -4093,7 +4198,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: @@ -4275,11 +4380,11 @@ static int nl80211_setup_ap(struct i802_bss *bss) if (drv->device_ap_sme && !drv->use_monitor) if (nl80211_mgmt_subscribe_ap_dev_sme(bss)) - return -1; + wpa_printf(MSG_DEBUG, + "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it"); if (!drv->device_ap_sme && drv->use_monitor && - nl80211_create_monitor_interface(drv) && - !drv->device_ap_sme) + nl80211_create_monitor_interface(drv)) return -1; if (drv->device_ap_sme && @@ -4800,15 +4905,24 @@ 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; if (params->rrm_used) { u32 drv_rrm_flags = drv->capa.rrm_flags; - if (!(drv_rrm_flags & - WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) || - !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) || + if ((!((drv_rrm_flags & + WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) && + (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) && + !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) || nla_put_flag(msg, NL80211_ATTR_USE_RRM)) return -1; } @@ -4825,6 +4939,16 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, return -1; } + drv->connect_reassoc = 0; + if (params->prev_bssid) { + wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, + MAC2STR(params->prev_bssid)); + if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, + params->prev_bssid)) + return -1; + drv->connect_reassoc = 1; + } + return 0; } @@ -4977,14 +5101,6 @@ static int wpa_driver_nl80211_associate( if (ret) goto fail; - if (params->prev_bssid) { - wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, - MAC2STR(params->prev_bssid)); - if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, - params->prev_bssid)) - goto fail; - } - ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { @@ -5040,6 +5156,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; @@ -6858,7 +6977,7 @@ static int nl80211_set_param(void *priv, const char *param) } -static void * nl80211_global_init(void) +static void * nl80211_global_init(void *ctx) { struct nl80211_global *global; struct netlink_config *cfg; @@ -6866,6 +6985,7 @@ static void * nl80211_global_init(void) global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; + global->ctx = ctx; global->ioctl_sock = -1; dl_list_init(&global->interfaces); global->if_add_ifindex = -1; @@ -7622,7 +7742,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; @@ -8230,6 +8350,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; @@ -8304,7 +8427,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); @@ -8340,9 +8464,8 @@ static int nl80211_join_mesh(struct i802_bss *bss, 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)) + if (nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, + params->conf.max_peer_links)) goto fail; /* @@ -8365,7 +8488,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: @@ -9031,9 +9154,216 @@ 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 */ +static int nl80211_write_to_file(const char *name, unsigned int val) +{ + int fd, len; + char tmp[128]; + + fd = open(name, O_RDWR); + if (fd < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s", + name, strerror(errno)); + return fd; + } + + len = os_snprintf(tmp, sizeof(tmp), "%u\n", val); + len = write(fd, tmp, len); + if (len < 0) + wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s", + name, strerror(errno)); + close(fd); + + return 0; +} + + +static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags) +{ + struct i802_bss *bss = priv; + char path[128]; + int ret; + + wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x", + filter_flags); + + /* Configure filtering of unicast frame encrypted using GTK */ + ret = os_snprintf(path, sizeof(path), + "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast", + bss->ifname); + if (os_snprintf_error(sizeof(path), ret)) + return -1; + + ret = nl80211_write_to_file(path, + !!(filter_flags & + WPA_DATA_FRAME_FILTER_FLAG_GTK)); + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to set IPv4 unicast in multicast filter"); + return ret; + } + + os_snprintf(path, sizeof(path), + "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast", + bss->ifname); + ret = nl80211_write_to_file(path, + !!(filter_flags & + WPA_DATA_FRAME_FILTER_FLAG_GTK)); + + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to set IPv6 unicast in multicast filter"); + return ret; + } + + /* Configure filtering of unicast frame encrypted using GTK */ + os_snprintf(path, sizeof(path), + "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp", + bss->ifname); + ret = nl80211_write_to_file(path, + !!(filter_flags & + WPA_DATA_FRAME_FILTER_FLAG_ARP)); + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Failed set gratuitous ARP filter"); + return ret; + } + + /* Configure filtering of IPv6 NA frames */ + os_snprintf(path, sizeof(path), + "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na", + bss->ifname); + ret = nl80211_write_to_file(path, + !!(filter_flags & + WPA_DATA_FRAME_FILTER_FLAG_NA)); + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to set unsolicited NA filter"); + return ret; + } + + return 0; +} + + +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", @@ -9128,9 +9458,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, @@ -9143,10 +9470,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .br_set_net_param = wpa_driver_br_set_net_param, .add_tx_ts = nl80211_add_ts, .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, };