1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file is part of wl12xx |
4 | * |
5 | * Copyright (C) 2012 Texas Instruments. All rights reserved. |
6 | */ |
7 | |
8 | #include <net/genetlink.h> |
9 | #include "event.h" |
10 | #include "scan.h" |
11 | #include "conf.h" |
12 | #include "../wlcore/cmd.h" |
13 | #include "../wlcore/debug.h" |
14 | #include "../wlcore/vendor_cmd.h" |
15 | |
16 | int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, |
17 | bool *timeout) |
18 | { |
19 | u32 local_event; |
20 | |
21 | switch (event) { |
22 | case WLCORE_EVENT_PEER_REMOVE_COMPLETE: |
23 | local_event = PEER_REMOVE_COMPLETE_EVENT_ID; |
24 | break; |
25 | |
26 | case WLCORE_EVENT_DFS_CONFIG_COMPLETE: |
27 | local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT; |
28 | break; |
29 | |
30 | default: |
31 | /* event not implemented */ |
32 | return 0; |
33 | } |
34 | return wlcore_cmd_wait_for_event_or_timeout(wl, mask: local_event, timeout); |
35 | } |
36 | |
37 | static const char *wl18xx_radar_type_decode(u8 radar_type) |
38 | { |
39 | switch (radar_type) { |
40 | case RADAR_TYPE_REGULAR: |
41 | return "REGULAR" ; |
42 | case RADAR_TYPE_CHIRP: |
43 | return "CHIRP" ; |
44 | case RADAR_TYPE_NONE: |
45 | default: |
46 | return "N/A" ; |
47 | } |
48 | } |
49 | |
50 | static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, |
51 | u8 sync_band) |
52 | { |
53 | struct sk_buff *skb; |
54 | enum nl80211_band band; |
55 | int freq; |
56 | |
57 | if (sync_band == WLCORE_BAND_5GHZ) |
58 | band = NL80211_BAND_5GHZ; |
59 | else |
60 | band = NL80211_BAND_2GHZ; |
61 | |
62 | freq = ieee80211_channel_to_frequency(chan: sync_channel, band); |
63 | |
64 | wl1271_debug(DEBUG_EVENT, |
65 | "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)" , |
66 | freq, sync_channel, sync_band); |
67 | skb = cfg80211_vendor_event_alloc(wiphy: wl->hw->wiphy, NULL, approxlen: 20, |
68 | event_idx: WLCORE_VENDOR_EVENT_SC_SYNC, |
69 | GFP_KERNEL); |
70 | |
71 | if (nla_put_u32(skb, attrtype: WLCORE_VENDOR_ATTR_FREQ, value: freq)) { |
72 | kfree_skb(skb); |
73 | return -EMSGSIZE; |
74 | } |
75 | cfg80211_vendor_event(skb, GFP_KERNEL); |
76 | return 0; |
77 | } |
78 | |
79 | static int wlcore_smart_config_decode_event(struct wl1271 *wl, |
80 | u8 ssid_len, u8 *ssid, |
81 | u8 pwd_len, u8 *pwd) |
82 | { |
83 | struct sk_buff *skb; |
84 | |
85 | wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID" ); |
86 | wl1271_dump_ascii(DEBUG_EVENT, "SSID:" , ssid, ssid_len); |
87 | |
88 | skb = cfg80211_vendor_event_alloc(wiphy: wl->hw->wiphy, NULL, |
89 | approxlen: ssid_len + pwd_len + 20, |
90 | event_idx: WLCORE_VENDOR_EVENT_SC_DECODE, |
91 | GFP_KERNEL); |
92 | |
93 | if (nla_put(skb, attrtype: WLCORE_VENDOR_ATTR_SSID, attrlen: ssid_len, data: ssid) || |
94 | nla_put(skb, attrtype: WLCORE_VENDOR_ATTR_PSK, attrlen: pwd_len, data: pwd)) { |
95 | kfree_skb(skb); |
96 | return -EMSGSIZE; |
97 | } |
98 | cfg80211_vendor_event(skb, GFP_KERNEL); |
99 | return 0; |
100 | } |
101 | |
102 | static void wlcore_event_time_sync(struct wl1271 *wl, |
103 | u16 tsf_high_msb, u16 tsf_high_lsb, |
104 | u16 tsf_low_msb, u16 tsf_low_lsb) |
105 | { |
106 | u32 clock_low; |
107 | u32 clock_high; |
108 | |
109 | clock_high = (tsf_high_msb << 16) | tsf_high_lsb; |
110 | clock_low = (tsf_low_msb << 16) | tsf_low_lsb; |
111 | |
112 | wl1271_info("TIME_SYNC_EVENT_ID: clock_high %u, clock low %u" , |
113 | clock_high, clock_low); |
114 | } |
115 | |
116 | int wl18xx_process_mailbox_events(struct wl1271 *wl) |
117 | { |
118 | struct wl18xx_event_mailbox *mbox = wl->mbox; |
119 | u32 vector; |
120 | |
121 | vector = le32_to_cpu(mbox->events_vector); |
122 | wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x" , vector); |
123 | |
124 | if (vector & SCAN_COMPLETE_EVENT_ID) { |
125 | wl1271_debug(DEBUG_EVENT, "scan results: %d" , |
126 | mbox->number_of_scan_results); |
127 | |
128 | if (wl->scan_wlvif) |
129 | wl18xx_scan_completed(wl, wlvif: wl->scan_wlvif); |
130 | } |
131 | |
132 | if (vector & TIME_SYNC_EVENT_ID) |
133 | wlcore_event_time_sync(wl, |
134 | le16_to_cpu(mbox->time_sync_tsf_high_msb), |
135 | le16_to_cpu(mbox->time_sync_tsf_high_lsb), |
136 | le16_to_cpu(mbox->time_sync_tsf_low_msb), |
137 | le16_to_cpu(mbox->time_sync_tsf_low_lsb)); |
138 | |
139 | if (vector & RADAR_DETECTED_EVENT_ID) { |
140 | wl1271_info("radar event: channel %d type %s" , |
141 | mbox->radar_channel, |
142 | wl18xx_radar_type_decode(mbox->radar_type)); |
143 | |
144 | if (!wl->radar_debug_mode) |
145 | ieee80211_radar_detected(hw: wl->hw); |
146 | } |
147 | |
148 | if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { |
149 | wl1271_debug(DEBUG_EVENT, |
150 | "PERIODIC_SCAN_REPORT_EVENT (results %d)" , |
151 | mbox->number_of_sched_scan_results); |
152 | |
153 | wlcore_scan_sched_scan_results(wl); |
154 | } |
155 | |
156 | if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) |
157 | wlcore_event_sched_scan_completed(wl, status: 1); |
158 | |
159 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) |
160 | wlcore_event_rssi_trigger(wl, metric_arr: mbox->rssi_snr_trigger_metric); |
161 | |
162 | if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) |
163 | wlcore_event_ba_rx_constraint(wl, |
164 | le16_to_cpu(mbox->rx_ba_role_id_bitmap), |
165 | le16_to_cpu(mbox->rx_ba_allowed_bitmap)); |
166 | |
167 | if (vector & BSS_LOSS_EVENT_ID) |
168 | wlcore_event_beacon_loss(wl, |
169 | le16_to_cpu(mbox->bss_loss_bitmap)); |
170 | |
171 | if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) |
172 | wlcore_event_channel_switch(wl, |
173 | le16_to_cpu(mbox->channel_switch_role_id_bitmap), |
174 | success: true); |
175 | |
176 | if (vector & DUMMY_PACKET_EVENT_ID) |
177 | wlcore_event_dummy_packet(wl); |
178 | |
179 | /* |
180 | * "TX retries exceeded" has a different meaning according to mode. |
181 | * In AP mode the offending station is disconnected. |
182 | */ |
183 | if (vector & MAX_TX_FAILURE_EVENT_ID) |
184 | wlcore_event_max_tx_failure(wl, |
185 | le16_to_cpu(mbox->tx_retry_exceeded_bitmap)); |
186 | |
187 | if (vector & INACTIVE_STA_EVENT_ID) |
188 | wlcore_event_inactive_sta(wl, |
189 | le16_to_cpu(mbox->inactive_sta_bitmap)); |
190 | |
191 | if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) |
192 | wlcore_event_roc_complete(wl); |
193 | |
194 | if (vector & SMART_CONFIG_SYNC_EVENT_ID) |
195 | wlcore_smart_config_sync_event(wl, sync_channel: mbox->sc_sync_channel, |
196 | sync_band: mbox->sc_sync_band); |
197 | |
198 | if (vector & SMART_CONFIG_DECODE_EVENT_ID) |
199 | wlcore_smart_config_decode_event(wl, |
200 | ssid_len: mbox->sc_ssid_len, |
201 | ssid: mbox->sc_ssid, |
202 | pwd_len: mbox->sc_pwd_len, |
203 | pwd: mbox->sc_pwd); |
204 | if (vector & FW_LOGGER_INDICATION) |
205 | wlcore_event_fw_logger(wl); |
206 | |
207 | if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) { |
208 | struct wl12xx_vif *wlvif; |
209 | struct ieee80211_vif *vif; |
210 | struct ieee80211_sta *sta; |
211 | u8 link_id = mbox->rx_ba_link_id; |
212 | u8 win_size = mbox->rx_ba_win_size; |
213 | const u8 *addr; |
214 | |
215 | wlvif = wl->links[link_id].wlvif; |
216 | vif = wl12xx_wlvif_to_vif(wlvif); |
217 | |
218 | /* Update RX aggregation window size and call |
219 | * MAC routine to stop active RX aggregations for this link |
220 | */ |
221 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) |
222 | addr = vif->bss_conf.bssid; |
223 | else |
224 | addr = wl->links[link_id].addr; |
225 | |
226 | sta = ieee80211_find_sta(vif, addr); |
227 | if (sta) { |
228 | sta->max_rx_aggregation_subframes = win_size; |
229 | ieee80211_stop_rx_ba_session(vif, |
230 | ba_rx_bitmap: wl->links[link_id].ba_bitmap, |
231 | addr); |
232 | } |
233 | } |
234 | |
235 | return 0; |
236 | } |
237 | |