1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
6 #include <net/mac80211.h>
11 static void ath12k_p2p_noa_ie_fill(u8
*data
, size_t len
,
12 const struct ath12k_wmi_p2p_noa_info
*noa
)
14 struct ieee80211_p2p_noa_attr
*noa_attr
;
15 u8 ctwindow
= le32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_CTWIN_TU
);
16 bool oppps
= le32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_OPP_PS
);
19 u8 noa_descriptors
= le32_get_bits(noa
->noa_attr
,
20 WMI_P2P_NOA_INFO_DESC_NUM
);
24 data
[0] = WLAN_EID_VENDOR_SPECIFIC
;
26 data
[2] = (WLAN_OUI_WFA
>> 16) & 0xff;
27 data
[3] = (WLAN_OUI_WFA
>> 8) & 0xff;
28 data
[4] = (WLAN_OUI_WFA
>> 0) & 0xff;
29 data
[5] = WLAN_OUI_TYPE_WFA_P2P
;
32 data
[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE
;
33 noa_attr_len
= (__le16
*)&data
[7]; /* 2 bytes */
34 noa_attr
= (struct ieee80211_p2p_noa_attr
*)&data
[9];
36 noa_attr
->index
= le32_get_bits(noa
->noa_attr
,
37 WMI_P2P_NOA_INFO_INDEX
);
38 noa_attr
->oppps_ctwindow
= ctwindow
;
40 noa_attr
->oppps_ctwindow
|= IEEE80211_P2P_OPPPS_ENABLE_BIT
;
42 for (i
= 0; i
< noa_descriptors
; i
++) {
43 noa_attr
->desc
[i
].count
=
44 __le32_to_cpu(noa
->descriptors
[i
].type_count
);
45 noa_attr
->desc
[i
].duration
= noa
->descriptors
[i
].duration
;
46 noa_attr
->desc
[i
].interval
= noa
->descriptors
[i
].interval
;
47 noa_attr
->desc
[i
].start_time
= noa
->descriptors
[i
].start_time
;
50 attr_len
= 2; /* index + oppps_ctwindow */
51 attr_len
+= noa_descriptors
* sizeof(struct ieee80211_p2p_noa_desc
);
52 *noa_attr_len
= __cpu_to_le16(attr_len
);
55 static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info
*noa
)
59 if (!(le32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_DESC_NUM
)) &&
60 !(le32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_OPP_PS
)))
63 len
+= 1 + 1 + 4; /* EID + len + OUI */
64 len
+= 1 + 2; /* noa attr + attr len */
65 len
+= 1 + 1; /* index + oppps_ctwindow */
66 len
+= le32_get_bits(noa
->noa_attr
, WMI_P2P_NOA_INFO_DESC_NUM
) *
67 sizeof(struct ieee80211_p2p_noa_desc
);
72 static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif
*arvif
, void *ie
,
75 struct ath12k
*ar
= arvif
->ar
;
77 lockdep_assert_held(&ar
->data_lock
);
79 kfree(arvif
->ahvif
->u
.ap
.noa_data
);
81 arvif
->ahvif
->u
.ap
.noa_data
= ie
;
82 arvif
->ahvif
->u
.ap
.noa_len
= len
;
85 static void __ath12k_p2p_noa_update(struct ath12k_link_vif
*arvif
,
86 const struct ath12k_wmi_p2p_noa_info
*noa
)
88 struct ath12k
*ar
= arvif
->ar
;
92 lockdep_assert_held(&ar
->data_lock
);
94 ath12k_p2p_noa_ie_assign(arvif
, NULL
, 0);
96 len
= ath12k_p2p_noa_ie_len_compute(noa
);
100 ie
= kmalloc(len
, GFP_ATOMIC
);
104 ath12k_p2p_noa_ie_fill(ie
, len
, noa
);
105 ath12k_p2p_noa_ie_assign(arvif
, ie
, len
);
108 void ath12k_p2p_noa_update(struct ath12k_link_vif
*arvif
,
109 const struct ath12k_wmi_p2p_noa_info
*noa
)
111 struct ath12k
*ar
= arvif
->ar
;
113 spin_lock_bh(&ar
->data_lock
);
114 __ath12k_p2p_noa_update(arvif
, noa
);
115 spin_unlock_bh(&ar
->data_lock
);
118 static void ath12k_p2p_noa_update_vdev_iter(void *data
, u8
*mac
,
119 struct ieee80211_vif
*vif
)
121 struct ath12k_vif
*ahvif
= ath12k_vif_to_ahvif(vif
);
122 struct ath12k_p2p_noa_arg
*arg
= data
;
123 struct ath12k_link_vif
*arvif
;
125 WARN_ON(!rcu_read_lock_any_held());
126 arvif
= &ahvif
->deflink
;
127 if (arvif
->ar
!= arg
->ar
|| arvif
->vdev_id
!= arg
->vdev_id
)
130 ath12k_p2p_noa_update(arvif
, arg
->noa
);
133 void ath12k_p2p_noa_update_by_vdev_id(struct ath12k
*ar
, u32 vdev_id
,
134 const struct ath12k_wmi_p2p_noa_info
*noa
)
136 struct ath12k_p2p_noa_arg arg
= {
142 ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar
),
143 IEEE80211_IFACE_ITER_NORMAL
,
144 ath12k_p2p_noa_update_vdev_iter
,