Add IGTK/MFP configuration (disabled by default)
[libeap.git] / hostapd / driver_nl80211.c
index 0a1abd0..0a2604b 100644 (file)
@@ -27,7 +27,7 @@
 #include <net/if.h>
 #include <linux/if_packet.h>
 #include <linux/if_ether.h>   /* The L2 protocols */
-#include <linux/wireless.h>
+#include "wireless_copy.h"
 #include <net/if_arp.h>
 
 #include "hostapd.h"
@@ -177,11 +177,10 @@ static int hostapd_set_iface_flags(struct i802_driver_data *drv,
 }
 
 
-static int i802_set_encryption(const char *iface, void *priv, const char *alg,
-                              const u8 *addr, int idx, const u8 *key,
-                              size_t key_len, int txkey)
+static int nl_set_encr(int ifindex, struct i802_driver_data *drv,
+                      const char *alg, const u8 *addr, int idx, const u8 *key,
+                      size_t key_len, int txkey)
 {
-       struct i802_driver_data *drv = priv;
        struct nl_msg *msg;
        int ret = -1;
        int err = 0;
@@ -208,19 +207,24 @@ static int i802_set_encryption(const char *iface, void *priv, const char *alg,
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
                else if (strcmp(alg, "CCMP") == 0)
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
-               else
+               else if (strcmp(alg, "IGTK") == 0)
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+               else {
+                       wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+                                  "algorithm '%s'", __func__, alg);
                        goto out;
+               }
        }
 
        if (addr)
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 
        if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
            (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
                if (err != -ENOENT) {
-                       err = 0;
+                       ret = 0;
                        goto out;
                }
        }
@@ -243,13 +247,20 @@ static int i802_set_encryption(const char *iface, void *priv, const char *alg,
        genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
                    0, NL80211_CMD_SET_KEY, 0);
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+#ifdef NL80211_MFP_PENDING
+       if (strcmp(alg, "IGTK") == 0)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+       else
+               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+#else /* NL80211_MFP_PENDING */
        NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+#endif /* NL80211_MFP_PENDING */
 
        if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
            (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
                if (err != -ENOENT) {
-                       err = 0;
+                       ret = 0;
                        goto out;
                }
        }
@@ -263,6 +274,27 @@ static int i802_set_encryption(const char *iface, void *priv, const char *alg,
 }
 
 
+static int i802_set_encryption(const char *iface, void *priv, const char *alg,
+                              const u8 *addr, int idx, const u8 *key,
+                              size_t key_len, int txkey)
+{
+       struct i802_driver_data *drv = priv;
+       int ret;
+
+       ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key,
+                         key_len, txkey);
+       if (ret < 0)
+               return ret;
+
+       if (strcmp(alg, "IGTK") == 0) {
+               ret = nl_set_encr(drv->monitor_ifidx, drv, alg, addr, idx, key,
+                                 key_len, txkey);
+       }
+
+       return ret;
+}
+
+
 static inline int min_int(int a, int b)
 {
        if (a < b)
@@ -273,7 +305,7 @@ static inline int min_int(int a, int b)
 
 static int get_key_handler(struct nl_msg *msg, void *arg)
 {
-       struct nlattr *tb[NL80211_ATTR_MAX];
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -861,6 +893,11 @@ static int i802_sta_set_flags(void *priv, const u8 *addr,
        if (total_flags & WLAN_STA_SHORT_PREAMBLE)
                NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
+#ifdef NL80211_MFP_PENDING
+       if (total_flags & WLAN_STA_MFP)
+               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+#endif /* NL80211_MFP_PENDING */
+
        if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
                goto nla_put_failure;
 
@@ -1152,6 +1189,9 @@ static int i802_set_beacon_int(void *priv, int value)
 
        drv->beacon_int = value;
 
+       if (!drv->beacon_set)
+               return 0;
+
        msg = nlmsg_alloc();
        if (!msg)
                goto out;
@@ -1416,7 +1456,7 @@ static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv,
        struct nl_msg *msg;
        int err = -1;
        struct nl_cb *cb = NULL;
-       int finished;
+       int finished = 0;
        struct phy_info_arg result = {
                .num_modes = num_modes,
                .modes = NULL,
@@ -1861,7 +1901,7 @@ static int nl80211_set_master_mode(struct i802_driver_data *drv,
 
        return 0;
 }
-  
+
 
 static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
 {
@@ -1953,12 +1993,12 @@ static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
                return -1;
        }
 
-        memset(&ifr, 0, sizeof(ifr));
-        os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
-        if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
+       memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+       if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
                perror("ioctl(SIOCGIFHWADDR)");
                return -1;
-        }
+       }
 
        if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
                printf("Invalid HW-addr family 0x%04x\n",