1*a9655020SBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*a9655020SBjoern A. Zeeb /*
3*a9655020SBjoern A. Zeeb * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*a9655020SBjoern A. Zeeb * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5*a9655020SBjoern A. Zeeb */
6*a9655020SBjoern A. Zeeb
7*a9655020SBjoern A. Zeeb #include <net/mac80211.h>
8*a9655020SBjoern A. Zeeb #include "core.h"
9*a9655020SBjoern A. Zeeb #include "mac.h"
10*a9655020SBjoern A. Zeeb #include "p2p.h"
11*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_ie_fill(u8 * data,size_t len,const struct ath12k_wmi_p2p_noa_info * noa)12*a9655020SBjoern A. Zeeb static void ath12k_p2p_noa_ie_fill(u8 *data, size_t len,
13*a9655020SBjoern A. Zeeb const struct ath12k_wmi_p2p_noa_info *noa)
14*a9655020SBjoern A. Zeeb {
15*a9655020SBjoern A. Zeeb struct ieee80211_p2p_noa_attr *noa_attr;
16*a9655020SBjoern A. Zeeb u8 ctwindow = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU);
17*a9655020SBjoern A. Zeeb bool oppps = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS);
18*a9655020SBjoern A. Zeeb __le16 *noa_attr_len;
19*a9655020SBjoern A. Zeeb u16 attr_len;
20*a9655020SBjoern A. Zeeb u8 noa_descriptors = le32_get_bits(noa->noa_attr,
21*a9655020SBjoern A. Zeeb WMI_P2P_NOA_INFO_DESC_NUM);
22*a9655020SBjoern A. Zeeb int i;
23*a9655020SBjoern A. Zeeb
24*a9655020SBjoern A. Zeeb /* P2P IE */
25*a9655020SBjoern A. Zeeb data[0] = WLAN_EID_VENDOR_SPECIFIC;
26*a9655020SBjoern A. Zeeb data[1] = len - 2;
27*a9655020SBjoern A. Zeeb data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
28*a9655020SBjoern A. Zeeb data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
29*a9655020SBjoern A. Zeeb data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
30*a9655020SBjoern A. Zeeb data[5] = WLAN_OUI_TYPE_WFA_P2P;
31*a9655020SBjoern A. Zeeb
32*a9655020SBjoern A. Zeeb /* NOA ATTR */
33*a9655020SBjoern A. Zeeb data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
34*a9655020SBjoern A. Zeeb noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
35*a9655020SBjoern A. Zeeb noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
36*a9655020SBjoern A. Zeeb
37*a9655020SBjoern A. Zeeb noa_attr->index = le32_get_bits(noa->noa_attr,
38*a9655020SBjoern A. Zeeb WMI_P2P_NOA_INFO_INDEX);
39*a9655020SBjoern A. Zeeb noa_attr->oppps_ctwindow = ctwindow;
40*a9655020SBjoern A. Zeeb if (oppps)
41*a9655020SBjoern A. Zeeb noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
42*a9655020SBjoern A. Zeeb
43*a9655020SBjoern A. Zeeb for (i = 0; i < noa_descriptors; i++) {
44*a9655020SBjoern A. Zeeb noa_attr->desc[i].count =
45*a9655020SBjoern A. Zeeb __le32_to_cpu(noa->descriptors[i].type_count);
46*a9655020SBjoern A. Zeeb noa_attr->desc[i].duration = noa->descriptors[i].duration;
47*a9655020SBjoern A. Zeeb noa_attr->desc[i].interval = noa->descriptors[i].interval;
48*a9655020SBjoern A. Zeeb noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
49*a9655020SBjoern A. Zeeb }
50*a9655020SBjoern A. Zeeb
51*a9655020SBjoern A. Zeeb attr_len = 2; /* index + oppps_ctwindow */
52*a9655020SBjoern A. Zeeb attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
53*a9655020SBjoern A. Zeeb *noa_attr_len = __cpu_to_le16(attr_len);
54*a9655020SBjoern A. Zeeb }
55*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info * noa)56*a9655020SBjoern A. Zeeb static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info *noa)
57*a9655020SBjoern A. Zeeb {
58*a9655020SBjoern A. Zeeb size_t len = 0;
59*a9655020SBjoern A. Zeeb
60*a9655020SBjoern A. Zeeb if (!(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)) &&
61*a9655020SBjoern A. Zeeb !(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS)))
62*a9655020SBjoern A. Zeeb return 0;
63*a9655020SBjoern A. Zeeb
64*a9655020SBjoern A. Zeeb len += 1 + 1 + 4; /* EID + len + OUI */
65*a9655020SBjoern A. Zeeb len += 1 + 2; /* noa attr + attr len */
66*a9655020SBjoern A. Zeeb len += 1 + 1; /* index + oppps_ctwindow */
67*a9655020SBjoern A. Zeeb len += le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM) *
68*a9655020SBjoern A. Zeeb sizeof(struct ieee80211_p2p_noa_desc);
69*a9655020SBjoern A. Zeeb
70*a9655020SBjoern A. Zeeb return len;
71*a9655020SBjoern A. Zeeb }
72*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_ie_assign(struct ath12k_link_vif * arvif,void * ie,size_t len)73*a9655020SBjoern A. Zeeb static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif *arvif, void *ie,
74*a9655020SBjoern A. Zeeb size_t len)
75*a9655020SBjoern A. Zeeb {
76*a9655020SBjoern A. Zeeb struct ath12k *ar = arvif->ar;
77*a9655020SBjoern A. Zeeb
78*a9655020SBjoern A. Zeeb lockdep_assert_held(&ar->data_lock);
79*a9655020SBjoern A. Zeeb
80*a9655020SBjoern A. Zeeb kfree(arvif->ahvif->u.ap.noa_data);
81*a9655020SBjoern A. Zeeb
82*a9655020SBjoern A. Zeeb arvif->ahvif->u.ap.noa_data = ie;
83*a9655020SBjoern A. Zeeb arvif->ahvif->u.ap.noa_len = len;
84*a9655020SBjoern A. Zeeb }
85*a9655020SBjoern A. Zeeb
__ath12k_p2p_noa_update(struct ath12k_link_vif * arvif,const struct ath12k_wmi_p2p_noa_info * noa)86*a9655020SBjoern A. Zeeb static void __ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
87*a9655020SBjoern A. Zeeb const struct ath12k_wmi_p2p_noa_info *noa)
88*a9655020SBjoern A. Zeeb {
89*a9655020SBjoern A. Zeeb struct ath12k *ar = arvif->ar;
90*a9655020SBjoern A. Zeeb void *ie;
91*a9655020SBjoern A. Zeeb size_t len;
92*a9655020SBjoern A. Zeeb
93*a9655020SBjoern A. Zeeb lockdep_assert_held(&ar->data_lock);
94*a9655020SBjoern A. Zeeb
95*a9655020SBjoern A. Zeeb ath12k_p2p_noa_ie_assign(arvif, NULL, 0);
96*a9655020SBjoern A. Zeeb
97*a9655020SBjoern A. Zeeb len = ath12k_p2p_noa_ie_len_compute(noa);
98*a9655020SBjoern A. Zeeb if (!len)
99*a9655020SBjoern A. Zeeb return;
100*a9655020SBjoern A. Zeeb
101*a9655020SBjoern A. Zeeb ie = kmalloc(len, GFP_ATOMIC);
102*a9655020SBjoern A. Zeeb if (!ie)
103*a9655020SBjoern A. Zeeb return;
104*a9655020SBjoern A. Zeeb
105*a9655020SBjoern A. Zeeb ath12k_p2p_noa_ie_fill(ie, len, noa);
106*a9655020SBjoern A. Zeeb ath12k_p2p_noa_ie_assign(arvif, ie, len);
107*a9655020SBjoern A. Zeeb }
108*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_update(struct ath12k_link_vif * arvif,const struct ath12k_wmi_p2p_noa_info * noa)109*a9655020SBjoern A. Zeeb void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
110*a9655020SBjoern A. Zeeb const struct ath12k_wmi_p2p_noa_info *noa)
111*a9655020SBjoern A. Zeeb {
112*a9655020SBjoern A. Zeeb struct ath12k *ar = arvif->ar;
113*a9655020SBjoern A. Zeeb
114*a9655020SBjoern A. Zeeb spin_lock_bh(&ar->data_lock);
115*a9655020SBjoern A. Zeeb __ath12k_p2p_noa_update(arvif, noa);
116*a9655020SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock);
117*a9655020SBjoern A. Zeeb }
118*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_update_vdev_iter(void * data,u8 * mac,struct ieee80211_vif * vif)119*a9655020SBjoern A. Zeeb static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
120*a9655020SBjoern A. Zeeb struct ieee80211_vif *vif)
121*a9655020SBjoern A. Zeeb {
122*a9655020SBjoern A. Zeeb struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
123*a9655020SBjoern A. Zeeb struct ath12k_p2p_noa_arg *arg = data;
124*a9655020SBjoern A. Zeeb struct ath12k_link_vif *arvif;
125*a9655020SBjoern A. Zeeb
126*a9655020SBjoern A. Zeeb WARN_ON(!rcu_read_lock_any_held());
127*a9655020SBjoern A. Zeeb arvif = &ahvif->deflink;
128*a9655020SBjoern A. Zeeb if (!arvif->is_created || arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
129*a9655020SBjoern A. Zeeb return;
130*a9655020SBjoern A. Zeeb
131*a9655020SBjoern A. Zeeb ath12k_p2p_noa_update(arvif, arg->noa);
132*a9655020SBjoern A. Zeeb }
133*a9655020SBjoern A. Zeeb
ath12k_p2p_noa_update_by_vdev_id(struct ath12k * ar,u32 vdev_id,const struct ath12k_wmi_p2p_noa_info * noa)134*a9655020SBjoern A. Zeeb void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id,
135*a9655020SBjoern A. Zeeb const struct ath12k_wmi_p2p_noa_info *noa)
136*a9655020SBjoern A. Zeeb {
137*a9655020SBjoern A. Zeeb struct ath12k_p2p_noa_arg arg = {
138*a9655020SBjoern A. Zeeb .vdev_id = vdev_id,
139*a9655020SBjoern A. Zeeb .ar = ar,
140*a9655020SBjoern A. Zeeb .noa = noa,
141*a9655020SBjoern A. Zeeb };
142*a9655020SBjoern A. Zeeb
143*a9655020SBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar),
144*a9655020SBjoern A. Zeeb IEEE80211_IFACE_ITER_NORMAL,
145*a9655020SBjoern A. Zeeb ath12k_p2p_noa_update_vdev_iter,
146*a9655020SBjoern A. Zeeb &arg);
147*a9655020SBjoern A. Zeeb }
148