Path: blob/main/sys/contrib/dev/iwlwifi/mld/nan.c
289285 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2025 Intel Corporation3*/45#include "mld.h"6#include "iface.h"7#include "mlo.h"8#include "fw/api/mac-cfg.h"910#define IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU 51211#define IWL_NAN_RSSI_CLOSE 5512#define IWL_NAN_RSSI_MIDDLE 701314bool iwl_mld_nan_supported(struct iwl_mld *mld)15{16return fw_has_capa(&mld->fw->ucode_capa,17IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT);18}1920static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld,21struct iwl_nan_config_cmd *cmd,22u8 *beacon_data, size_t beacon_data_len)23{24struct iwl_host_cmd hcmd = {25.id = WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD),26};2728hcmd.len[0] = sizeof(*cmd);29hcmd.data[0] = cmd;3031if (beacon_data_len) {32hcmd.len[1] = beacon_data_len;33hcmd.data[1] = beacon_data;34hcmd.dataflags[1] = IWL_HCMD_DFL_DUP;35}3637return iwl_mld_send_cmd(mld, &hcmd);38}3940static int iwl_mld_nan_config(struct iwl_mld *mld,41struct ieee80211_vif *vif,42struct cfg80211_nan_conf *conf,43enum iwl_ctxt_action action)44{45struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);46struct iwl_nan_config_cmd cmd = {47.action = cpu_to_le32(action),48};49u8 *data __free(kfree) = NULL;5051lockdep_assert_wiphy(mld->wiphy);5253ether_addr_copy(cmd.nmi_addr, vif->addr);54cmd.master_pref = conf->master_pref;5556if (conf->cluster_id)57memcpy(cmd.cluster_id, conf->cluster_id + 4,58sizeof(cmd.cluster_id));5960cmd.scan_period = conf->scan_period < 255 ? conf->scan_period : 255;61cmd.dwell_time =62conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255;6364if (conf->discovery_beacon_interval)65cmd.discovery_beacon_interval =66cpu_to_le32(conf->discovery_beacon_interval);67else68cmd.discovery_beacon_interval =69cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU);7071if (conf->enable_dw_notification)72cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED;7374/* 2 GHz band must be supported */75cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_close =76abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);77cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_middle =78abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);79cmd.band_config[IWL_NAN_BAND_2GHZ].dw_interval =80conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval;8182/* 5 GHz band operation is optional. Configure its operation if83* supported. Note that conf->bands might be zero, so we need to check84* the channel pointer, not the band mask.85*/86if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {87cmd.hb_channel =88conf->band_cfgs[NL80211_BAND_5GHZ].chan->hw_value;8990cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_close =91abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);92cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_middle =93abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);94cmd.band_config[IWL_NAN_BAND_5GHZ].dw_interval =95conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval;96}9798if (conf->extra_nan_attrs_len || conf->vendor_elems_len) {99data = kmalloc(conf->extra_nan_attrs_len +100conf->vendor_elems_len, GFP_KERNEL);101if (!data)102return -ENOMEM;103104cmd.nan_attr_len = cpu_to_le32(conf->extra_nan_attrs_len);105cmd.nan_vendor_elems_len = cpu_to_le32(conf->vendor_elems_len);106107if (conf->extra_nan_attrs_len)108memcpy(data, conf->extra_nan_attrs,109conf->extra_nan_attrs_len);110111if (conf->vendor_elems_len)112memcpy(data + conf->extra_nan_attrs_len,113conf->vendor_elems,114conf->vendor_elems_len);115}116117cmd.sta_id = mld_vif->aux_sta.sta_id;118return iwl_mld_nan_send_config_cmd(mld, &cmd, data,119conf->extra_nan_attrs_len +120conf->vendor_elems_len);121}122123int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,124struct cfg80211_nan_conf *conf)125{126struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);127struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);128struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta;129int ret;130131IWL_DEBUG_MAC80211(mld, "NAN: start: bands=0x%x\n", conf->bands);132133ret = iwl_mld_update_emlsr_block(mld, true, IWL_MLD_EMLSR_BLOCKED_NAN);134if (ret)135return ret;136137ret = iwl_mld_add_aux_sta(mld, aux_sta);138if (ret)139goto unblock_emlsr;140141ret = iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_ADD);142if (ret) {143IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret);144goto remove_aux;145}146return 0;147148remove_aux:149iwl_mld_remove_aux_sta(mld, vif);150unblock_emlsr:151iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN);152153return ret;154}155156int iwl_mld_nan_change_config(struct ieee80211_hw *hw,157struct ieee80211_vif *vif,158struct cfg80211_nan_conf *conf,159u32 changes)160{161struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);162163IWL_DEBUG_MAC80211(mld, "NAN: change: changes=0x%x, bands=0x%x\n",164changes, conf->bands);165166/* Note that we do not use 'changes' as the FW always expects the167* complete configuration, and mac80211 always provides the complete168* configuration.169*/170return iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_MODIFY);171}172173int iwl_mld_stop_nan(struct ieee80211_hw *hw,174struct ieee80211_vif *vif)175{176struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);177struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);178struct iwl_nan_config_cmd cmd = {179.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),180};181int ret;182183lockdep_assert_wiphy(mld->wiphy);184185ret = iwl_mld_send_cmd_pdu(mld,186WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD),187&cmd);188if (ret)189IWL_ERR(mld, "NAN: Failed to stop NAN. ret=%d\n", ret);190191/* assume that higher layer guarantees that no additional frames are192* added before calling this callback193*/194iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id);195iwl_mld_remove_aux_sta(mld, vif);196197/* cancel based on object type being NAN, as the NAN objects do198* not have a unique identifier associated with them199*/200iwl_mld_cancel_notifications_of_object(mld,201IWL_MLD_OBJECT_TYPE_NAN,2020);203204iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN);205206return 0;207}208209void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld,210struct iwl_rx_packet *pkt)211{212struct iwl_nan_cluster_notif *notif = (void *)pkt->data;213struct wireless_dev *wdev = mld->nan_device_vif ?214ieee80211_vif_to_wdev(mld->nan_device_vif) : NULL;215bool new_cluster = !!(notif->flags &216IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER);217u8 cluster_id[ETH_ALEN] = {2180x50, 0x6f, 0x9a, 0x01,219notif->cluster_id[0], notif->cluster_id[1]220};221222IWL_DEBUG_INFO(mld,223"NAN: cluster event: cluster_id=%pM, flags=0x%x\n",224cluster_id, notif->flags);225226if (IWL_FW_CHECK(mld, !wdev, "NAN: cluster event without wdev\n"))227return;228229if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif),230"NAN: cluster event without NAN started\n"))231return;232233cfg80211_nan_cluster_joined(wdev, cluster_id, new_cluster, GFP_KERNEL);234}235236bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld,237struct iwl_rx_packet *pkt,238u32 obj_id)239{240return true;241}242243bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,244struct iwl_rx_packet *pkt,245u32 obj_id)246{247return true;248}249250void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,251struct iwl_rx_packet *pkt)252{253struct iwl_nan_dw_end_notif *notif = (void *)pkt->data;254struct iwl_mld_vif *mld_vif = mld->nan_device_vif ?255iwl_mld_vif_from_mac80211(mld->nan_device_vif) :256NULL;257struct wireless_dev *wdev;258struct ieee80211_channel *chan;259260IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band);261262if (IWL_FW_CHECK(mld, !mld_vif, "NAN: DW end without mld_vif\n"))263return;264265if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif),266"NAN: DW end without NAN started\n"))267return;268269if (WARN_ON(mld_vif->aux_sta.sta_id == IWL_INVALID_STA))270return;271272IWL_DEBUG_INFO(mld, "NAN: flush queues for aux sta=%u\n",273mld_vif->aux_sta.sta_id);274275iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id);276277/* TODO: currently the notification specified the band on which the DW278* ended. Need to change that to the actual channel on which the next DW279* will be started.280*/281switch (notif->band) {282case IWL_NAN_BAND_2GHZ:283chan = ieee80211_get_channel(mld->wiphy, 2437);284break;285case IWL_NAN_BAND_5GHZ:286/* TODO: use the actual channel */287chan = ieee80211_get_channel(mld->wiphy, 5745);288break;289default:290IWL_FW_CHECK(mld, false,291"NAN: Invalid band %u in DW end notif\n",292notif->band);293return;294}295296wdev = ieee80211_vif_to_wdev(mld->nan_device_vif);297cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL);298}299300301