Add own_addr as a parameter to sta_deauth() and sta_disassoc()
[wpasupplicant] / src / drivers / driver_nl80211.c
index 41fc29e..6e3a191 100644 (file)
@@ -116,11 +116,9 @@ struct wpa_driver_nl80211_data {
        int nlmode;
        int ap_scan_as_station;
 
-#if defined(CONFIG_AP) || defined(HOSTAPD)
        int beacon_int;
        int monitor_sock;
        int monitor_ifidx;
-#endif /* CONFIG_AP || HOSTAPD */
 
 #ifdef CONFIG_AP
        unsigned int beacon_set:1;
@@ -159,6 +157,10 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
                                 int ifindex);
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+                                int ifidx);
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int i802_del_beacon(struct wpa_driver_nl80211_data *drv);
 #endif /* HOSTAPD */
 
 
@@ -289,6 +291,52 @@ nla_put_failure:
 }
 
 
+#ifdef HOSTAPD
+static int get_ifhwaddr(struct wpa_driver_nl80211_data *drv,
+                       const char *ifname, u8 *addr)
+{
+       struct ifreq ifr;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+       if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr)) {
+               wpa_printf(MSG_ERROR, "%s: ioctl(SIOCGIFHWADDR): %d (%s)",
+                          ifname, errno, strerror(errno));
+               return -1;
+       }
+
+       if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+               wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
+                          ifname, ifr.ifr_hwaddr.sa_family);
+               return -1;
+       }
+       os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+       return 0;
+}
+
+
+static int set_ifhwaddr(struct wpa_driver_nl80211_data *drv,
+                       const char *ifname, const u8 *addr)
+{
+       struct ifreq ifr;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+       os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+       ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+       if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) {
+               wpa_printf(MSG_DEBUG, "%s: ioctl(SIOCSIFHWADDR): %d (%s)",
+                          ifname, errno, strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+#endif /* HOSTAPD */
+
+
 static int wpa_driver_nl80211_send_oper_ifla(
        struct wpa_driver_nl80211_data *drv,
        int linkmode, int operstate)
@@ -931,6 +979,7 @@ nla_put_failure:
 }
 
 
+#ifndef HOSTAPD
 struct wiphy_info_data {
        int max_scan_ssids;
        int ap_supported;
@@ -1010,6 +1059,7 @@ static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        if (info.ap_supported)
                drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
 }
+#endif /* HOSTAPD */
 
 
 static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv,
@@ -1098,6 +1148,39 @@ err1:
 }
 
 
+static int wpa_driver_nl80211_init_link_events(
+       struct wpa_driver_nl80211_data *drv)
+{
+#ifdef HOSTAPD
+       return 0;
+#else /* HOSTAPD */
+       int s;
+       struct sockaddr_nl local;
+
+       s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (s < 0) {
+               perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+               return -1;
+       }
+
+       os_memset(&local, 0, sizeof(local));
+       local.nl_family = AF_NETLINK;
+       local.nl_groups = RTMGRP_LINK;
+       if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+               perror("bind(netlink)");
+               close(s);
+               return -1;
+       }
+
+       eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv,
+                                drv->ctx);
+       drv->link_event_sock = s;
+
+       return 0;
+#endif /* HOSTAPD */
+}
+
+
 /**
  * wpa_driver_nl80211_init - Initialize nl80211 driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -1107,8 +1190,6 @@ err1:
  */
 static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
 {
-       int s;
-       struct sockaddr_nl local;
        struct wpa_driver_nl80211_data *drv;
 
        drv = os_zalloc(sizeof(*drv));
@@ -1116,59 +1197,43 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
                return NULL;
        drv->ctx = ctx;
        os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-#ifdef CONFIG_AP
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
-#endif /* CONFIG_AP */
+       drv->link_event_sock = -1;
+       drv->ioctl_sock = -1;
 
-       if (wpa_driver_nl80211_init_nl(drv, ctx))
-               goto err1;
+       if (wpa_driver_nl80211_init_nl(drv, ctx)) {
+               os_free(drv);
+               return NULL;
+       }
 
        drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
 
        drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
        if (drv->ioctl_sock < 0) {
                perror("socket(PF_INET,SOCK_DGRAM)");
-               goto err5;
-       }
-
-       s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-       if (s < 0) {
-               perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
-               goto err6;
-       }
-
-       os_memset(&local, 0, sizeof(local));
-       local.nl_family = AF_NETLINK;
-       local.nl_groups = RTMGRP_LINK;
-       if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
-               perror("bind(netlink)");
-               close(s);
-               goto err6;
+               goto failed;
        }
 
-#ifndef HOSTAPD
-       eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv,
-                                ctx);
-#endif /* HOSTAPD */
-       drv->link_event_sock = s;
-
-       if (wpa_driver_nl80211_finish_drv_init(drv))
-               goto err7;
+       if (wpa_driver_nl80211_init_link_events(drv) ||
+           wpa_driver_nl80211_finish_drv_init(drv))
+               goto failed;
 
        return drv;
 
-err7:
-       eloop_unregister_read_sock(drv->link_event_sock);
-       close(drv->link_event_sock);
-err6:
-       close(drv->ioctl_sock);
-err5:
+failed:
+       if (drv->link_event_sock >= 0) {
+               eloop_unregister_read_sock(drv->link_event_sock);
+               close(drv->link_event_sock);
+       }
+       if (drv->ioctl_sock >= 0)
+               close(drv->ioctl_sock);
+
        genl_family_put(drv->nl80211);
        nl_cache_free(drv->nl_cache);
        nl_handle_destroy(drv->nl_handle);
        nl_cb_put(drv->nl_cb);
-err1:
+
        os_free(drv);
        return NULL;
 }
@@ -1179,6 +1244,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
        drv->ifindex = if_nametoindex(drv->ifname);
 
+#ifndef HOSTAPD
        if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
                           "use managed mode");
@@ -1193,11 +1259,26 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
        wpa_driver_nl80211_capa(drv);
 
        wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+#endif /* HOSTAPD */
 
        return 0;
 }
 
 
+#ifdef HOSTAPD
+static void wpa_driver_nl80211_free_bss(struct wpa_driver_nl80211_data *drv)
+{
+       struct i802_bss *bss, *prev;
+       bss = drv->bss.next;
+       while (bss) {
+               prev = bss;
+               bss = bss->next;
+               os_free(bss);
+       }
+}
+#endif /* HOSTAPD */
+
+
 /**
  * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
  * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
@@ -1209,30 +1290,55 @@ static void wpa_driver_nl80211_deinit(void *priv)
 {
        struct wpa_driver_nl80211_data *drv = priv;
 
-#ifdef CONFIG_AP
+#if defined(CONFIG_AP) || defined(HOSTAPD)
        if (drv->monitor_ifidx >= 0)
                nl80211_remove_iface(drv, drv->monitor_ifidx);
        if (drv->monitor_sock >= 0) {
                eloop_unregister_read_sock(drv->monitor_sock);
                close(drv->monitor_sock);
        }
-#endif /* CONFIG_AP */
+#endif /* CONFIG_AP || HOSTAPD */
 
-       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+#ifdef HOSTAPD
+       if (drv->last_freq_ht) {
+               /* Clear HT flags from the driver */
+               struct hostapd_freq_params freq;
+               os_memset(&freq, 0, sizeof(freq));
+               freq.freq = drv->last_freq;
+               i802_set_freq(priv, &freq);
+       }
+
+       i802_del_beacon(drv);
+
+       if (drv->eapol_sock >= 0) {
+               eloop_unregister_read_sock(drv->eapol_sock);
+               close(drv->eapol_sock);
+       }
 
+       if (drv->if_indices != drv->default_if_indices)
+               os_free(drv->if_indices);
+
+       wpa_driver_nl80211_free_bss(drv);
+#else /* HOSTAPD */
 #ifndef NO_WEXT
        wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 0);
 #endif /* NO_WEXT */
 
        wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
 
-       eloop_unregister_read_sock(drv->link_event_sock);
+       if (drv->link_event_sock >= 0) {
+               eloop_unregister_read_sock(drv->link_event_sock);
+               close(drv->link_event_sock);
+       }
+#endif /* HOSTAPD */
+
+       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       hostapd_set_iface_flags(drv, drv->ifname, 0);
+       (void) hostapd_set_iface_flags(drv, drv->ifname, 0);
        wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA);
 
-       close(drv->link_event_sock);
-       close(drv->ioctl_sock);
+       if (drv->ioctl_sock >= 0)
+               close(drv->ioctl_sock);
 
        eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
        genl_family_put(drv->nl80211);
@@ -2256,12 +2362,6 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
        struct nl_msg *msg, *flags = NULL;
        int ifidx;
        int ret = -ENOBUFS;
-#ifdef HOSTAPD
-       struct ifreq ifreq;
-#ifndef NO_WEXT
-       struct iwreq iwr;
-#endif /* NO_WEXT */
-#endif /* HOSTAPD */
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -2307,34 +2407,10 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
        /* start listening for EAPOL on this interface */
        add_ifidx(drv, ifidx);
 
-       if (addr) {
-               switch (iftype) {
-               case NL80211_IFTYPE_AP:
-                       os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ);
-                       memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-                       ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER;
-
-                       if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) {
-                               nl80211_remove_iface(drv, ifidx);
-                               return -1;
-                       }
-                       break;
-               case NL80211_IFTYPE_WDS:
-#ifdef NO_WEXT
-                       return -1;
-#else /* NO_WEXT */
-                       memset(&iwr, 0, sizeof(iwr));
-                       os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
-                       iwr.u.addr.sa_family = ARPHRD_ETHER;
-                       memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN);
-                       if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr))
-                               return -1;
-                       break;
-#endif /* NO_WEXT */
-               default:
-                       /* nothing */
-                       break;
-               }
+       if (addr && iftype == NL80211_IFTYPE_AP &&
+           set_ifhwaddr(drv, ifname, addr)) {
+               nl80211_remove_iface(drv, ifidx);
+               return -1;
        }
 #endif /* HOSTAPD */
 
@@ -3008,9 +3084,6 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
 
 static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
-static int i802_sta_deauth(void *priv, const u8 *addr, int reason);
-static int i802_sta_disassoc(void *priv, const u8 *addr, int reason);
-
 
 static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
                                 int ifindex)
@@ -3719,8 +3792,6 @@ static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type)
        switch (type) {
        case HOSTAPD_IF_VLAN:
                return NL80211_IFTYPE_AP_VLAN;
-       case HOSTAPD_IF_WDS:
-               return NL80211_IFTYPE_WDS;
        }
        return -1;
 }
@@ -3824,7 +3895,8 @@ static int i802_sta_clear_stats(void *priv, const u8 *addr)
 }
 
 
-static int i802_sta_deauth(void *priv, const u8 *addr, int reason)
+static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+                          int reason)
 {
        struct wpa_driver_nl80211_data *drv = priv;
        struct ieee80211_mgmt mgmt;
@@ -3833,8 +3905,8 @@ static int i802_sta_deauth(void *priv, const u8 *addr, int reason)
        mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                          WLAN_FC_STYPE_DEAUTH);
        memcpy(mgmt.da, addr, ETH_ALEN);
-       memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
-       memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+       memcpy(mgmt.sa, own_addr, ETH_ALEN);
+       memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.deauth.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
@@ -3842,7 +3914,8 @@ static int i802_sta_deauth(void *priv, const u8 *addr, int reason)
 }
 
 
-static int i802_sta_disassoc(void *priv, const u8 *addr, int reason)
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+                            int reason)
 {
        struct wpa_driver_nl80211_data *drv = priv;
        struct ieee80211_mgmt mgmt;
@@ -3851,8 +3924,8 @@ static int i802_sta_disassoc(void *priv, const u8 *addr, int reason)
        mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                          WLAN_FC_STYPE_DISASSOC);
        memcpy(mgmt.da, addr, ETH_ALEN);
-       memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
-       memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+       memcpy(mgmt.sa, own_addr, ETH_ALEN);
+       memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
@@ -3865,18 +3938,12 @@ static void *i802_init(struct hostapd_data *hapd,
 {
        struct wpa_driver_nl80211_data *drv;
        size_t i;
-       struct ifreq ifr;
 
-       drv = os_zalloc(sizeof(struct wpa_driver_nl80211_data));
-       if (drv == NULL) {
-               printf("Could not allocate memory for i802 driver data\n");
+       drv = wpa_driver_nl80211_init(hapd, params->ifname);
+       if (drv == NULL)
                return NULL;
-       }
 
        drv->hapd = hapd;
-       drv->ctx = hapd;
-       memcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
-       drv->ifindex = if_nametoindex(drv->ifname);
        drv->bss.ifindex = drv->ifindex;
 
        drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
@@ -3886,30 +3953,13 @@ static void *i802_init(struct hostapd_data *hapd,
                        add_ifidx(drv, if_nametoindex(params->bridge[i]));
        }
 
-       drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->ioctl_sock < 0) {
-               perror("socket[PF_INET,SOCK_DGRAM]");
-               goto failed;
-       }
-
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
        if (hostapd_set_iface_flags(drv, drv->ifname, 0))
                goto failed;
 
-       if (params->bssid) {
-               os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
-               os_memcpy(ifr.ifr_hwaddr.sa_data, params->bssid, ETH_ALEN);
-               ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
-
-               if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) {
-                       perror("ioctl(SIOCSIFHWADDR)");
-                       goto failed;
-               }
-       }
-
-       if (wpa_driver_nl80211_init_nl(drv, drv->hapd))
+       if (params->bssid && set_ifhwaddr(drv, drv->ifname, params->bssid))
                goto failed;
 
        /* Initialise a monitor interface */
@@ -3919,16 +3969,16 @@ static void *i802_init(struct hostapd_data *hapd,
        if (nl80211_set_mode(drv, drv->ifindex, NL80211_IFTYPE_AP)) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
                           "into AP mode", drv->ifname);
-               goto fail1;
+               goto failed;
        }
 
        if (hostapd_set_iface_flags(drv, drv->ifname, 1))
-               goto fail1;
+               goto failed;
 
        drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
        if (drv->eapol_sock < 0) {
                perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
-               goto fail1;
+               goto failed;
        }
 
        if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
@@ -3937,78 +3987,30 @@ static void *i802_init(struct hostapd_data *hapd,
                goto failed;
        }
 
-       os_memset(&ifr, 0, sizeof(ifr));
-       os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-       if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
-               perror("ioctl(SIOCGIFHWADDR)");
-               goto fail1;
-       }
-
-       if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-               printf("Invalid HW-addr family 0x%04x\n",
-                      ifr.ifr_hwaddr.sa_family);
-               goto fail1;
-       }
-       os_memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+       if (get_ifhwaddr(drv, drv->ifname, drv->hapd->own_addr))
+               goto failed;
 
        return drv;
 
-fail1:
-       nl80211_remove_iface(drv, drv->monitor_ifidx);
 failed:
-       free(drv);
-       return NULL;
-}
-
-
-static void i802_deinit(void *priv)
-{
-       struct wpa_driver_nl80211_data *drv = priv;
-       struct i802_bss *bss, *prev;
-
-       if (drv->last_freq_ht) {
-               /* Clear HT flags from the driver */
-               struct hostapd_freq_params freq;
-               os_memset(&freq, 0, sizeof(freq));
-               freq.freq = drv->last_freq;
-               i802_set_freq(priv, &freq);
-       }
-
-       i802_del_beacon(drv);
-
-       /* remove monitor interface */
-       nl80211_remove_iface(drv, drv->monitor_ifidx);
-
-       (void) hostapd_set_iface_flags(drv, drv->ifname, 0);
-
-       if (drv->monitor_sock >= 0) {
-               eloop_unregister_read_sock(drv->monitor_sock);
-               close(drv->monitor_sock);
-       }
+       if (drv->monitor_ifidx >= 0)
+               nl80211_remove_iface(drv, drv->monitor_ifidx);
        if (drv->ioctl_sock >= 0)
                close(drv->ioctl_sock);
-       if (drv->eapol_sock >= 0) {
-               eloop_unregister_read_sock(drv->eapol_sock);
-               close(drv->eapol_sock);
-       }
 
-       eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
        genl_family_put(drv->nl80211);
        nl_cache_free(drv->nl_cache);
        nl_handle_destroy(drv->nl_handle);
        nl_cb_put(drv->nl_cb);
 
-       if (drv->if_indices != drv->default_if_indices)
-               free(drv->if_indices);
+       os_free(drv);
+       return NULL;
+}
 
-       bss = drv->bss.next;
-       while (bss) {
-               prev = bss;
-               bss = bss->next;
-               os_free(bss);
-       }
 
-       free(drv);
+static void i802_deinit(void *priv)
+{
+       wpa_driver_nl80211_deinit(priv);
 }
 
 #endif /* HOSTAPD */