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