hostapd: Allow FTM functionality to be published
[mech_eap.git] / wlantest / inject.c
index 23642a8..ed25033 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wlantest frame injection
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -56,7 +50,7 @@ static int inject_frame(int s, const void *data, size_t len)
 
        ret = sendmsg(s, &msg, 0);
        if (ret < 0)
-               perror("sendmsg");
+               wpa_printf(MSG_ERROR, "sendmsg: %s", strerror(errno));
        return ret;
 }
 
@@ -87,58 +81,24 @@ static int is_robust_mgmt(u8 *frame, size_t len)
 static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss,
                               u8 *frame, size_t len, int incorrect_key)
 {
-       u8 *prot, *pos, *buf;
-       u8 mic[16];
-       u8 dummy[16];
+       u8 *prot;
+       u8 dummy[32];
        int ret;
-       u16 fc;
-       struct ieee80211_hdr *hdr;
        size_t plen;
 
-       if (!bss->igtk_set[bss->igtk_idx])
+       if (!bss->igtk_len[bss->igtk_idx])
                return -1;
 
-       plen = len + 18;
-       prot = os_malloc(plen);
-       if (prot == NULL)
-               return -1;
-       os_memcpy(prot, frame, len);
-       pos = prot + len;
-       *pos++ = WLAN_EID_MMIE;
-       *pos++ = 16;
-       WPA_PUT_LE16(pos, bss->igtk_idx);
-       pos += 2;
+       os_memset(dummy, 0x11, sizeof(dummy));
        inc_byte_array(bss->ipn[bss->igtk_idx], 6);
-       os_memcpy(pos, bss->ipn[bss->igtk_idx], 6);
-       pos += 6;
-       os_memset(pos, 0, 8); /* MIC */
-
-       buf = os_malloc(plen + 20 - 24);
-       if (buf == NULL) {
-               os_free(prot);
-               return -1;
-       }
 
-       /* BIP AAD: FC(masked) A1 A2 A3 */
-       hdr = (struct ieee80211_hdr *) frame;
-       fc = le_to_host16(hdr->frame_control);
-       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
-       WPA_PUT_LE16(buf, fc);
-       os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
-       os_memcpy(buf + 20, prot + 24, plen - 24);
-       wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
-       /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
-       os_memset(dummy, 0x11, sizeof(dummy));
-       if (omac1_aes_128(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
-                         buf, plen + 20 - 24, mic) < 0) {
-               os_free(prot);
-               os_free(buf);
+       prot = bip_protect(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
+                          bss->igtk_len[bss->igtk_idx],
+                          frame, len, bss->ipn[bss->igtk_idx],
+                          bss->igtk_idx, &plen);
+       if (prot == NULL)
                return -1;
-       }
-       os_free(buf);
 
-       os_memcpy(pos, mic, 8);
-       wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
 
        ret = inject_frame(wt->monitor_sock, prot, plen);
        os_free(prot);
@@ -209,12 +169,44 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
        int tid = 0;
        u8 *qos = NULL;
        int hdrlen;
+       struct wlantest_tdls *tdls = NULL;
+       const u8 *tk = NULL;
 
        hdr = (struct ieee80211_hdr *) frame;
        hdrlen = 24;
        fc = le_to_host16(hdr->frame_control);
 
-       if (sta == NULL) {
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
+           (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == 0) {
+               struct wlantest_sta *sta2;
+               bss = bss_get(wt, hdr->addr3);
+               if (bss == NULL) {
+                       wpa_printf(MSG_DEBUG, "No BSS found for TDLS "
+                                  "injection");
+                       return -1;
+               }
+               sta = sta_find(bss, hdr->addr2);
+               sta2 = sta_find(bss, hdr->addr1);
+               if (sta == NULL || sta2 == NULL) {
+                       wpa_printf(MSG_DEBUG, "No stations found for TDLS "
+                                  "injection");
+                       return -1;
+               }
+               dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list)
+               {
+                       if ((tdls->init == sta && tdls->resp == sta2) ||
+                           (tdls->init == sta2 && tdls->resp == sta)) {
+                               if (!tdls->link_up)
+                                       wpa_printf(MSG_DEBUG, "TDLS: Link not "
+                                                  "up, but injecting Data "
+                                                  "frame on direct link");
+                               tk = tdls->tpk.tk;
+                               break;
+                       }
+               }
+       }
+
+       if (tk == NULL && sta == NULL) {
                if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
                        return wlantest_inject_bip(wt, bss, frame, len,
                                                   incorrect_key);
@@ -222,8 +214,10 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
                                               incorrect_key);
        }
 
-       if (!sta->ptk_set)
+       if (tk == NULL && !sta->ptk_set) {
+               wpa_printf(MSG_DEBUG, "No key known for injection");
                return -1;
+       }
 
        if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
                tid = 16;
@@ -237,28 +231,40 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
                        tid = qos[0] & 0x0f;
                }
        }
-       if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
+       if (tk) {
+               if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
+                       pn = tdls->rsc_init[tid];
+               else
+                       pn = tdls->rsc_resp[tid];
+       } else if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
                pn = sta->rsc_fromds[tid];
        else
                pn = sta->rsc_tods[tid];
        inc_byte_array(pn, 6);
 
        os_memset(dummy, 0x11, sizeof(dummy));
-       if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
-               crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+       if (tk) 
+               crypt = ccmp_encrypt(incorrect_key ? dummy : tk,
+                                    frame, len, hdrlen, qos, pn, 0,
+                                    &crypt_len);
+       else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
+               crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk,
                                     frame, len, hdrlen, qos, pn, 0,
                                     &crypt_len);
        else
-               crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+               crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk,
                                     frame, len, hdrlen, qos, pn, 0,
                                     &crypt_len);
 
-       if (crypt == NULL)
+       if (crypt == NULL) {
+               wpa_printf(MSG_DEBUG, "Frame encryption failed");
                return -1;
+       }
 
        wpa_hexdump(MSG_DEBUG, "Inject frame (encrypted)", crypt, crypt_len);
        ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
        os_free(crypt);
+       wpa_printf(MSG_DEBUG, "inject_frame for protected frame: %d", ret);
 
        return (ret < 0) ? -1 : 0;
 }
@@ -280,16 +286,22 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
                return -1;
        }
 
+       if (prot != WLANTEST_INJECT_UNPROTECTED && bss == NULL) {
+               wpa_printf(MSG_INFO, "No BSS information to inject "
+                          "protected frames");
+               return -1;
+       }
+
        hdr = (struct ieee80211_hdr *) frame;
        fc = le_to_host16(hdr->frame_control);
        protectable = WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ||
                is_robust_mgmt(frame, len);
 
-       if (prot == WLANTEST_INJECT_PROTECTED ||
-           prot == WLANTEST_INJECT_INCORRECT_KEY) {
+       if ((prot == WLANTEST_INJECT_PROTECTED ||
+            prot == WLANTEST_INJECT_INCORRECT_KEY) && bss) {
                if (!sta &&
                    ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-                     !bss->igtk_set[bss->igtk_idx]) ||
+                     !bss->igtk_len[bss->igtk_idx]) ||
                     (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
                      !bss->gtk_len[bss->gtk_idx]))) {
                        wpa_printf(MSG_INFO, "No GTK/IGTK known for "
@@ -304,7 +316,7 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
                        return -1;
                }
                protect = 1;
-       } else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED) {
+       } else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED && bss) {
                if (sta && sta->ptk_set)
                        protect = 1;
                else if (!sta) {
@@ -312,22 +324,17 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
                            bss->gtk_len[bss->gtk_idx])
                                protect = 1;
                        if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-                           bss->igtk_set[bss->igtk_idx])
+                           bss->igtk_len[bss->igtk_idx])
                                protect = 1;
                }
        }
 
-       if ((prot == WLANTEST_INJECT_PROTECTED ||
-            prot == WLANTEST_INJECT_INCORRECT_KEY) && !protect) {
-               wpa_printf(MSG_INFO, "Cannot protect injected frame");
-               return -1;
-       }
-
-       if (protect)
+       if (protect && bss)
                return wlantest_inject_prot(
                        wt, bss, sta, frame, len,
                        prot == WLANTEST_INJECT_INCORRECT_KEY);
 
        ret = inject_frame(wt->monitor_sock, frame, len);
+       wpa_printf(MSG_DEBUG, "inject_frame for unprotected frame: %d", ret);
        return (ret < 0) ? -1 : 0;
 }