From ff4e65581eb5349b7cefeda4083abe6eba44378a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:33 +0100 Subject: ieee802154: remove default channel settings This patch removes the default channel setting. A channel is always set and there is no default channel setting according 802.15.4. Drivers should set the default channel and page in probing routine. This behaviour is currently a lack of all 802.15.4 drivers. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 620abc2ba5fc..dc294a415d05 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -100,9 +100,6 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) phy->dev.class = &wpan_phy_class; - phy->current_channel = -1; /* not initialised */ - phy->current_page = 0; /* for compatibility */ - return phy; out: -- cgit v1.2.3-70-g09d2 From a5dd1d72d868ec9c8f44d60ca29900b6a38321b4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:35 +0100 Subject: cfg802154: introduce cfg802154_registered_device This patch introduce the cfg802154_registered_device struct. Like cfg80211_registered_device in wireless this should contain similar functionality for cfg802154. This patch should not change any behaviour. We just adds cfg802154_registered_device as container for wpan_phy struct. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 8 +++++++- net/ieee802154/core.c | 39 ++++++++++++++++++++++++++------------- net/ieee802154/core.h | 18 ++++++++++++++++++ net/ieee802154/sysfs.c | 15 ++++++++++++--- net/mac802154/main.c | 2 +- 5 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 net/ieee802154/core.h (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 440b9bece9c6..12de66bda9a5 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -29,6 +29,11 @@ #define WPAN_NUM_CHANNELS 27 #define WPAN_NUM_PAGES 32 +struct wpan_phy; + +struct cfg802154_ops { +}; + struct wpan_phy { struct mutex pib_lock; @@ -62,7 +67,8 @@ struct wpan_phy { #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) -struct wpan_phy *wpan_phy_alloc(size_t priv_size); +struct wpan_phy * +wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size); static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) { phy->dev.parent = dev; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index dc294a415d05..ed5b014dbec7 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -21,6 +21,7 @@ #include "ieee802154.h" #include "sysfs.h" +#include "core.h" static DEFINE_MUTEX(wpan_phy_mutex); static int wpan_phy_idx; @@ -76,31 +77,38 @@ static int wpan_phy_idx_valid(int idx) return idx >= 0; } -struct wpan_phy *wpan_phy_alloc(size_t priv_size) +struct wpan_phy * +wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size) { - struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size, - GFP_KERNEL); + struct cfg802154_registered_device *rdev; + size_t alloc_size; + + alloc_size = sizeof(*rdev) + priv_size; + rdev = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev) + return NULL; + + rdev->ops = ops; - if (!phy) - goto out; mutex_lock(&wpan_phy_mutex); - phy->idx = wpan_phy_idx++; - if (unlikely(!wpan_phy_idx_valid(phy->idx))) { + rdev->wpan_phy.idx = wpan_phy_idx++; + if (unlikely(!wpan_phy_idx_valid(rdev->wpan_phy.idx))) { wpan_phy_idx--; mutex_unlock(&wpan_phy_mutex); - kfree(phy); + kfree(rdev); goto out; } mutex_unlock(&wpan_phy_mutex); - mutex_init(&phy->pib_lock); + mutex_init(&rdev->wpan_phy.pib_lock); - device_initialize(&phy->dev); - dev_set_name(&phy->dev, "wpan-phy%d", phy->idx); + device_initialize(&rdev->wpan_phy.dev); + dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy.idx); - phy->dev.class = &wpan_phy_class; + rdev->wpan_phy.dev.class = &wpan_phy_class; + rdev->wpan_phy.dev.platform_data = rdev; - return phy; + return &rdev->wpan_phy; out: return NULL; @@ -125,6 +133,11 @@ void wpan_phy_free(struct wpan_phy *phy) } EXPORT_SYMBOL(wpan_phy_free); +void cfg802154_dev_free(struct cfg802154_registered_device *rdev) +{ + kfree(rdev); +} + static int __init wpan_phy_class_init(void) { int rc; diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h new file mode 100644 index 000000000000..26752ca54b4f --- /dev/null +++ b/net/ieee802154/core.h @@ -0,0 +1,18 @@ +#ifndef __IEEE802154_CORE_H +#define __IEEE802154_CORE_H + +#include + +struct cfg802154_registered_device { + const struct cfg802154_ops *ops; + + /* must be last because of the way we do wpan_phy_priv(), + * and it should at least be aligned to NETDEV_ALIGN + */ + struct wpan_phy wpan_phy __aligned(NETDEV_ALIGN); +}; + +/* free object */ +void cfg802154_dev_free(struct cfg802154_registered_device *rdev); + +#endif /* __IEEE802154_CORE_H */ diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c index eb9ca6f99122..c6e038099e07 100644 --- a/net/ieee802154/sysfs.c +++ b/net/ieee802154/sysfs.c @@ -17,6 +17,15 @@ #include +#include "core.h" + +static inline struct cfg802154_registered_device * +dev_to_rdev(struct device *dev) +{ + return container_of(dev, struct cfg802154_registered_device, + wpan_phy.dev); +} + #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ static ssize_t name ## _show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -60,11 +69,11 @@ static ssize_t channels_supported_show(struct device *dev, } static DEVICE_ATTR_RO(channels_supported); -static void wpan_phy_release(struct device *d) +static void wpan_phy_release(struct device *dev) { - struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); + struct cfg802154_registered_device *rdev = dev_to_rdev(dev); - kfree(phy); + cfg802154_dev_free(rdev); } static struct attribute *pmib_attrs[] = { diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 86e533ed3775..ebc2bb123cfe 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -169,7 +169,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; - phy = wpan_phy_alloc(priv_size); + phy = wpan_phy_alloc(NULL, priv_size); if (!phy) { pr_err("failure to allocate master IEEE802.15.4 device\n"); return NULL; -- cgit v1.2.3-70-g09d2 From ea4dcd32a445908c12e04b3b879c57ec5b3e659a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:37 +0100 Subject: ieee802154: add helper wpan_phy_to_rdev function This patch introduce a function to get the cfg802154_registered_device from a wpan_phy. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/core.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net/ieee802154') diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index 26752ca54b4f..1bc172587157 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -12,6 +12,14 @@ struct cfg802154_registered_device { struct wpan_phy wpan_phy __aligned(NETDEV_ALIGN); }; +static inline struct cfg802154_registered_device * +wpan_phy_to_rdev(struct wpan_phy *wpan_phy) +{ + BUG_ON(!wpan_phy); + return container_of(wpan_phy, struct cfg802154_registered_device, + wpan_phy); +} + /* free object */ void cfg802154_dev_free(struct cfg802154_registered_device *rdev); -- cgit v1.2.3-70-g09d2 From 4a9a816a4f8c79260446811bdf80615b36539949 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:38 +0100 Subject: cfg802154: convert deprecated iface add and del This patch removes the wpan_phy callbacks for add and del an interface on a phy. Instead we introduce deprecated cfg802154 callbacks for this. Furthermore we introduce a new netlink interface nl802154 which use different callbacks. The deprecated function is to have a backwards compatibility with the current netlink interface. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 9 +++++---- net/ieee802154/nl-phy.c | 19 ++++++------------- net/ieee802154/rdev-ops.h | 23 +++++++++++++++++++++++ net/mac802154/cfg.c | 17 +++++++++++++++++ net/mac802154/ieee802154_i.h | 4 ++++ net/mac802154/main.c | 8 ++------ 6 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 net/ieee802154/rdev-ops.h (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 12de66bda9a5..864bce2b0728 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -32,6 +32,11 @@ struct wpan_phy; struct cfg802154_ops { + struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, + const char *name, + int type); + void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, + struct net_device *dev); }; struct wpan_phy { @@ -58,10 +63,6 @@ struct wpan_phy { struct device dev; int idx; - struct net_device *(*add_iface)(struct wpan_phy *phy, - const char *name, int type); - void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); - char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 0afe760ff512..5d914d30e0b1 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -30,6 +30,8 @@ #include #include "ieee802154.h" +#include "rdev-ops.h" +#include "core.h" static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, u32 seq, int flags, struct wpan_phy *phy) @@ -203,11 +205,6 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) if (!msg) goto out_dev; - if (!phy->add_iface) { - rc = -EINVAL; - goto nla_put_failure; - } - if (info->attrs[IEEE802154_ATTR_HW_ADDR] && nla_len(info->attrs[IEEE802154_ATTR_HW_ADDR]) != IEEE802154_ADDR_LEN) { @@ -223,7 +220,8 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) } } - dev = phy->add_iface(phy, devname, type); + dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, + type); if (IS_ERR(dev)) { rc = PTR_ERR(dev); goto nla_put_failure; @@ -257,7 +255,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) dev_unregister: rtnl_lock(); /* del_iface must be called with RTNL lock */ - phy->del_iface(phy, dev); + rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev); dev_put(dev); rtnl_unlock(); nla_put_failure: @@ -319,13 +317,8 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) if (!msg) goto out_dev; - if (!phy->del_iface) { - rc = -EINVAL; - goto nla_put_failure; - } - rtnl_lock(); - phy->del_iface(phy, dev); + rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev); /* We don't have device anymore */ dev_put(dev); diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h new file mode 100644 index 000000000000..ac8824ec168c --- /dev/null +++ b/net/ieee802154/rdev-ops.h @@ -0,0 +1,23 @@ +#ifndef __CFG802154_RDEV_OPS +#define __CFG802154_RDEV_OPS + +#include + +#include "core.h" + +static inline struct net_device * +rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, + const char *name, int type) +{ + return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name, + type); +} + +static inline void +rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, + struct net_device *dev) +{ + rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev); +} + +#endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 105468ec8f26..75a5d258ac24 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -15,5 +15,22 @@ #include +#include "ieee802154_i.h" + +static struct net_device * +ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy, + const char *name, int type) +{ + return mac802154_add_iface(wpan_phy, name, type); +} + +static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, + struct net_device *dev) +{ + mac802154_del_iface(wpan_phy, dev); +} + const struct cfg802154_ops mac802154_config_ops = { + .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, + .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, }; diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 1086a9d96f8f..39af6eaec410 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -174,4 +174,8 @@ void mac802154_get_table(struct net_device *dev, struct ieee802154_llsec_table **t); void mac802154_unlock_table(struct net_device *dev); +struct net_device * +mac802154_add_iface(struct wpan_phy *phy, const char *name, int type); +void mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev); + #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 785abb1aafb4..b34ddbf43c3d 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -59,8 +59,7 @@ mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev) return 0; } -static void -mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) +void mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) { struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); @@ -76,7 +75,7 @@ mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) unregister_netdevice(sdata->dev); } -static struct net_device * +struct net_device * mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) { struct net_device *dev; @@ -221,9 +220,6 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) wpan_phy_set_dev(local->phy, local->hw.parent); - local->phy->add_iface = mac802154_add_iface; - local->phy->del_iface = mac802154_del_iface; - rc = wpan_phy_register(local->phy); if (rc < 0) goto out_wq; -- cgit v1.2.3-70-g09d2 From 8f499f991c275d5251a427c424360a9c60f549e4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:39 +0100 Subject: ieee802154: don't allow to change addr while netif_running This patch changes the actual behaviour for setting address attributes. We should not change addresses while netif_running is true. Furthermore when netif_running is running the address attributes becomes read only and we can remove locking mechanism in receive and transmit hothpaths of 802.15.4 subsystem. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl-mac.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index abd0f31bdc66..cc2919dbe5e0 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -477,7 +477,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) u8 channel, bcn_ord, sf_ord; u8 page; int pan_coord, blx, coord_realign; - int ret = -EOPNOTSUPP; + int ret = -EBUSY; if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || @@ -493,9 +493,15 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) dev = ieee802154_nl_get_dev(info); if (!dev) return -ENODEV; - if (!ieee802154_mlme_ops(dev)->start_req) + + if (netif_running(dev)) goto out; + if (!ieee802154_mlme_ops(dev)->start_req) { + ret = -EOPNOTSUPP; + goto out; + } + addr.mode = IEEE802154_ADDR_SHORT; addr.short_addr = nla_get_shortaddr( info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); -- cgit v1.2.3-70-g09d2 From 62906710182a7d079a69932a93ebd003caaa7135 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 04:18:47 +0100 Subject: ieee802154: 6lowpan: remove set of mac address Currently the ieee802154 6lowpan interface operates on wpan interfaces only. Setting the wpan mac address over 6lowpan interface is complex and maybe we can't never do this. This patch removes the set of mac address handling in ieee802154 6lowpan interface for now. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/6lowpan_rtnl.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 519a65452d90..659f7b25ea1a 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -206,19 +206,6 @@ drop: return -EINVAL; } -static int lowpan_set_address(struct net_device *dev, void *p) -{ - struct sockaddr *sa = p; - - if (netif_running(dev)) - return -EBUSY; - - /* TODO: validate addr */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - - return 0; -} - static struct sk_buff* lowpan_alloc_frag(struct sk_buff *skb, int size, const struct ieee802154_hdr *master_hdr) @@ -474,7 +461,6 @@ static int lowpan_dev_init(struct net_device *dev) static const struct net_device_ops lowpan_netdev_ops = { .ndo_init = lowpan_dev_init, .ndo_start_xmit = lowpan_xmit, - .ndo_set_mac_address = lowpan_set_address, }; static struct ieee802154_mlme_ops lowpan_mlme = { -- cgit v1.2.3-70-g09d2 From c5fbbc4683276598ca1bfca95c90c35d1a3d962f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 2 Nov 2014 21:43:04 +0100 Subject: ieee802154: sysfs: add missing include Running make C=2 occurs in warnings: symbol 'wpan_phy_class' was not declared. Should it be static? symbol 'wpan_phy_sysfs_init' was not declared. Should it be static? symbol 'wpan_phy_sysfs_exit' wasnot declared. Should it be static? This patch adds a missing include "sysfs.h" to solve these warnings. Signed-off-by: Alexander Aring Reported-by: Marcel Holtmann Signed-off-by: Marcel Holtmann --- net/ieee802154/sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/ieee802154') diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c index c6e038099e07..88199980dae9 100644 --- a/net/ieee802154/sysfs.c +++ b/net/ieee802154/sysfs.c @@ -18,6 +18,7 @@ #include #include "core.h" +#include "sysfs.h" static inline struct cfg802154_registered_device * dev_to_rdev(struct device *dev) -- cgit v1.2.3-70-g09d2 From 53f9ee61b46d81a43d8c6694d136896e8f49a7b8 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Nov 2014 20:51:12 +0100 Subject: ieee802154: rework wpan_phy index assignment This patch reworks the wpan_phy index incrementation. It's now similar like wireless wiphy index incrementation. We move the wpan_phy index attribute inside of cfg802154_registered_device and use atomic operations instead locking mechanism via wpan_phy_mutex. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 1 - net/ieee802154/core.c | 30 +++++++++++------------------- net/ieee802154/core.h | 3 +++ 3 files changed, 14 insertions(+), 20 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 864bce2b0728..29c6de5a426c 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -61,7 +61,6 @@ struct wpan_phy { s32 cca_ed_level; struct device dev; - int idx; char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index ed5b014dbec7..d1cd0edfb149 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -23,9 +23,6 @@ #include "sysfs.h" #include "core.h" -static DEFINE_MUTEX(wpan_phy_mutex); -static int wpan_phy_idx; - static int wpan_phy_match(struct device *dev, const void *data) { return !strcmp(dev_name(dev), (const char *)data); @@ -72,14 +69,10 @@ int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), } EXPORT_SYMBOL(wpan_phy_for_each); -static int wpan_phy_idx_valid(int idx) -{ - return idx >= 0; -} - struct wpan_phy * wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size) { + static atomic_t wpan_phy_counter = ATOMIC_INIT(0); struct cfg802154_registered_device *rdev; size_t alloc_size; @@ -90,28 +83,27 @@ wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size) rdev->ops = ops; - mutex_lock(&wpan_phy_mutex); - rdev->wpan_phy.idx = wpan_phy_idx++; - if (unlikely(!wpan_phy_idx_valid(rdev->wpan_phy.idx))) { - wpan_phy_idx--; - mutex_unlock(&wpan_phy_mutex); + rdev->wpan_phy_idx = atomic_inc_return(&wpan_phy_counter); + + if (unlikely(rdev->wpan_phy_idx < 0)) { + /* ugh, wrapped! */ + atomic_dec(&wpan_phy_counter); kfree(rdev); - goto out; + return NULL; } - mutex_unlock(&wpan_phy_mutex); + + /* atomic_inc_return makes it start at 1, make it start at 0 */ + rdev->wpan_phy_idx--; mutex_init(&rdev->wpan_phy.pib_lock); device_initialize(&rdev->wpan_phy.dev); - dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy.idx); + dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx); rdev->wpan_phy.dev.class = &wpan_phy_class; rdev->wpan_phy.dev.platform_data = rdev; return &rdev->wpan_phy; - -out: - return NULL; } EXPORT_SYMBOL(wpan_phy_alloc); diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index 1bc172587157..fea60b3a8846 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -6,6 +6,9 @@ struct cfg802154_registered_device { const struct cfg802154_ops *ops; + /* wpan_phy index, internal only */ + int wpan_phy_idx; + /* must be last because of the way we do wpan_phy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ -- cgit v1.2.3-70-g09d2 From 9f3295b9ea8e54a6c65231d267f069edf420b64f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Nov 2014 20:51:13 +0100 Subject: ieee802154: remove nl802154 unused functions The include/net/nl802154.h file contains a lot of prototypes which are not used inside of ieee802154 subsystem. This patch removes this file and make the only one used prototype "ieee802154_nl_start_confirm" as static declaration in ieee802154/nl-mac.c Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- MAINTAINERS | 1 - include/net/nl802154.h | 122 ------------------------------- net/ieee802154/nl-mac.c | 187 ++---------------------------------------------- net/mac802154/mac_cmd.c | 6 -- 4 files changed, 6 insertions(+), 310 deletions(-) delete mode 100644 include/net/nl802154.h (limited to 'net/ieee802154') diff --git a/MAINTAINERS b/MAINTAINERS index 7ec37a396ffe..b42eb50b7426 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4699,7 +4699,6 @@ F: net/mac802154/ F: drivers/net/ieee802154/ F: include/linux/nl802154.h F: include/linux/ieee802154.h -F: include/net/nl802154.h F: include/net/mac802154.h F: include/net/af_ieee802154.h F: include/net/cfg802154.h diff --git a/include/net/nl802154.h b/include/net/nl802154.h deleted file mode 100644 index b5cdea29d9d9..000000000000 --- a/include/net/nl802154.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * nl802154.h - * - * Copyright (C) 2007, 2008, 2009 Siemens AG - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef IEEE802154_NL_H -#define IEEE802154_NL_H - -struct net_device; -struct ieee802154_addr; - -/** - * ieee802154_nl_assoc_indic - Notify userland of an association request. - * @dev: The network device on which this association request was - * received. - * @addr: The address of the device requesting association. - * @cap: The capability information field from the device. - * - * This informs a userland coordinator of a device requesting to - * associate with the PAN controlled by the coordinator. - * - * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. - */ -int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap); - -/** - * ieee802154_nl_assoc_confirm - Notify userland of association. - * @dev: The device which has completed association. - * @short_addr: The short address assigned to the device. - * @status: The status of the association. - * - * Inform userland of the result of an association request. If the - * association request included asking the coordinator to allocate - * a short address then it is returned in @short_addr. - * - * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_assoc_confirm(struct net_device *dev, - __le16 short_addr, u8 status); - -/** - * ieee802154_nl_disassoc_indic - Notify userland of disassociation. - * @dev: The device on which disassociation was indicated. - * @addr: The device which is disassociating. - * @reason: The reason for the disassociation. - * - * Inform userland that a device has disassociated from the network. - * - * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason); - -/** - * ieee802154_nl_disassoc_confirm - Notify userland of disassociation - * completion. - * @dev: The device on which disassociation was ordered. - * @status: The result of the disassociation. - * - * Inform userland of the result of requesting that a device - * disassociate, or the result of requesting that we disassociate from - * a PAN managed by another coordinator. - * - * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_disassoc_confirm(struct net_device *dev, - u8 status); - -/** - * ieee802154_nl_scan_confirm - Notify userland of completion of scan. - * @dev: The device which was instructed to scan. - * @status: The status of the scan operation. - * @scan_type: What type of scan was performed. - * @unscanned: Any channels that the device was unable to scan. - * @edl: The energy levels (if a passive scan). - * - * - * Note: This is in section 7.1.11 of the IEEE 802.15.4 document. - * Note: This API does not permit the return of an active scan result. - */ -int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, u8 page, - u8 *edl/*, struct list_head *pan_desc_list */); - -/** - * ieee802154_nl_beacon_indic - Notify userland of a received beacon. - * @dev: The device on which a beacon was received. - * @panid: The PAN of the coordinator. - * @coord_addr: The short address of the coordinator on that PAN. - * - * Note: This is in section 7.1.5 of the IEEE 802.15.4 document. - * Note: This API does not provide extended information such as what - * channel the PAN is on or what the LQI of the beacon frame was on - * receipt. - * Note: This API cannot indicate a beacon frame for a coordinator - * operating in long addressing mode. - */ -int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid, - __le16 coord_addr); - -/** - * ieee802154_nl_start_confirm - Notify userland of completion of start. - * @dev: The device which was instructed to scan. - * @status: The status of the scan operation. - * - * Note: This is in section 7.1.14 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_start_confirm(struct net_device *dev, u8 status); - -#endif diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index cc2919dbe5e0..91a1855e521c 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -55,186 +54,7 @@ static __le16 nla_get_shortaddr(const struct nlattr *nla) return cpu_to_le16(nla_get_u16(nla)); } -int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, - u8 cap) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - if (addr->mode != IEEE802154_ADDR_LONG) { - pr_err("%s: received non-long source address!\n", __func__); - return -EINVAL; - } - - msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr) || - nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR, - addr->extended_addr) || - nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) - goto nla_put_failure; - - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_assoc_indic); - -int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, - u8 status) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr) || - nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || - nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) - goto nla_put_failure; - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); - -int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, - u8 reason) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr)) - goto nla_put_failure; - if (addr->mode == IEEE802154_ADDR_LONG) { - if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR, - addr->extended_addr)) - goto nla_put_failure; - } else { - if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, - addr->short_addr)) - goto nla_put_failure; - } - if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) - goto nla_put_failure; - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); - -int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr) || - nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) - goto nla_put_failure; - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); - -int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid, - __le16 coord_addr) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr) || - nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, - coord_addr) || - nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) - goto nla_put_failure; - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_beacon_indic); - -int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, - u32 unscanned, u8 page, - u8 *edl/* , struct list_head *pan_desc_list */) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); - if (!msg) - return -ENOBUFS; - - if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || - nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || - nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr) || - nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) || - nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) || - nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) || - nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) || - (edl && - nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl))) - goto nla_put_failure; - return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_scan_confirm); - -int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) +static int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) { struct sk_buff *msg; @@ -530,6 +350,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, bcn_ord, sf_ord, pan_coord, blx, coord_realign); + /* FIXME: add validation for unused parameters to be sane + * for SoftMAC + */ + ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS); + out: dev_put(dev); return ret; diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index 9c2d6f61f194..e1ad83e35899 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "ieee802154_i.h" #include "driver-ops.h" @@ -65,11 +64,6 @@ static int mac802154_mlme_start_req(struct net_device *dev, rc = ops->llsec->set_params(dev, ¶ms, changed); } - /* FIXME: add validation for unused parameters to be sane - * for SoftMAC - */ - ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS); - return rc; } -- cgit v1.2.3-70-g09d2 From 12cb56c2370b2911295026630a71af044c12d2aa Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Nov 2014 20:51:16 +0100 Subject: mac802154: move dev_hold out of ieee802154_if_add This patch moves the dev_hold call inside of nl-phy ieee802154_add_iface function. The ieee802154_add_iface is the only one function which use the ieee802154_if_add function and contains the corresponding dev_put call. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl-phy.c | 1 + net/mac802154/iface.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 5d914d30e0b1..397ca126d9a2 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -226,6 +226,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) rc = PTR_ERR(dev); goto nla_put_failure; } + dev_hold(dev); if (info->attrs[IEEE802154_ATTR_HW_ADDR]) { struct sockaddr addr; diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index fced04b05275..78cb38124a2a 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -501,7 +501,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, if (err) goto err_free; - dev_hold(dev); /* we return an incremented device refcount */ return dev; err_free: -- cgit v1.2.3-70-g09d2 From bd28a11f25f2c2a563620e7be588dc4dd8a91396 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Nov 2014 20:51:18 +0100 Subject: ieee802154: remove mlme get_phy callback This patch removes the get_phy callback from mlme ops structure. Instead we doing a dereference via ieee802154_ptr dev pointer. For backwards compatibility we need to run get_device after dereference wpan_phy via ieee802154_ptr. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/ieee802154_netdev.h | 12 ------------ net/ieee802154/6lowpan_rtnl.c | 8 -------- net/ieee802154/nl-mac.c | 6 ++++-- net/ieee802154/nl-phy.c | 3 ++- net/mac802154/iface.c | 1 - net/mac802154/mac_cmd.c | 14 -------------- 6 files changed, 6 insertions(+), 38 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 5e62d758eea5..83bb8a73d23c 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -423,8 +423,6 @@ struct ieee802154_mlme_ops { /* The fields below are required. */ - struct wpan_phy *(*get_phy)(const struct net_device *dev); - /* * FIXME: these should become the part of PIB/MIB interface. * However we still don't have IB interface of any kind @@ -434,16 +432,6 @@ struct ieee802154_mlme_ops { u8 (*get_dsn)(const struct net_device *dev); }; -/* The IEEE 802.15.4 standard defines 2 type of the devices: - * - FFD - full functionality device - * - RFD - reduce functionality device - * - * So 2 sets of mlme operations are needed - */ -struct ieee802154_reduced_mlme_ops { - struct wpan_phy *(*get_phy)(const struct net_device *dev); -}; - static inline struct ieee802154_mlme_ops * ieee802154_mlme_ops(const struct net_device *dev) { diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 659f7b25ea1a..a96b64c9a73d 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -407,13 +407,6 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) } } -static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) -{ - struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; - - return ieee802154_mlme_ops(real_dev)->get_phy(real_dev); -} - static __le16 lowpan_get_pan_id(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; @@ -465,7 +458,6 @@ static const struct net_device_ops lowpan_netdev_ops = { static struct ieee802154_mlme_ops lowpan_mlme = { .get_pan_id = lowpan_get_pan_id, - .get_phy = lowpan_get_phy, .get_short_addr = lowpan_get_short_addr, .get_dsn = lowpan_get_dsn, }; diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 91a1855e521c..7127b9d1a684 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -94,8 +94,9 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, goto out; ops = ieee802154_mlme_ops(dev); - phy = ops->get_phy(dev); + phy = dev->ieee802154_ptr->wpan_phy; BUG_ON(!phy); + get_device(&phy->dev); short_addr = ops->get_short_addr(dev); pan_id = ops->get_pan_id(dev); @@ -493,7 +494,8 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) !info->attrs[IEEE802154_ATTR_FRAME_RETRIES]) goto out; - phy = ops->get_phy(dev); + phy = dev->ieee802154_ptr->wpan_phy; + get_device(&phy->dev); ops->get_mac_params(dev, ¶ms); diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 397ca126d9a2..80a946dddd90 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -287,8 +287,9 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; - phy = ieee802154_mlme_ops(dev)->get_phy(dev); + phy = dev->ieee802154_ptr->wpan_phy; BUG_ON(!phy); + get_device(&phy->dev); rc = -EINVAL; /* phy name is optional, but should be checked if it's given */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index f9ed608aa260..2e2638e72ae8 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -428,7 +428,6 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, int type) case IEEE802154_DEV_MONITOR: sdata->dev->destructor = free_netdev; sdata->dev->netdev_ops = &mac802154_monitor_ops; - sdata->dev->ml_priv = &mac802154_mlme_reduced; sdata->promisuous_mode = true; break; default: diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index e1ad83e35899..00b2b214770e 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -67,15 +67,6 @@ static int mac802154_mlme_start_req(struct net_device *dev, return rc; } -static struct wpan_phy *mac802154_get_phy(const struct net_device *dev) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - return to_phy(get_device(&sdata->local->phy->dev)); -} - static int mac802154_set_mac_params(struct net_device *dev, const struct ieee802154_mac_params *params) { @@ -134,12 +125,7 @@ static struct ieee802154_llsec_ops mac802154_llsec_ops = { .unlock_table = mac802154_unlock_table, }; -struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced = { - .get_phy = mac802154_get_phy, -}; - struct ieee802154_mlme_ops mac802154_mlme_wpan = { - .get_phy = mac802154_get_phy, .start_req = mac802154_mlme_start_req, .get_pan_id = mac802154_dev_get_pan_id, .get_short_addr = mac802154_dev_get_short_addr, -- cgit v1.2.3-70-g09d2 From 56b2c3eea398c772dd895dc62c18cbdd1ba127b1 Mon Sep 17 00:00:00 2001 From: Martin Townsend Date: Thu, 6 Nov 2014 19:15:13 +0000 Subject: 6lowpan: move skb_free from error paths in decompression Currently we ensure that the skb is freed on every error path in IPHC decompression which makes it easy to introduce skb leaks. By centralising the skb_free into the receive function it makes future decompression routines easier to maintain. It does come at the expense of ensuring that the skb passed into the decompression routine must not be copied. Signed-off-by: Martin Townsend Acked-by: Jukka Rissanen Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 31 ++++++++++++------------------- net/bluetooth/6lowpan.c | 15 +++++++-------- net/ieee802154/6lowpan_rtnl.c | 16 ++++++---------- 3 files changed, 25 insertions(+), 37 deletions(-) (limited to 'net/ieee802154') diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index cd5f8b8e34cd..aced97db62f0 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -319,7 +319,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, if (iphc1 & LOWPAN_IPHC_CID) { pr_debug("CID flag is set, increase header with one\n"); if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context))) - goto drop; + return -EINVAL; } hdr.version = 6; @@ -331,7 +331,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, */ case 0: /* 00b */ if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) - goto drop; + return -EINVAL; memcpy(&hdr.flow_lbl, &skb->data[0], 3); skb_pull(skb, 3); @@ -344,7 +344,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, */ case 2: /* 10b */ if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) - goto drop; + return -EINVAL; hdr.priority = ((tmp >> 2) & 0x0f); hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); @@ -354,7 +354,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, */ case 1: /* 01b */ if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) - goto drop; + return -EINVAL; hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); @@ -371,7 +371,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { /* Next header is carried inline */ if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) - goto drop; + return -EINVAL; pr_debug("NH flag is set, next header carried inline: %02x\n", hdr.nexthdr); @@ -383,7 +383,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, } else { if (lowpan_fetch_skb(skb, &hdr.hop_limit, sizeof(hdr.hop_limit))) - goto drop; + return -EINVAL; } /* Extract SAM to the tmp variable */ @@ -402,7 +402,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, /* Check on error of previous branch */ if (err) - goto drop; + return -EINVAL; /* Extract DAM to the tmp variable */ tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; @@ -417,7 +417,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, tmp); if (err) - goto drop; + return -EINVAL; } } else { err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, @@ -425,7 +425,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, pr_debug("dest: stateless compression mode %d dest %pI6c\n", tmp, &hdr.daddr); if (err) - goto drop; + return -EINVAL; } /* UDP data uncompression */ @@ -434,16 +434,14 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, const int needed = sizeof(struct udphdr) + sizeof(hdr); if (uncompress_udp_header(skb, &uh)) - goto drop; + return -EINVAL; /* replace the compressed UDP head by the uncompressed UDP * header */ err = skb_cow(skb, needed); - if (unlikely(err)) { - kfree_skb(skb); + if (unlikely(err)) return err; - } skb_push(skb, sizeof(struct udphdr)); skb_reset_transport_header(skb); @@ -455,10 +453,8 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, hdr.nexthdr = UIP_PROTO_UDP; } else { err = skb_cow(skb, sizeof(hdr)); - if (unlikely(err)) { - kfree_skb(skb); + if (unlikely(err)) return err; - } } hdr.payload_len = htons(skb->len); @@ -478,9 +474,6 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); return 0; -drop: - kfree_skb(skb); - return -EINVAL; } EXPORT_SYMBOL_GPL(lowpan_header_decompress); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index eef298d17452..dc23c55f1ab6 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -294,20 +294,20 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, peer = __peer_lookup_chan(dev, chan); rcu_read_unlock(); if (!peer) - goto drop; + return -EINVAL; saddr = peer->eui64_addr; daddr = dev->netdev->dev_addr; /* at least two bytes will be used for the encoding */ if (skb->len < 2) - goto drop; + return -EINVAL; if (lowpan_fetch_skb_u8(skb, &iphc0)) - goto drop; + return -EINVAL; if (lowpan_fetch_skb_u8(skb, &iphc1)) - goto drop; + return -EINVAL; return lowpan_header_decompress(skb, netdev, saddr, IEEE802154_ADDR_LONG, @@ -315,9 +315,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, iphc0, iphc1); -drop: - kfree_skb(skb); - return -EINVAL; } static int recv_pkt(struct sk_buff *skb, struct net_device *dev, @@ -370,8 +367,10 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, goto drop; ret = iphc_decompress(local_skb, dev, chan); - if (ret < 0) + if (ret < 0) { + kfree_skb(local_skb); goto drop; + } local_skb->protocol = htons(ETH_P_IPV6); local_skb->pkt_type = PACKET_HOST; diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index a96b64c9a73d..290e14f2e92e 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -176,13 +176,13 @@ iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr) raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len); /* at least two bytes will be used for the encoding */ if (skb->len < 2) - goto drop; + return -EINVAL; if (lowpan_fetch_skb_u8(skb, &iphc0)) - goto drop; + return -EINVAL; if (lowpan_fetch_skb_u8(skb, &iphc1)) - goto drop; + return -EINVAL; ieee802154_addr_to_sa(&sa, &hdr->source); ieee802154_addr_to_sa(&da, &hdr->dest); @@ -200,10 +200,6 @@ iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr) return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type, IEEE802154_ADDR_LEN, dap, da.addr_type, IEEE802154_ADDR_LEN, iphc0, iphc1); - -drop: - kfree_skb(skb); - return -EINVAL; } static struct sk_buff* @@ -522,7 +518,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ ret = iphc_decompress(skb, &hdr); if (ret < 0) - goto drop; + goto drop_skb; return lowpan_give_skb_to_devices(skb, NULL); case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ @@ -530,7 +526,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ret == 1) { ret = iphc_decompress(skb, &hdr); if (ret < 0) - goto drop; + goto drop_skb; return lowpan_give_skb_to_devices(skb, NULL); } else if (ret == -1) { @@ -543,7 +539,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ret == 1) { ret = iphc_decompress(skb, &hdr); if (ret < 0) - goto drop; + goto drop_skb; return lowpan_give_skb_to_devices(skb, NULL); } else if (ret == -1) { -- cgit v1.2.3-70-g09d2 From f601379fa113906b8bf4389a62002def283519c9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:47 +0100 Subject: ieee802154: rename wpan_phy_alloc This patch renames the wpan_phy_alloc function to wpan_phy_new. This naming convention is like wireless and "wiphy_new" function. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 +- net/ieee802154/core.c | 4 ++-- net/mac802154/main.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index ac8dd3b8669d..72c4723a1206 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -88,7 +88,7 @@ struct wpan_dev { #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) struct wpan_phy * -wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size); +wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size); static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) { phy->dev.parent = dev; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index d1cd0edfb149..a3aa23f8c36c 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -70,7 +70,7 @@ int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), EXPORT_SYMBOL(wpan_phy_for_each); struct wpan_phy * -wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size) +wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) { static atomic_t wpan_phy_counter = ATOMIC_INIT(0); struct cfg802154_registered_device *rdev; @@ -105,7 +105,7 @@ wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size) return &rdev->wpan_phy; } -EXPORT_SYMBOL(wpan_phy_alloc); +EXPORT_SYMBOL(wpan_phy_new); int wpan_phy_register(struct wpan_phy *phy) { diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 7d0ff7fd2cd4..234084d26906 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -86,7 +86,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; - phy = wpan_phy_alloc(&mac802154_config_ops, priv_size); + phy = wpan_phy_new(&mac802154_config_ops, priv_size); if (!phy) { pr_err("failure to allocate master IEEE802.15.4 device\n"); return NULL; -- cgit v1.2.3-70-g09d2 From f3ada640c25f2d57beef79b7b98619748be3f3ca Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:48 +0100 Subject: ieee802154: add cfg802154_registered_device list This patch adds a new cfg802154_rdev_list to remember all registered cfg802154_registered_device structs. This is needed to prepare the upcomming nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/core.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- net/ieee802154/core.h | 1 + 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index a3aa23f8c36c..11a1d2ed5b26 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -18,11 +18,16 @@ #include #include +#include #include "ieee802154.h" #include "sysfs.h" #include "core.h" +/* RCU-protected (and RTNL for writers) */ +static LIST_HEAD(cfg802154_rdev_list); +static int cfg802154_rdev_list_generation; + static int wpan_phy_match(struct device *dev, const void *data) { return !strcmp(dev_name(dev), (const char *)data); @@ -109,13 +114,51 @@ EXPORT_SYMBOL(wpan_phy_new); int wpan_phy_register(struct wpan_phy *phy) { - return device_add(&phy->dev); + struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); + int ret; + + rtnl_lock(); + ret = device_add(&phy->dev); + if (ret) { + rtnl_unlock(); + return ret; + } + + list_add_rcu(&rdev->list, &cfg802154_rdev_list); + cfg802154_rdev_list_generation++; + + /* TODO phy registered lock */ + rtnl_unlock(); + + /* TODO nl802154 phy notify */ + + return 0; } EXPORT_SYMBOL(wpan_phy_register); void wpan_phy_unregister(struct wpan_phy *phy) { + struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); + + /* TODO open count */ + + rtnl_lock(); + /* TODO nl802154 phy notify */ + /* TODO phy registered lock */ + + /* TODO WARN_ON wpan_dev_list */ + + /* First remove the hardware from everywhere, this makes + * it impossible to find from userspace. + */ + list_del_rcu(&rdev->list); + synchronize_rcu(); + + cfg802154_rdev_list_generation++; + device_del(&phy->dev); + + rtnl_unlock(); } EXPORT_SYMBOL(wpan_phy_unregister); diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index fea60b3a8846..38887cb2eaf4 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -5,6 +5,7 @@ struct cfg802154_registered_device { const struct cfg802154_ops *ops; + struct list_head list; /* wpan_phy index, internal only */ int wpan_phy_idx; -- cgit v1.2.3-70-g09d2 From fcf39e6e88e9492f6688ec8ba4e1be622b904232 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:50 +0100 Subject: ieee802154: add wpan_dev_list This patch adds a wpan_dev_list list into cfg802154_registered_device struct. Also adding new wpan_dev into this list while cfg802154_netdev_notifier_call. This behaviour is mostly grab from wireless core.c implementation and is needed for preparing nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 6 ++++ net/ieee802154/core.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-- net/ieee802154/core.h | 11 ++++++ 3 files changed, 109 insertions(+), 3 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 7e1bc21423b0..e5570e011116 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -66,6 +66,12 @@ struct wpan_dev { struct wpan_phy *wpan_phy; int iftype; + /* the remainder of this struct should be private to cfg802154 */ + struct list_head list; + struct net_device *netdev; + + u32 identifier; + /* MAC PIB */ __le16 pan_id; __le16 short_addr; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 11a1d2ed5b26..3ee00bf0e514 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -102,12 +102,15 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) mutex_init(&rdev->wpan_phy.pib_lock); + INIT_LIST_HEAD(&rdev->wpan_dev_list); device_initialize(&rdev->wpan_phy.dev); dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx); rdev->wpan_phy.dev.class = &wpan_phy_class; rdev->wpan_phy.dev.platform_data = rdev; + init_waitqueue_head(&rdev->dev_wait); + return &rdev->wpan_phy; } EXPORT_SYMBOL(wpan_phy_new); @@ -140,13 +143,18 @@ void wpan_phy_unregister(struct wpan_phy *phy) { struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); - /* TODO open count */ + wait_event(rdev->dev_wait, ({ + int __count; + rtnl_lock(); + __count = rdev->opencount; + rtnl_unlock(); + __count == 0; })); rtnl_lock(); /* TODO nl802154 phy notify */ /* TODO phy registered lock */ - /* TODO WARN_ON wpan_dev_list */ + WARN_ON(!list_empty(&rdev->wpan_dev_list)); /* First remove the hardware from everywhere, this makes * it impossible to find from userspace. @@ -173,6 +181,79 @@ void cfg802154_dev_free(struct cfg802154_registered_device *rdev) kfree(rdev); } +static void +cfg802154_update_iface_num(struct cfg802154_registered_device *rdev, + int iftype, int num) +{ + ASSERT_RTNL(); + + rdev->num_running_ifaces += num; +} + +static int cfg802154_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + struct cfg802154_registered_device *rdev; + + if (!wpan_dev) + return NOTIFY_DONE; + + rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); + + /* TODO WARN_ON unspec type */ + + switch (state) { + /* TODO NETDEV_DEVTYPE */ + case NETDEV_REGISTER: + wpan_dev->identifier = ++rdev->wpan_dev_id; + list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list); + rdev->devlist_generation++; + + wpan_dev->netdev = dev; + break; + case NETDEV_DOWN: + cfg802154_update_iface_num(rdev, wpan_dev->iftype, -1); + + rdev->opencount--; + wake_up(&rdev->dev_wait); + break; + case NETDEV_UP: + cfg802154_update_iface_num(rdev, wpan_dev->iftype, 1); + + rdev->opencount++; + break; + case NETDEV_UNREGISTER: + /* It is possible to get NETDEV_UNREGISTER + * multiple times. To detect that, check + * that the interface is still on the list + * of registered interfaces, and only then + * remove and clean it up. + */ + if (!list_empty(&wpan_dev->list)) { + list_del_rcu(&wpan_dev->list); + rdev->devlist_generation++; + } + /* synchronize (so that we won't find this netdev + * from other code any more) and then clear the list + * head so that the above code can safely check for + * !list_empty() to avoid double-cleanup. + */ + synchronize_rcu(); + INIT_LIST_HEAD(&wpan_dev->list); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block cfg802154_netdev_notifier = { + .notifier_call = cfg802154_netdev_notifier_call, +}; + static int __init wpan_phy_class_init(void) { int rc; @@ -181,11 +262,18 @@ static int __init wpan_phy_class_init(void) if (rc) goto err; - rc = ieee802154_nl_init(); + rc = register_netdevice_notifier(&cfg802154_netdev_notifier); if (rc) goto err_nl; + rc = ieee802154_nl_init(); + if (rc) + goto err_notifier; + return 0; + +err_notifier: + unregister_netdevice_notifier(&cfg802154_netdev_notifier); err_nl: wpan_phy_sysfs_exit(); err: @@ -196,6 +284,7 @@ subsys_initcall(wpan_phy_class_init); static void __exit wpan_phy_class_exit(void) { ieee802154_nl_exit(); + unregister_netdevice_notifier(&cfg802154_netdev_notifier); wpan_phy_sysfs_exit(); } module_exit(wpan_phy_class_exit); diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index 38887cb2eaf4..e708d9d5878b 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -10,6 +10,17 @@ struct cfg802154_registered_device { /* wpan_phy index, internal only */ int wpan_phy_idx; + /* also protected by devlist_mtx */ + int opencount; + wait_queue_head_t dev_wait; + + /* protected by RTNL only */ + int num_running_ifaces; + + /* associated wpan interfaces, protected by rtnl or RCU */ + struct list_head wpan_dev_list; + int devlist_generation, wpan_dev_id; + /* must be last because of the way we do wpan_phy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ -- cgit v1.2.3-70-g09d2 From a6fd693f6b862cd73fc90849353492406cfba5f6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:51 +0100 Subject: ieee802154: sysfs add wpan_phy index and name This patch adds new sysfs entries for wpan_phy index and name. This needed for the new 802.15.4 userspace tool. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/sysfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'net/ieee802154') diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c index 88199980dae9..1613b9c65dfa 100644 --- a/net/ieee802154/sysfs.c +++ b/net/ieee802154/sysfs.c @@ -27,6 +27,27 @@ dev_to_rdev(struct device *dev) wpan_phy.dev); } +#define SHOW_FMT(name, fmt, member) \ +static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ +} \ +static DEVICE_ATTR_RO(name) + +SHOW_FMT(index, "%d", wpan_phy_idx); + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wpan_phy *wpan_phy = &dev_to_rdev(dev)->wpan_phy; + + return sprintf(buf, "%s\n", dev_name(&wpan_phy->dev)); +} +static DEVICE_ATTR_RO(name); + #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ static ssize_t name ## _show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -78,6 +99,9 @@ static void wpan_phy_release(struct device *dev) } static struct attribute *pmib_attrs[] = { + &dev_attr_index.attr, + &dev_attr_name.attr, + /* below will be removed soon */ &dev_attr_current_channel.attr, &dev_attr_current_page.attr, &dev_attr_channels_supported.attr, -- cgit v1.2.3-70-g09d2 From 79fe1a2aa7b504c68642e510154f17e2de60da60 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:53 +0100 Subject: ieee802154: add nl802154 framework This patch adds a basic nl802154 framework. Most of this code was grabbed from nl80211 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/Makefile | 2 +- net/ieee802154/core.c | 28 +++- net/ieee802154/core.h | 4 + net/ieee802154/ieee802154.h | 2 +- net/ieee802154/netlink.c | 2 +- net/ieee802154/nl802154.c | 309 ++++++++++++++++++++++++++++++++++++++++++++ net/ieee802154/nl802154.h | 7 + 7 files changed, 350 insertions(+), 4 deletions(-) create mode 100644 net/ieee802154/nl802154.c create mode 100644 net/ieee802154/nl802154.h (limited to 'net/ieee802154') diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 38354d4a70cb..9f6970f2a28b 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ - header_ops.o sysfs.o + header_ops.o sysfs.o nl802154.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 3ee00bf0e514..ae5ecbc2ca0a 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -21,11 +21,12 @@ #include #include "ieee802154.h" +#include "nl802154.h" #include "sysfs.h" #include "core.h" /* RCU-protected (and RTNL for writers) */ -static LIST_HEAD(cfg802154_rdev_list); +LIST_HEAD(cfg802154_rdev_list); static int cfg802154_rdev_list_generation; static int wpan_phy_match(struct device *dev, const void *data) @@ -74,6 +75,23 @@ int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), } EXPORT_SYMBOL(wpan_phy_for_each); +struct cfg802154_registered_device * +cfg802154_rdev_by_wpan_phy_idx(int wpan_phy_idx) +{ + struct cfg802154_registered_device *result = NULL, *rdev; + + ASSERT_RTNL(); + + list_for_each_entry(rdev, &cfg802154_rdev_list, list) { + if (rdev->wpan_phy_idx == wpan_phy_idx) { + result = rdev; + break; + } + } + + return result; +} + struct wpan_phy * wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) { @@ -270,8 +288,15 @@ static int __init wpan_phy_class_init(void) if (rc) goto err_notifier; + rc = nl802154_init(); + if (rc) + goto err_ieee802154_nl; + return 0; +err_ieee802154_nl: + ieee802154_nl_exit(); + err_notifier: unregister_netdevice_notifier(&cfg802154_netdev_notifier); err_nl: @@ -283,6 +308,7 @@ subsys_initcall(wpan_phy_class_init); static void __exit wpan_phy_class_exit(void) { + nl802154_exit(); ieee802154_nl_exit(); unregister_netdevice_notifier(&cfg802154_netdev_notifier); wpan_phy_sysfs_exit(); diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index e708d9d5878b..c8319bf1b61a 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -35,7 +35,11 @@ wpan_phy_to_rdev(struct wpan_phy *wpan_phy) wpan_phy); } +extern struct list_head cfg802154_rdev_list; + /* free object */ void cfg802154_dev_free(struct cfg802154_registered_device *rdev); +struct cfg802154_registered_device * +cfg802154_rdev_by_wpan_phy_idx(int wpan_phy_idx); #endif /* __IEEE802154_CORE_H */ diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 42ae63a345ab..a5d7515b7f62 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -15,7 +15,7 @@ #define IEEE_802154_LOCAL_H int __init ieee802154_nl_init(void); -void __exit ieee802154_nl_exit(void); +void ieee802154_nl_exit(void); #define IEEE802154_OP(_cmd, _func) \ { \ diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 6c3c2595a201..63ee7d66950e 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -155,7 +155,7 @@ int __init ieee802154_nl_init(void) ieee802154_mcgrps); } -void __exit ieee802154_nl_exit(void) +void ieee802154_nl_exit(void) { genl_unregister_family(&nl802154_family); } diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c new file mode 100644 index 000000000000..5dec0bb5bb55 --- /dev/null +++ b/net/ieee802154/nl802154.c @@ -0,0 +1,309 @@ +/* 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Authors: + * Alexander Aring + * + * Based on: net/wireless/nl80211.c + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "nl802154.h" +#include "core.h" + +static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + +static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + +/* the netlink family */ +static struct genl_family nl802154_fam = { + .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ + .name = NL802154_GENL_NAME, /* have users key off the name instead */ + .hdrsize = 0, /* no private header */ + .version = 1, /* no particular meaning now */ + .maxattr = NL802154_ATTR_MAX, + .netnsok = true, + .pre_doit = nl802154_pre_doit, + .post_doit = nl802154_post_doit, +}; + +/* multicast groups */ +enum nl802154_multicast_groups { + NL802154_MCGRP_CONFIG, +}; + +static const struct genl_multicast_group nl802154_mcgrps[] = { + [NL802154_MCGRP_CONFIG] = { .name = "config", }, +}; + +/* returns ERR_PTR values */ +static struct wpan_dev * +__cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs) +{ + struct cfg802154_registered_device *rdev; + struct wpan_dev *result = NULL; + bool have_ifidx = attrs[NL802154_ATTR_IFINDEX]; + bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV]; + u64 wpan_dev_id; + int wpan_phy_idx = -1; + int ifidx = -1; + + ASSERT_RTNL(); + + if (!have_ifidx && !have_wpan_dev_id) + return ERR_PTR(-EINVAL); + + if (have_ifidx) + ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]); + if (have_wpan_dev_id) { + wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]); + wpan_phy_idx = wpan_dev_id >> 32; + } + + list_for_each_entry(rdev, &cfg802154_rdev_list, list) { + struct wpan_dev *wpan_dev; + + /* TODO netns compare */ + + if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx) + continue; + + list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { + if (have_ifidx && wpan_dev->netdev && + wpan_dev->netdev->ifindex == ifidx) { + result = wpan_dev; + break; + } + if (have_wpan_dev_id && + wpan_dev->identifier == (u32)wpan_dev_id) { + result = wpan_dev; + break; + } + } + + if (result) + break; + } + + if (result) + return result; + + return ERR_PTR(-ENODEV); +} + +static struct cfg802154_registered_device * +__cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs) +{ + struct cfg802154_registered_device *rdev = NULL, *tmp; + struct net_device *netdev; + + ASSERT_RTNL(); + + if (!attrs[NL802154_ATTR_WPAN_PHY] && + !attrs[NL802154_ATTR_IFINDEX] && + !attrs[NL802154_ATTR_WPAN_DEV]) + return ERR_PTR(-EINVAL); + + if (attrs[NL802154_ATTR_WPAN_PHY]) + rdev = cfg802154_rdev_by_wpan_phy_idx( + nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY])); + + if (attrs[NL802154_ATTR_WPAN_DEV]) { + u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]); + struct wpan_dev *wpan_dev; + bool found = false; + + tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32); + if (tmp) { + /* make sure wpan_dev exists */ + list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) { + if (wpan_dev->identifier != (u32)wpan_dev_id) + continue; + found = true; + break; + } + + if (!found) + tmp = NULL; + + if (rdev && tmp != rdev) + return ERR_PTR(-EINVAL); + rdev = tmp; + } + } + + if (attrs[NL802154_ATTR_IFINDEX]) { + int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]); + + netdev = __dev_get_by_index(netns, ifindex); + if (netdev) { + if (netdev->ieee802154_ptr) + tmp = wpan_phy_to_rdev( + netdev->ieee802154_ptr->wpan_phy); + else + tmp = NULL; + + /* not wireless device -- return error */ + if (!tmp) + return ERR_PTR(-EINVAL); + + /* mismatch -- return error */ + if (rdev && tmp != rdev) + return ERR_PTR(-EINVAL); + + rdev = tmp; + } + } + + if (!rdev) + return ERR_PTR(-ENODEV); + + /* TODO netns compare */ + + return rdev; +} + +/* This function returns a pointer to the driver + * that the genl_info item that is passed refers to. + * + * The result of this can be a PTR_ERR and hence must + * be checked with IS_ERR() for errors. + */ +static struct cfg802154_registered_device * +cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info) +{ + return __cfg802154_rdev_from_attrs(netns, info->attrs); +} + +/* policy for the attributes */ +static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { +}; + +/* message building helper */ +static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, + int flags, u8 cmd) +{ + /* since there is no private header just add the generic one */ + return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd); +} + +#define NL802154_FLAG_NEED_WPAN_PHY 0x01 +#define NL802154_FLAG_NEED_NETDEV 0x02 +#define NL802154_FLAG_NEED_RTNL 0x04 +#define NL802154_FLAG_CHECK_NETDEV_UP 0x08 +#define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\ + NL802154_FLAG_CHECK_NETDEV_UP) +#define NL802154_FLAG_NEED_WPAN_DEV 0x10 +#define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\ + NL802154_FLAG_CHECK_NETDEV_UP) + +static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg802154_registered_device *rdev; + struct wpan_dev *wpan_dev; + struct net_device *dev; + bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL; + + if (rtnl) + rtnl_lock(); + + if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) { + rdev = cfg802154_get_dev_from_info(genl_info_net(info), info); + if (IS_ERR(rdev)) { + if (rtnl) + rtnl_unlock(); + return PTR_ERR(rdev); + } + info->user_ptr[0] = rdev; + } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV || + ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { + ASSERT_RTNL(); + wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info), + info->attrs); + if (IS_ERR(wpan_dev)) { + if (rtnl) + rtnl_unlock(); + return PTR_ERR(wpan_dev); + } + + dev = wpan_dev->netdev; + rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); + + if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) { + if (!dev) { + if (rtnl) + rtnl_unlock(); + return -EINVAL; + } + + info->user_ptr[1] = dev; + } else { + info->user_ptr[1] = wpan_dev; + } + + if (dev) { + if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } + + dev_hold(dev); + } + + info->user_ptr[0] = rdev; + } + + return 0; +} + +static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + if (info->user_ptr[1]) { + if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { + struct wpan_dev *wpan_dev = info->user_ptr[1]; + + if (wpan_dev->netdev) + dev_put(wpan_dev->netdev); + } else { + dev_put(info->user_ptr[1]); + } + } + + if (ops->internal_flags & NL802154_FLAG_NEED_RTNL) + rtnl_unlock(); +} + +static const struct genl_ops nl802154_ops[] = { +}; + +/* initialisation/exit functions */ +int nl802154_init(void) +{ + return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops, + nl802154_mcgrps); +} + +void nl802154_exit(void) +{ + genl_unregister_family(&nl802154_fam); +} diff --git a/net/ieee802154/nl802154.h b/net/ieee802154/nl802154.h new file mode 100644 index 000000000000..3846a89d0958 --- /dev/null +++ b/net/ieee802154/nl802154.h @@ -0,0 +1,7 @@ +#ifndef __IEEE802154_NL802154_H +#define __IEEE802154_NL802154_H + +int nl802154_init(void); +void nl802154_exit(void); + +#endif /* __IEEE802154_NL802154_H */ -- cgit v1.2.3-70-g09d2 From ca20ce201c8d4123de0fd2b0d59ea19b0160d88f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:54 +0100 Subject: ieee802154: add wpan_phy dump support This patch adds support for dumping wpan_phy attributes via nl802154. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/core.c | 2 +- net/ieee802154/core.h | 1 + net/ieee802154/nl802154.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index ae5ecbc2ca0a..18bc7e738507 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -27,7 +27,7 @@ /* RCU-protected (and RTNL for writers) */ LIST_HEAD(cfg802154_rdev_list); -static int cfg802154_rdev_list_generation; +int cfg802154_rdev_list_generation; static int wpan_phy_match(struct device *dev, const void *data) { diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index c8319bf1b61a..f3e95580caee 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h @@ -36,6 +36,7 @@ wpan_phy_to_rdev(struct wpan_phy *wpan_phy) } extern struct list_head cfg802154_rdev_list; +extern int cfg802154_rdev_list_generation; /* free object */ void cfg802154_dev_free(struct cfg802154_registered_device *rdev); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 5dec0bb5bb55..32e884732eb1 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -193,6 +193,22 @@ cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info) /* policy for the attributes */ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { + [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 }, + [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING, + .len = 20-1 }, + + [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 }, + + [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 }, + + [NL802154_ATTR_PAGE] = { .type = NLA_U8, }, + [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, }, + + [NL802154_ATTR_TX_POWER] = { .type = NLA_S8, }, + + [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, + + [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, }; /* message building helper */ @@ -203,6 +219,201 @@ static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd); } +static int +nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, + struct sk_buff *msg) +{ + struct nlattr *nl_page; + unsigned long page; + + nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED); + if (!nl_page) + return -ENOBUFS; + + for (page = 0; page < WPAN_NUM_PAGES; page++) { + if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL, + rdev->wpan_phy.channels_supported[page])) + return -ENOBUFS; + } + nla_nest_end(msg, nl_page); + + return 0; +} + +static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, + enum nl802154_commands cmd, + struct sk_buff *msg, u32 portid, u32 seq, + int flags) +{ + void *hdr; + + hdr = nl802154hdr_put(msg, portid, seq, flags, cmd); + if (!hdr) + return -ENOBUFS; + + if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || + nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME, + wpan_phy_name(&rdev->wpan_phy)) || + nla_put_u32(msg, NL802154_ATTR_GENERATION, + cfg802154_rdev_list_generation)) + goto nla_put_failure; + + if (cmd != NL802154_CMD_NEW_WPAN_PHY) + goto finish; + + /* DUMP PHY PIB */ + + /* current channel settings */ + if (nla_put_u8(msg, NL802154_ATTR_PAGE, + rdev->wpan_phy.current_page) || + nla_put_u8(msg, NL802154_ATTR_CHANNEL, + rdev->wpan_phy.current_channel)) + goto nla_put_failure; + + /* supported channels array */ + if (nl802154_send_wpan_phy_channels(rdev, msg)) + goto nla_put_failure; + + /* cca mode */ + if (nla_put_u8(msg, NL802154_ATTR_CCA_MODE, + rdev->wpan_phy.cca_mode)) + goto nla_put_failure; + + if (nla_put_s8(msg, NL802154_ATTR_TX_POWER, + rdev->wpan_phy.transmit_power)) + goto nla_put_failure; + +finish: + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +struct nl802154_dump_wpan_phy_state { + s64 filter_wpan_phy; + long start; + +}; + +static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb, + struct netlink_callback *cb, + struct nl802154_dump_wpan_phy_state *state) +{ + struct nlattr **tb = nl802154_fam.attrbuf; + int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize, + tb, nl802154_fam.maxattr, nl802154_policy); + + /* TODO check if we can handle error here, + * we have no backward compatibility + */ + if (ret) + return 0; + + if (tb[NL802154_ATTR_WPAN_PHY]) + state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]); + if (tb[NL802154_ATTR_WPAN_DEV]) + state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32; + if (tb[NL802154_ATTR_IFINDEX]) { + struct net_device *netdev; + struct cfg802154_registered_device *rdev; + int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]); + + /* TODO netns */ + netdev = __dev_get_by_index(&init_net, ifidx); + if (!netdev) + return -ENODEV; + if (netdev->ieee802154_ptr) { + rdev = wpan_phy_to_rdev( + netdev->ieee802154_ptr->wpan_phy); + state->filter_wpan_phy = rdev->wpan_phy_idx; + } + } + + return 0; +} + +static int +nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb) +{ + int idx = 0, ret; + struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0]; + struct cfg802154_registered_device *rdev; + + rtnl_lock(); + if (!state) { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { + rtnl_unlock(); + return -ENOMEM; + } + state->filter_wpan_phy = -1; + ret = nl802154_dump_wpan_phy_parse(skb, cb, state); + if (ret) { + kfree(state); + rtnl_unlock(); + return ret; + } + cb->args[0] = (long)state; + } + + list_for_each_entry(rdev, &cfg802154_rdev_list, list) { + /* TODO net ns compare */ + if (++idx <= state->start) + continue; + if (state->filter_wpan_phy != -1 && + state->filter_wpan_phy != rdev->wpan_phy_idx) + continue; + /* attempt to fit multiple wpan_phy data chunks into the skb */ + ret = nl802154_send_wpan_phy(rdev, + NL802154_CMD_NEW_WPAN_PHY, + skb, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI); + if (ret < 0) { + if ((ret == -ENOBUFS || ret == -EMSGSIZE) && + !skb->len && cb->min_dump_alloc < 4096) { + cb->min_dump_alloc = 4096; + rtnl_unlock(); + return 1; + } + idx--; + break; + } + break; + } + rtnl_unlock(); + + state->start = idx; + + return skb->len; +} + +static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb) +{ + kfree((void *)cb->args[0]); + return 0; +} + +static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg, + info->snd_portid, info->snd_seq, 0) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -294,6 +505,16 @@ static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, } static const struct genl_ops nl802154_ops[] = { + { + .cmd = NL802154_CMD_GET_WPAN_PHY, + .doit = nl802154_get_wpan_phy, + .dumpit = nl802154_dump_wpan_phy, + .done = nl802154_dump_wpan_phy_done, + .policy = nl802154_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ -- cgit v1.2.3-70-g09d2 From 4b96aea0fcdbba18287f6cca87c8d796f33157b6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:55 +0100 Subject: ieee802154: add wpan_dev dump support This patch adds support for wpan_dev dump via nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl802154.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) (limited to 'net/ieee802154') diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 32e884732eb1..46df7dca92d9 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -198,6 +198,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { .len = 20-1 }, [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 }, + [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 }, + [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 }, @@ -209,6 +211,18 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, + + [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, }, + [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, + [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, + + [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, }, + [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, }, + [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, }, + + [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, }, + + [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, }, }; /* message building helper */ @@ -414,6 +428,128 @@ static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev) +{ + return (u64)wpan_dev->identifier | + ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32); +} + +static int +nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, + struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev) +{ + struct net_device *dev = wpan_dev->netdev; + void *hdr; + + hdr = nl802154hdr_put(msg, portid, seq, flags, + NL802154_CMD_NEW_INTERFACE); + if (!hdr) + return -1; + + if (dev && + (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) || + nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name))) + goto nla_put_failure; + + if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || + nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) || + nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) || + nla_put_u32(msg, NL802154_ATTR_GENERATION, + rdev->devlist_generation ^ + (cfg802154_rdev_list_generation << 2))) + goto nla_put_failure; + + /* address settings */ + if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR, + wpan_dev->extended_addr) || + nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR, + wpan_dev->short_addr) || + nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id)) + goto nla_put_failure; + + /* ARET handling */ + if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES, + wpan_dev->frame_retries) || + nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) || + nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS, + wpan_dev->csma_retries) || + nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be)) + goto nla_put_failure; + + /* listen before transmit */ + if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt)) + goto nla_put_failure; + + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct cfg802154_registered_device *rdev; + struct wpan_dev *wpan_dev; + + rtnl_lock(); + list_for_each_entry(rdev, &cfg802154_rdev_list, list) { + /* TODO netns compare */ + if (wp_idx < wp_start) { + wp_idx++; + continue; + } + if_idx = 0; + + list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { + if (if_idx < if_start) { + if_idx++; + continue; + } + if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + rdev, wpan_dev) < 0) { + goto out; + } + if_idx++; + } + + wp_idx++; + } +out: + rtnl_unlock(); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + + return skb->len; +} + +static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct wpan_dev *wdev = info->user_ptr[1]; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0, + rdev, wdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -515,6 +651,15 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_GET_INTERFACE, + .doit = nl802154_get_interface, + .dumpit = nl802154_dump_interface, + .policy = nl802154_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ -- cgit v1.2.3-70-g09d2 From 7bea1ea7b4c16af7c9263648e10f7edc88e5fc21 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:57 +0100 Subject: ieee802154: netlink add rtnl lock This patch adds rtnl lock hold mechanism while accessing wpan_dev attributes. Furthermore these attributes should be protected by rtnl lock and netif_running only. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl-mac.c | 6 ++++++ net/mac802154/mac_cmd.c | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 7127b9d1a684..50e9863823a5 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -113,7 +113,9 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, if (ops->get_mac_params) { struct ieee802154_mac_params params; + rtnl_lock(); ops->get_mac_params(dev, ¶ms); + rtnl_unlock(); if (nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, params.transmit_power) || @@ -348,8 +350,10 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + rtnl_lock(); ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, bcn_ord, sf_ord, pan_coord, blx, coord_realign); + rtnl_unlock(); /* FIXME: add validation for unused parameters to be sane * for SoftMAC @@ -497,6 +501,7 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) phy = dev->ieee802154_ptr->wpan_phy; get_device(&phy->dev); + rtnl_lock(); ops->get_mac_params(dev, ¶ms); if (info->attrs[IEEE802154_ATTR_TXPOWER]) @@ -524,6 +529,7 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) params.frame_retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]); rc = ops->set_mac_params(dev, ¶ms); + rtnl_unlock(); wpan_phy_put(phy); dev_put(dev); diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index b8bd95263aab..6aacb1816889 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -39,6 +39,8 @@ static int mac802154_mlme_start_req(struct net_device *dev, struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); int rc = 0; + ASSERT_RTNL(); + BUG_ON(addr->mode != IEEE802154_ADDR_SHORT); mac802154_dev_set_pan_id(dev, addr->pan_id); @@ -75,7 +77,8 @@ static int mac802154_set_mac_params(struct net_device *dev, struct wpan_dev *wpan_dev = &sdata->wpan_dev; int ret; - mutex_lock(&sdata->local->iflist_mtx); + ASSERT_RTNL(); + /* PHY */ wpan_dev->wpan_phy->transmit_power = params->transmit_power; wpan_dev->wpan_phy->cca_mode = params->cca_mode; @@ -87,7 +90,6 @@ static int mac802154_set_mac_params(struct net_device *dev, wpan_dev->csma_retries = params->csma_retries; wpan_dev->frame_retries = params->frame_retries; wpan_dev->lbt = params->lbt; - mutex_unlock(&sdata->local->iflist_mtx); if (local->hw.flags & IEEE802154_HW_TXPOWER) { ret = drv_set_tx_power(local, params->transmit_power); @@ -116,7 +118,8 @@ static void mac802154_get_mac_params(struct net_device *dev, struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); struct wpan_dev *wpan_dev = &sdata->wpan_dev; - mutex_lock(&sdata->local->iflist_mtx); + ASSERT_RTNL(); + /* PHY */ params->transmit_power = wpan_dev->wpan_phy->transmit_power; params->cca_mode = wpan_dev->wpan_phy->cca_mode; @@ -128,7 +131,6 @@ static void mac802154_get_mac_params(struct net_device *dev, params->csma_retries = wpan_dev->csma_retries; params->frame_retries = wpan_dev->frame_retries; params->lbt = wpan_dev->lbt; - mutex_unlock(&sdata->local->iflist_mtx); } static struct ieee802154_llsec_ops mac802154_llsec_ops = { -- cgit v1.2.3-70-g09d2 From 87023e1058c9ead2314c27761991816b48f949ef Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Nov 2014 08:36:58 +0100 Subject: ieee802154: fix iface dump with lowpan This patch adds a hacked solution for an interface dump with a running lowpan interface. This will crash because lowpan and wpan interface use the same arphdr. To change the arphdr will change the UAPI, this patch checks on mtu which should on lowpan interface always different than IEEE802154_MTU. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl-mac.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 50e9863823a5..fe77f0c770b8 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -166,7 +166,10 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) if (!dev) return NULL; - if (dev->type != ARPHRD_IEEE802154) { + /* Check on mtu is currently a hacked solution because lowpan + * and wpan have the same ARPHRD type. + */ + if (dev->type != ARPHRD_IEEE802154 || dev->mtu != IEEE802154_MTU) { dev_put(dev); return NULL; } @@ -448,7 +451,11 @@ int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) idx = 0; for_each_netdev(net, dev) { - if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) + /* Check on mtu is currently a hacked solution because lowpan + * and wpan have the same ARPHRD type. + */ + if (idx < s_idx || dev->type != ARPHRD_IEEE802154 || + dev->mtu != IEEE802154_MTU) goto cont; if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid, @@ -782,7 +789,11 @@ ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb, int rc; for_each_netdev(net, dev) { - if (idx < first_dev || dev->type != ARPHRD_IEEE802154) + /* Check on mtu is currently a hacked solution because lowpan + * and wpan have the same ARPHRD type. + */ + if (idx < first_dev || dev->type != ARPHRD_IEEE802154 || + dev->mtu != IEEE802154_MTU) goto skip; data.ops = ieee802154_mlme_ops(dev); -- cgit v1.2.3-70-g09d2 From ab0bd561724bf3c09aa80e76ca0a187c6880bc5c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:36:55 +0100 Subject: ieee820154: add channel set support This patch adds page and channel setting support to nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 1 + net/ieee802154/nl802154.c | 28 ++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 24 ++++++++++++++++++++++++ 4 files changed, 60 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 8a3edc5edad1..391fdb37208d 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -37,6 +37,7 @@ struct cfg802154_ops { int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); + int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 46df7dca92d9..d8ef2c8a182f 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -23,6 +23,7 @@ #include #include "nl802154.h" +#include "rdev-ops.h" #include "core.h" static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, @@ -550,6 +551,25 @@ static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + u8 channel, page; + + if (!info->attrs[NL802154_ATTR_PAGE] || + !info->attrs[NL802154_ATTR_CHANNEL]) + return -EINVAL; + + page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]); + channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]); + + /* check 802.15.4 constraints */ + if (page >= WPAN_NUM_PAGES || channel >= WPAN_NUM_CHANNELS) + return -EINVAL; + + return rdev_set_channel(rdev, page, channel); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -660,6 +680,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_CHANNEL, + .doit = nl802154_set_channel, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index ac8824ec168c..8a3b0eb4e026 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -20,4 +20,11 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev); } +static inline int +rdev_set_channel(struct cfg802154_registered_device *rdev, const u8 page, + const u8 channel) +{ + return rdev->ops->set_channel(&rdev->wpan_phy, page, channel); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index d2c4e8f89720..9d5b1895c752 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -17,6 +17,7 @@ #include #include "ieee802154_i.h" +#include "driver-ops.h" #include "cfg.h" static struct net_device * @@ -41,7 +42,30 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, ieee802154_if_remove(sdata); } +static int +ieee802154_set_channel(struct wpan_phy *wpan_phy, const u8 page, + const u8 channel) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + int ret; + + ASSERT_RTNL(); + + /* check if phy support this setting */ + if (!(wpan_phy->channels_supported[page] & BIT(channel))) + return -EINVAL; + + ret = drv_set_channel(local, page, channel); + if (!ret) { + wpan_phy->current_page = page; + wpan_phy->current_channel = channel; + } + + return ret; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, + .set_channel = ieee802154_set_channel, }; -- cgit v1.2.3-70-g09d2 From 702bf371282f5912fe53f0b247fa2d7df9d7951f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:36:57 +0100 Subject: ieee820154: add pan_id setting support This patch adds support for setting pan_id via nl802154 framework. Adding a comment because setting 0xffff as pan_id seems to be valid setting. The pan_id 0xffff as source pan is invalid. I am not sure now about this setting but for the current netlink interface this is an invalid setting, so we do the same now. Maybe we need to change that when we have coordinator support and association support. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 2 ++ include/net/cfg802154.h | 2 ++ net/ieee802154/nl802154.c | 31 +++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 20 ++++++++++++++++++++ 5 files changed, 62 insertions(+) (limited to 'net/ieee802154') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index d043449a079d..d40379876b84 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -30,6 +30,8 @@ #define IEEE802154_MTU 127 #define IEEE802154_MIN_PSDU_LEN 5 +#define IEEE802154_PAN_ID_BROADCAST 0xffff + #define IEEE802154_EXTENDED_ADDR_LEN 8 #define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 391fdb37208d..d07b0726b285 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -38,6 +38,8 @@ struct cfg802154_ops { void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); + int (*set_pan_id)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, u16 pan_id); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index d8ef2c8a182f..88cd1293283a 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -570,6 +570,29 @@ static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) return rdev_set_channel(rdev, page, channel); } +static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + u16 pan_id; + + /* conflict here while tx/rx calls */ + if (netif_running(dev)) + return -EBUSY; + + /* don't change address fields on monitor */ + if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) + return -EINVAL; + + if (!info->attrs[NL802154_ATTR_PAN_ID]) + return -EINVAL; + + pan_id = nla_get_u16(info->attrs[NL802154_ATTR_PAN_ID]); + + return rdev_set_pan_id(rdev, wpan_dev, pan_id); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -688,6 +711,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_PAN_ID, + .doit = nl802154_set_pan_id, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 8a3b0eb4e026..4115ea264fd5 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -27,4 +27,11 @@ rdev_set_channel(struct cfg802154_registered_device *rdev, const u8 page, return rdev->ops->set_channel(&rdev->wpan_phy, page, channel); } +static inline int +rdev_set_pan_id(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, u16 pan_id) +{ + return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 9d5b1895c752..db6e5e981a83 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -64,8 +64,28 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, const u8 page, return ret; } +static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, const u16 pan_id) +{ + ASSERT_RTNL(); + + /* TODO + * I am not sure about to check here on broadcast pan_id. + * Broadcast is a valid setting, comment from 802.15.4: + * If this value is 0xffff, the device is not associated. + * + * This could useful to simple deassociate an device. + */ + if (pan_id == IEEE802154_PAN_ID_BROADCAST) + return -EINVAL; + + wpan_dev->pan_id = cpu_to_le16(pan_id); + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, .set_channel = ieee802154_set_channel, + .set_pan_id = ieee802154_set_pan_id, }; -- cgit v1.2.3-70-g09d2 From 9830c62a0b3d57d9d00880989cfe987f581bc03f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:36:58 +0100 Subject: ieee820154: add short_addr setting support This patch adds support for setting short address via nl802154 framework. Also added a comment because a 0xffff seems to be valid address that we don't have a short address. This is a valid setting but we need more checks in upper layers to don't allow this address as source address. Also the current netlink interface doesn't allow to set the short_addr to 0xffff. Same for the 0xfffe short address which describes a not allocated short address. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 2 ++ include/net/cfg802154.h | 2 ++ net/ieee802154/nl802154.c | 31 +++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 26 ++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) (limited to 'net/ieee802154') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index d40379876b84..ce0f96a55976 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -31,6 +31,8 @@ #define IEEE802154_MIN_PSDU_LEN 5 #define IEEE802154_PAN_ID_BROADCAST 0xffff +#define IEEE802154_ADDR_SHORT_BROADCAST 0xffff +#define IEEE802154_ADDR_SHORT_UNSPEC 0xfffe #define IEEE802154_EXTENDED_ADDR_LEN 8 diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index d07b0726b285..e8a4c2b70720 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -40,6 +40,8 @@ struct cfg802154_ops { int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u16 pan_id); + int (*set_short_addr)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, u16 short_addr); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 88cd1293283a..2978c1a78017 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -593,6 +593,29 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) return rdev_set_pan_id(rdev, wpan_dev, pan_id); } +static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + u16 short_addr; + + /* conflict here while tx/rx calls */ + if (netif_running(dev)) + return -EBUSY; + + /* don't change address fields on monitor */ + if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) + return -EINVAL; + + if (!info->attrs[NL802154_ATTR_SHORT_ADDR]) + return -EINVAL; + + short_addr = nla_get_u16(info->attrs[NL802154_ATTR_SHORT_ADDR]); + + return rdev_set_short_addr(rdev, wpan_dev, short_addr); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -719,6 +742,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_SHORT_ADDR, + .doit = nl802154_set_short_addr, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 4115ea264fd5..16b0de06c3af 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -34,4 +34,11 @@ rdev_set_pan_id(struct cfg802154_registered_device *rdev, return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); } +static inline int +rdev_set_short_addr(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, u16 short_addr) +{ + return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index db6e5e981a83..df29976d1321 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -83,9 +83,35 @@ static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, return 0; } +static int +ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + const u16 short_addr) +{ + ASSERT_RTNL(); + + /* TODO + * I am not sure about to check here on broadcast short_addr. + * Broadcast is a valid setting, comment from 802.15.4: + * A value of 0xfffe indicates that the device has + * associated but has not been allocated an address. A + * value of 0xffff indicates that the device does not + * have a short address. + * + * I think we should allow to set these settings but + * don't allow to allow socket communication with it. + */ + if (short_addr == IEEE802154_ADDR_SHORT_UNSPEC || + short_addr == IEEE802154_ADDR_SHORT_BROADCAST) + return -EINVAL; + + wpan_dev->short_addr = cpu_to_le16(short_addr); + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, .set_channel = ieee802154_set_channel, .set_pan_id = ieee802154_set_pan_id, + .set_short_addr = ieee802154_set_short_addr, }; -- cgit v1.2.3-70-g09d2 From 656a999e8701c1e3d17040f051d3a080ec6c710c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:36:59 +0100 Subject: ieee820154: add backoff exponent setting support This patch adds support for setting backoff exponents via nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 3 +++ net/ieee802154/nl802154.c | 34 ++++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 9 +++++++++ net/mac802154/cfg.c | 18 ++++++++++++++++++ 4 files changed, 64 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index e8a4c2b70720..27e98d10fb2c 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -42,6 +42,9 @@ struct cfg802154_ops { struct wpan_dev *wpan_dev, u16 pan_id); int (*set_short_addr)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u16 short_addr); + int (*set_backoff_exponent)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, u8 min_be, + u8 max_be); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 2978c1a78017..d1cf3021ff36 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -616,6 +616,32 @@ static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) return rdev_set_short_addr(rdev, wpan_dev, short_addr); } +static int +nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + u8 min_be, max_be; + + /* should be set on netif open inside phy settings */ + if (netif_running(dev)) + return -EBUSY; + + if (!info->attrs[NL802154_ATTR_MIN_BE] || + !info->attrs[NL802154_ATTR_MAX_BE]) + return -EINVAL; + + min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]); + max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]); + + /* check 802.15.4 constraints */ + if (max_be < 3 || max_be > 8 || min_be > max_be) + return -EINVAL; + + return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -750,6 +776,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT, + .doit = nl802154_set_backoff_exponent, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 16b0de06c3af..dbccfa9383fd 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -41,4 +41,13 @@ rdev_set_short_addr(struct cfg802154_registered_device *rdev, return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); } +static inline int +rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, const u8 min_be, + const u8 max_be) +{ + return rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, + min_be, max_be); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index df29976d1321..67c96f981693 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -83,6 +83,23 @@ static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, return 0; } +static int +ieee802154_set_backoff_exponent(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + const u8 min_be, const u8 max_be) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + + ASSERT_RTNL(); + + if (!(local->hw.flags & IEEE802154_HW_CSMA_PARAMS)) + return -EOPNOTSUPP; + + wpan_dev->min_be = min_be; + wpan_dev->max_be = max_be; + return 0; +} + static int ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, const u16 short_addr) @@ -114,4 +131,5 @@ const struct cfg802154_ops mac802154_config_ops = { .set_channel = ieee802154_set_channel, .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, + .set_backoff_exponent = ieee802154_set_backoff_exponent, }; -- cgit v1.2.3-70-g09d2 From a01ba7652cda5602b248efff168450ec658640b8 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:37:01 +0100 Subject: ieee820154: add max csma backoffs setting support This patch add support for max csma backoffs setting via nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 3 +++ net/ieee802154/nl802154.c | 33 +++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 9 +++++++++ net/mac802154/cfg.c | 16 ++++++++++++++++ 4 files changed, 61 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 27e98d10fb2c..79b9ae0abb3b 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -45,6 +45,9 @@ struct cfg802154_ops { int (*set_backoff_exponent)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u8 min_be, u8 max_be); + int (*set_max_csma_backoffs)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + u8 max_csma_backoffs); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index d1cf3021ff36..af383553bdd2 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -642,6 +642,31 @@ nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info) return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be); } +static int +nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + u8 max_csma_backoffs; + + /* conflict here while other running iface settings */ + if (netif_running(dev)) + return -EBUSY; + + if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]) + return -EINVAL; + + max_csma_backoffs = nla_get_u8( + info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]); + + /* check 802.15.4 constraints */ + if (max_csma_backoffs > 5) + return -EINVAL; + + return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -784,6 +809,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS, + .doit = nl802154_set_max_csma_backoffs, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index dbccfa9383fd..263095c8686c 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -50,4 +50,13 @@ rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, min_be, max_be); } +static inline int +rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, + const u8 max_csma_backoffs) +{ + return rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, + max_csma_backoffs); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 67c96f981693..d72feebb939d 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -125,6 +125,21 @@ ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, return 0; } +static int ieee802154_set_max_csma_backoffs(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + const u8 max_csma_backoffs) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + + ASSERT_RTNL(); + + if (!(local->hw.flags & IEEE802154_HW_CSMA_PARAMS)) + return -EOPNOTSUPP; + + wpan_dev->csma_retries = max_csma_backoffs; + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, @@ -132,4 +147,5 @@ const struct cfg802154_ops mac802154_config_ops = { .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, .set_backoff_exponent = ieee802154_set_backoff_exponent, + .set_max_csma_backoffs = ieee802154_set_max_csma_backoffs, }; -- cgit v1.2.3-70-g09d2 From 17a3a46bfbf1c2b944812a81b11ffe255a55e9ca Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:37:03 +0100 Subject: ieee820154: add max frame retries setting support This patch add support for setting mac frame retries setting via nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 3 +++ net/ieee802154/nl802154.c | 32 ++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 9 +++++++++ net/mac802154/cfg.c | 16 ++++++++++++++++ 4 files changed, 60 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 79b9ae0abb3b..5c3bc12706c2 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -48,6 +48,9 @@ struct cfg802154_ops { int (*set_max_csma_backoffs)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u8 max_csma_backoffs); + int (*set_max_frame_retries)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + s8 max_frame_retries); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index af383553bdd2..0e272c67c49b 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -667,6 +667,30 @@ nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info) return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs); } +static int +nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + s8 max_frame_retries; + + if (netif_running(dev)) + return -EBUSY; + + if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]) + return -EINVAL; + + max_frame_retries = nla_get_s8( + info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]); + + /* check 802.15.4 constraints */ + if (max_frame_retries < -1 || max_frame_retries > 7) + return -EINVAL; + + return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -817,6 +841,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES, + .doit = nl802154_set_max_frame_retries, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 263095c8686c..f9171aaf985e 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -59,4 +59,13 @@ rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, max_csma_backoffs); } +static inline int +rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, + const s8 max_frame_retries) +{ + return rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, + max_frame_retries); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index d72feebb939d..a8f6eaa76d4d 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -140,6 +140,21 @@ static int ieee802154_set_max_csma_backoffs(struct wpan_phy *wpan_phy, return 0; } +static int ieee802154_set_max_frame_retries(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + const s8 max_frame_retries) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + + ASSERT_RTNL(); + + if (!(local->hw.flags & IEEE802154_HW_FRAME_RETRIES)) + return -EOPNOTSUPP; + + wpan_dev->frame_retries = max_frame_retries; + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, @@ -148,4 +163,5 @@ const struct cfg802154_ops mac802154_config_ops = { .set_short_addr = ieee802154_set_short_addr, .set_backoff_exponent = ieee802154_set_backoff_exponent, .set_max_csma_backoffs = ieee802154_set_max_csma_backoffs, + .set_max_frame_retries = ieee802154_set_max_frame_retries, }; -- cgit v1.2.3-70-g09d2 From c8937a1d112b1a948454f4fa2f9b747fee2a3f66 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 12 Nov 2014 03:37:05 +0100 Subject: ieee820154: add lbt setting support This patch adds support for setting listen before transmit mode via nl802154 framework. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 ++ net/ieee802154/nl802154.c | 25 +++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 16 ++++++++++++++++ 4 files changed, 50 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 5c3bc12706c2..fa0a9e519523 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -51,6 +51,8 @@ struct cfg802154_ops { int (*set_max_frame_retries)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, s8 max_frame_retries); + int (*set_lbt_mode)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, bool mode); }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 0e272c67c49b..ccdf33ecee0b 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -691,6 +691,23 @@ nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info) return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries); } +static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + bool mode; + + if (netif_running(dev)) + return -EBUSY; + + if (!info->attrs[NL802154_ATTR_LBT_MODE]) + return -EINVAL; + + mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); + return rdev_set_lbt_mode(rdev, wpan_dev, mode); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -849,6 +866,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_LBT_MODE, + .doit = nl802154_set_lbt_mode, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index f9171aaf985e..a78f700bc821 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -68,4 +68,11 @@ rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, max_frame_retries); } +static inline int +rdev_set_lbt_mode(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, const bool mode) +{ + return rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index a8f6eaa76d4d..5d669d87dd7d 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -155,6 +155,21 @@ static int ieee802154_set_max_frame_retries(struct wpan_phy *wpan_phy, return 0; } +static int ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + const bool mode) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + + ASSERT_RTNL(); + + if (!(local->hw.flags & IEEE802154_HW_LBT)) + return -EOPNOTSUPP; + + wpan_dev->lbt = mode; + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, @@ -164,4 +179,5 @@ const struct cfg802154_ops mac802154_config_ops = { .set_backoff_exponent = ieee802154_set_backoff_exponent, .set_max_csma_backoffs = ieee802154_set_max_csma_backoffs, .set_max_frame_retries = ieee802154_set_max_frame_retries, + .set_lbt_mode = ieee802154_set_lbt_mode, }; -- cgit v1.2.3-70-g09d2 From 628b1e1136515c096ba995df694294dbe4ac876d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:47 +0100 Subject: mac802154: remove const for non pointer in rdev-ops This patches removes the const keyword in variables which are non pointers. There is no sense to declare call by value parameters as const. Signed-off-by: Alexander Aring Reported-by: Marc Kleine-Budde Signed-off-by: Marcel Holtmann --- net/ieee802154/rdev-ops.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'net/ieee802154') diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index a78f700bc821..578bc41e92d3 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -21,8 +21,7 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, } static inline int -rdev_set_channel(struct cfg802154_registered_device *rdev, const u8 page, - const u8 channel) +rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) { return rdev->ops->set_channel(&rdev->wpan_phy, page, channel); } @@ -43,8 +42,7 @@ rdev_set_short_addr(struct cfg802154_registered_device *rdev, static inline int rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, const u8 min_be, - const u8 max_be) + struct wpan_dev *wpan_dev, u8 min_be, u8 max_be) { return rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, min_be, max_be); @@ -52,8 +50,7 @@ rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, static inline int rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, - const u8 max_csma_backoffs) + struct wpan_dev *wpan_dev, u8 max_csma_backoffs) { return rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, max_csma_backoffs); @@ -61,8 +58,7 @@ rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, static inline int rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, - const s8 max_frame_retries) + struct wpan_dev *wpan_dev, s8 max_frame_retries) { return rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, max_frame_retries); @@ -70,7 +66,7 @@ rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, static inline int rdev_set_lbt_mode(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, const bool mode) + struct wpan_dev *wpan_dev, bool mode) { return rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); } -- cgit v1.2.3-70-g09d2 From f3ea5e44231a88eaea69a13410d1b80c19cfa1df Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:51 +0100 Subject: ieee802154: add new interface command This patch adds a new nl802154 command for adding a new interface according to a wpan phy via nl802154. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 5 +++++ net/ieee802154/nl802154.c | 34 ++++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 15 +++++++++++++++ 4 files changed, 61 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 17b4fc0705b2..24c7321f3647 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -21,6 +21,8 @@ #include #include +#include + /* According to the IEEE 802.15.4 stadard the upper most significant bits of * the 32-bit channel bitmaps shall be used as an integer value to specify 32 * possible channel pages. The lower 27 bits of the channel bit map shall be @@ -37,6 +39,9 @@ struct cfg802154_ops { int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); + int (*add_virtual_intf)(struct wpan_phy *wpan_phy, + const char *name, + enum nl802154_iftype type); int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u16 pan_id); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index ccdf33ecee0b..e7224f3c1584 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -551,6 +551,32 @@ static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC; + + /* TODO avoid failing a new interface + * creation due to pending removal? + */ + + if (!info->attrs[NL802154_ATTR_IFNAME]) + return -EINVAL; + + if (info->attrs[NL802154_ATTR_IFTYPE]) { + type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]); + if (type > NL802154_IFTYPE_MAX) + return -EINVAL; + } + + if (!rdev->ops->add_virtual_intf) + return -EOPNOTSUPP; + + return rdev_add_virtual_intf(rdev, + nla_data(info->attrs[NL802154_ATTR_IFNAME]), + type); +} + static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg802154_registered_device *rdev = info->user_ptr[0]; @@ -818,6 +844,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_NEW_INTERFACE, + .doit = nl802154_new_interface, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | + NL802154_FLAG_NEED_RTNL, + }, { .cmd = NL802154_CMD_SET_CHANNEL, .doit = nl802154_set_channel, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 578bc41e92d3..d3a4f94c5fdc 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -20,6 +20,13 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev); } +static inline int +rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, + enum nl802154_iftype type) +{ + return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type); +} + static inline int rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) { diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 2abe7e5f0974..ae1a9ef2d42c 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -42,6 +42,20 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, ieee802154_if_remove(sdata); } +static int +ieee802154_add_iface(struct wpan_phy *phy, const char *name, + enum nl802154_iftype type) +{ + struct ieee802154_local *local = wpan_phy_priv(phy); + struct net_device *err; + + err = ieee802154_if_add(local, name, type); + if (IS_ERR(err)) + return PTR_ERR(err); + + return 0; +} + static int ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) { @@ -175,6 +189,7 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, + .add_virtual_intf = ieee802154_add_iface, .set_channel = ieee802154_set_channel, .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, -- cgit v1.2.3-70-g09d2 From 0e57547eb7f0aa99aba32b50c49dbd722a80d6fb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:52 +0100 Subject: ieee802154: setting extended address while iface add This patch adds support for setting an extended address while registration a new interface. If ieee802154_is_valid_extended_addr getting as parameter and invalid extended address then the perm address is fallback. This is useful to make some default handling while for example default registration of a wpan interface while phy registration. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 3 ++- net/ieee802154/nl802154.c | 8 +++++++- net/ieee802154/rdev-ops.h | 5 +++-- net/mac802154/cfg.c | 7 ++++--- net/mac802154/ieee802154_i.h | 2 +- net/mac802154/iface.c | 12 ++++++++---- net/mac802154/main.c | 3 ++- 7 files changed, 27 insertions(+), 13 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 24c7321f3647..4a9bb0e3db2b 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -41,7 +41,8 @@ struct cfg802154_ops { struct net_device *dev); int (*add_virtual_intf)(struct wpan_phy *wpan_phy, const char *name, - enum nl802154_iftype type); + enum nl802154_iftype type, + __le64 extended_addr); int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u16 pan_id); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index e7224f3c1584..49c4d8a5004a 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -555,6 +555,7 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg802154_registered_device *rdev = info->user_ptr[0]; enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC; + __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL); /* TODO avoid failing a new interface * creation due to pending removal? @@ -569,12 +570,17 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + /* TODO add nla_get_le64 to netlink */ + if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) + extended_addr = (__force __le64)nla_get_u64( + info->attrs[NL802154_ATTR_EXTENDED_ADDR]); + if (!rdev->ops->add_virtual_intf) return -EOPNOTSUPP; return rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL802154_ATTR_IFNAME]), - type); + type, extended_addr); } static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index d3a4f94c5fdc..06e97542dafb 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -22,9 +22,10 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, static inline int rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, - enum nl802154_iftype type) + enum nl802154_iftype type, __le64 extended_addr) { - return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type); + return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type, + extended_addr); } static inline int diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index ae1a9ef2d42c..568d712bfc8c 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -28,7 +28,8 @@ ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy, struct net_device *dev; rtnl_lock(); - dev = ieee802154_if_add(local, name, type); + dev = ieee802154_if_add(local, name, type, + cpu_to_le64(0x0000000000000000ULL)); rtnl_unlock(); return dev; @@ -44,12 +45,12 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, static int ieee802154_add_iface(struct wpan_phy *phy, const char *name, - enum nl802154_iftype type) + enum nl802154_iftype type, __le64 extended_addr) { struct ieee802154_local *local = wpan_phy_priv(phy); struct net_device *err; - err = ieee802154_if_add(local, name, type); + err = ieee802154_if_add(local, name, type, extended_addr); if (IS_ERR(err)) return PTR_ERR(err); diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 46553830896d..cc691637d24b 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -176,7 +176,7 @@ void ieee802154_iface_exit(void); void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata); struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type); + enum nl802154_iftype type, __le64 extended_addr); void ieee802154_remove_interfaces(struct ieee802154_local *local); #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index ba63ac93ae90..38dfc72d24b6 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -458,7 +458,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type) + enum nl802154_iftype type, __le64 extended_addr) { struct net_device *ndev = NULL; struct ieee802154_sub_if_data *sdata = NULL; @@ -477,9 +477,16 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, if (ret < 0) goto err; + ieee802154_le64_to_be64(ndev->perm_addr, + &local->hw.phy->perm_extended_addr); switch (type) { case NL802154_IFTYPE_NODE: ndev->type = ARPHRD_IEEE802154; + if (ieee802154_is_valid_extended_addr(extended_addr)) + ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr); + else + memcpy(ndev->dev_addr, ndev->perm_addr, + IEEE802154_EXTENDED_ADDR_LEN); break; case NL802154_IFTYPE_MONITOR: ndev->type = ARPHRD_IEEE802154_MONITOR; @@ -489,9 +496,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, goto err; } - ieee802154_le64_to_be64(ndev->perm_addr, - &local->hw.phy->perm_extended_addr); - memcpy(ndev->dev_addr, ndev->perm_addr, IEEE802154_EXTENDED_ADDR_LEN); /* TODO check this */ SET_NETDEV_DEV(ndev, &local->phy->dev); sdata = netdev_priv(ndev); diff --git a/net/mac802154/main.c b/net/mac802154/main.c index bbb19dd585a0..8500378c8318 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -161,7 +161,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) rtnl_lock(); - dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE); + dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE, + cpu_to_le64(0x0000000000000000ULL)); if (IS_ERR(dev)) { rtnl_unlock(); rc = PTR_ERR(dev); -- cgit v1.2.3-70-g09d2 From b821ecd4c8a0b3b1fc1bdd191bb7d555d818cafe Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:53 +0100 Subject: ieee802154: add del interface command This patch adds support for deleting a wpan interface via nl802154. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 ++ net/ieee802154/nl802154.c | 28 ++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 7 +++++++ net/mac802154/cfg.c | 9 +++++++++ net/mac802154/ieee802154_i.h | 6 ++++++ 5 files changed, 52 insertions(+) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 4a9bb0e3db2b..507ac9d3d38a 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -43,6 +43,8 @@ struct cfg802154_ops { const char *name, enum nl802154_iftype type, __le64 extended_addr); + int (*del_virtual_intf)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev); int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u16 pan_id); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 49c4d8a5004a..6b9bc93944a6 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -583,6 +583,26 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) type, extended_addr); } +static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct wpan_dev *wpan_dev = info->user_ptr[1]; + + if (!rdev->ops->del_virtual_intf) + return -EOPNOTSUPP; + + /* If we remove a wpan device without a netdev then clear + * user_ptr[1] so that nl802154_post_doit won't dereference it + * to check if it needs to do dev_put(). Otherwise it crashes + * since the wpan_dev has been freed, unlike with a netdev where + * we need the dev_put() for the netdev to really be freed. + */ + if (!wpan_dev->netdev) + info->user_ptr[1] = NULL; + + return rdev_del_virtual_intf(rdev, wpan_dev); +} + static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg802154_registered_device *rdev = info->user_ptr[0]; @@ -858,6 +878,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_DEL_INTERFACE, + .doit = nl802154_del_interface, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | + NL802154_FLAG_NEED_RTNL, + }, { .cmd = NL802154_CMD_SET_CHANNEL, .doit = nl802154_set_channel, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 06e97542dafb..40ffbc0d8b85 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -28,6 +28,13 @@ rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, extended_addr); } +static inline int +rdev_del_virtual_intf(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev) +{ + return rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev); +} + static inline int rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) { diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 568d712bfc8c..7def2625eaca 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -57,6 +57,14 @@ ieee802154_add_iface(struct wpan_phy *phy, const char *name, return 0; } +static int +ieee802154_del_iface(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev) +{ + ieee802154_if_remove(IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev)); + + return 0; +} + static int ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) { @@ -191,6 +199,7 @@ const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, .add_virtual_intf = ieee802154_add_iface, + .del_virtual_intf = ieee802154_del_iface, .set_channel = ieee802154_set_channel, .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index cc691637d24b..bebd70ffc7a3 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -115,6 +115,12 @@ IEEE802154_DEV_TO_SUB_IF(const struct net_device *dev) return netdev_priv(dev); } +static inline struct ieee802154_sub_if_data * +IEEE802154_WPAN_DEV_TO_SUB_IF(struct wpan_dev *wpan_dev) +{ + return container_of(wpan_dev, struct ieee802154_sub_if_data, wpan_dev); +} + static inline bool ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) { -- cgit v1.2.3-70-g09d2 From cb41c8dd01d74d091618f72e28f0282f064a9f0a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:54 +0100 Subject: ieee802154: rename and move WPAN_NUM_ defines This patch moves the 802.15.4 constraints WPAN_NUM_ defines into "net/ieee802154.h" which should contain all necessary 802.15.4 related information. Also rename these defines to a common name which is IEEE802154_MAX_CHANNEL and IEEE802154_MAX_PAGE. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 3 +++ include/net/cfg802154.h | 11 ++--------- net/ieee802154/nl802154.c | 4 ++-- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'net/ieee802154') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index 5a40c0418438..6e82d888287c 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -39,6 +39,9 @@ #define IEEE802154_LIFS_PERIOD 40 #define IEEE802154_SIFS_PERIOD 12 +#define IEEE802154_MAX_CHANNEL 26 +#define IEEE802154_MAX_PAGE 31 + #define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ #define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ #define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 507ac9d3d38a..228f1f7668f7 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -17,20 +17,13 @@ #ifndef __NET_CFG802154_H #define __NET_CFG802154_H +#include #include #include #include #include -/* According to the IEEE 802.15.4 stadard the upper most significant bits of - * the 32-bit channel bitmaps shall be used as an integer value to specify 32 - * possible channel pages. The lower 27 bits of the channel bit map shall be - * used as a bit mask to specify channel numbers within a channel page. - */ -#define WPAN_NUM_CHANNELS 27 -#define WPAN_NUM_PAGES 32 - struct wpan_phy; struct cfg802154_ops { @@ -81,7 +74,7 @@ struct wpan_phy { */ u8 current_channel; u8 current_page; - u32 channels_supported[32]; + u32 channels_supported[IEEE802154_MAX_PAGE + 1]; s8 transmit_power; u8 cca_mode; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 6b9bc93944a6..b82b01669a67 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -245,7 +245,7 @@ nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, if (!nl_page) return -ENOBUFS; - for (page = 0; page < WPAN_NUM_PAGES; page++) { + for (page = 0; page <= IEEE802154_MAX_PAGE; page++) { if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL, rdev->wpan_phy.channels_supported[page])) return -ENOBUFS; @@ -616,7 +616,7 @@ static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]); /* check 802.15.4 constraints */ - if (page >= WPAN_NUM_PAGES || channel >= WPAN_NUM_CHANNELS) + if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL) return -EINVAL; return rdev_set_channel(rdev, page, channel); -- cgit v1.2.3-70-g09d2 From ee7b9053bd69ff43cbc87a9bb987f4d92dc2c29f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 17 Nov 2014 08:20:55 +0100 Subject: ieee802154: fix byteorder for short address and panid This patch changes the byteorder handling for short and panid handling. We now except to get little endian in nl802154 for these attributes. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 4 ++-- net/ieee802154/nl802154.c | 8 ++++---- net/ieee802154/rdev-ops.h | 4 ++-- net/mac802154/cfg.c | 14 +++++++------- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'net/ieee802154') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 228f1f7668f7..7f713acfa106 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -40,9 +40,9 @@ struct cfg802154_ops { struct wpan_dev *wpan_dev); int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_pan_id)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, u16 pan_id); + struct wpan_dev *wpan_dev, __le16 pan_id); int (*set_short_addr)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, u16 short_addr); + struct wpan_dev *wpan_dev, __le16 short_addr); int (*set_backoff_exponent)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, u8 min_be, u8 max_be); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index b82b01669a67..889647744697 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -627,7 +627,7 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) struct cfg802154_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wpan_dev *wpan_dev = dev->ieee802154_ptr; - u16 pan_id; + __le16 pan_id; /* conflict here while tx/rx calls */ if (netif_running(dev)) @@ -640,7 +640,7 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL802154_ATTR_PAN_ID]) return -EINVAL; - pan_id = nla_get_u16(info->attrs[NL802154_ATTR_PAN_ID]); + pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); return rdev_set_pan_id(rdev, wpan_dev, pan_id); } @@ -650,7 +650,7 @@ static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) struct cfg802154_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wpan_dev *wpan_dev = dev->ieee802154_ptr; - u16 short_addr; + __le16 short_addr; /* conflict here while tx/rx calls */ if (netif_running(dev)) @@ -663,7 +663,7 @@ static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL802154_ATTR_SHORT_ADDR]) return -EINVAL; - short_addr = nla_get_u16(info->attrs[NL802154_ATTR_SHORT_ADDR]); + short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); return rdev_set_short_addr(rdev, wpan_dev, short_addr); } diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 40ffbc0d8b85..aff54fbd9264 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -43,14 +43,14 @@ rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) static inline int rdev_set_pan_id(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, u16 pan_id) + struct wpan_dev *wpan_dev, __le16 pan_id) { return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); } static inline int rdev_set_short_addr(struct cfg802154_registered_device *rdev, - struct wpan_dev *wpan_dev, u16 short_addr) + struct wpan_dev *wpan_dev, __le16 short_addr) { return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); } diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 7def2625eaca..c035708ada16 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -88,7 +88,7 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, - u16 pan_id) + __le16 pan_id) { ASSERT_RTNL(); @@ -99,10 +99,10 @@ ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, * * This could useful to simple deassociate an device. */ - if (pan_id == IEEE802154_PAN_ID_BROADCAST) + if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)) return -EINVAL; - wpan_dev->pan_id = cpu_to_le16(pan_id); + wpan_dev->pan_id = pan_id; return 0; } @@ -125,7 +125,7 @@ ieee802154_set_backoff_exponent(struct wpan_phy *wpan_phy, static int ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, - u16 short_addr) + __le16 short_addr) { ASSERT_RTNL(); @@ -140,11 +140,11 @@ ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, * I think we should allow to set these settings but * don't allow to allow socket communication with it. */ - if (short_addr == IEEE802154_ADDR_SHORT_UNSPEC || - short_addr == IEEE802154_ADDR_SHORT_BROADCAST) + if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) || + short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST)) return -EINVAL; - wpan_dev->short_addr = cpu_to_le16(short_addr); + wpan_dev->short_addr = short_addr; return 0; } -- cgit v1.2.3-70-g09d2