From: Aditya Kumar Singh Currently whenever stop iface is called, the complete iface is getting stopped. However, there could be a need for AP/P2P_GO type, where one would like to stop a link alone instead of the whole interface. Hence, extend stop iface infra to handle the event on the passed link id and stop that link alone instead of the whole iface. Signed-off-by: Aditya Kumar Singh Signed-off-by: Manish Dharanenthiran --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +- include/net/cfg80211.h | 6 +++++- net/mac80211/cfg.c | 2 +- net/mac80211/chan.c | 2 +- net/mac80211/iface.c | 5 +++-- net/wireless/core.c | 22 ++++++++++++++++------ net/wireless/core.h | 3 ++- net/wireless/reg.c | 2 +- net/wireless/sysfs.c | 2 +- net/wireless/trace.h | 11 +++++++---- net/wireless/util.c | 3 ++- 11 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index a395829ebadf0964b13bc3c6c5bf16c501ce19ee..008844218a9d7d46d4f778509afa11b2cc7ec67f 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1606,7 +1606,7 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO) wilc_wfi_deinit_mon_interface(wl, true); vif = netdev_priv(wdev->netdev); - cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL); + cfg80211_stop_iface(wiphy, wdev, -1, GFP_KERNEL); cfg80211_unregister_netdevice(vif->ndev); vif->monitor_flag = 0; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 406626ff6cc89df4df30e6e623403b4d9ceb6cbd..41bf31687dfdd1419850050f69acd12c2c9bff45 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -9559,15 +9559,19 @@ int cfg80211_get_radio_idx_by_chan(struct wiphy *wiphy, * * @wiphy: the wiphy * @wdev: wireless device + * @link_id: valid link ID in case of MLO AP/P2P_GO Operation or else -1 * @gfp: context flags * * Trigger interface to be stopped as if AP was stopped, IBSS/mesh left, STA * disconnected. + * In case of AP/P2P_GO types, if link_id is passed, it would only stop that + * link on the iface alone. If need to stop the whole iface, -1 should be + * passed. * * Note: This doesn't need any locks and is asynchronous. */ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, - gfp_t gfp); + int link_id, gfp_t gfp); /** * cfg80211_shutdown_all_interfaces - shut down all interfaces for a wiphy diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2ed07fa121ab73d3afd2f841eb53e6cdc0be91a3..9c951c1a2d6b00bc204d6f4097e9b1fe43c039f8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4036,7 +4036,7 @@ static void ieee80211_csa_finalize(struct ieee80211_link_data *link_data) sdata_info(sdata, "failed to finalize CSA on link %d, disconnecting\n", link_data->link_id); cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev, - GFP_KERNEL); + -1, GFP_KERNEL); } } diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c9cea0e7ac169839f883f73186b575eacfe55db5..38d02fa26198c49009404bf36548ce78a7a9032b 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1820,7 +1820,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_link_unreserve_chanctx(link); cfg80211_stop_iface(local->hw.wiphy, &link->sdata->wdev, - GFP_KERNEL); + -1, GFP_KERNEL); } } } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 07ba68f7cd817df2085eb6dd1dbdb554be117f56..073b581971f0eabaaf8cce510e90aecd93eedbb2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -778,13 +778,14 @@ void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) * removal can be supported. */ cfg80211_stop_iface(link_sdata->wdev.wiphy, &link_sdata->wdev, - GFP_KERNEL); + -1, GFP_KERNEL); } /* If we are not tx sdata, remove links of tx sdata and proceed */ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) cfg80211_stop_iface(tx_sdata->wdev.wiphy, - &tx_sdata->wdev, GFP_KERNEL); + &tx_sdata->wdev, -1, + GFP_KERNEL); } } diff --git a/net/wireless/core.c b/net/wireless/core.c index a7e2931ffb2ef5fb3b14dee39c96d4c6d21a488b..5c4f6e4bb89e46b9573a625aa519028315534507 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -344,7 +344,7 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) guard(wiphy)(&rdev->wiphy); - cfg80211_leave(rdev, wdev); + cfg80211_leave(rdev, wdev, -1); cfg80211_remove_virtual_intf(rdev, wdev); } } @@ -1347,7 +1347,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, } void cfg80211_leave(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev) + struct wireless_dev *wdev, int link_id) { struct net_device *dev = wdev->netdev; struct cfg80211_sched_scan_request *pos, *tmp; @@ -1384,7 +1384,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - cfg80211_stop_ap(rdev, dev, -1, true); + cfg80211_stop_ap(rdev, dev, link_id, true); break; case NL80211_IFTYPE_OCB: cfg80211_leave_ocb(rdev, dev); @@ -1406,13 +1406,16 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, } void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, - gfp_t gfp) + int link_id, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_event *ev; unsigned long flags; - trace_cfg80211_stop_iface(wiphy, wdev); + trace_cfg80211_stop_iface(wiphy, wdev, link_id); + + if (WARN_ON_ONCE(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) + return; ev = kzalloc(sizeof(*ev), gfp); if (!ev) @@ -1420,6 +1423,13 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, ev->type = EVENT_STOPPED; + /* link_id is expected only for AP/P2P_GO type currently */ + if (WARN_ON_ONCE((wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO) && link_id >= 0)) + link_id = -1; + + ev->link_id = link_id; + spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); @@ -1564,7 +1574,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, break; case NETDEV_GOING_DOWN: scoped_guard(wiphy, &rdev->wiphy) { - cfg80211_leave(rdev, wdev); + cfg80211_leave(rdev, wdev, -1); cfg80211_remove_links(wdev); } /* since we just did cfg80211_leave() nothing to do there */ diff --git a/net/wireless/core.h b/net/wireless/core.h index b6bd7f4d6385a128ba8fb7fc82ca4b2e8dd7d7d8..f4a440bf90cc874d676b7eb1b9a3b184d30a2ded 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -288,6 +288,7 @@ struct cfg80211_event { const u8 *td_bitmap; u8 td_bitmap_len; } pa; + int link_id; }; }; @@ -536,7 +537,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype, int num); void cfg80211_leave(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev); + struct wireless_dev *wdev, int link_id); void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3b0ac3437f81909b69efaccc3c5db8079736fe39..5f85ac0129713ea1b179c57e9fcaec3a8b4a6467 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2472,7 +2472,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy) list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) if (!reg_wdev_chan_valid(wiphy, wdev)) - cfg80211_leave(rdev, wdev); + cfg80211_leave(rdev, wdev, -1); } static void reg_check_chans_work(struct work_struct *work) diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 62f26618f674741a5163fa8e8d14c5319b2ceff8..848600bdb9f7527d7fdeb1c54ed42feb65162b12 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -88,7 +88,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) struct wireless_dev *wdev; list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) - cfg80211_leave(rdev, wdev); + cfg80211_leave(rdev, wdev, -1); } static int wiphy_suspend(struct device *dev) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 34c584a215e5d4d2acd00651e7d1a24c4c17eeed..88412dadb77eddf638239cae3782224c4e31cebb 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3951,18 +3951,21 @@ TRACE_EVENT(cfg80211_ft_event, ); TRACE_EVENT(cfg80211_stop_iface, - TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev), + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + int link_id), + TP_ARGS(wiphy, wdev, link_id), TP_STRUCT__entry( WIPHY_ENTRY WDEV_ENTRY + __field(int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; WDEV_ASSIGN; + __entry->link_id = link_id; ), - TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, - WIPHY_PR_ARG, WDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id) ); TRACE_EVENT(cfg80211_pmsr_report, diff --git a/net/wireless/util.c b/net/wireless/util.c index 240c68baa3d1f71a80a36af854acf4aa7ce75d05..6e7f89480a2e75d99aa4e63d1f3ab4caefcef33b 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1171,7 +1171,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) ev->ij.channel); break; case EVENT_STOPPED: - cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev); + cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev, + ev->link_id); break; case EVENT_PORT_AUTHORIZED: __cfg80211_port_authorized(wdev, ev->pa.peer_addr, -- 2.34.1