]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_nl80211.c
nl80211: Extended Key ID support
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
index 64bea49e173308afca1d69f715de479cc98d5aeb..ba8d079b28790217acb865d614524c405dea2d26 100644 (file)
@@ -2182,6 +2182,7 @@ static int nl80211_init_connect_handle(struct i802_bss *bss)
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
+       u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
        int ret = 0;
 
        if (nl80211_alloc_mgmt_handle(bss))
@@ -2189,13 +2190,14 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
                   "handle %p", bss->nl_mgmt);
 
-       if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
-           ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
-            !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
-               u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
+       if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
                /* register for any AUTH message */
                nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+       } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+                  !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+               /* register for SAE Authentication frames */
+               nl80211_register_frame(bss, bss->nl_mgmt, type,
+                                      (u8 *) "\x03\x00", 2);
        }
 
 #ifdef CONFIG_INTERWORKING
@@ -2881,7 +2883,6 @@ static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
        case WPA_ALG_KRK:
                return RSN_CIPHER_SUITE_KRK;
        case WPA_ALG_NONE:
-       case WPA_ALG_PMK:
                wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
                           alg);
                return 0;
@@ -2942,6 +2943,40 @@ static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
 }
 
 
+static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
+                                 int max_suites)
+{
+       int num_suites = 0;
+
+#define __AKM(a, b) \
+       if (num_suites < max_suites && \
+           (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
+               suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
+       __AKM(IEEE8021X, UNSPEC_802_1X);
+       __AKM(PSK, PSK_OVER_802_1X);
+       __AKM(FT_IEEE8021X, FT_802_1X);
+       __AKM(FT_PSK, FT_PSK);
+       __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
+       __AKM(PSK_SHA256, PSK_SHA256);
+       __AKM(SAE, SAE);
+       __AKM(FT_SAE, FT_SAE);
+       __AKM(CCKM, CCKM);
+       __AKM(OSEN, OSEN);
+       __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
+       __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
+       __AKM(FILS_SHA256, FILS_SHA256);
+       __AKM(FILS_SHA384, FILS_SHA384);
+       __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
+       __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
+       __AKM(OWE, OWE);
+       __AKM(DPP, DPP);
+       __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
+#undef __AKM
+
+       return num_suites;
+}
+
+
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
                                  const u8 *key, size_t key_len)
@@ -3019,7 +3054,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
        struct nl_msg *msg;
        struct nl_msg *key_msg;
        int ret;
-       int tdls = 0;
+       int skip_set_key = 1;
        const char *ifname = params->ifname;
        enum wpa_alg alg = params->alg;
        const u8 *addr = params->addr;
@@ -3030,6 +3065,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
        const u8 *key = params->key;
        size_t key_len = params->key_len;
        int vlan_id = params->vlan_id;
+       enum key_flag key_flag = params->key_flag;
 
        /* Ignore for P2P Device */
        if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
@@ -3037,18 +3073,17 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
 
        ifindex = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
-                  "set_tx=%d seq_len=%lu key_len=%lu",
+                  "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
                   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
-                  (unsigned long) seq_len, (unsigned long) key_len);
-#ifdef CONFIG_TDLS
-       if (key_idx == -1) {
-               key_idx = 0;
-               tdls = 1;
+                  (unsigned long) seq_len, (unsigned long) key_len, key_flag);
+
+       if (check_key_flag(key_flag)) {
+               wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
+               return -EINVAL;
        }
-#endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
-       if (alg == WPA_ALG_PMK &&
+       if ((key_flag & KEY_FLAG_PMK) &&
            (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
                wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
                           __func__);
@@ -3057,15 +3092,30 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
        }
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
-       if (alg == WPA_ALG_PMK &&
-           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
-               return nl80211_set_pmk(drv, key, key_len, addr);
+       if (key_flag & KEY_FLAG_PMK) {
+               if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
+                       return nl80211_set_pmk(drv, key, key_len, addr);
+               /* The driver does not have any offload mechanism for PMK, so
+                * there is no need to configure this key. */
+               return 0;
+       }
 
+       ret = -ENOBUFS;
        key_msg = nlmsg_alloc();
        if (!key_msg)
-               return -ENOBUFS;
+               return ret;
 
-       if (alg == WPA_ALG_NONE) {
+       if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+           KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+               msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+               if (!msg)
+                       goto fail2;
+       } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
+               wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
+                          __func__);
+               ret = -EINVAL;
+               goto fail2;
+       } else if (alg == WPA_ALG_NONE) {
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
                if (!msg)
                        goto fail2;
@@ -3073,8 +3123,10 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
                u32 suite;
 
                suite = wpa_alg_to_cipher_suite(alg, key_len);
-               if (!suite)
+               if (!suite) {
+                       ret = -EINVAL;
                        goto fail2;
+               }
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
                if (!msg)
                        goto fail2;
@@ -3082,12 +3134,13 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
                    nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
                        goto fail;
                wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
-       }
 
-       if (seq && seq_len) {
-               if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
-                       goto fail;
-               wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
+               if (seq && seq_len) {
+                       if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
+                               goto fail;
+                       wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
+                                   seq, seq_len);
+               }
        }
 
        if (addr && !is_broadcast_ether_addr(addr)) {
@@ -3095,22 +3148,42 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
                if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
                        goto fail;
 
-               if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+               if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+                   KEY_FLAG_PAIRWISE_RX ||
+                   (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+                   KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+                       if (nla_put_u8(key_msg, NL80211_KEY_MODE,
+                                      key_flag == KEY_FLAG_PAIRWISE_RX ?
+                                      NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
+                               goto fail;
+               } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
+                          KEY_FLAG_GROUP_RX) {
                        wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
                        if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
                                        NL80211_KEYTYPE_GROUP))
                                goto fail;
+               } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "   key_flag missing PAIRWISE when setting a pairwise key");
+                       ret = -EINVAL;
+                       goto fail;
+               } else if (alg == WPA_ALG_WEP &&
+                          (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
+                       wpa_printf(MSG_DEBUG, "   unicast WEP key");
+                       skip_set_key = 0;
+               } else {
+                       wpa_printf(MSG_DEBUG, "   pairwise key");
                }
-       } else if (addr && is_broadcast_ether_addr(addr)) {
-               struct nlattr *types;
-
+       } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
+                  !(key_flag & KEY_FLAG_GROUP)) {
+               wpa_printf(MSG_DEBUG,
+                          "   invalid key_flag for a broadcast key");
+               ret = -EINVAL;
+               goto fail;
+       } else {
                wpa_printf(MSG_DEBUG, "   broadcast key");
-
-               types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
-               if (!types ||
-                   nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
-                       goto fail;
-               nla_nest_end(key_msg, types);
+               if (key_flag & KEY_FLAG_DEFAULT)
+                       skip_set_key = 0;
        }
        if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
            nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
@@ -3129,22 +3202,21 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
        if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
                ret = 0;
        if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+               wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
                           ret, strerror(-ret));
 
        /*
-        * If we failed or don't need to set the default TX key (below),
+        * If we failed or don't need to set the key as default (below),
         * we're done here.
         */
-       if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
-               return ret;
-       if (is_ap_interface(drv->nlmode) && addr &&
-           !is_broadcast_ether_addr(addr))
+       if (ret || skip_set_key)
                return ret;
+       wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
 
+       ret = -ENOBUFS;
        key_msg = nlmsg_alloc();
        if (!key_msg)
-               return -ENOBUFS;
+               return ret;
 
        msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
        if (!msg)
@@ -3155,8 +3227,10 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
                                   alg == WPA_ALG_BIP_GMAC_128 ||
                                   alg == WPA_ALG_BIP_GMAC_256 ||
                                   alg == WPA_ALG_BIP_CMAC_256) ?
-                                  NL80211_KEY_DEFAULT_MGMT :
-                                  NL80211_KEY_DEFAULT))
+                        (key_idx == 6 || key_idx == 7 ?
+                         NL80211_KEY_DEFAULT_BEACON :
+                         NL80211_KEY_DEFAULT_MGMT) :
+                        NL80211_KEY_DEFAULT))
                goto fail;
        if (addr && is_broadcast_ether_addr(addr)) {
                struct nlattr *types;
@@ -3190,11 +3264,10 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret == -ENOENT)
-               ret = 0;
        if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
-                          "err=%d %s)", ret, strerror(-ret));
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: set_key default failed; err=%d %s",
+                          ret, strerror(-ret));
        return ret;
 
 fail:
@@ -3203,7 +3276,7 @@ fail:
 fail2:
        nl80211_nlmsg_clear(key_msg);
        nlmsg_free(key_msg);
-       return -ENOBUFS;
+       return ret;
 }
 
 
@@ -3517,6 +3590,9 @@ retry:
                p.set_tx = i == params->wep_tx_keyidx;
                p.key = params->wep_key[i];
                p.key_len = params->wep_key_len[i];
+               p.key_flag = i == params->wep_tx_keyidx ?
+                       KEY_FLAG_GROUP_RX_TX_DEFAULT :
+                       KEY_FLAG_GROUP_RX_TX;
                wpa_driver_nl80211_set_key(bss, &p);
                if (params->wep_tx_keyidx != i)
                        continue;
@@ -3696,7 +3772,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 
        mgmt = (struct ieee80211_mgmt *) data;
        fc = le_to_host16(mgmt->frame_control);
-       wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
+       wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
                   " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
                   MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
                   no_encrypt, fc, fc2str(fc), drv->nlmode);
@@ -3747,6 +3823,17 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
                        encrypt = 0;
        }
 
+       if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+           WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+           WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+               freq = nl80211_get_assoc_freq(drv);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+                          freq);
+       }
+
        if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
                freq = nl80211_get_assoc_freq(drv);
                wpa_printf(MSG_DEBUG,
@@ -4091,8 +4178,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        int ret = -ENOBUFS;
        int beacon_set;
        int num_suites;
-       int smps_mode;
-       u32 suites[10], suite;
+       u32 suites[20], suite;
        u32 ver;
 #ifdef CONFIG_MESH
        struct wpa_driver_mesh_bss_params mesh_params;
@@ -4186,14 +4272,15 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 
        wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
                   params->key_mgmt_suites);
-       num_suites = 0;
-       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
-               suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
-       if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
-               suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-       if (num_suites &&
-           nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
-                   suites))
+       num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
+                                           suites, ARRAY_SIZE(suites));
+       if (num_suites > NL80211_MAX_NR_AKM_SUITES)
+               wpa_printf(MSG_WARNING,
+                          "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
+                          num_suites);
+       else if (num_suites &&
+                nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+                        suites))
                goto fail;
 
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
@@ -4224,27 +4311,6 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
                goto fail;
 
-       if (params->ht_opmode != -1) {
-               switch (params->smps_mode) {
-               case HT_CAP_INFO_SMPS_DYNAMIC:
-                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
-                       smps_mode = NL80211_SMPS_DYNAMIC;
-                       break;
-               case HT_CAP_INFO_SMPS_STATIC:
-                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
-                       smps_mode = NL80211_SMPS_STATIC;
-                       break;
-               default:
-                       /* invalid - fallback to smps off */
-               case HT_CAP_INFO_SMPS_DISABLED:
-                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
-                       smps_mode = NL80211_SMPS_OFF;
-                       break;
-               }
-               if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
-                       goto fail;
-       }
-
        if (params->beacon_ies) {
                wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
                                params->beacon_ies);
@@ -4329,7 +4395,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
                wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
 
-               if (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+               if (!spr ||
+                   nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
                               params->he_spr_srg_obss_pd_min_offset) ||
                    nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
                               params->he_spr_srg_obss_pd_max_offset))
@@ -4337,6 +4404,28 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 
                nla_nest_end(msg, spr);
        }
+
+       if (params->freq && params->freq->he_enabled) {
+               struct nlattr *bss_color;
+
+               bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
+               if (!bss_color ||
+                   (params->he_bss_color_disabled &&
+                    nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
+                   (params->he_bss_color_partial &&
+                    nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
+                   nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
+                              params->he_bss_color))
+                       goto fail;
+               nla_nest_end(msg, bss_color);
+       }
+
+       if (params->twt_responder) {
+               wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
+                          params->twt_responder);
+               if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
+                       goto fail;
+       }
 #endif /* CONFIG_IEEE80211AX */
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -5144,7 +5233,7 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
        if (ret)
                wpa_printf(MSG_DEBUG,
                           "nl80211: tx_control_port failed: ret=%d (%s)",
-                          ret, strerror(ret));
+                          ret, strerror(-ret));
 
        return ret;
 }
@@ -5238,9 +5327,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
 
        res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
        if (res < 0) {
-               wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
-                          "failed: %d (%s)",
-                          (unsigned long) len, res, strerror(res));
+               wpa_printf(MSG_ERROR,
+                          "hapd_send_eapol - packet len: %lu - failed",
+                          (unsigned long) len);
        }
        os_free(hdr);
 
@@ -8794,11 +8883,11 @@ static int driver_nl80211_send_mlme(void *priv, const u8 *data,
                                    size_t data_len, int noack,
                                    unsigned int freq,
                                    const u16 *csa_offs, size_t csa_offs_len,
-                                   int no_encrypt)
+                                   int no_encrypt, unsigned int wait)
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-                                           freq, 0, 0, 0, csa_offs,
+                                           freq, 0, 0, wait, csa_offs,
                                            csa_offs_len, no_encrypt);
 }