diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 39 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 25 | ||||
-rw-r--r-- | net/mac80211/iface.c | 19 | ||||
-rw-r--r-- | net/mac80211/pm.c | 4 | ||||
-rw-r--r-- | net/mac80211/rx.c | 39 | ||||
-rw-r--r-- | net/mac80211/trace.h | 37 | ||||
-rw-r--r-- | net/mac80211/util.c | 6 |
7 files changed, 114 insertions, 55 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5eab1325a0f6..34fd3eba3090 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -922,6 +922,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return err; changed |= err; + err = drv_start_ap(sdata->local, sdata); + if (err) { + old = rtnl_dereference(sdata->u.ap.beacon); + if (old) + kfree_rcu(old, rcu_head); + RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + return err; + } + ieee80211_bss_info_change_notify(sdata, changed); netif_carrier_on(dev); @@ -953,26 +962,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { - struct ieee80211_sub_if_data *sdata, *vlan; - struct beacon_data *old; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *vlan; + struct ieee80211_local *local = sdata->local; + struct beacon_data *old_beacon; + struct probe_resp *old_probe_resp; - old = rtnl_dereference(sdata->u.ap.beacon); - if (!old) + old_beacon = rtnl_dereference(sdata->u.ap.beacon); + if (!old_beacon) return -ENOENT; + old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); + /* turn off carrier for this interface and dependent VLANs */ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) netif_carrier_off(vlan->dev); netif_carrier_off(dev); + /* remove beacon and probe response */ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); + kfree_rcu(old_beacon, rcu_head); + if (old_probe_resp) + kfree_rcu(old_probe_resp, rcu_head); - kfree_rcu(old, rcu_head); - - sta_info_flush(sdata->local, sdata); + sta_info_flush(local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + drv_stop_ap(sdata->local, sdata); + + /* free all potentially still buffered bcast frames */ + local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); + skb_queue_purge(&sdata->u.ap.ps.bc_buf); + ieee80211_vif_release_channel(sdata); return 0; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 77407b31e1ff..1701ad7013a4 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -936,4 +936,29 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_start_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + int ret = 0; + + check_sdata_in_driver(sdata); + + trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); + if (local->ops->start_ap) + ret = local->ops->start_ap(&local->hw, &sdata->vif); + trace_drv_return_int(local, ret); + return ret; +} + +static inline void drv_stop_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + check_sdata_in_driver(sdata); + + trace_drv_stop_ap(local, sdata); + if (local->ops->stop_ap) + local->ops->stop_ap(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bc3e3e1db093..1a6fe135f201 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -744,31 +744,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { struct ieee80211_sub_if_data *vlan, *tmpsdata; - struct beacon_data *old_beacon = - rtnl_dereference(sdata->u.ap.beacon); - struct probe_resp *old_probe_resp = - rtnl_dereference(sdata->u.ap.probe_resp); - - /* sdata_running will return false, so this will disable */ - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_ENABLED); - - /* remove beacon and probe response */ - RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); - RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); - synchronize_rcu(); - kfree(old_beacon); - kfree(old_probe_resp); /* down all dependent devices, that is VLANs */ list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, u.vlan.list) dev_close(vlan->dev); WARN_ON(!list_empty(&sdata->u.ap.vlans)); - - /* free all potentially still buffered bcast frames */ - local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); - skb_queue_purge(&sdata->u.ap.ps.bc_buf); } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { ieee80211_mgd_stop(sdata); } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9f404ac901ab..0f1c434638bc 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -135,6 +135,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + if (sdata->vif.type == NL80211_IFTYPE_AP && + rcu_access_pointer(sdata->u.ap.beacon)) + drv_stop_ap(local, sdata); + /* the interface is leaving the channel and is removed */ ieee80211_vif_release_channel(sdata); drv_remove_interface(local, sdata); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c1f1527d671..38b382682cae 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -54,8 +54,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, return skb; } -static inline int should_drop_frame(struct sk_buff *skb, - int present_fcs_len) +static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -130,15 +129,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, (1 << IEEE80211_RADIOTAP_RX_FLAGS)); rthdr->it_len = cpu_to_le16(rtap_len); - pos = (unsigned char *)(rthdr+1); + pos = (unsigned char *)(rthdr + 1); /* the order of the following fields is important */ /* IEEE80211_RADIOTAP_TSFT */ if (status->flag & RX_FLAG_MACTIME_MPDU) { put_unaligned_le64(status->mactime, pos); - rthdr->it_present |= - cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; } @@ -374,7 +372,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, return origskb; } - static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -481,8 +478,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; struct ieee80211_mmie *mmie; - if (skb->len < 24 + sizeof(*mmie) || - !is_multicast_ether_addr(hdr->da)) + if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) return -1; if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) @@ -497,9 +493,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return le16_to_cpu(mmie->key_id); } - -static ieee80211_rx_result -ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) +static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; char *dev_addr = rx->sdata->vif.addr; @@ -507,7 +501,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr1)) { if (ieee80211_has_tods(hdr->frame_control) || - !ieee80211_has_fromds(hdr->frame_control)) + !ieee80211_has_fromds(hdr->frame_control)) return RX_DROP_MONITOR; if (ether_addr_equal(hdr->addr3, dev_addr)) return RX_DROP_MONITOR; @@ -539,7 +533,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) mgmt = (struct ieee80211_mgmt *)hdr; category = mgmt->u.action.category; if (category != WLAN_CATEGORY_MESH_ACTION && - category != WLAN_CATEGORY_SELF_PROTECTED) + category != WLAN_CATEGORY_SELF_PROTECTED) return RX_DROP_MONITOR; return RX_CONTINUE; } @@ -551,7 +545,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) return RX_CONTINUE; return RX_DROP_MONITOR; - } return RX_CONTINUE; @@ -575,7 +568,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) return (sq1 - sq2) & SEQ_MASK; } - static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, int index) @@ -1585,18 +1577,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static int -ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) +static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { - if (unlikely(!rx->sta || - !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) + if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) return -EACCES; return 0; } -static int -ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) +static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) { struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); @@ -1618,8 +1607,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) return 0; } -static int -ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) +static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); @@ -2003,7 +1991,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } else { /* unable to resolve next hop */ mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, - 0, reason, fwd_hdr->addr2, sdata); + 0, reason, fwd_hdr->addr2, sdata); IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); kfree_skb(fwd_skb); return RX_DROP_MONITOR; @@ -2412,7 +2400,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!ieee80211_vif_is_mesh(&sdata->vif)) break; if (mesh_action_is_path_sel(mgmt) && - (!mesh_path_sel_is_hwmp(sdata))) + !mesh_path_sel_is_hwmp(sdata)) break; goto queue; } @@ -2468,7 +2456,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } - return RX_CONTINUE; } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0638541b625f..5e74e77cba9a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1396,6 +1396,43 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_ARGS(local, sdata, ctx) ); +TRACE_EVENT(drv_start_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *info), + + TP_ARGS(local, sdata, info), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u8, dtimper) + __field(u16, bcnint) + __dynamic_array(u8, ssid, info->ssid_len); + __field(bool, hidden_ssid); + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + __entry->hidden_ssid = info->hidden_ssid; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG + ) +); + +DEFINE_EVENT(local_sdata_evt, drv_stop_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) +); + /* * Tracing for API calls that drivers call. */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9556391b05d7..6636d3962317 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1495,9 +1495,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_AP: changed |= BSS_CHANGED_SSID; - if (sdata->vif.type == NL80211_IFTYPE_AP) + if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; + if (rcu_access_pointer(sdata->u.ap.beacon)) + drv_start_ap(local, sdata); + } + /* fall through */ case NL80211_IFTYPE_MESH_POINT: changed |= BSS_CHANGED_BEACON | |