cfg80211: 802.11p OCB mode handling

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>
This commit is contained in:
Rostislav Lisovy 2014-11-03 10:33:18 +01:00 committed by Johannes Berg
parent 5b3dc42b1b
commit 6e0bd6c35b
15 changed files with 238 additions and 2 deletions

View 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);

View File

@ -746,6 +746,11 @@
* 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,

View 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;

View 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;

View 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);

View 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 */

View 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

View 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:

View 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;

View 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);

View 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,

88
net/wireless/ocb.c Normal file
View File

@ -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;
}

View 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)

View 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),

View 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;