cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nl-phy.c (7792B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Netlink interface for IEEE 802.15.4 stack
      4 *
      5 * Copyright 2007, 2008 Siemens AG
      6 *
      7 * Written by:
      8 * Sergey Lapin <slapin@ossfans.org>
      9 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
     10 * Maxim Osipov <maxim.osipov@siemens.com>
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/slab.h>
     15#include <linux/if_arp.h>
     16#include <net/netlink.h>
     17#include <net/genetlink.h>
     18#include <net/cfg802154.h>
     19#include <net/af_ieee802154.h>
     20#include <net/ieee802154_netdev.h>
     21#include <net/rtnetlink.h> /* for rtnl_{un,}lock */
     22#include <linux/nl802154.h>
     23
     24#include "ieee802154.h"
     25#include "rdev-ops.h"
     26#include "core.h"
     27
     28static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
     29				  u32 seq, int flags, struct wpan_phy *phy)
     30{
     31	void *hdr;
     32	int i, pages = 0;
     33	u32 *buf = kcalloc(IEEE802154_MAX_PAGE + 1, sizeof(u32), GFP_KERNEL);
     34
     35	pr_debug("%s\n", __func__);
     36
     37	if (!buf)
     38		return -EMSGSIZE;
     39
     40	hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
     41			  IEEE802154_LIST_PHY);
     42	if (!hdr)
     43		goto out;
     44
     45	rtnl_lock();
     46	if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
     47	    nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
     48	    nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel))
     49		goto nla_put_failure;
     50	for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
     51		if (phy->supported.channels[i])
     52			buf[pages++] = phy->supported.channels[i] | (i << 27);
     53	}
     54	if (pages &&
     55	    nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
     56		    pages * sizeof(uint32_t), buf))
     57		goto nla_put_failure;
     58	rtnl_unlock();
     59	kfree(buf);
     60	genlmsg_end(msg, hdr);
     61	return 0;
     62
     63nla_put_failure:
     64	rtnl_unlock();
     65	genlmsg_cancel(msg, hdr);
     66out:
     67	kfree(buf);
     68	return -EMSGSIZE;
     69}
     70
     71int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info)
     72{
     73	/* Request for interface name, index, type, IEEE address,
     74	 * PAN Id, short address
     75	 */
     76	struct sk_buff *msg;
     77	struct wpan_phy *phy;
     78	const char *name;
     79	int rc = -ENOBUFS;
     80
     81	pr_debug("%s\n", __func__);
     82
     83	if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
     84		return -EINVAL;
     85
     86	name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
     87	if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
     88		return -EINVAL; /* phy name should be null-terminated */
     89
     90	phy = wpan_phy_find(name);
     91	if (!phy)
     92		return -ENODEV;
     93
     94	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
     95	if (!msg)
     96		goto out_dev;
     97
     98	rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq,
     99				    0, phy);
    100	if (rc < 0)
    101		goto out_free;
    102
    103	wpan_phy_put(phy);
    104
    105	return genlmsg_reply(msg, info);
    106out_free:
    107	nlmsg_free(msg);
    108out_dev:
    109	wpan_phy_put(phy);
    110	return rc;
    111}
    112
    113struct dump_phy_data {
    114	struct sk_buff *skb;
    115	struct netlink_callback *cb;
    116	int idx, s_idx;
    117};
    118
    119static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data)
    120{
    121	int rc;
    122	struct dump_phy_data *data = _data;
    123
    124	pr_debug("%s\n", __func__);
    125
    126	if (data->idx++ < data->s_idx)
    127		return 0;
    128
    129	rc = ieee802154_nl_fill_phy(data->skb,
    130				    NETLINK_CB(data->cb->skb).portid,
    131				    data->cb->nlh->nlmsg_seq,
    132				    NLM_F_MULTI,
    133				    phy);
    134
    135	if (rc < 0) {
    136		data->idx--;
    137		return rc;
    138	}
    139
    140	return 0;
    141}
    142
    143int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb)
    144{
    145	struct dump_phy_data data = {
    146		.cb = cb,
    147		.skb = skb,
    148		.s_idx = cb->args[0],
    149		.idx = 0,
    150	};
    151
    152	pr_debug("%s\n", __func__);
    153
    154	wpan_phy_for_each(ieee802154_dump_phy_iter, &data);
    155
    156	cb->args[0] = data.idx;
    157
    158	return skb->len;
    159}
    160
    161int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
    162{
    163	struct sk_buff *msg;
    164	struct wpan_phy *phy;
    165	const char *name;
    166	const char *devname;
    167	int rc = -ENOBUFS;
    168	struct net_device *dev;
    169	int type = __IEEE802154_DEV_INVALID;
    170	unsigned char name_assign_type;
    171
    172	pr_debug("%s\n", __func__);
    173
    174	if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
    175		return -EINVAL;
    176
    177	name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
    178	if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
    179		return -EINVAL; /* phy name should be null-terminated */
    180
    181	if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
    182		devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
    183		if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
    184				!= '\0')
    185			return -EINVAL; /* phy name should be null-terminated */
    186		name_assign_type = NET_NAME_USER;
    187	} else  {
    188		devname = "wpan%d";
    189		name_assign_type = NET_NAME_ENUM;
    190	}
    191
    192	if (strlen(devname) >= IFNAMSIZ)
    193		return -ENAMETOOLONG;
    194
    195	phy = wpan_phy_find(name);
    196	if (!phy)
    197		return -ENODEV;
    198
    199	msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE);
    200	if (!msg)
    201		goto out_dev;
    202
    203	if (info->attrs[IEEE802154_ATTR_HW_ADDR] &&
    204	    nla_len(info->attrs[IEEE802154_ATTR_HW_ADDR]) !=
    205			IEEE802154_ADDR_LEN) {
    206		rc = -EINVAL;
    207		goto nla_put_failure;
    208	}
    209
    210	if (info->attrs[IEEE802154_ATTR_DEV_TYPE]) {
    211		type = nla_get_u8(info->attrs[IEEE802154_ATTR_DEV_TYPE]);
    212		if (type >= __IEEE802154_DEV_MAX) {
    213			rc = -EINVAL;
    214			goto nla_put_failure;
    215		}
    216	}
    217
    218	dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname,
    219					       name_assign_type, type);
    220	if (IS_ERR(dev)) {
    221		rc = PTR_ERR(dev);
    222		goto nla_put_failure;
    223	}
    224	dev_hold(dev);
    225
    226	if (info->attrs[IEEE802154_ATTR_HW_ADDR]) {
    227		struct sockaddr addr;
    228
    229		addr.sa_family = ARPHRD_IEEE802154;
    230		nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR],
    231			   IEEE802154_ADDR_LEN);
    232
    233		/* strangely enough, some callbacks (inetdev_event) from
    234		 * dev_set_mac_address require RTNL_LOCK
    235		 */
    236		rtnl_lock();
    237		rc = dev_set_mac_address(dev, &addr, NULL);
    238		rtnl_unlock();
    239		if (rc)
    240			goto dev_unregister;
    241	}
    242
    243	if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
    244	    nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name)) {
    245		rc = -EMSGSIZE;
    246		goto nla_put_failure;
    247	}
    248	dev_put(dev);
    249
    250	wpan_phy_put(phy);
    251
    252	return ieee802154_nl_reply(msg, info);
    253
    254dev_unregister:
    255	rtnl_lock(); /* del_iface must be called with RTNL lock */
    256	rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
    257	dev_put(dev);
    258	rtnl_unlock();
    259nla_put_failure:
    260	nlmsg_free(msg);
    261out_dev:
    262	wpan_phy_put(phy);
    263	return rc;
    264}
    265
    266int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
    267{
    268	struct sk_buff *msg;
    269	struct wpan_phy *phy;
    270	const char *name;
    271	int rc;
    272	struct net_device *dev;
    273
    274	pr_debug("%s\n", __func__);
    275
    276	if (!info->attrs[IEEE802154_ATTR_DEV_NAME])
    277		return -EINVAL;
    278
    279	name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
    280	if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0')
    281		return -EINVAL; /* name should be null-terminated */
    282
    283	rc = -ENODEV;
    284	dev = dev_get_by_name(genl_info_net(info), name);
    285	if (!dev)
    286		return rc;
    287	if (dev->type != ARPHRD_IEEE802154)
    288		goto out;
    289
    290	phy = dev->ieee802154_ptr->wpan_phy;
    291	BUG_ON(!phy);
    292	get_device(&phy->dev);
    293
    294	rc = -EINVAL;
    295	/* phy name is optional, but should be checked if it's given */
    296	if (info->attrs[IEEE802154_ATTR_PHY_NAME]) {
    297		struct wpan_phy *phy2;
    298
    299		const char *pname =
    300			nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
    301		if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1]
    302				!= '\0')
    303			/* name should be null-terminated */
    304			goto out_dev;
    305
    306		phy2 = wpan_phy_find(pname);
    307		if (!phy2)
    308			goto out_dev;
    309
    310		if (phy != phy2) {
    311			wpan_phy_put(phy2);
    312			goto out_dev;
    313		}
    314	}
    315
    316	rc = -ENOBUFS;
    317
    318	msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE);
    319	if (!msg)
    320		goto out_dev;
    321
    322	rtnl_lock();
    323	rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
    324
    325	/* We don't have device anymore */
    326	dev_put(dev);
    327	dev = NULL;
    328
    329	rtnl_unlock();
    330
    331	if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
    332	    nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, name))
    333		goto nla_put_failure;
    334	wpan_phy_put(phy);
    335
    336	return ieee802154_nl_reply(msg, info);
    337
    338nla_put_failure:
    339	nlmsg_free(msg);
    340out_dev:
    341	wpan_phy_put(phy);
    342out:
    343	dev_put(dev);
    344
    345	return rc;
    346}