xref: /freebsd/sys/contrib/dev/athk/ath12k/p2p.c (revision a96550206e4bde15bf615ff2127b80404a7ec41f)
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