xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/quantenna/qtnfmac/event.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/module.h>
6*4882a593Smuzhiyun #include <linux/slab.h>
7*4882a593Smuzhiyun #include <linux/nospec.h>
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include "cfg80211.h"
10*4882a593Smuzhiyun #include "core.h"
11*4882a593Smuzhiyun #include "qlink.h"
12*4882a593Smuzhiyun #include "bus.h"
13*4882a593Smuzhiyun #include "trans.h"
14*4882a593Smuzhiyun #include "util.h"
15*4882a593Smuzhiyun #include "event.h"
16*4882a593Smuzhiyun #include "qlink_util.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static int
qtnf_event_handle_sta_assoc(struct qtnf_wmac * mac,struct qtnf_vif * vif,const struct qlink_event_sta_assoc * sta_assoc,u16 len)19*4882a593Smuzhiyun qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
20*4882a593Smuzhiyun 			    const struct qlink_event_sta_assoc *sta_assoc,
21*4882a593Smuzhiyun 			    u16 len)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	const u8 *sta_addr;
24*4882a593Smuzhiyun 	u16 frame_control;
25*4882a593Smuzhiyun 	struct station_info *sinfo;
26*4882a593Smuzhiyun 	size_t payload_len;
27*4882a593Smuzhiyun 	u16 tlv_type;
28*4882a593Smuzhiyun 	u16 tlv_value_len;
29*4882a593Smuzhiyun 	const struct qlink_tlv_hdr *tlv;
30*4882a593Smuzhiyun 	int ret = 0;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (unlikely(len < sizeof(*sta_assoc))) {
33*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
34*4882a593Smuzhiyun 		       mac->macid, vif->vifid, len, sizeof(*sta_assoc));
35*4882a593Smuzhiyun 		return -EINVAL;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
39*4882a593Smuzhiyun 		pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
40*4882a593Smuzhiyun 		       mac->macid, vif->vifid);
41*4882a593Smuzhiyun 		return -EPROTO;
42*4882a593Smuzhiyun 	}
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
45*4882a593Smuzhiyun 	if (!sinfo)
46*4882a593Smuzhiyun 		return -ENOMEM;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	sta_addr = sta_assoc->sta_addr;
49*4882a593Smuzhiyun 	frame_control = le16_to_cpu(sta_assoc->frame_control);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
52*4882a593Smuzhiyun 		 frame_control);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	qtnf_sta_list_add(vif, sta_addr);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	sinfo->assoc_req_ies = NULL;
57*4882a593Smuzhiyun 	sinfo->assoc_req_ies_len = 0;
58*4882a593Smuzhiyun 	sinfo->generation = vif->generation;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	payload_len = len - sizeof(*sta_assoc);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	qlink_for_each_tlv(tlv, sta_assoc->ies, payload_len) {
63*4882a593Smuzhiyun 		tlv_type = le16_to_cpu(tlv->type);
64*4882a593Smuzhiyun 		tlv_value_len = le16_to_cpu(tlv->len);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 		if (tlv_type == QTN_TLV_ID_IE_SET) {
67*4882a593Smuzhiyun 			const struct qlink_tlv_ie_set *ie_set;
68*4882a593Smuzhiyun 			unsigned int ie_len;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 			if (tlv_value_len <
71*4882a593Smuzhiyun 			    (sizeof(*ie_set) - sizeof(ie_set->hdr))) {
72*4882a593Smuzhiyun 				ret = -EINVAL;
73*4882a593Smuzhiyun 				goto out;
74*4882a593Smuzhiyun 			}
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 			ie_set = (const struct qlink_tlv_ie_set *)tlv;
77*4882a593Smuzhiyun 			ie_len = tlv_value_len -
78*4882a593Smuzhiyun 				(sizeof(*ie_set) - sizeof(ie_set->hdr));
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 			if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) {
81*4882a593Smuzhiyun 				sinfo->assoc_req_ies = ie_set->ie_data;
82*4882a593Smuzhiyun 				sinfo->assoc_req_ies_len = ie_len;
83*4882a593Smuzhiyun 			}
84*4882a593Smuzhiyun 		}
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (!qlink_tlv_parsing_ok(tlv, sta_assoc->ies, payload_len)) {
88*4882a593Smuzhiyun 		pr_err("Malformed TLV buffer\n");
89*4882a593Smuzhiyun 		ret = -EINVAL;
90*4882a593Smuzhiyun 		goto out;
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo,
94*4882a593Smuzhiyun 			 GFP_KERNEL);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun out:
97*4882a593Smuzhiyun 	kfree(sinfo);
98*4882a593Smuzhiyun 	return ret;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static int
qtnf_event_handle_sta_deauth(struct qtnf_wmac * mac,struct qtnf_vif * vif,const struct qlink_event_sta_deauth * sta_deauth,u16 len)102*4882a593Smuzhiyun qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
103*4882a593Smuzhiyun 			     const struct qlink_event_sta_deauth *sta_deauth,
104*4882a593Smuzhiyun 			     u16 len)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	const u8 *sta_addr;
107*4882a593Smuzhiyun 	u16 reason;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (unlikely(len < sizeof(*sta_deauth))) {
110*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
111*4882a593Smuzhiyun 		       mac->macid, vif->vifid, len,
112*4882a593Smuzhiyun 		       sizeof(struct qlink_event_sta_deauth));
113*4882a593Smuzhiyun 		return -EINVAL;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
117*4882a593Smuzhiyun 		pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
118*4882a593Smuzhiyun 		       mac->macid, vif->vifid);
119*4882a593Smuzhiyun 		return -EPROTO;
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	sta_addr = sta_deauth->sta_addr;
123*4882a593Smuzhiyun 	reason = le16_to_cpu(sta_deauth->reason);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
126*4882a593Smuzhiyun 		 sta_addr, reason);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (qtnf_sta_list_del(vif, sta_addr))
129*4882a593Smuzhiyun 		cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
130*4882a593Smuzhiyun 				 GFP_KERNEL);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun static int
qtnf_event_handle_bss_join(struct qtnf_vif * vif,const struct qlink_event_bss_join * join_info,u16 len)136*4882a593Smuzhiyun qtnf_event_handle_bss_join(struct qtnf_vif *vif,
137*4882a593Smuzhiyun 			   const struct qlink_event_bss_join *join_info,
138*4882a593Smuzhiyun 			   u16 len)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
141*4882a593Smuzhiyun 	enum ieee80211_statuscode status = le16_to_cpu(join_info->status);
142*4882a593Smuzhiyun 	struct cfg80211_chan_def chandef;
143*4882a593Smuzhiyun 	struct cfg80211_bss *bss = NULL;
144*4882a593Smuzhiyun 	u8 *ie = NULL;
145*4882a593Smuzhiyun 	size_t payload_len;
146*4882a593Smuzhiyun 	u16 tlv_type;
147*4882a593Smuzhiyun 	u16 tlv_value_len;
148*4882a593Smuzhiyun 	const struct qlink_tlv_hdr *tlv;
149*4882a593Smuzhiyun 	const u8 *rsp_ies = NULL;
150*4882a593Smuzhiyun 	size_t rsp_ies_len = 0;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (unlikely(len < sizeof(*join_info))) {
153*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
154*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, len,
155*4882a593Smuzhiyun 		       sizeof(struct qlink_event_bss_join));
156*4882a593Smuzhiyun 		return -EINVAL;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
160*4882a593Smuzhiyun 		pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
161*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid);
162*4882a593Smuzhiyun 		return -EPROTO;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n",
166*4882a593Smuzhiyun 		 vif->mac->macid, vif->vifid, join_info->bssid,
167*4882a593Smuzhiyun 		 le16_to_cpu(join_info->chan.chan.center_freq), status);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (status != WLAN_STATUS_SUCCESS)
170*4882a593Smuzhiyun 		goto done;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef);
173*4882a593Smuzhiyun 	if (!cfg80211_chandef_valid(&chandef)) {
174*4882a593Smuzhiyun 		pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
175*4882a593Smuzhiyun 			vif->mac->macid, vif->vifid,
176*4882a593Smuzhiyun 			chandef.chan ? chandef.chan->center_freq : 0,
177*4882a593Smuzhiyun 			chandef.center_freq1,
178*4882a593Smuzhiyun 			chandef.center_freq2,
179*4882a593Smuzhiyun 			chandef.width);
180*4882a593Smuzhiyun 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
181*4882a593Smuzhiyun 		goto done;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid,
185*4882a593Smuzhiyun 			       NULL, 0, IEEE80211_BSS_TYPE_ESS,
186*4882a593Smuzhiyun 			       IEEE80211_PRIVACY_ANY);
187*4882a593Smuzhiyun 	if (!bss) {
188*4882a593Smuzhiyun 		pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n",
189*4882a593Smuzhiyun 			vif->mac->macid, vif->vifid,
190*4882a593Smuzhiyun 			join_info->bssid, chandef.chan->hw_value);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		if (!vif->wdev.ssid_len) {
193*4882a593Smuzhiyun 			pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n",
194*4882a593Smuzhiyun 				vif->mac->macid, vif->vifid,
195*4882a593Smuzhiyun 				join_info->bssid);
196*4882a593Smuzhiyun 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
197*4882a593Smuzhiyun 			goto done;
198*4882a593Smuzhiyun 		}
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 		ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL);
201*4882a593Smuzhiyun 		if (!ie) {
202*4882a593Smuzhiyun 			pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n",
203*4882a593Smuzhiyun 				vif->mac->macid, vif->vifid,
204*4882a593Smuzhiyun 				join_info->bssid);
205*4882a593Smuzhiyun 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
206*4882a593Smuzhiyun 			goto done;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		ie[0] = WLAN_EID_SSID;
210*4882a593Smuzhiyun 		ie[1] = vif->wdev.ssid_len;
211*4882a593Smuzhiyun 		memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 		bss = cfg80211_inform_bss(wiphy, chandef.chan,
214*4882a593Smuzhiyun 					  CFG80211_BSS_FTYPE_UNKNOWN,
215*4882a593Smuzhiyun 					  join_info->bssid, 0,
216*4882a593Smuzhiyun 					  WLAN_CAPABILITY_ESS, 100,
217*4882a593Smuzhiyun 					  ie, 2 + vif->wdev.ssid_len,
218*4882a593Smuzhiyun 					  0, GFP_KERNEL);
219*4882a593Smuzhiyun 		if (!bss) {
220*4882a593Smuzhiyun 			pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n",
221*4882a593Smuzhiyun 				vif->mac->macid, vif->vifid,
222*4882a593Smuzhiyun 				join_info->bssid);
223*4882a593Smuzhiyun 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
224*4882a593Smuzhiyun 			goto done;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	payload_len = len - sizeof(*join_info);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	qlink_for_each_tlv(tlv, join_info->ies, payload_len) {
231*4882a593Smuzhiyun 		tlv_type = le16_to_cpu(tlv->type);
232*4882a593Smuzhiyun 		tlv_value_len = le16_to_cpu(tlv->len);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		if (tlv_type == QTN_TLV_ID_IE_SET) {
235*4882a593Smuzhiyun 			const struct qlink_tlv_ie_set *ie_set;
236*4882a593Smuzhiyun 			unsigned int ie_len;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 			if (tlv_value_len <
239*4882a593Smuzhiyun 			    (sizeof(*ie_set) - sizeof(ie_set->hdr))) {
240*4882a593Smuzhiyun 				pr_warn("invalid IE_SET TLV\n");
241*4882a593Smuzhiyun 				status = WLAN_STATUS_UNSPECIFIED_FAILURE;
242*4882a593Smuzhiyun 				goto done;
243*4882a593Smuzhiyun 			}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 			ie_set = (const struct qlink_tlv_ie_set *)tlv;
246*4882a593Smuzhiyun 			ie_len = tlv_value_len -
247*4882a593Smuzhiyun 				(sizeof(*ie_set) - sizeof(ie_set->hdr));
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 			switch (ie_set->type) {
250*4882a593Smuzhiyun 			case QLINK_IE_SET_ASSOC_RESP:
251*4882a593Smuzhiyun 				if (ie_len) {
252*4882a593Smuzhiyun 					rsp_ies = ie_set->ie_data;
253*4882a593Smuzhiyun 					rsp_ies_len = ie_len;
254*4882a593Smuzhiyun 				}
255*4882a593Smuzhiyun 				break;
256*4882a593Smuzhiyun 			default:
257*4882a593Smuzhiyun 				pr_warn("unexpected IE type: %u\n",
258*4882a593Smuzhiyun 					ie_set->type);
259*4882a593Smuzhiyun 				break;
260*4882a593Smuzhiyun 			}
261*4882a593Smuzhiyun 		}
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (!qlink_tlv_parsing_ok(tlv, join_info->ies, payload_len))
265*4882a593Smuzhiyun 		pr_warn("Malformed TLV buffer\n");
266*4882a593Smuzhiyun done:
267*4882a593Smuzhiyun 	cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies,
268*4882a593Smuzhiyun 				rsp_ies_len, status, GFP_KERNEL);
269*4882a593Smuzhiyun 	if (bss) {
270*4882a593Smuzhiyun 		if (!ether_addr_equal(vif->bssid, join_info->bssid))
271*4882a593Smuzhiyun 			ether_addr_copy(vif->bssid, join_info->bssid);
272*4882a593Smuzhiyun 		cfg80211_put_bss(wiphy, bss);
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	if (status == WLAN_STATUS_SUCCESS)
276*4882a593Smuzhiyun 		netif_carrier_on(vif->netdev);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	kfree(ie);
279*4882a593Smuzhiyun 	return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static int
qtnf_event_handle_bss_leave(struct qtnf_vif * vif,const struct qlink_event_bss_leave * leave_info,u16 len)283*4882a593Smuzhiyun qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
284*4882a593Smuzhiyun 			    const struct qlink_event_bss_leave *leave_info,
285*4882a593Smuzhiyun 			    u16 len)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	if (unlikely(len < sizeof(*leave_info))) {
288*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
289*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, len,
290*4882a593Smuzhiyun 		       sizeof(struct qlink_event_bss_leave));
291*4882a593Smuzhiyun 		return -EINVAL;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
295*4882a593Smuzhiyun 		pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
296*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid);
297*4882a593Smuzhiyun 		return -EPROTO;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
303*4882a593Smuzhiyun 			      NULL, 0, 0, GFP_KERNEL);
304*4882a593Smuzhiyun 	netif_carrier_off(vif->netdev);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun static int
qtnf_event_handle_mgmt_received(struct qtnf_vif * vif,const struct qlink_event_rxmgmt * rxmgmt,u16 len)310*4882a593Smuzhiyun qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
311*4882a593Smuzhiyun 				const struct qlink_event_rxmgmt *rxmgmt,
312*4882a593Smuzhiyun 				u16 len)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	const size_t min_len = sizeof(*rxmgmt) +
315*4882a593Smuzhiyun 			       sizeof(struct ieee80211_hdr_3addr);
316*4882a593Smuzhiyun 	const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
317*4882a593Smuzhiyun 	const u16 frame_len = len - sizeof(*rxmgmt);
318*4882a593Smuzhiyun 	enum nl80211_rxmgmt_flags flags = 0;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (unlikely(len < min_len)) {
321*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
322*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, len, min_len);
323*4882a593Smuzhiyun 		return -EINVAL;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
327*4882a593Smuzhiyun 		flags |= NL80211_RXMGMT_FLAG_ANSWERED;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
330*4882a593Smuzhiyun 		 le16_to_cpu(frame->frame_control), frame->addr2);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm,
333*4882a593Smuzhiyun 			 rxmgmt->frame_data, frame_len, flags);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return 0;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun static int
qtnf_event_handle_scan_results(struct qtnf_vif * vif,const struct qlink_event_scan_result * sr,u16 len)339*4882a593Smuzhiyun qtnf_event_handle_scan_results(struct qtnf_vif *vif,
340*4882a593Smuzhiyun 			       const struct qlink_event_scan_result *sr,
341*4882a593Smuzhiyun 			       u16 len)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	struct cfg80211_bss *bss;
344*4882a593Smuzhiyun 	struct ieee80211_channel *channel;
345*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
346*4882a593Smuzhiyun 	enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
347*4882a593Smuzhiyun 	size_t payload_len;
348*4882a593Smuzhiyun 	u16 tlv_type;
349*4882a593Smuzhiyun 	u16 tlv_value_len;
350*4882a593Smuzhiyun 	const struct qlink_tlv_hdr *tlv;
351*4882a593Smuzhiyun 	const u8 *ies = NULL;
352*4882a593Smuzhiyun 	size_t ies_len = 0;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (len < sizeof(*sr)) {
355*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
356*4882a593Smuzhiyun 		       vif->vifid);
357*4882a593Smuzhiyun 		return -EINVAL;
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
361*4882a593Smuzhiyun 	if (!channel) {
362*4882a593Smuzhiyun 		pr_err("VIF%u.%u: channel at %u MHz not found\n",
363*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
364*4882a593Smuzhiyun 		return -EINVAL;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	payload_len = len - sizeof(*sr);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	qlink_for_each_tlv(tlv, sr->payload, payload_len) {
370*4882a593Smuzhiyun 		tlv_type = le16_to_cpu(tlv->type);
371*4882a593Smuzhiyun 		tlv_value_len = le16_to_cpu(tlv->len);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		if (tlv_type == QTN_TLV_ID_IE_SET) {
374*4882a593Smuzhiyun 			const struct qlink_tlv_ie_set *ie_set;
375*4882a593Smuzhiyun 			unsigned int ie_len;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 			if (tlv_value_len <
378*4882a593Smuzhiyun 			    (sizeof(*ie_set) - sizeof(ie_set->hdr)))
379*4882a593Smuzhiyun 				return -EINVAL;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 			ie_set = (const struct qlink_tlv_ie_set *)tlv;
382*4882a593Smuzhiyun 			ie_len = tlv_value_len -
383*4882a593Smuzhiyun 				(sizeof(*ie_set) - sizeof(ie_set->hdr));
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 			switch (ie_set->type) {
386*4882a593Smuzhiyun 			case QLINK_IE_SET_BEACON_IES:
387*4882a593Smuzhiyun 				frame_type = CFG80211_BSS_FTYPE_BEACON;
388*4882a593Smuzhiyun 				break;
389*4882a593Smuzhiyun 			case QLINK_IE_SET_PROBE_RESP_IES:
390*4882a593Smuzhiyun 				frame_type = CFG80211_BSS_FTYPE_PRESP;
391*4882a593Smuzhiyun 				break;
392*4882a593Smuzhiyun 			default:
393*4882a593Smuzhiyun 				frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
394*4882a593Smuzhiyun 			}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 			if (ie_len) {
397*4882a593Smuzhiyun 				ies = ie_set->ie_data;
398*4882a593Smuzhiyun 				ies_len = ie_len;
399*4882a593Smuzhiyun 			}
400*4882a593Smuzhiyun 		}
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	if (!qlink_tlv_parsing_ok(tlv, sr->payload, payload_len))
404*4882a593Smuzhiyun 		return -EINVAL;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	bss = cfg80211_inform_bss(wiphy, channel, frame_type,
407*4882a593Smuzhiyun 				  sr->bssid, get_unaligned_le64(&sr->tsf),
408*4882a593Smuzhiyun 				  le16_to_cpu(sr->capab),
409*4882a593Smuzhiyun 				  le16_to_cpu(sr->bintval), ies, ies_len,
410*4882a593Smuzhiyun 				  DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL);
411*4882a593Smuzhiyun 	if (!bss)
412*4882a593Smuzhiyun 		return -ENOMEM;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	cfg80211_put_bss(wiphy, bss);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun static int
qtnf_event_handle_scan_complete(struct qtnf_wmac * mac,const struct qlink_event_scan_complete * status,u16 len)420*4882a593Smuzhiyun qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
421*4882a593Smuzhiyun 				const struct qlink_event_scan_complete *status,
422*4882a593Smuzhiyun 				u16 len)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	if (len < sizeof(*status)) {
425*4882a593Smuzhiyun 		pr_err("MAC%u: payload is too short\n", mac->macid);
426*4882a593Smuzhiyun 		return -EINVAL;
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static int
qtnf_event_handle_freq_change(struct qtnf_wmac * mac,const struct qlink_event_freq_change * data,u16 len)435*4882a593Smuzhiyun qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
436*4882a593Smuzhiyun 			      const struct qlink_event_freq_change *data,
437*4882a593Smuzhiyun 			      u16 len)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(mac);
440*4882a593Smuzhiyun 	struct cfg80211_chan_def chandef;
441*4882a593Smuzhiyun 	struct qtnf_vif *vif;
442*4882a593Smuzhiyun 	int i;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	if (len < sizeof(*data)) {
445*4882a593Smuzhiyun 		pr_err("MAC%u: payload is too short\n", mac->macid);
446*4882a593Smuzhiyun 		return -EINVAL;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if (!wiphy->registered)
450*4882a593Smuzhiyun 		return 0;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (!cfg80211_chandef_valid(&chandef)) {
455*4882a593Smuzhiyun 		pr_err("MAC%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
456*4882a593Smuzhiyun 		       mac->macid, chandef.chan->center_freq,
457*4882a593Smuzhiyun 		       chandef.center_freq1, chandef.center_freq2,
458*4882a593Smuzhiyun 		       chandef.width);
459*4882a593Smuzhiyun 		return -EINVAL;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n",
463*4882a593Smuzhiyun 		 mac->macid, chandef.chan->hw_value, chandef.center_freq1,
464*4882a593Smuzhiyun 		 chandef.center_freq2, chandef.width);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	for (i = 0; i < QTNF_MAX_INTF; i++) {
467*4882a593Smuzhiyun 		vif = &mac->iflist[i];
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
470*4882a593Smuzhiyun 			continue;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
473*4882a593Smuzhiyun 		    !vif->wdev.current_bss)
474*4882a593Smuzhiyun 			continue;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 		if (!vif->netdev)
477*4882a593Smuzhiyun 			continue;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		mutex_lock(&vif->wdev.mtx);
480*4882a593Smuzhiyun 		cfg80211_ch_switch_notify(vif->netdev, &chandef);
481*4882a593Smuzhiyun 		mutex_unlock(&vif->wdev.mtx);
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
qtnf_event_handle_radar(struct qtnf_vif * vif,const struct qlink_event_radar * ev,u16 len)487*4882a593Smuzhiyun static int qtnf_event_handle_radar(struct qtnf_vif *vif,
488*4882a593Smuzhiyun 				   const struct qlink_event_radar *ev,
489*4882a593Smuzhiyun 				   u16 len)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
492*4882a593Smuzhiyun 	struct cfg80211_chan_def chandef;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (len < sizeof(*ev)) {
495*4882a593Smuzhiyun 		pr_err("MAC%u: payload is too short\n", vif->mac->macid);
496*4882a593Smuzhiyun 		return -EINVAL;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if (!wiphy->registered || !vif->netdev)
500*4882a593Smuzhiyun 		return 0;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	if (!cfg80211_chandef_valid(&chandef)) {
505*4882a593Smuzhiyun 		pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n",
506*4882a593Smuzhiyun 		       vif->mac->macid,
507*4882a593Smuzhiyun 		       chandef.center_freq1, chandef.center_freq2,
508*4882a593Smuzhiyun 		       chandef.width);
509*4882a593Smuzhiyun 		return -EINVAL;
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n",
513*4882a593Smuzhiyun 		vif->netdev->name, ev->event,
514*4882a593Smuzhiyun 		chandef.center_freq1, chandef.center_freq2,
515*4882a593Smuzhiyun 		chandef.width);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	switch (ev->event) {
518*4882a593Smuzhiyun 	case QLINK_RADAR_DETECTED:
519*4882a593Smuzhiyun 		cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
520*4882a593Smuzhiyun 		break;
521*4882a593Smuzhiyun 	case QLINK_RADAR_CAC_FINISHED:
522*4882a593Smuzhiyun 		if (!vif->wdev.cac_started)
523*4882a593Smuzhiyun 			break;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 		cfg80211_cac_event(vif->netdev, &chandef,
526*4882a593Smuzhiyun 				   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
527*4882a593Smuzhiyun 		break;
528*4882a593Smuzhiyun 	case QLINK_RADAR_CAC_ABORTED:
529*4882a593Smuzhiyun 		if (!vif->wdev.cac_started)
530*4882a593Smuzhiyun 			break;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 		cfg80211_cac_event(vif->netdev, &chandef,
533*4882a593Smuzhiyun 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 	case QLINK_RADAR_CAC_STARTED:
536*4882a593Smuzhiyun 		if (vif->wdev.cac_started)
537*4882a593Smuzhiyun 			break;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		if (!wiphy_ext_feature_isset(wiphy,
540*4882a593Smuzhiyun 					     NL80211_EXT_FEATURE_DFS_OFFLOAD))
541*4882a593Smuzhiyun 			break;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		cfg80211_cac_event(vif->netdev, &chandef,
544*4882a593Smuzhiyun 				   NL80211_RADAR_CAC_STARTED, GFP_KERNEL);
545*4882a593Smuzhiyun 		break;
546*4882a593Smuzhiyun 	default:
547*4882a593Smuzhiyun 		pr_warn("%s: unhandled radar event %u\n",
548*4882a593Smuzhiyun 			vif->netdev->name, ev->event);
549*4882a593Smuzhiyun 		break;
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun static int
qtnf_event_handle_external_auth(struct qtnf_vif * vif,const struct qlink_event_external_auth * ev,u16 len)556*4882a593Smuzhiyun qtnf_event_handle_external_auth(struct qtnf_vif *vif,
557*4882a593Smuzhiyun 				const struct qlink_event_external_auth *ev,
558*4882a593Smuzhiyun 				u16 len)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct cfg80211_external_auth_params auth = {0};
561*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
562*4882a593Smuzhiyun 	int ret;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	if (len < sizeof(*ev)) {
565*4882a593Smuzhiyun 		pr_err("MAC%u: payload is too short\n", vif->mac->macid);
566*4882a593Smuzhiyun 		return -EINVAL;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	if (!wiphy->registered || !vif->netdev)
570*4882a593Smuzhiyun 		return 0;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	if (ev->ssid_len) {
573*4882a593Smuzhiyun 		int len = clamp_val(ev->ssid_len, 0, IEEE80211_MAX_SSID_LEN);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 		memcpy(auth.ssid.ssid, ev->ssid, len);
576*4882a593Smuzhiyun 		auth.ssid.ssid_len = len;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite);
580*4882a593Smuzhiyun 	ether_addr_copy(auth.bssid, ev->bssid);
581*4882a593Smuzhiyun 	auth.action = ev->action;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	pr_debug("%s: external SAE processing: bss=%pM action=%u akm=%u\n",
584*4882a593Smuzhiyun 		 vif->netdev->name, auth.bssid, auth.action,
585*4882a593Smuzhiyun 		 auth.key_mgmt_suite);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL);
588*4882a593Smuzhiyun 	if (ret)
589*4882a593Smuzhiyun 		pr_warn("failed to offload external auth request\n");
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	return ret;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun static int
qtnf_event_handle_mic_failure(struct qtnf_vif * vif,const struct qlink_event_mic_failure * mic_ev,u16 len)595*4882a593Smuzhiyun qtnf_event_handle_mic_failure(struct qtnf_vif *vif,
596*4882a593Smuzhiyun 			      const struct qlink_event_mic_failure *mic_ev,
597*4882a593Smuzhiyun 			      u16 len)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
600*4882a593Smuzhiyun 	u8 pairwise;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (len < sizeof(*mic_ev)) {
603*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
604*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, len,
605*4882a593Smuzhiyun 		       sizeof(struct qlink_event_mic_failure));
606*4882a593Smuzhiyun 		return -EINVAL;
607*4882a593Smuzhiyun 	}
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (!wiphy->registered || !vif->netdev)
610*4882a593Smuzhiyun 		return 0;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
613*4882a593Smuzhiyun 		pr_err("VIF%u.%u: MIC_FAILURE event when not in STA mode\n",
614*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid);
615*4882a593Smuzhiyun 		return -EPROTO;
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	pairwise = mic_ev->pairwise ?
619*4882a593Smuzhiyun 		NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	pr_info("%s: MIC error: src=%pM key_index=%u pairwise=%u\n",
622*4882a593Smuzhiyun 		vif->netdev->name, mic_ev->src, mic_ev->key_index, pairwise);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise,
625*4882a593Smuzhiyun 				     mic_ev->key_index, NULL, GFP_KERNEL);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	return 0;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun static int
qtnf_event_handle_update_owe(struct qtnf_vif * vif,const struct qlink_event_update_owe * owe_ev,u16 len)631*4882a593Smuzhiyun qtnf_event_handle_update_owe(struct qtnf_vif *vif,
632*4882a593Smuzhiyun 			     const struct qlink_event_update_owe *owe_ev,
633*4882a593Smuzhiyun 			     u16 len)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
636*4882a593Smuzhiyun 	struct cfg80211_update_owe_info owe_info = {};
637*4882a593Smuzhiyun 	const u16 ie_len = len - sizeof(*owe_ev);
638*4882a593Smuzhiyun 	u8 *ie;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (len < sizeof(*owe_ev)) {
641*4882a593Smuzhiyun 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
642*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid, len,
643*4882a593Smuzhiyun 		       sizeof(struct qlink_event_update_owe));
644*4882a593Smuzhiyun 		return -EINVAL;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if (!wiphy->registered || !vif->netdev)
648*4882a593Smuzhiyun 		return 0;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
651*4882a593Smuzhiyun 		pr_err("VIF%u.%u: UPDATE_OWE event when not in AP mode\n",
652*4882a593Smuzhiyun 		       vif->mac->macid, vif->vifid);
653*4882a593Smuzhiyun 		return -EPROTO;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	ie = kzalloc(ie_len, GFP_KERNEL);
657*4882a593Smuzhiyun 	if (!ie)
658*4882a593Smuzhiyun 		return -ENOMEM;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	memcpy(owe_info.peer, owe_ev->peer, ETH_ALEN);
661*4882a593Smuzhiyun 	memcpy(ie, owe_ev->ies, ie_len);
662*4882a593Smuzhiyun 	owe_info.ie_len = ie_len;
663*4882a593Smuzhiyun 	owe_info.ie = ie;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	pr_info("%s: external OWE processing: peer=%pM\n",
666*4882a593Smuzhiyun 		vif->netdev->name, owe_ev->peer);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	cfg80211_update_owe_info_event(vif->netdev, &owe_info, GFP_KERNEL);
669*4882a593Smuzhiyun 	kfree(ie);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	return 0;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
qtnf_event_parse(struct qtnf_wmac * mac,const struct sk_buff * event_skb)674*4882a593Smuzhiyun static int qtnf_event_parse(struct qtnf_wmac *mac,
675*4882a593Smuzhiyun 			    const struct sk_buff *event_skb)
676*4882a593Smuzhiyun {
677*4882a593Smuzhiyun 	const struct qlink_event *event;
678*4882a593Smuzhiyun 	struct qtnf_vif *vif = NULL;
679*4882a593Smuzhiyun 	int ret = -1;
680*4882a593Smuzhiyun 	u16 event_id;
681*4882a593Smuzhiyun 	u16 event_len;
682*4882a593Smuzhiyun 	u8 vifid;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	event = (const struct qlink_event *)event_skb->data;
685*4882a593Smuzhiyun 	event_id = le16_to_cpu(event->event_id);
686*4882a593Smuzhiyun 	event_len = le16_to_cpu(event->mhdr.len);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	if (event->vifid >= QTNF_MAX_INTF) {
689*4882a593Smuzhiyun 		pr_err("invalid vif(%u)\n", event->vifid);
690*4882a593Smuzhiyun 		return -EINVAL;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	vifid = array_index_nospec(event->vifid, QTNF_MAX_INTF);
694*4882a593Smuzhiyun 	vif = &mac->iflist[vifid];
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	switch (event_id) {
697*4882a593Smuzhiyun 	case QLINK_EVENT_STA_ASSOCIATED:
698*4882a593Smuzhiyun 		ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
699*4882a593Smuzhiyun 						  event_len);
700*4882a593Smuzhiyun 		break;
701*4882a593Smuzhiyun 	case QLINK_EVENT_STA_DEAUTH:
702*4882a593Smuzhiyun 		ret = qtnf_event_handle_sta_deauth(mac, vif,
703*4882a593Smuzhiyun 						   (const void *)event,
704*4882a593Smuzhiyun 						   event_len);
705*4882a593Smuzhiyun 		break;
706*4882a593Smuzhiyun 	case QLINK_EVENT_MGMT_RECEIVED:
707*4882a593Smuzhiyun 		ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
708*4882a593Smuzhiyun 						      event_len);
709*4882a593Smuzhiyun 		break;
710*4882a593Smuzhiyun 	case QLINK_EVENT_SCAN_RESULTS:
711*4882a593Smuzhiyun 		ret = qtnf_event_handle_scan_results(vif, (const void *)event,
712*4882a593Smuzhiyun 						     event_len);
713*4882a593Smuzhiyun 		break;
714*4882a593Smuzhiyun 	case QLINK_EVENT_SCAN_COMPLETE:
715*4882a593Smuzhiyun 		ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
716*4882a593Smuzhiyun 						      event_len);
717*4882a593Smuzhiyun 		break;
718*4882a593Smuzhiyun 	case QLINK_EVENT_BSS_JOIN:
719*4882a593Smuzhiyun 		ret = qtnf_event_handle_bss_join(vif, (const void *)event,
720*4882a593Smuzhiyun 						 event_len);
721*4882a593Smuzhiyun 		break;
722*4882a593Smuzhiyun 	case QLINK_EVENT_BSS_LEAVE:
723*4882a593Smuzhiyun 		ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
724*4882a593Smuzhiyun 						  event_len);
725*4882a593Smuzhiyun 		break;
726*4882a593Smuzhiyun 	case QLINK_EVENT_FREQ_CHANGE:
727*4882a593Smuzhiyun 		ret = qtnf_event_handle_freq_change(mac, (const void *)event,
728*4882a593Smuzhiyun 						    event_len);
729*4882a593Smuzhiyun 		break;
730*4882a593Smuzhiyun 	case QLINK_EVENT_RADAR:
731*4882a593Smuzhiyun 		ret = qtnf_event_handle_radar(vif, (const void *)event,
732*4882a593Smuzhiyun 					      event_len);
733*4882a593Smuzhiyun 		break;
734*4882a593Smuzhiyun 	case QLINK_EVENT_EXTERNAL_AUTH:
735*4882a593Smuzhiyun 		ret = qtnf_event_handle_external_auth(vif, (const void *)event,
736*4882a593Smuzhiyun 						      event_len);
737*4882a593Smuzhiyun 		break;
738*4882a593Smuzhiyun 	case QLINK_EVENT_MIC_FAILURE:
739*4882a593Smuzhiyun 		ret = qtnf_event_handle_mic_failure(vif, (const void *)event,
740*4882a593Smuzhiyun 						    event_len);
741*4882a593Smuzhiyun 		break;
742*4882a593Smuzhiyun 	case QLINK_EVENT_UPDATE_OWE:
743*4882a593Smuzhiyun 		ret = qtnf_event_handle_update_owe(vif, (const void *)event,
744*4882a593Smuzhiyun 						   event_len);
745*4882a593Smuzhiyun 		break;
746*4882a593Smuzhiyun 	default:
747*4882a593Smuzhiyun 		pr_warn("unknown event type: %x\n", event_id);
748*4882a593Smuzhiyun 		break;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	return ret;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun 
qtnf_event_process_skb(struct qtnf_bus * bus,const struct sk_buff * skb)754*4882a593Smuzhiyun static int qtnf_event_process_skb(struct qtnf_bus *bus,
755*4882a593Smuzhiyun 				  const struct sk_buff *skb)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	const struct qlink_event *event;
758*4882a593Smuzhiyun 	struct qtnf_wmac *mac;
759*4882a593Smuzhiyun 	int res;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	if (unlikely(!skb || skb->len < sizeof(*event))) {
762*4882a593Smuzhiyun 		pr_err("invalid event buffer\n");
763*4882a593Smuzhiyun 		return -EINVAL;
764*4882a593Smuzhiyun 	}
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	event = (struct qlink_event *)skb->data;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	mac = qtnf_core_get_mac(bus, event->macid);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
771*4882a593Smuzhiyun 		 le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
772*4882a593Smuzhiyun 		 event->macid, event->vifid);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	if (unlikely(!mac))
775*4882a593Smuzhiyun 		return -ENXIO;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	rtnl_lock();
778*4882a593Smuzhiyun 	res = qtnf_event_parse(mac, skb);
779*4882a593Smuzhiyun 	rtnl_unlock();
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	return res;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun 
qtnf_event_work_handler(struct work_struct * work)784*4882a593Smuzhiyun void qtnf_event_work_handler(struct work_struct *work)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
787*4882a593Smuzhiyun 	struct sk_buff_head *event_queue = &bus->trans.event_queue;
788*4882a593Smuzhiyun 	struct sk_buff *current_event_skb = skb_dequeue(event_queue);
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	while (current_event_skb) {
791*4882a593Smuzhiyun 		qtnf_event_process_skb(bus, current_event_skb);
792*4882a593Smuzhiyun 		dev_kfree_skb_any(current_event_skb);
793*4882a593Smuzhiyun 		current_event_skb = skb_dequeue(event_queue);
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun }
796