cfg80211: 802.11p OCB mode handling
authorRostislav Lisovy <lisovy@gmail.com>
Mon, 3 Nov 2014 09:33:18 +0000 (10:33 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 4 Nov 2014 12:18:17 +0000 (13:18 +0100)
This patch adds new iface type (NL80211_IFTYPE_OCB) representing
the OCB (Outside the Context of a BSS) mode.
When establishing a connection to the network a cfg80211_join_ocb
function is called (particular nl80211_command is added as well).
A mandatory parameters during the ocb_join operation are 'center
frequency' and 'channel width (5/10 MHz)'.

Changes done in mac80211 are minimal possible required to avoid
many warnings (warning: enumeration value 'NL80211_IFTYPE_OCB'
not handled in switch) during compilation. Full functionality
(where needed) is added in the following patch.

Signed-off-by: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
15 files changed:
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/iface.c
net/mac80211/util.c
net/wireless/Makefile
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/ocb.c [new file with mode: 0644]
net/wireless/rdev-ops.h
net/wireless/trace.h
net/wireless/util.c

index f67948e18600b313a18fcb18194a6dab496093d0..5c3acd07acd982be8b38097d91e1908003aea66c 100644 (file)
@@ -1358,6 +1358,16 @@ struct mesh_setup {
        u32 basic_rates;
 };
 
+/**
+ * struct ocb_setup - 802.11p OCB mode setup configuration
+ * @chandef: defines the channel to use
+ *
+ * These parameters are fixed when connecting to the network
+ */
+struct ocb_setup {
+       struct cfg80211_chan_def chandef;
+};
+
 /**
  * struct ieee80211_txq_params - TX queue parameters
  * @ac: AC identifier
@@ -2352,6 +2362,11 @@ struct cfg80211_qos_map {
  *     with the peer followed by immediate teardown when the addition is later
  *     rejected)
  * @del_tx_ts: remove an existing TX TS
+ *
+ * @join_ocb: join the OCB network with the specified parameters
+ *     (invoked with the wireless_dev mutex held)
+ * @leave_ocb: leave the current OCB network
+ *     (invoked with the wireless_dev mutex held)
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2433,6 +2448,10 @@ struct cfg80211_ops {
                             const struct mesh_setup *setup);
        int     (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
 
+       int     (*join_ocb)(struct wiphy *wiphy, struct net_device *dev,
+                           struct ocb_setup *setup);
+       int     (*leave_ocb)(struct wiphy *wiphy, struct net_device *dev);
+
        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                              struct bss_parameters *params);
 
index f7daae59248e3d63ff330f8b3c495f460a423b05..9b3025e4377a6e1ab9663341ee433afbd2f1d1c6 100644 (file)
  *     destination %NL80211_ATTR_MAC on the interface identified by
  *     %NL80211_ATTR_IFINDEX.
  *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ *     bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ *     network is determined by the network interface.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -922,6 +927,9 @@ enum nl80211_commands {
 
        NL80211_CMD_GET_MPP,
 
+       NL80211_CMD_JOIN_OCB,
+       NL80211_CMD_LEAVE_OCB,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -2074,6 +2082,8 @@ enum nl80211_attrs {
  *     and therefore can't be created in the normal ways, use the
  *     %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
  *     commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ *     This mode corresponds to the MIB variable dot11OCBActivated=true
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
  * @NUM_NL80211_IFTYPES: number of defined interface types
  *
@@ -2093,6 +2103,7 @@ enum nl80211_iftype {
        NL80211_IFTYPE_P2P_CLIENT,
        NL80211_IFTYPE_P2P_GO,
        NL80211_IFTYPE_P2P_DEVICE,
+       NL80211_IFTYPE_OCB,
 
        /* keep last */
        NUM_NL80211_IFTYPES,
index b9659b8b70f853c1aec7d2811dfa2132a4bb9208..1e2afc95ad09127ad308b6001d591fbf411bfd23 100644 (file)
@@ -230,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        case NUM_NL80211_IFTYPES:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_OCB:
                /* shouldn't happen */
                WARN_ON_ONCE(1);
                break;
index ee71bb6f64f72475c4a65a804cb2a3d07245b44d..ff1f877e3b639de849ec0ad42b9a2a7b4046bcda 100644 (file)
@@ -270,6 +270,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_WDS:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        width = vif->bss_conf.chandef.width;
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
@@ -909,6 +910,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_OCB:
                ieee80211_queue_work(&sdata->local->hw,
                                     &sdata->csa_finalize_work);
                break;
index 1ffcc070124490e8a55f528f76e248efe3d73673..d69e7532095f61bd3bbf6261f23ac31da03c48a4 100644 (file)
@@ -521,6 +521,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_OCB:
                /* no special treatment */
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
@@ -631,6 +632,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        netif_carrier_off(dev);
                        break;
                case NL80211_IFTYPE_WDS:
@@ -1351,6 +1353,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
                ieee80211_sta_setup_sdata(sdata);
                break;
+       case NL80211_IFTYPE_OCB:
+               /* to be implemented in the future */
+               break;
        case NL80211_IFTYPE_ADHOC:
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
                ieee80211_ibss_setup_sdata(sdata);
index 666aa1306c45f5d8e71a4e677a1c13841c3acd57..d7d69c89ff34958f2c6fd93b6f07f65063762ff7 100644 (file)
@@ -1841,6 +1841,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        ieee80211_bss_info_change_notify(sdata, changed);
                        sdata_unlock(sdata);
                        break;
+               case NL80211_IFTYPE_OCB:
+                       /* to be implemented in the future */
+                       break;
                case NL80211_IFTYPE_ADHOC:
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
index a761670af31dd7076b32e7f61f26bb4b94b22728..4c9e39f04ef8fae38e21070fddbb89bb5a150863 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
index 8f39e33e71bbc301d2fdae11f5ccb390f4f59048..85506f1d078920117b1030abc1e50a0ec70fdc6b 100644 (file)
@@ -366,6 +366,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
                break;
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
@@ -892,6 +893,13 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                                *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
+       case NL80211_IFTYPE_OCB:
+               if (wdev->chandef.chan) {
+                       *chan = wdev->chandef.chan;
+                       *chanmode = CHAN_MODE_SHARED;
+                       return;
+               }
+               break;
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_WDS:
index da4dcb65ade433d9230e84be0e0419f239487111..a4d27927aba25930870630c0927d425b51bd6ee9 100644 (file)
@@ -869,6 +869,9 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
        case NL80211_IFTYPE_P2P_GO:
                __cfg80211_stop_ap(rdev, dev, true);
                break;
+       case NL80211_IFTYPE_OCB:
+               __cfg80211_leave_ocb(rdev, dev);
+               break;
        case NL80211_IFTYPE_WDS:
                /* must be handled by mac80211/driver, has no APIs */
                break;
index 7e3a3cef7df93b4c6936515f05f91d2ec14446ea..61ee664cf2bd94a3183eaa1398b84777b4790828 100644 (file)
@@ -290,6 +290,18 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
                              struct wireless_dev *wdev,
                              struct cfg80211_chan_def *chandef);
 
+/* OCB */
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ocb_setup *setup);
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct ocb_setup *setup);
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev);
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev);
+
 /* AP */
 int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, bool notify);
index f7d918858d32863b461d343a9e40bff5907db3d8..1a31736914e5ca9a9ac2cd2083deb43bfb7e6fc3 100644 (file)
@@ -885,6 +885,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_P2P_DEVICE:
        case NL80211_IFTYPE_WDS:
@@ -8275,6 +8276,28 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
        return -EINVAL;
 }
 
+static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct ocb_setup setup = {};
+       int err;
+
+       err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+       if (err)
+               return err;
+
+       return cfg80211_join_ocb(rdev, dev, &setup);
+}
+
+static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+
+       return cfg80211_leave_ocb(rdev, dev);
+}
+
 static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -10218,6 +10241,22 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_JOIN_OCB,
+               .doit = nl80211_join_ocb,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_LEAVE_OCB,
+               .doit = nl80211_leave_ocb,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 #ifdef CONFIG_PM
        {
                .cmd = NL80211_CMD_GET_WOWLAN,
diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c
new file mode 100644 (file)
index 0000000..c00d4a7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * OCB mode implementation
+ *
+ * Copyright: (c) 2014 Czech Technical University in Prague
+ *            (c) 2014 Volkswagen Group Research
+ * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * 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.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+#include "core.h"
+#include "rdev-ops.h"
+
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ocb_setup *setup)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+               return -EOPNOTSUPP;
+
+       if (WARN_ON(!setup->chandef.chan))
+               return -EINVAL;
+
+       err = rdev_join_ocb(rdev, dev, setup);
+       if (!err)
+               wdev->chandef = setup->chandef;
+
+       return err;
+}
+
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct ocb_setup *setup)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_join_ocb(rdev, dev, setup);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->leave_ocb)
+               return -EOPNOTSUPP;
+
+       err = rdev_leave_ocb(rdev, dev);
+       if (!err)
+               memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+
+       return err;
+}
+
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_leave_ocb(rdev, dev);
+       wdev_unlock(wdev);
+
+       return err;
+}
index 71b1db3cc6458f798922263f3499a691d90b51b4..1b3864cd50cadb714ca16afbb660ffeab4703c0b 100644 (file)
@@ -348,6 +348,27 @@ static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int rdev_join_ocb(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev,
+                               struct ocb_setup *setup)
+{
+       int ret;
+       trace_rdev_join_ocb(&rdev->wiphy, dev, setup);
+       ret = rdev->ops->join_ocb(&rdev->wiphy, dev, setup);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_leave_ocb(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev)
+{
+       int ret;
+       trace_rdev_leave_ocb(&rdev->wiphy, dev);
+       ret = rdev->ops->leave_ocb(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
 static inline int rdev_change_bss(struct cfg80211_registered_device *rdev,
                                  struct net_device *dev,
                                  struct bss_parameters *params)
index cdb2c2ef1ae19c243608cc3672f75a522b170f10..277a85df910eef03fe9c0354addf28fe3f2e4adc 100644 (file)
@@ -600,6 +600,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss,
        TP_ARGS(wiphy, netdev)
 );
 
+DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ocb,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
 DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa,
        TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
        TP_ARGS(wiphy, netdev)
@@ -1316,6 +1321,22 @@ TRACE_EVENT(rdev_join_ibss,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid)
 );
 
+TRACE_EVENT(rdev_join_ocb,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                const struct ocb_setup *setup),
+       TP_ARGS(wiphy, netdev, setup),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
 TRACE_EVENT(rdev_set_wiphy_params,
        TP_PROTO(struct wiphy *wiphy, u32 changed),
        TP_ARGS(wiphy, changed),
index 5e233a577d0fcd15e39b5eebc5678598c37637df..d0ac795445b7e40dc92ebb1e0bd9095fc4bab048 100644 (file)
@@ -442,7 +442,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                break;
        case cpu_to_le16(0):
                if (iftype != NL80211_IFTYPE_ADHOC &&
-                   iftype != NL80211_IFTYPE_STATION)
+                   iftype != NL80211_IFTYPE_STATION &&
+                   iftype != NL80211_IFTYPE_OCB)
                                return -1;
                break;
        }
@@ -519,6 +520,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                hdrlen = 24;
                break;
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -937,6 +939,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                        if (dev->ieee80211_ptr->use_4addr)
                                break;
                        /* fall through */
+               case NL80211_IFTYPE_OCB:
                case NL80211_IFTYPE_P2P_CLIENT:
                case NL80211_IFTYPE_ADHOC:
                        dev->priv_flags |= IFF_DONT_BRIDGE;