1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
11 static void ath11k_p2p_noa_ie_fill(u8
*data
, size_t len
,
12 const struct ath11k_wmi_p2p_noa_info
*noa
)
14 struct ieee80211_p2p_noa_attr
*noa_attr
;
15 u8 noa_descriptors
, ctwindow
;
21 ctwindow
= u32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_CTWIN_TU
);
22 oppps
= u32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_OPP_PS
);
23 noa_descriptors
= u32_get_bits(noa
->noa_attr
,
24 WMI_P2P_NOA_INFO_DESC_NUM
);
27 data
[0] = WLAN_EID_VENDOR_SPECIFIC
;
29 data
[2] = (WLAN_OUI_WFA
>> 16) & 0xff;
30 data
[3] = (WLAN_OUI_WFA
>> 8) & 0xff;
31 data
[4] = (WLAN_OUI_WFA
>> 0) & 0xff;
32 data
[5] = WLAN_OUI_TYPE_WFA_P2P
;
35 data
[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE
;
36 noa_attr_len
= (__le16
*)&data
[7]; /* 2 bytes */
37 noa_attr
= (struct ieee80211_p2p_noa_attr
*)&data
[9];
39 noa_attr
->index
= u32_get_bits(noa
->noa_attr
,
40 WMI_P2P_NOA_INFO_INDEX
);
41 noa_attr
->oppps_ctwindow
= ctwindow
;
43 noa_attr
->oppps_ctwindow
|= IEEE80211_P2P_OPPPS_ENABLE_BIT
;
45 for (i
= 0; i
< noa_descriptors
; i
++) {
46 noa_attr
->desc
[i
].count
= noa
->descriptors
[i
].type_count
;
47 noa_attr
->desc
[i
].duration
=
48 cpu_to_le32(noa
->descriptors
[i
].duration
);
49 noa_attr
->desc
[i
].interval
=
50 cpu_to_le32(noa
->descriptors
[i
].interval
);
51 noa_attr
->desc
[i
].start_time
=
52 cpu_to_le32(noa
->descriptors
[i
].start_time
);
55 attr_len
= 2; /* index + oppps_ctwindow */
56 attr_len
+= noa_descriptors
* sizeof(struct ieee80211_p2p_noa_desc
);
57 *noa_attr_len
= __cpu_to_le16(attr_len
);
61 ath11k_p2p_noa_ie_len_compute(const struct ath11k_wmi_p2p_noa_info
*noa
)
64 u8 noa_descriptors
= u32_get_bits(noa
->noa_attr
,
65 WMI_P2P_NOA_INFO_DESC_NUM
);
67 if (!(noa_descriptors
) &&
68 !(u32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_OPP_PS
)))
71 len
+= 1 + 1 + 4; /* EID + len + OUI */
72 len
+= 1 + 2; /* noa attr + attr len */
73 len
+= 1 + 1; /* index + oppps_ctwindow */
74 len
+= noa_descriptors
*
75 sizeof(struct ieee80211_p2p_noa_desc
);
80 static void ath11k_p2p_noa_ie_assign(struct ath11k_vif
*arvif
, void *ie
,
83 struct ath11k
*ar
= arvif
->ar
;
85 lockdep_assert_held(&ar
->data_lock
);
87 kfree(arvif
->u
.ap
.noa_data
);
89 arvif
->u
.ap
.noa_data
= ie
;
90 arvif
->u
.ap
.noa_len
= len
;
93 static void __ath11k_p2p_noa_update(struct ath11k_vif
*arvif
,
94 const struct ath11k_wmi_p2p_noa_info
*noa
)
96 struct ath11k
*ar
= arvif
->ar
;
100 lockdep_assert_held(&ar
->data_lock
);
102 ath11k_p2p_noa_ie_assign(arvif
, NULL
, 0);
104 len
= ath11k_p2p_noa_ie_len_compute(noa
);
108 ie
= kmalloc(len
, GFP_ATOMIC
);
112 ath11k_p2p_noa_ie_fill(ie
, len
, noa
);
113 ath11k_p2p_noa_ie_assign(arvif
, ie
, len
); }
115 void ath11k_p2p_noa_update(struct ath11k_vif
*arvif
,
116 const struct ath11k_wmi_p2p_noa_info
*noa
)
118 struct ath11k
*ar
= arvif
->ar
;
120 spin_lock_bh(&ar
->data_lock
);
121 __ath11k_p2p_noa_update(arvif
, noa
);
122 spin_unlock_bh(&ar
->data_lock
);
125 static void ath11k_p2p_noa_update_vdev_iter(void *data
, u8
*mac
,
126 struct ieee80211_vif
*vif
)
128 struct ath11k_vif
*arvif
= ath11k_vif_to_arvif(vif
);
129 struct ath11k_p2p_noa_arg
*arg
= data
;
131 if (arvif
->vdev_id
!= arg
->vdev_id
)
134 ath11k_p2p_noa_update(arvif
, arg
->noa
);
137 void ath11k_p2p_noa_update_by_vdev_id(struct ath11k
*ar
, u32 vdev_id
,
138 const struct ath11k_wmi_p2p_noa_info
*noa
)
140 struct ath11k_p2p_noa_arg arg
= {
145 ieee80211_iterate_active_interfaces_atomic(ar
->hw
,
146 IEEE80211_IFACE_ITER_NORMAL
,
147 ath11k_p2p_noa_update_vdev_iter
,