diff options
Diffstat (limited to 'net/ieee802154/nl-phy.c')
| -rw-r--r-- | net/ieee802154/nl-phy.c | 149 |
1 files changed, 56 insertions, 93 deletions
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 22b1a7058fd3..4c07a475c567 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Netlink inteface for IEEE 802.15.4 stack + * Netlink interface for IEEE 802.15.4 stack * * Copyright 2007, 2008 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * * Written by: * Sergey Lapin <slapin@ossfans.org> * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> @@ -27,20 +15,22 @@ #include <linux/if_arp.h> #include <net/netlink.h> #include <net/genetlink.h> -#include <net/wpan-phy.h> +#include <net/cfg802154.h> #include <net/af_ieee802154.h> #include <net/ieee802154_netdev.h> #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ #include <linux/nl802154.h> #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) + u32 seq, int flags, struct wpan_phy *phy) { void *hdr; int i, pages = 0; - uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL); + u32 *buf = kcalloc(IEEE802154_MAX_PAGE + 1, sizeof(u32), GFP_KERNEL); pr_debug("%s\n", __func__); @@ -48,40 +38,41 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, return -EMSGSIZE; hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, - IEEE802154_LIST_PHY); + IEEE802154_LIST_PHY); if (!hdr) goto out; - mutex_lock(&phy->pib_lock); + rtnl_lock(); if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel)) goto nla_put_failure; - for (i = 0; i < 32; i++) { - if (phy->channels_supported[i]) - buf[pages++] = phy->channels_supported[i] | (i << 27); + for (i = 0; i <= IEEE802154_MAX_PAGE; i++) { + if (phy->supported.channels[i]) + buf[pages++] = phy->supported.channels[i] | (i << 27); } if (pages && nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, pages * sizeof(uint32_t), buf)) goto nla_put_failure; - mutex_unlock(&phy->pib_lock); + rtnl_unlock(); kfree(buf); - return genlmsg_end(msg, hdr); + genlmsg_end(msg, hdr); + return 0; nla_put_failure: - mutex_unlock(&phy->pib_lock); + rtnl_unlock(); genlmsg_cancel(msg, hdr); out: kfree(buf); return -EMSGSIZE; } -static int ieee802154_list_phy(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) { /* Request for interface name, index, type, IEEE address, - PAN Id, short address */ + * PAN Id, short address + */ struct sk_buff *msg; struct wpan_phy *phy; const char *name; @@ -96,7 +87,6 @@ static int ieee802154_list_phy(struct sk_buff *skb, if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') return -EINVAL; /* phy name should be null-terminated */ - phy = wpan_phy_find(name); if (!phy) return -ENODEV; @@ -106,7 +96,7 @@ static int ieee802154_list_phy(struct sk_buff *skb, goto out_dev; rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq, - 0, phy); + 0, phy); if (rc < 0) goto out_free; @@ -118,7 +108,6 @@ out_free: out_dev: wpan_phy_put(phy); return rc; - } struct dump_phy_data { @@ -138,10 +127,10 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) return 0; rc = ieee802154_nl_fill_phy(data->skb, - NETLINK_CB(data->cb->skb).portid, - data->cb->nlh->nlmsg_seq, - NLM_F_MULTI, - phy); + NETLINK_CB(data->cb->skb).portid, + data->cb->nlh->nlmsg_seq, + NLM_F_MULTI, + phy); if (rc < 0) { data->idx--; @@ -151,8 +140,7 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) return 0; } -static int ieee802154_dump_phy(struct sk_buff *skb, - struct netlink_callback *cb) +int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb) { struct dump_phy_data data = { .cb = cb, @@ -170,8 +158,7 @@ static int ieee802154_dump_phy(struct sk_buff *skb, return skb->len; } -static int ieee802154_add_iface(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct wpan_phy *phy; @@ -180,6 +167,7 @@ static int ieee802154_add_iface(struct sk_buff *skb, int rc = -ENOBUFS; struct net_device *dev; int type = __IEEE802154_DEV_INVALID; + unsigned char name_assign_type; pr_debug("%s\n", __func__); @@ -195,8 +183,10 @@ static int ieee802154_add_iface(struct sk_buff *skb, if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') return -EINVAL; /* phy name should be null-terminated */ + name_assign_type = NET_NAME_USER; } else { devname = "wpan%d"; + name_assign_type = NET_NAME_ENUM; } if (strlen(devname) >= IFNAMSIZ) @@ -210,11 +200,6 @@ static int ieee802154_add_iface(struct sk_buff *skb, 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) { @@ -224,37 +209,42 @@ static int ieee802154_add_iface(struct sk_buff *skb, if (info->attrs[IEEE802154_ATTR_DEV_TYPE]) { type = nla_get_u8(info->attrs[IEEE802154_ATTR_DEV_TYPE]); - if (type >= __IEEE802154_DEV_MAX) - return -EINVAL; + if (type >= __IEEE802154_DEV_MAX) { + rc = -EINVAL; + goto nla_put_failure; + } } - dev = phy->add_iface(phy, devname, type); + dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, + name_assign_type, type); if (IS_ERR(dev)) { rc = PTR_ERR(dev); goto nla_put_failure; } + dev_hold(dev); if (info->attrs[IEEE802154_ATTR_HW_ADDR]) { - struct sockaddr addr; + struct sockaddr_storage addr; - addr.sa_family = ARPHRD_IEEE802154; - nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR], - IEEE802154_ADDR_LEN); + addr.ss_family = ARPHRD_IEEE802154; + nla_memcpy(&addr.__data, info->attrs[IEEE802154_ATTR_HW_ADDR], + IEEE802154_ADDR_LEN); - /* - * strangely enough, some callbacks (inetdev_event) from + /* strangely enough, some callbacks (inetdev_event) from * dev_set_mac_address require RTNL_LOCK */ rtnl_lock(); - rc = dev_set_mac_address(dev, &addr); + rc = dev_set_mac_address(dev, &addr, NULL); rtnl_unlock(); if (rc) goto dev_unregister; } if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || - nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name)) + nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name)) { + rc = -EMSGSIZE; goto nla_put_failure; + } dev_put(dev); wpan_phy_put(phy); @@ -263,7 +253,7 @@ static int ieee802154_add_iface(struct sk_buff *skb, 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: @@ -273,8 +263,7 @@ out_dev: return rc; } -static int ieee802154_del_iface(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct wpan_phy *phy; @@ -291,12 +280,16 @@ static int ieee802154_del_iface(struct sk_buff *skb, if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') return -EINVAL; /* name should be null-terminated */ + rc = -ENODEV; dev = dev_get_by_name(genl_info_net(info), name); if (!dev) - return -ENODEV; + return rc; + if (dev->type != ARPHRD_IEEE802154) + goto out; - 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 */ @@ -326,13 +319,8 @@ static int ieee802154_del_iface(struct sk_buff *skb, 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); @@ -351,33 +339,8 @@ nla_put_failure: nlmsg_free(msg); out_dev: wpan_phy_put(phy); - if (dev) - dev_put(dev); +out: + dev_put(dev); return rc; } - -static struct genl_ops ieee802154_phy_ops[] = { - IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, - ieee802154_dump_phy), - IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), - IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), -}; - -/* - * No need to unregister as family unregistration will do it. - */ -int nl802154_phy_register(void) -{ - int i; - int rc; - - for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) { - rc = genl_register_ops(&nl802154_family, - &ieee802154_phy_ops[i]); - if (rc) - return rc; - } - - return 0; -} |
