P2P: Add option for offloading off-channel TX to the driver
authorJohannes Berg <johannes.berg@intel.com>
Wed, 29 Dec 2010 11:59:17 +0000 (13:59 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 29 Dec 2010 11:59:17 +0000 (13:59 +0200)
With the new kernel functionality coming to Linux to allow off-channel
TX, we can take advantage of that in the P2P code that currently uses
remain-on-channel. If a driver advertises support for it, it will be
asked to handle off-channel TX by itself.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
src/drivers/driver.h
src/drivers/driver_ndis.c
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
wpa_supplicant/driver_i.h
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant_i.h

index 728ef79..d3b285c 100644 (file)
@@ -559,6 +559,8 @@ struct wpa_driver_capa {
  * operation does not end up getting completed successfully later.
  */
 #define WPA_DRIVER_FLAGS_SANE_ERROR_CODES              0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX                 0x00008000
        unsigned int flags;
 
        int max_scan_ssids;
@@ -1724,6 +1726,7 @@ struct wpa_driver_ops {
         * send_action - Transmit an Action frame
         * @priv: Private driver interface data
         * @freq: Frequency (in MHz) of the channel
+        * @wait: Time to wait off-channel for a response (in ms), or zero
         * @dst: Destination MAC address (Address 1)
         * @src: Source MAC address (Address 2)
         * @bssid: BSSID (Address 3)
@@ -1732,17 +1735,33 @@ struct wpa_driver_ops {
         * Returns: 0 on success, -1 on failure
         *
         * This command can be used to request the driver to transmit an action
-        * frame to the specified destination. If a remain-on-channel duration
-        * is in progress, the frame is transmitted on that channel. Otherwise,
-        * the frame is transmitted on the current operational channel if in
-        * associated state in station mode or if operating as an AP. If none
-        * of these conditions is in effect, send_action() cannot be used.
+        * frame to the specified destination.
+        *
+        * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
+        * be transmitted on the given channel and the device will wait for a
+        * response on that channel for the given wait time.
+        *
+        * If the flag is not set, the wait time will be ignored. In this case,
+        * if a remain-on-channel duration is in progress, the frame must be
+        * transmitted on that channel; alternatively the frame may be sent on
+        * the current operational channel (if in associated state in station
+        * mode or while operating as an AP.)
         */
-       int (*send_action)(void *priv, unsigned int freq,
+       int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
                           const u8 *dst, const u8 *src, const u8 *bssid,
                           const u8 *data, size_t data_len);
 
        /**
+        * send_action_cancel_wait - Cancel action frame TX wait
+        * @priv: Private driver interface data
+        *
+        * This command cancels the wait time associated with sending an action
+        * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is
+        * set in the driver flags.
+        */
+       void (*send_action_cancel_wait)(void *priv);
+
+       /**
         * remain_on_channel - Remain awake on a channel
         * @priv: Private driver interface data
         * @freq: Frequency (in MHz) of the channel
index 34bfa2b..56359c1 100644 (file)
@@ -3295,6 +3295,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* set_supp_port */,
        NULL /* set_wds_sta */,
        NULL /* send_action */,
+       NULL /* send_action_cancel_wait */,
        NULL /* remain_on_channel */,
        NULL /* cancel_remain_on_channel */,
        NULL /* probe_req_report */,
index f792099..f2e5a74 100644 (file)
@@ -5835,6 +5835,7 @@ nla_put_failure:
 
 
 static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+                                         unsigned int wait_time,
                                          const u8 *dst, const u8 *src,
                                          const u8 *bssid,
                                          const u8 *data, size_t data_len)
@@ -6146,8 +6147,8 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
        pos += ETH_ALEN;
        os_memcpy(pos, ies, ies_len);
 
-       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
-                                            own_addr, drv->bssid,
+       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
+                                            drv->bssid, own_addr, drv->bssid,
                                             data, data_len);
        os_free(data);
 
index c630e4c..2741182 100644 (file)
@@ -2598,6 +2598,7 @@ static int wpa_driver_test_set_freq(void *priv,
 
 
 static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+                                      unsigned int wait,
                                       const u8 *dst, const u8 *src,
                                       const u8 *bssid,
                                       const u8 *data, size_t data_len)
index af8232a..3436481 100644 (file)
@@ -383,17 +383,24 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
 
 static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
                                      unsigned int freq,
+                                     unsigned int wait,
                                      const u8 *dst, const u8 *src,
                                      const u8 *bssid,
                                      const u8 *data, size_t data_len)
 {
        if (wpa_s->driver->send_action)
                return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
-                                                 dst, src, bssid, data,
-                                                 data_len);
+                                                 wait, dst, src, bssid,
+                                                 data, data_len);
        return -1;
 }
 
+static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->driver->send_action_cancel_wait)
+               wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv);
+}
+
 static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
                                   struct hostapd_freq_params *freq)
 {
index d08492f..3745551 100644 (file)
@@ -614,7 +614,7 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
        wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
                   MACSTR " using interface %s",
                   MAC2STR(wpa_s->pending_action_dst), iface->ifname);
-       res = wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+       res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
                                  wpa_s->pending_action_dst,
                                  wpa_s->pending_action_src,
                                  wpa_s->pending_action_bssid,
@@ -705,6 +705,20 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
        wpa_s->pending_action_freq = freq;
 
+       if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               struct wpa_supplicant *iface;
+
+               iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+               wpa_s->action_tx_wait_time = wait_time;
+
+               return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+                                       wait_time, wpa_s->pending_action_dst,
+                                       wpa_s->pending_action_src,
+                                       wpa_s->pending_action_bssid,
+                                       wpabuf_head(wpa_s->pending_action_tx),
+                                       wpabuf_len(wpa_s->pending_action_tx));
+       }
+
        if (freq) {
                struct wpa_supplicant *tx_iface;
                tx_iface = wpas_get_tx_interface(wpa_s, src);
@@ -757,7 +771,11 @@ static void wpas_send_action_done(void *ctx)
        wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
        wpabuf_free(wpa_s->pending_action_tx);
        wpa_s->pending_action_tx = NULL;
-       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               if (wpa_s->action_tx_wait_time)
+                       wpa_drv_send_action_cancel_wait(wpa_s);
+               wpa_s->off_channel_freq = 0;
+       } else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
                wpa_s->off_channel_freq = 0;
                wpa_s->roc_waiting_drv_freq = 0;
index 018b372..60c6752 100644 (file)
@@ -538,7 +538,7 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
        req[0] = WLAN_ACTION_SA_QUERY;
        req[1] = WLAN_SA_QUERY_REQUEST;
        os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, wpa_s->bssid,
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
                                wpa_s->own_addr, wpa_s->bssid,
                                req, sizeof(req)) < 0)
                wpa_printf(MSG_INFO, "SME: Failed to send SA Query Request");
index a6c4a9a..9fdd799 100644 (file)
@@ -503,6 +503,7 @@ struct wpa_supplicant {
        int pending_join_wps_method;
        int p2p_join_scan_count;
        unsigned int roc_waiting_drv_freq;
+       int action_tx_wait_time;
        int force_long_sd;
 
        /*