Path: blob/main/sys/contrib/dev/athk/ath10k/p2p.c
106917 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2015 Qualcomm Atheros, Inc.3*/45#include "core.h"6#include "wmi.h"7#include "mac.h"8#include "p2p.h"910static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,11const struct wmi_p2p_noa_info *noa)12{13struct ieee80211_p2p_noa_attr *noa_attr;14u8 ctwindow_oppps = noa->ctwindow_oppps;15u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;16bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);17__le16 *noa_attr_len;18u16 attr_len;19u8 noa_descriptors = noa->num_descriptors;20int i;2122/* P2P IE */23data[0] = WLAN_EID_VENDOR_SPECIFIC;24data[1] = len - 2;25data[2] = (WLAN_OUI_WFA >> 16) & 0xff;26data[3] = (WLAN_OUI_WFA >> 8) & 0xff;27data[4] = (WLAN_OUI_WFA >> 0) & 0xff;28data[5] = WLAN_OUI_TYPE_WFA_P2P;2930/* NOA ATTR */31data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;32noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */33noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];3435noa_attr->index = noa->index;36noa_attr->oppps_ctwindow = ctwindow;37if (oppps)38noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;3940for (i = 0; i < noa_descriptors; i++) {41noa_attr->desc[i].count =42__le32_to_cpu(noa->descriptors[i].type_count);43noa_attr->desc[i].duration = noa->descriptors[i].duration;44noa_attr->desc[i].interval = noa->descriptors[i].interval;45noa_attr->desc[i].start_time = noa->descriptors[i].start_time;46}4748attr_len = 2; /* index + oppps_ctwindow */49attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);50*noa_attr_len = __cpu_to_le16(attr_len);51}5253static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)54{55size_t len = 0;5657if (!noa->num_descriptors &&58!(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))59return 0;6061len += 1 + 1 + 4; /* EID + len + OUI */62len += 1 + 2; /* noa attr + attr len */63len += 1 + 1; /* index + oppps_ctwindow */64len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);6566return len;67}6869static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,70size_t len)71{72struct ath10k *ar = arvif->ar;7374lockdep_assert_held(&ar->data_lock);7576kfree(arvif->u.ap.noa_data);7778arvif->u.ap.noa_data = ie;79arvif->u.ap.noa_len = len;80}8182static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,83const struct wmi_p2p_noa_info *noa)84{85struct ath10k *ar = arvif->ar;86void *ie;87size_t len;8889lockdep_assert_held(&ar->data_lock);9091ath10k_p2p_noa_ie_assign(arvif, NULL, 0);9293len = ath10k_p2p_noa_ie_len_compute(noa);94if (!len)95return;9697ie = kmalloc(len, GFP_ATOMIC);98if (!ie)99return;100101ath10k_p2p_noa_ie_fill(ie, len, noa);102ath10k_p2p_noa_ie_assign(arvif, ie, len);103}104105void ath10k_p2p_noa_update(struct ath10k_vif *arvif,106const struct wmi_p2p_noa_info *noa)107{108struct ath10k *ar = arvif->ar;109110spin_lock_bh(&ar->data_lock);111__ath10k_p2p_noa_update(arvif, noa);112spin_unlock_bh(&ar->data_lock);113}114115struct ath10k_p2p_noa_arg {116u32 vdev_id;117const struct wmi_p2p_noa_info *noa;118};119120static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,121struct ieee80211_vif *vif)122{123struct ath10k_vif *arvif = (void *)vif->drv_priv;124struct ath10k_p2p_noa_arg *arg = data;125126if (arvif->vdev_id != arg->vdev_id)127return;128129ath10k_p2p_noa_update(arvif, arg->noa);130}131132void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,133const struct wmi_p2p_noa_info *noa)134{135struct ath10k_p2p_noa_arg arg = {136.vdev_id = vdev_id,137.noa = noa,138};139140ieee80211_iterate_active_interfaces_atomic(ar->hw,141ATH10K_ITER_NORMAL_FLAGS,142ath10k_p2p_noa_update_vdev_iter,143&arg);144}145146147