GAS: Use off-channel operations for requests
[mech_eap.git] / wpa_supplicant / offchannel.c
1 /*
2  * wpa_supplicant - Off-channel Action frame TX/RX
3  * Copyright (c) 2009-2010, Atheros Communications
4  * Copyright (c) 2011, Qualcomm Atheros
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include "includes.h"
17
18 #include "common.h"
19 #include "utils/eloop.h"
20 #include "wpa_supplicant_i.h"
21 #include "driver_i.h"
22 #include "offchannel.h"
23
24
25
26 static struct wpa_supplicant *
27 wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
28 {
29         struct wpa_supplicant *iface;
30
31         if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
32                 return wpa_s;
33
34         /*
35          * Try to find a group interface that matches with the source address.
36          */
37         iface = wpa_s->global->ifaces;
38         while (iface) {
39                 if (os_memcmp(wpa_s->pending_action_src,
40                               iface->own_addr, ETH_ALEN) == 0)
41                         break;
42                 iface = iface->next;
43         }
44         if (iface) {
45                 wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
46                            "instead of interface %s for Action TX",
47                            iface->ifname, wpa_s->ifname);
48                 return iface;
49         }
50
51         return wpa_s;
52 }
53
54
55 static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
56 {
57         struct wpa_supplicant *wpa_s = eloop_ctx;
58         struct wpa_supplicant *iface;
59         int res;
60         int without_roc;
61
62         without_roc = wpa_s->pending_action_without_roc;
63         wpa_s->pending_action_without_roc = 0;
64         wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
65                    "(without_roc=%d pending_action_tx=%p)",
66                    without_roc, wpa_s->pending_action_tx);
67
68         if (wpa_s->pending_action_tx == NULL)
69                 return;
70
71         /*
72          * This call is likely going to be on the P2P device instance if the
73          * driver uses a separate interface for that purpose. However, some
74          * Action frames are actually sent within a P2P Group and when that is
75          * the case, we need to follow power saving (e.g., GO buffering the
76          * frame for a client in PS mode or a client following the advertised
77          * NoA from its GO). To make that easier for the driver, select the
78          * correct group interface here.
79          */
80         iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
81
82         if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
83             wpa_s->pending_action_freq != 0 &&
84             wpa_s->pending_action_freq != iface->assoc_freq) {
85                 wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
86                            "waiting for another freq=%u (off_channel_freq=%u "
87                            "assoc_freq=%u)",
88                            wpa_s->pending_action_freq,
89                            wpa_s->off_channel_freq,
90                            iface->assoc_freq);
91                 if (without_roc && wpa_s->off_channel_freq == 0) {
92                         /*
93                          * We may get here if wpas_send_action() found us to be
94                          * on the correct channel, but remain-on-channel cancel
95                          * event was received before getting here.
96                          */
97                         wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
98                                    "remain-on-channel to send Action frame");
99                         if (wpa_drv_remain_on_channel(
100                                     wpa_s, wpa_s->pending_action_freq, 200) <
101                             0) {
102                                 wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
103                                            "request driver to remain on "
104                                            "channel (%u MHz) for Action Frame "
105                                            "TX", wpa_s->pending_action_freq);
106                         } else {
107                                 wpa_s->off_channel_freq = 0;
108                                 wpa_s->roc_waiting_drv_freq =
109                                         wpa_s->pending_action_freq;
110                         }
111                 }
112                 return;
113         }
114
115         wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
116                    MACSTR " using interface %s",
117                    MAC2STR(wpa_s->pending_action_dst), iface->ifname);
118         res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
119                                   wpa_s->pending_action_dst,
120                                   wpa_s->pending_action_src,
121                                   wpa_s->pending_action_bssid,
122                                   wpabuf_head(wpa_s->pending_action_tx),
123                                   wpabuf_len(wpa_s->pending_action_tx));
124         if (res) {
125                 wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
126                            "pending Action frame");
127                 /*
128                  * Use fake TX status event to allow state machines to
129                  * continue.
130                  */
131                 offchannel_send_action_tx_status(
132                         wpa_s, wpa_s->pending_action_dst,
133                         wpabuf_head(wpa_s->pending_action_tx),
134                         wpabuf_len(wpa_s->pending_action_tx),
135                         OFFCHANNEL_SEND_ACTION_FAILED);
136         }
137 }
138
139
140 void offchannel_send_action_tx_status(
141         struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
142         size_t data_len, enum offchannel_send_action_result result)
143 {
144         if (wpa_s->pending_action_tx == NULL) {
145                 wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
146                            "no pending operation");
147                 return;
148         }
149
150         if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
151                 wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
152                            "unknown destination address");
153                 return;
154         }
155
156         wpabuf_free(wpa_s->pending_action_tx);
157         wpa_s->pending_action_tx = NULL;
158
159         wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
160                    result, wpa_s->pending_action_tx_status_cb);
161
162         if (wpa_s->pending_action_tx_status_cb) {
163                 wpa_s->pending_action_tx_status_cb(
164                         wpa_s, wpa_s->pending_action_freq,
165                         wpa_s->pending_action_dst, wpa_s->pending_action_src,
166                         wpa_s->pending_action_bssid,
167                         data, data_len, result);
168         }
169 }
170
171
172 int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
173                            const u8 *dst, const u8 *src, const u8 *bssid,
174                            const u8 *buf, size_t len, unsigned int wait_time,
175                            void (*tx_cb)(struct wpa_supplicant *wpa_s,
176                                          unsigned int freq, const u8 *dst,
177                                          const u8 *src, const u8 *bssid,
178                                          const u8 *data, size_t data_len,
179                                          enum offchannel_send_action_result
180                                          result))
181 {
182         wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
183                    MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
184                    freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
185                    (int) len);
186
187         wpa_s->pending_action_tx_status_cb = tx_cb;
188
189         if (wpa_s->pending_action_tx) {
190                 wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
191                            "frame TX to " MACSTR,
192                            MAC2STR(wpa_s->pending_action_dst));
193                 wpabuf_free(wpa_s->pending_action_tx);
194         }
195         wpa_s->pending_action_tx = wpabuf_alloc(len);
196         if (wpa_s->pending_action_tx == NULL) {
197                 wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
198                            "frame TX buffer (len=%llu)",
199                            (unsigned long long) len);
200                 return -1;
201         }
202         wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
203         os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
204         os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
205         os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
206         wpa_s->pending_action_freq = freq;
207
208         if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
209                 struct wpa_supplicant *iface;
210
211                 iface = wpas_get_tx_interface(wpa_s,
212                                               wpa_s->pending_action_src);
213                 wpa_s->action_tx_wait_time = wait_time;
214
215                 return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
216                                         wait_time, wpa_s->pending_action_dst,
217                                         wpa_s->pending_action_src,
218                                         wpa_s->pending_action_bssid,
219                                         wpabuf_head(wpa_s->pending_action_tx),
220                                         wpabuf_len(wpa_s->pending_action_tx));
221         }
222
223         if (freq) {
224                 struct wpa_supplicant *tx_iface;
225                 tx_iface = wpas_get_tx_interface(wpa_s, src);
226                 if (tx_iface->assoc_freq == freq) {
227                         wpa_printf(MSG_DEBUG, "Off-channel: Already on "
228                                    "requested channel (TX interface operating "
229                                    "channel)");
230                         freq = 0;
231                 }
232         }
233
234         if (wpa_s->off_channel_freq == freq || freq == 0) {
235                 wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
236                            "channel; send Action frame immediately");
237                 /* TODO: Would there ever be need to extend the current
238                  * duration on the channel? */
239                 wpa_s->pending_action_without_roc = 1;
240                 eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
241                 eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
242                 return 0;
243         }
244         wpa_s->pending_action_without_roc = 0;
245
246         if (wpa_s->roc_waiting_drv_freq == freq) {
247                 wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
248                            "driver to get to frequency %u MHz; continue "
249                            "waiting to send the Action frame", freq);
250                 return 0;
251         }
252
253         wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
254                    "transmitted once the driver gets to the requested "
255                    "channel");
256         if (wait_time > wpa_s->max_remain_on_chan)
257                 wait_time = wpa_s->max_remain_on_chan;
258         if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
259                 wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
260                            "to remain on channel (%u MHz) for Action "
261                            "Frame TX", freq);
262                 return -1;
263         }
264         wpa_s->off_channel_freq = 0;
265         wpa_s->roc_waiting_drv_freq = freq;
266
267         return 0;
268 }
269
270
271 void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
272 {
273         wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
274                    "notification");
275         wpabuf_free(wpa_s->pending_action_tx);
276         wpa_s->pending_action_tx = NULL;
277         if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
278             wpa_s->action_tx_wait_time)
279                 wpa_drv_send_action_cancel_wait(wpa_s);
280
281         if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
282                 wpa_drv_cancel_remain_on_channel(wpa_s);
283                 wpa_s->off_channel_freq = 0;
284                 wpa_s->roc_waiting_drv_freq = 0;
285         }
286 }
287
288
289 void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
290                                      unsigned int freq, unsigned int duration)
291 {
292         wpa_s->roc_waiting_drv_freq = 0;
293         wpa_s->off_channel_freq = freq;
294         wpas_send_action_cb(wpa_s, NULL);
295 }
296
297
298 void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
299                                             unsigned int freq)
300 {
301         wpa_s->off_channel_freq = 0;
302 }
303
304
305 void offchannel_deinit(struct wpa_supplicant *wpa_s)
306 {
307         wpabuf_free(wpa_s->pending_action_tx);
308         wpa_s->pending_action_tx = NULL;
309         eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
310 }