diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 190 |
1 files changed, 125 insertions, 65 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 334213571ad0..be70c70d3f5b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -136,7 +136,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&sdata->local->sta_mtx); if (mac_addr) { - sta = sta_info_get_bss(sdata, mac_addr); + if (ieee80211_vif_is_mesh(&sdata->vif)) + sta = sta_info_get(sdata, mac_addr); + else + sta = sta_info_get_bss(sdata, mac_addr); if (!sta) { ieee80211_key_free(sdata->local, key); err = -ENOENT; @@ -157,13 +160,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool pairwise, const u8 *mac_addr) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; + struct ieee80211_key *key = NULL; int ret; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - mutex_lock(&sdata->local->sta_mtx); + mutex_lock(&local->sta_mtx); + mutex_lock(&local->key_mtx); if (mac_addr) { ret = -ENOENT; @@ -172,33 +176,24 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (!sta) goto out_unlock; - if (pairwise) { - if (sta->ptk) { - ieee80211_key_free(sdata->local, sta->ptk); - ret = 0; - } - } else { - if (sta->gtk[key_idx]) { - ieee80211_key_free(sdata->local, - sta->gtk[key_idx]); - ret = 0; - } - } - - goto out_unlock; - } + if (pairwise) + key = key_mtx_dereference(local, sta->ptk); + else + key = key_mtx_dereference(local, sta->gtk[key_idx]); + } else + key = key_mtx_dereference(local, sdata->keys[key_idx]); - if (!sdata->keys[key_idx]) { + if (!key) { ret = -ENOENT; goto out_unlock; } - ieee80211_key_free(sdata->local, sdata->keys[key_idx]); - WARN_ON(sdata->keys[key_idx]); + __ieee80211_key_free(key); ret = 0; out_unlock: - mutex_unlock(&sdata->local->sta_mtx); + mutex_unlock(&local->key_mtx); + mutex_unlock(&local->sta_mtx); return ret; } @@ -228,11 +223,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, goto out; if (pairwise) - key = sta->ptk; + key = rcu_dereference(sta->ptk); else if (key_idx < NUM_DEFAULT_KEYS) - key = sta->gtk[key_idx]; + key = rcu_dereference(sta->gtk[key_idx]); } else - key = sdata->keys[key_idx]; + key = rcu_dereference(sdata->keys[key_idx]); if (!key) goto out; @@ -330,6 +325,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct timespec uptime; sinfo->generation = sdata->local->sta_generation; @@ -342,7 +338,12 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_FAILED | STATION_INFO_TX_BITRATE | STATION_INFO_RX_BITRATE | - STATION_INFO_RX_DROP_MISC; + STATION_INFO_RX_DROP_MISC | + STATION_INFO_BSS_PARAM | + STATION_INFO_CONNECTED_TIME; + + do_posix_clock_monotonic_gettime(&uptime); + sinfo->connected_time = uptime.tv_sec - sta->last_connected; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; @@ -389,6 +390,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->plink_state = sta->plink_state; #endif } + + sinfo->bss_param.flags = 0; + if (sdata->vif.bss_conf.use_cts_prot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (sdata->vif.bss_conf.use_short_preamble) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (sdata->vif.bss_conf.use_short_slot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; + sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; } @@ -452,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, int size; int err = -EINVAL; - old = sdata->u.ap.beacon; + old = rtnl_dereference(sdata->u.ap.beacon); /* head must not be zero-length */ if (params->head && !params->head_len) @@ -547,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (old) return -EALREADY; @@ -563,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (!old) return -ENOENT; @@ -578,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (!old) return -ENOENT; @@ -675,6 +683,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (set & BIT(NL80211_STA_FLAG_MFP)) sta->flags |= WLAN_STA_MFP; } + + if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { + sta->flags &= ~WLAN_STA_AUTH; + if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) + sta->flags |= WLAN_STA_AUTH; + } spin_unlock_irqrestore(&sta->flaglock, flags); /* @@ -712,15 +726,29 @@ static void sta_apply_parameters(struct ieee80211_local *local, params->ht_capa, &sta->sta.ht_cap); - if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { - switch (params->plink_action) { - case PLINK_ACTION_OPEN: - mesh_plink_open(sta); - break; - case PLINK_ACTION_BLOCK: - mesh_plink_block(sta); - break; - } + if (ieee80211_vif_is_mesh(&sdata->vif)) { +#ifdef CONFIG_MAC80211_MESH + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) + switch (params->plink_state) { + case NL80211_PLINK_LISTEN: + case NL80211_PLINK_ESTAB: + case NL80211_PLINK_BLOCKED: + sta->plink_state = params->plink_state; + break; + default: + /* nothing */ + break; + } + else + switch (params->plink_action) { + case PLINK_ACTION_OPEN: + mesh_plink_open(sta); + break; + case PLINK_ACTION_BLOCK: + mesh_plink_block(sta); + break; + } +#endif } } @@ -921,8 +949,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, struct mpath_info *pinfo) { - if (mpath->next_hop) - memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); + struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); + + if (next_hop_sta) + memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN); else memset(next_hop, 0, ETH_ALEN); @@ -1023,26 +1053,30 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, u8 *new_ie; const u8 *old_ie; - /* first allocate the new vendor information element */ + /* allocate information elements */ new_ie = NULL; - old_ie = ifmsh->vendor_ie; + old_ie = ifmsh->ie; - ifmsh->vendor_ie_len = setup->vendor_ie_len; - if (setup->vendor_ie_len) { - new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, + if (setup->ie_len) { + new_ie = kmemdup(setup->ie, setup->ie_len, GFP_KERNEL); if (!new_ie) return -ENOMEM; } + ifmsh->ie_len = setup->ie_len; + ifmsh->ie = new_ie; + kfree(old_ie); /* now copy the rest of the setup parameters */ ifmsh->mesh_id_len = setup->mesh_id_len; memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); ifmsh->mesh_pp_id = setup->path_sel_proto; ifmsh->mesh_pm_id = setup->path_metric; - ifmsh->vendor_ie = new_ie; - - kfree(old_ie); + ifmsh->security = IEEE80211_MESH_SEC_NONE; + if (setup->is_authenticated) + ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; + if (setup->is_secure) + ifmsh->security |= IEEE80211_MESH_SEC_SECURED; return 0; } @@ -1275,9 +1309,10 @@ static int ieee80211_set_channel(struct wiphy *wiphy, } #ifdef CONFIG_PM -static int ieee80211_suspend(struct wiphy *wiphy) +static int ieee80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wowlan) { - return __ieee80211_suspend(wiphy_priv(wiphy)); + return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); } static int ieee80211_resume(struct wiphy *wiphy) @@ -1320,6 +1355,30 @@ static int ieee80211_scan(struct wiphy *wiphy, return ieee80211_request_scan(sdata, req); } +static int +ieee80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *req) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (!sdata->local->ops->sched_scan_start) + return -EOPNOTSUPP; + + return ieee80211_request_sched_scan_start(sdata, req); +} + +static int +ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (!sdata->local->ops->sched_scan_stop) + return -EOPNOTSUPP; + + return ieee80211_request_sched_scan_stop(sdata); +} + static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { @@ -1504,6 +1563,8 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode old_req; int err; + lockdep_assert_held(&sdata->u.mgd.mtx); + old_req = sdata->u.mgd.req_smps; sdata->u.mgd.req_smps = smps_mode; @@ -1609,16 +1670,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - /* - * This _could_ be supported by providing a hook for - * drivers for this function, but at this point it - * doesn't seem worth bothering. - */ - if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) - return -EOPNOTSUPP; + int i, ret; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { + ret = drv_set_bitrate_mask(local, sdata, mask); + if (ret) + return ret; + } for (i = 0; i < IEEE80211_NUM_BANDS; i++) sdata->rc_rateidx_mask[i] = mask->control[i].legacy; @@ -2062,6 +2120,8 @@ struct cfg80211_ops mac80211_config_ops = { .suspend = ieee80211_suspend, .resume = ieee80211_resume, .scan = ieee80211_scan, + .sched_scan_start = ieee80211_sched_scan_start, + .sched_scan_stop = ieee80211_sched_scan_stop, .auth = ieee80211_auth, .assoc = ieee80211_assoc, .deauth = ieee80211_deauth, |