diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 9 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 16 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 61 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 2 | ||||
-rw-r--r-- | net/mac80211/scan.c | 42 | ||||
-rw-r--r-- | net/mac80211/tx.c | 38 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 4 | ||||
-rw-r--r-- | net/wireless/reg.c | 25 | ||||
-rw-r--r-- | net/wireless/scan.c | 2 | ||||
-rw-r--r-- | net/wireless/wext-core.c | 8 |
13 files changed, 121 insertions, 94 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 929f897a8ded..03fe6d1cff42 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1389,6 +1389,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, else memset(next_hop, 0, ETH_ALEN); + memset(pinfo, 0, sizeof(*pinfo)); + pinfo->generation = mesh_paths_generation; pinfo->filled = MPATH_INFO_FRAME_QLEN | @@ -1407,7 +1409,6 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, pinfo->discovery_timeout = jiffies_to_msecs(mpath->discovery_timeout); pinfo->discovery_retries = mpath->discovery_retries; - pinfo->flags = 0; if (mpath->flags & MESH_PATH_ACTIVE) pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; if (mpath->flags & MESH_PATH_RESOLVING) @@ -1416,10 +1417,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID; if (mpath->flags & MESH_PATH_FIXED) pinfo->flags |= NL80211_MPATH_FLAG_FIXED; - if (mpath->flags & MESH_PATH_RESOLVING) - pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; - - pinfo->flags = mpath->flags; + if (mpath->flags & MESH_PATH_RESOLVED) + pinfo->flags |= NL80211_MPATH_FLAG_RESOLVED; } static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 204bfedba306..e2ab03c773e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -411,6 +411,7 @@ struct ieee80211_if_managed { struct work_struct monitor_work; struct work_struct chswitch_work; struct work_struct beacon_connection_loss_work; + struct work_struct csa_connection_drop_work; unsigned long beacon_timeout; unsigned long probe_timeout; @@ -970,7 +971,6 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - struct ieee80211_sched_scan_ies sched_scan_ies; struct work_struct sched_scan_stopped_work; struct ieee80211_sub_if_data __rcu *sched_scan_sdata; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 59f8adc2aa5f..d747da541747 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -278,13 +278,15 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) int n_queues = sdata->local->hw.queues; int i; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == - IEEE80211_INVAL_HW_QUEUE)) - return -EINVAL; - if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= - n_queues)) - return -EINVAL; + if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == + IEEE80211_INVAL_HW_QUEUE)) + return -EINVAL; + if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= + n_queues)) + return -EINVAL; + } } if ((sdata->vif.type != NL80211_IFTYPE_AP) || diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f4a636ffe023..ff0296c7bab8 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -637,6 +637,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); + del_timer_sync(&sdata->u.mesh.mesh_path_timer); /* * If the timer fired while we waited for it, it will have * requeued the work. Now the work will be running again @@ -649,6 +650,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); ieee80211_configure_filter(local); + + sdata->u.mesh.timers_running = 0; } static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b65b2149b23b..6e374cb04af6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -730,16 +730,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) trace_api_chswitch_done(sdata, success); if (!success) { - /* - * If the channel switch was not successful, stay - * around on the old channel. We currently lack - * good handling of this situation, possibly we - * should just drop the association. - */ - sdata->local->csa_channel = sdata->local->oper_channel; + sdata_info(sdata, + "driver channel switch failed, disconnecting\n"); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + } else { + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } - - ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } EXPORT_SYMBOL(ieee80211_chswitch_done); @@ -784,8 +781,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); - if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) + if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { + sdata_info(sdata, + "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", + ifmgd->associated->bssid, new_freq); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); return; + } sdata->local->csa_channel = new_ch; @@ -1467,6 +1470,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, del_timer_sync(&sdata->u.mgd.bcn_mon_timer); del_timer_sync(&sdata->u.mgd.timer); del_timer_sync(&sdata->u.mgd.chswitch_timer); + + sdata->u.mgd.timers_running = 0; } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -1690,7 +1695,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ap_probereq_get); -static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, + bool transmit_frame) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1702,12 +1708,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) return; } - sdata_info(sdata, "Connection to AP %pM lost\n", - ifmgd->associated->bssid); - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - false, frame_buf); + transmit_frame, frame_buf); + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; mutex_unlock(&ifmgd->mtx); /* @@ -1737,10 +1741,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) rcu_read_unlock(); } - if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) - __ieee80211_connection_loss(sdata); - else + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { + sdata_info(sdata, "Connection to AP %pM lost\n", + ifmgd->bssid); + __ieee80211_disconnect(sdata, false); + } else { ieee80211_mgd_probe_ap(sdata, true); + } +} + +static void ieee80211_csa_connection_drop_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.csa_connection_drop_work); + + ieee80211_wake_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); + __ieee80211_disconnect(sdata, true); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -2927,6 +2945,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->monitor_work); cancel_work_sync(&ifmgd->beacon_connection_loss_work); + cancel_work_sync(&ifmgd->csa_connection_drop_work); if (del_timer_sync(&ifmgd->timer)) set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); @@ -2983,6 +3002,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); INIT_WORK(&ifmgd->beacon_connection_loss_work, ieee80211_beacon_connection_loss_work); + INIT_WORK(&ifmgd->csa_connection_drop_work, + ieee80211_csa_connection_drop_work); INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); @@ -3298,6 +3319,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, goto out_unlock; err_clear: + memset(ifmgd->bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; err_free: kfree(auth_data); @@ -3506,6 +3529,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, err = 0; goto out; err_clear: + memset(ifmgd->bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; err_free: kfree(assoc_data); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 507121dad082..83608ac16780 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -233,8 +233,7 @@ static void ieee80211_hw_roc_start(struct work_struct *work) u32 dur = dep->duration; dep->duration = dur - roc->duration; roc->duration = dur; - list_del(&dep->list); - list_add(&dep->list, &roc->list); + list_move(&dep->list, &roc->list); } } out_unlock: diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b382605c5733..61c621e9273f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -103,7 +103,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, return len; } -/** +/* * ieee80211_add_rx_radiotap_header - add radiotap header * * add a radiotap header containing all the fields which the hardware provided. diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ef1d69306315..e9b19294dd45 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -299,7 +299,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); local->scanning = 0; local->scan_channel = NULL; @@ -917,6 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req) { struct ieee80211_local *local = sdata->local; + struct ieee80211_sched_scan_ies sched_scan_ies; int ret, i; mutex_lock(&local->mtx); @@ -935,33 +936,28 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, if (!local->hw.wiphy->bands[i]) continue; - local->sched_scan_ies.ie[i] = kzalloc(2 + - IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + - req->ie_len, - GFP_KERNEL); - if (!local->sched_scan_ies.ie[i]) { + sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + + req->ie_len, + GFP_KERNEL); + if (!sched_scan_ies.ie[i]) { ret = -ENOMEM; goto out_free; } - local->sched_scan_ies.len[i] = - ieee80211_build_preq_ies(local, - local->sched_scan_ies.ie[i], + sched_scan_ies.len[i] = + ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], req->ie, req->ie_len, i, (u32) -1, 0); } - ret = drv_sched_scan_start(local, sdata, req, - &local->sched_scan_ies); - if (ret == 0) { + ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); + if (ret == 0) rcu_assign_pointer(local->sched_scan_sdata, sdata); - goto out; - } out_free: while (i > 0) - kfree(local->sched_scan_ies.ie[--i]); + kfree(sched_scan_ies.ie[--i]); out: mutex_unlock(&local->mtx); return ret; @@ -970,7 +966,7 @@ out: int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - int ret = 0, i; + int ret = 0; mutex_lock(&local->mtx); @@ -979,13 +975,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) goto out; } - if (rcu_access_pointer(local->sched_scan_sdata)) { - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - kfree(local->sched_scan_ies.ie[i]); - + if (rcu_access_pointer(local->sched_scan_sdata)) drv_sched_scan_stop(local, sdata); - rcu_assign_pointer(local->sched_scan_sdata, NULL); - } + out: mutex_unlock(&local->mtx); @@ -1007,7 +999,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) struct ieee80211_local *local = container_of(work, struct ieee80211_local, sched_scan_stopped_work); - int i; mutex_lock(&local->mtx); @@ -1016,9 +1007,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) return; } - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - kfree(local->sched_scan_ies.ie[i]); - rcu_assign_pointer(local->sched_scan_sdata, NULL); mutex_unlock(&local->mtx); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3b807bcb8fc9..29eb4e678235 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1807,37 +1807,31 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, NULL, NULL); } else { - int is_mesh_mcast = 1; - const u8 *mesh_da; + /* DS -> MBSS (802.11-2012 13.11.3.3). + * For unicast with unknown forwarding information, + * destination might be in the MBSS or if that fails + * forwarded to another mesh gate. In either case + * resolution will be handled in ieee80211_xmit(), so + * leave the original DA. This also works for mcast */ + const u8 *mesh_da = skb->data; + + if (mppath) + mesh_da = mppath->mpp; + else if (mpath) + mesh_da = mpath->dst; + rcu_read_unlock(); - if (is_multicast_ether_addr(skb->data)) - /* DA TA mSA AE:SA */ - mesh_da = skb->data; - else { - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - if (mppath) { - /* RA TA mDA mSA AE:DA SA */ - mesh_da = mppath->mpp; - is_mesh_mcast = 0; - } else if (mpath) { - mesh_da = mpath->dst; - is_mesh_mcast = 0; - } else { - /* DA TA mSA AE:SA */ - mesh_da = bcast; - } - } hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, mesh_da, sdata->vif.addr); - rcu_read_unlock(); - if (is_mesh_mcast) + if (is_multicast_ether_addr(mesh_da)) + /* DA TA mSA AE:SA */ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, skb->data + ETH_ALEN, NULL); else + /* RA TA mDA mSA AE:DA SA */ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 787aeaa902fe..222189b6ed53 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5656,8 +5656,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) sizeof(connect.ht_capa_mask)); if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { - if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) + if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) { + kfree(connkeys); return -EINVAL; + } memcpy(&connect.ht_capa, nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), sizeof(connect.ht_capa)); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2303ee73b50a..1ad04e54014c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -680,6 +680,8 @@ static u32 map_regdom_flags(u32 rd_flags) channel_flags |= IEEE80211_CHAN_NO_IBSS; if (rd_flags & NL80211_RRF_DFS) channel_flags |= IEEE80211_CHAN_RADAR; + if (rd_flags & NL80211_RRF_NO_OFDM) + channel_flags |= IEEE80211_CHAN_NO_OFDM; return channel_flags; } @@ -901,7 +903,21 @@ static void handle_channel(struct wiphy *wiphy, chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); - chan->max_power = min(chan->max_power, chan->max_reg_power); + if (chan->orig_mpwr) { + /* + * Devices that have their own custom regulatory domain + * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the + * passed country IE power settings. + */ + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + chan->max_power = chan->max_reg_power; + else + chan->max_power = min(chan->orig_mpwr, + chan->max_reg_power); + } else + chan->max_power = chan->max_reg_power; } static void handle_band(struct wiphy *wiphy, @@ -1885,6 +1901,7 @@ static void restore_custom_reg_settings(struct wiphy *wiphy) chan->flags = chan->orig_flags; chan->max_antenna_gain = chan->orig_mag; chan->max_power = chan->orig_mpwr; + chan->beacon_found = false; } } } @@ -1932,8 +1949,7 @@ static void restore_regulatory_settings(bool reset_user) if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER) continue; - list_del(®_request->list); - list_add_tail(®_request->list, &tmp_reg_req_list); + list_move_tail(®_request->list, &tmp_reg_req_list); } } spin_unlock(®_requests_lock); @@ -1992,8 +2008,7 @@ static void restore_regulatory_settings(bool reset_user) "into the queue\n", reg_request->alpha2[0], reg_request->alpha2[1]); - list_del(®_request->list); - list_add_tail(®_request->list, ®_requests_list); + list_move_tail(®_request->list, ®_requests_list); } spin_unlock(®_requests_lock); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 848523a2b22f..9730c9862bdc 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -815,7 +815,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, return NULL; if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (signal < 0 || signal > 100))) + (signal < 0 || signal > 100))) return NULL; if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index b0eb7aa49b60..c8717c1d082e 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -478,13 +478,13 @@ void wireless_send_event(struct net_device * dev, if (descr->header_type == IW_HEADER_TYPE_POINT) { /* Check if number of token fits within bounds */ if (wrqu->data.length > descr->max_tokens) { - netdev_err(dev, "(WE) : Wireless Event too big (%d)\n", - wrqu->data.length); + netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too big (%d)\n", + cmd, wrqu->data.length); return; } if (wrqu->data.length < descr->min_tokens) { - netdev_err(dev, "(WE) : Wireless Event too small (%d)\n", - wrqu->data.length); + netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too small (%d)\n", + cmd, wrqu->data.length); return; } /* Calculate extra_len - extra is NULL for restricted events */ |