nl80211: Add support for P2P Device in add interface
[mech_eap.git] / src / drivers / driver_nl80211.c
index accc5d5..a9a9c4a 100644 (file)
@@ -183,12 +183,14 @@ struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
+       u64 wdev_id;
        char ifname[IFNAMSIZ + 1];
        char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
        unsigned int in_deinit:1;
+       unsigned int wdev_id_set:1;
 
        u8 addr[ETH_ALEN];
 
@@ -587,6 +589,19 @@ struct family_data {
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+       if (bss->wdev_id_set)
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
        struct family_data *res = arg;
@@ -2594,19 +2609,31 @@ static int process_drv_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
-       if (tb[NL80211_ATTR_IFINDEX])
+       if (tb[NL80211_ATTR_IFINDEX]) {
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-       for (bss = &drv->first_bss; bss; bss = bss->next) {
-               if (ifidx == -1 || ifidx == bss->ifindex) {
-                       do_process_drv_event(bss, gnlh->cmd, tb);
-                       return NL_SKIP;
+               for (bss = &drv->first_bss; bss; bss = bss->next)
+                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+                          gnlh->cmd, ifidx);
+       } else if (tb[NL80211_ATTR_WDEV]) {
+               u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
                }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+                          gnlh->cmd, (long long unsigned int) wdev_id);
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-                  "interface (ifindex %d)", gnlh->cmd, ifidx);
-
        return NL_SKIP;
 }
 
@@ -2619,17 +2646,26 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
        struct i802_bss *bss;
+       u64 wdev_id;
+       int wdev_id_set = 0;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_IFINDEX])
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+       else if (tb[NL80211_ATTR_WDEV]) {
+               wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wdev_id_set = 1;
+       }
 
        dl_list_for_each_safe(drv, tmp, &global->interfaces,
                              struct wpa_driver_nl80211_data, list) {
                for (bss = &drv->first_bss; bss; bss = bss->next) {
-                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                       if ((ifidx == -1 && !wdev_id_set) ||
+                           ifidx == bss->ifindex ||
+                           (wdev_id_set && bss->wdev_id_set &&
+                            wdev_id == bss->wdev_id)) {
                                do_process_drv_event(bss, gnlh->cmd, tb);
                                return NL_SKIP;
                        }
@@ -2813,6 +2849,10 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                case NL80211_IFTYPE_ADHOC:
                        info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
                        break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       info->capa->flags |=
+                               WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+                       break;
                case NL80211_IFTYPE_P2P_GO:
                        info->p2p_go_supported = 1;
                        break;
@@ -3596,7 +3636,9 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -4016,7 +4058,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-                   struct wpa_driver_scan_params *params)
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
        struct nl_msg *msg;
        size_t i;
@@ -4027,8 +4069,10 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
 
        nl80211_cmd(drv, msg, 0, cmd);
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-               goto fail;
+       if (!wdev_id)
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       else
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
 
        if (params->num_ssids) {
                struct nlattr *ssids;
@@ -4077,6 +4121,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        return msg;
 
 fail:
+nla_put_failure:
        nlmsg_free(msg);
        return NULL;
 }
@@ -4098,7 +4143,8 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
        drv->scan_for_auth = 0;
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                return -1;
 
@@ -4201,7 +4247,8 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                goto nla_put_failure;
 
@@ -6511,6 +6558,8 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
                return "P2P_CLIENT";
        case NL80211_IFTYPE_P2P_GO:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -6520,7 +6569,9 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
-                                    const u8 *addr, int wds)
+                                    const u8 *addr, int wds,
+                                    int (*handler)(struct nl_msg *, void *),
+                                    void *arg)
 {
        struct nl_msg *msg;
        int ifidx;
@@ -6552,7 +6603,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, handler, arg);
        msg = NULL;
        if (ret) {
  nla_put_failure:
@@ -6562,6 +6613,13 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: New P2P Device interface %s created",
+                          ifname);
+               return 0;
+       }
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -6584,11 +6642,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
-                               const u8 *addr, int wds)
+                               const u8 *addr, int wds,
+                               int (*handler)(struct nl_msg *, void *),
+                               void *arg)
 {
        int ret;
 
-       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+                                       arg);
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -6599,7 +6660,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
                /* Try to create the interface again */
                ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-                                               wds);
+                                               wds, handler, arg);
        }
 
        if (ret >= 0 && is_p2p_net_interface(iftype))
@@ -6949,7 +7010,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -8460,7 +8521,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                bss->addr, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -8676,6 +8737,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_AP;
        case WPA_IF_P2P_GO:
                return NL80211_IFTYPE_P2P_GO;
+       case WPA_IF_P2P_DEVICE:
+               return NL80211_IFTYPE_P2P_DEVICE;
        }
        return -1;
 }
@@ -8745,7 +8808,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memcpy(if_addr, addr, ETH_ALEN);
        ifidx = nl80211_create_iface(drv, ifname,
                                     wpa_driver_nl80211_if_type(type), addr,
-                                    0);
+                                    0, NULL, NULL);
        if (ifidx < 0) {
 #ifdef HOSTAPD
                os_free(new_bss);
@@ -8922,7 +8985,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                   freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -9044,7 +9109,9 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -9091,7 +9158,9 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);