mac80211: add p2p device type support
Johannes Berg [Thu, 16 Sep 2010 12:58:23 +0000 (14:58 +0200)]
When a driver advertises p2p device support,
mac80211 will handle it, but internally it will
rewrite the interface type to STA/AP rather than
P2P-STA/GO since otherwise a lot of paths need
to be touched that are otherwise identical. A
p2p boolean tells drivers whether or not a given
interface will be used for p2p or not.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

drivers/net/wireless/mac80211_hwsim.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/rx.c
net/mac80211/util.c

index 92b486d..7eaaa3b 100644 (file)
@@ -595,7 +595,8 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif)
 {
        wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
-                   __func__, vif->type, vif->addr);
+                   __func__, ieee80211_vif_type_p2p(vif),
+                   vif->addr);
        hwsim_set_magic(vif);
        return 0;
 }
@@ -603,11 +604,14 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 
 static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif,
-                                          enum nl80211_iftype newtype)
+                                          enum nl80211_iftype newtype,
+                                          bool newp2p)
 {
+       newtype = ieee80211_iftype_p2p(newtype, newp2p);
        wiphy_debug(hw->wiphy,
                    "%s (old type=%d, new type=%d, mac_addr=%pM)\n",
-                   __func__, vif->type, newtype, vif->addr);
+                   __func__, ieee80211_vif_type_p2p(vif),
+                   newtype, vif->addr);
        hwsim_check_magic(vif);
 
        return 0;
@@ -617,7 +621,8 @@ static void mac80211_hwsim_remove_interface(
        struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
-                   __func__, vif->type, vif->addr);
+                   __func__, ieee80211_vif_type_p2p(vif),
+                   vif->addr);
        hwsim_check_magic(vif);
        hwsim_clear_magic(vif);
 }
@@ -1310,6 +1315,8 @@ static int __init init_mac80211_hwsim(void)
                hw->wiphy->interface_modes =
                        BIT(NL80211_IFTYPE_STATION) |
                        BIT(NL80211_IFTYPE_AP) |
+                       BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                       BIT(NL80211_IFTYPE_P2P_GO) |
                        BIT(NL80211_IFTYPE_ADHOC) |
                        BIT(NL80211_IFTYPE_MESH_POINT);
 
index 19a5cb4..12a49f0 100644 (file)
@@ -769,6 +769,8 @@ struct ieee80211_channel_switch {
  * @bss_conf: BSS configuration for this interface, either our own
  *     or the BSS we're associated to
  * @addr: address of this interface
+ * @p2p: indicates whether this AP or STA interface is a p2p
+ *     interface, i.e. a GO or p2p-sta respectively
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
  */
@@ -776,6 +778,7 @@ struct ieee80211_vif {
        enum nl80211_iftype type;
        struct ieee80211_bss_conf bss_conf;
        u8 addr[ETH_ALEN];
+       bool p2p;
        /* must be last */
        u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
 };
@@ -1701,7 +1704,7 @@ struct ieee80211_ops {
                             struct ieee80211_vif *vif);
        int (*change_interface)(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
-                               enum nl80211_iftype new_type);
+                               enum nl80211_iftype new_type, bool p2p);
        void (*remove_interface)(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif);
        int (*config)(struct ieee80211_hw *hw, u32 changed);
@@ -2721,4 +2724,26 @@ conf_is_ht(struct ieee80211_conf *conf)
        return conf->channel_type != NL80211_CHAN_NO_HT;
 }
 
+static inline enum nl80211_iftype
+ieee80211_iftype_p2p(enum nl80211_iftype type, bool p2p)
+{
+       if (p2p) {
+               switch (type) {
+               case NL80211_IFTYPE_STATION:
+                       return NL80211_IFTYPE_P2P_CLIENT;
+               case NL80211_IFTYPE_AP:
+                       return NL80211_IFTYPE_P2P_GO;
+               default:
+                       break;
+               }
+       }
+       return type;
+}
+
+static inline enum nl80211_iftype
+ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
+{
+       return ieee80211_iftype_p2p(vif->type, vif->p2p);
+}
+
 #endif /* MAC80211_H */
index 171e8ff..c981604 100644 (file)
@@ -1151,15 +1151,26 @@ static int ieee80211_scan(struct wiphy *wiphy,
                          struct net_device *dev,
                          struct cfg80211_scan_request *req)
 {
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-           sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
-           (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon))
+       switch (ieee80211_vif_type_p2p(&sdata->vif)) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+               if (sdata->local->ops->hw_scan)
+                       break;
+               /* FIXME: implement NoA while scanning in software */
+               return -EOPNOTSUPP;
+       case NL80211_IFTYPE_AP:
+               if (sdata->u.ap.beacon)
+                       return -EOPNOTSUPP;
+               break;
+       default:
                return -EOPNOTSUPP;
+       }
 
        return ieee80211_request_scan(sdata, req);
 }
index 6064b7b..1698382 100644 (file)
@@ -56,14 +56,14 @@ static inline int drv_add_interface(struct ieee80211_local *local,
 
 static inline int drv_change_interface(struct ieee80211_local *local,
                                       struct ieee80211_sub_if_data *sdata,
-                                      enum nl80211_iftype type)
+                                      enum nl80211_iftype type, bool p2p)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_change_interface(local, sdata, type);
-       ret = local->ops->change_interface(&local->hw, &sdata->vif, type);
+       trace_drv_change_interface(local, sdata, type, p2p);
+       ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
        trace_drv_return_int(local, ret);
        return ret;
 }
index f6f3d89..6831fb1 100644 (file)
@@ -25,12 +25,14 @@ static inline void trace_ ## name(proto) {}
 #define STA_PR_FMT     " sta:%pM"
 #define STA_PR_ARG     __entry->sta_addr
 
-#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
+#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata)   \
+                       __field(bool, p2p)                                              \
                        __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
+#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata;    \
+                       __entry->p2p = sdata->vif.p2p;                                  \
                        __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_PR_FMT     " vif:%s(%d)"
-#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type
+#define VIF_PR_FMT     " vif:%s(%d%s)"
+#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
 
 /*
  * Tracing for driver callbacks.
@@ -139,25 +141,28 @@ TRACE_EVENT(drv_add_interface,
 TRACE_EVENT(drv_change_interface,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
-                enum nl80211_iftype type),
+                enum nl80211_iftype type, bool p2p),
 
-       TP_ARGS(local, sdata, type),
+       TP_ARGS(local, sdata, type, p2p),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
                VIF_ENTRY
                __field(u32, new_type)
+               __field(bool, new_p2p)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
                __entry->new_type = type;
+               __entry->new_p2p = p2p;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type
+               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d%s",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
+               __entry->new_p2p ? "/p2p" : ""
        )
 );
 
index 95908aa..6678573 100644 (file)
@@ -188,6 +188,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case NUM_NL80211_IFTYPES:
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_P2P_GO:
                /* cannot happen */
                WARN_ON(1);
                break;
@@ -844,6 +846,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
        /* and set some type-dependent values */
        sdata->vif.type = type;
+       sdata->vif.p2p = false;
        sdata->dev->netdev_ops = &ieee80211_dataif_ops;
        sdata->wdev.iftype = type;
 
@@ -857,10 +860,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        INIT_WORK(&sdata->work, ieee80211_iface_work);
 
        switch (type) {
+       case NL80211_IFTYPE_P2P_GO:
+               type = NL80211_IFTYPE_AP;
+               sdata->vif.type = type;
+               sdata->vif.p2p = true;
+               /* fall through */
        case NL80211_IFTYPE_AP:
                skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
                INIT_LIST_HEAD(&sdata->u.ap.vlans);
                break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+               type = NL80211_IFTYPE_STATION;
+               sdata->vif.type = type;
+               sdata->vif.p2p = true;
+               /* fall through */
        case NL80211_IFTYPE_STATION:
                ieee80211_sta_setup_sdata(sdata);
                break;
@@ -894,6 +907,8 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        int ret, err;
+       enum nl80211_iftype internal_type = type;
+       bool p2p = false;
 
        ASSERT_RTNL();
 
@@ -926,11 +941,19 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
                 * code isn't prepared to handle).
                 */
                break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+               p2p = true;
+               internal_type = NL80211_IFTYPE_STATION;
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+               p2p = true;
+               internal_type = NL80211_IFTYPE_AP;
+               break;
        default:
                return -EBUSY;
        }
 
-       ret = ieee80211_check_concurrent_iface(sdata, type);
+       ret = ieee80211_check_concurrent_iface(sdata, internal_type);
        if (ret)
                return ret;
 
@@ -938,7 +961,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_teardown_sdata(sdata->dev);
 
-       ret = drv_change_interface(local, sdata, type);
+       ret = drv_change_interface(local, sdata, internal_type, p2p);
        if (ret)
                type = sdata->vif.type;
 
@@ -957,7 +980,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
 
        ASSERT_RTNL();
 
-       if (type == sdata->vif.type)
+       if (type == ieee80211_vif_type_p2p(&sdata->vif))
                return 0;
 
        /* Setting ad-hoc mode on non-IBSS channel is not supported. */
index 7fb1148..18fdeca 100644 (file)
@@ -459,6 +459,21 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
                        BIT(IEEE80211_STYPE_DEAUTH >> 4) |
                        BIT(IEEE80211_STYPE_ACTION >> 4),
        },
+       [NL80211_IFTYPE_P2P_CLIENT] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+       },
+       [NL80211_IFTYPE_P2P_GO] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
 };
 
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
index ac205a3..c036815 100644 (file)
@@ -2588,9 +2588,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
                        return 0;
                break;
-       case NL80211_IFTYPE_MONITOR:
-       case NL80211_IFTYPE_UNSPECIFIED:
-       case NUM_NL80211_IFTYPES:
+       default:
                /* should never get here */
                WARN_ON(1);
                break;
index 9f21a69..737f426 100644 (file)
@@ -474,16 +474,10 @@ void ieee80211_iterate_active_interfaces(
 
        list_for_each_entry(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
-               case NUM_NL80211_IFTYPES:
-               case NL80211_IFTYPE_UNSPECIFIED:
                case NL80211_IFTYPE_MONITOR:
                case NL80211_IFTYPE_AP_VLAN:
                        continue;
-               case NL80211_IFTYPE_AP:
-               case NL80211_IFTYPE_STATION:
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_WDS:
-               case NL80211_IFTYPE_MESH_POINT:
+               default:
                        break;
                }
                if (ieee80211_sdata_running(sdata))
@@ -508,16 +502,10 @@ void ieee80211_iterate_active_interfaces_atomic(
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
-               case NUM_NL80211_IFTYPES:
-               case NL80211_IFTYPE_UNSPECIFIED:
                case NL80211_IFTYPE_MONITOR:
                case NL80211_IFTYPE_AP_VLAN:
                        continue;
-               case NL80211_IFTYPE_AP:
-               case NL80211_IFTYPE_STATION:
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_WDS:
-               case NL80211_IFTYPE_MESH_POINT:
+               default:
                        break;
                }
                if (ieee80211_sdata_running(sdata))
@@ -1193,6 +1181,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
                case NUM_NL80211_IFTYPES:
+               case NL80211_IFTYPE_P2P_CLIENT:
+               case NL80211_IFTYPE_P2P_GO:
                        WARN_ON(1);
                        break;
                }