1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2015 Qualcomm Atheros, Inc.
11 static void ath10k_p2p_noa_ie_fill(u8
*data
, size_t len
,
12 const struct wmi_p2p_noa_info
*noa
)
14 struct ieee80211_p2p_noa_attr
*noa_attr
;
15 u8 ctwindow_oppps
= noa
->ctwindow_oppps
;
16 u8 ctwindow
= ctwindow_oppps
>> WMI_P2P_OPPPS_CTWINDOW_OFFSET
;
17 bool oppps
= !!(ctwindow_oppps
& WMI_P2P_OPPPS_ENABLE_BIT
);
20 u8 noa_descriptors
= noa
->num_descriptors
;
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
= noa
->index
;
37 noa_attr
->oppps_ctwindow
= ctwindow
;
39 noa_attr
->oppps_ctwindow
|= IEEE80211_P2P_OPPPS_ENABLE_BIT
;
41 for (i
= 0; i
< noa_descriptors
; i
++) {
42 noa_attr
->desc
[i
].count
=
43 __le32_to_cpu(noa
->descriptors
[i
].type_count
);
44 noa_attr
->desc
[i
].duration
= noa
->descriptors
[i
].duration
;
45 noa_attr
->desc
[i
].interval
= noa
->descriptors
[i
].interval
;
46 noa_attr
->desc
[i
].start_time
= noa
->descriptors
[i
].start_time
;
49 attr_len
= 2; /* index + oppps_ctwindow */
50 attr_len
+= noa_descriptors
* sizeof(struct ieee80211_p2p_noa_desc
);
51 *noa_attr_len
= __cpu_to_le16(attr_len
);
54 static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info
*noa
)
58 if (!noa
->num_descriptors
&&
59 !(noa
->ctwindow_oppps
& WMI_P2P_OPPPS_ENABLE_BIT
))
62 len
+= 1 + 1 + 4; /* EID + len + OUI */
63 len
+= 1 + 2; /* noa attr + attr len */
64 len
+= 1 + 1; /* index + oppps_ctwindow */
65 len
+= noa
->num_descriptors
* sizeof(struct ieee80211_p2p_noa_desc
);
70 static void ath10k_p2p_noa_ie_assign(struct ath10k_vif
*arvif
, void *ie
,
73 struct ath10k
*ar
= arvif
->ar
;
75 lockdep_assert_held(&ar
->data_lock
);
77 kfree(arvif
->u
.ap
.noa_data
);
79 arvif
->u
.ap
.noa_data
= ie
;
80 arvif
->u
.ap
.noa_len
= len
;
83 static void __ath10k_p2p_noa_update(struct ath10k_vif
*arvif
,
84 const struct wmi_p2p_noa_info
*noa
)
86 struct ath10k
*ar
= arvif
->ar
;
90 lockdep_assert_held(&ar
->data_lock
);
92 ath10k_p2p_noa_ie_assign(arvif
, NULL
, 0);
94 len
= ath10k_p2p_noa_ie_len_compute(noa
);
98 ie
= kmalloc(len
, GFP_ATOMIC
);
102 ath10k_p2p_noa_ie_fill(ie
, len
, noa
);
103 ath10k_p2p_noa_ie_assign(arvif
, ie
, len
);
106 void ath10k_p2p_noa_update(struct ath10k_vif
*arvif
,
107 const struct wmi_p2p_noa_info
*noa
)
109 struct ath10k
*ar
= arvif
->ar
;
111 spin_lock_bh(&ar
->data_lock
);
112 __ath10k_p2p_noa_update(arvif
, noa
);
113 spin_unlock_bh(&ar
->data_lock
);
116 struct ath10k_p2p_noa_arg
{
118 const struct wmi_p2p_noa_info
*noa
;
121 static void ath10k_p2p_noa_update_vdev_iter(void *data
, u8
*mac
,
122 struct ieee80211_vif
*vif
)
124 struct ath10k_vif
*arvif
= (void *)vif
->drv_priv
;
125 struct ath10k_p2p_noa_arg
*arg
= data
;
127 if (arvif
->vdev_id
!= arg
->vdev_id
)
130 ath10k_p2p_noa_update(arvif
, arg
->noa
);
133 void ath10k_p2p_noa_update_by_vdev_id(struct ath10k
*ar
, u32 vdev_id
,
134 const struct wmi_p2p_noa_info
*noa
)
136 struct ath10k_p2p_noa_arg arg
= {
141 ieee80211_iterate_active_interfaces_atomic(ar
->hw
,
142 IEEE80211_IFACE_ITER_NORMAL
,
143 ath10k_p2p_noa_update_vdev_iter
,