mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
ieee802154: add support for creation/removal of logic interfaces
Add support for two more NL802154 commands: ADD_IFACE and DEL_IFACE, thus allowing creation and removal of logic WPAN interfaces on the top of wpan-phy. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
This commit is contained in:
parent
0a868b26c8
commit
bb1cafb8fc
3 changed files with 162 additions and 0 deletions
|
@ -118,6 +118,8 @@ enum {
|
||||||
|
|
||||||
IEEE802154_LIST_IFACE,
|
IEEE802154_LIST_IFACE,
|
||||||
IEEE802154_LIST_PHY,
|
IEEE802154_LIST_PHY,
|
||||||
|
IEEE802154_ADD_IFACE,
|
||||||
|
IEEE802154_DEL_IFACE,
|
||||||
|
|
||||||
__IEEE802154_CMD_MAX,
|
__IEEE802154_CMD_MAX,
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,10 @@ struct wpan_phy {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
|
struct net_device *(*add_iface)(struct wpan_phy *phy,
|
||||||
|
const char *name);
|
||||||
|
void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
|
||||||
|
|
||||||
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
|
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
#include <net/genetlink.h>
|
#include <net/genetlink.h>
|
||||||
#include <net/wpan-phy.h>
|
#include <net/wpan-phy.h>
|
||||||
|
#include <net/af_ieee802154.h>
|
||||||
|
#include <net/ieee802154_netdev.h>
|
||||||
|
#include <net/rtnetlink.h> /* for rtnl_{un,}lock */
|
||||||
#include <linux/nl802154.h>
|
#include <linux/nl802154.h>
|
||||||
|
|
||||||
#include "ieee802154.h"
|
#include "ieee802154.h"
|
||||||
|
@ -164,9 +167,162 @@ static int ieee802154_dump_phy(struct sk_buff *skb,
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ieee802154_add_iface(struct sk_buff *skb,
|
||||||
|
struct genl_info *info)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
struct wpan_phy *phy;
|
||||||
|
const char *name;
|
||||||
|
const char *devname;
|
||||||
|
int rc = -ENOBUFS;
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
pr_debug("%s\n", __func__);
|
||||||
|
|
||||||
|
if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
|
||||||
|
if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
|
||||||
|
return -EINVAL; /* phy name should be null-terminated */
|
||||||
|
|
||||||
|
if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
|
||||||
|
devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
|
||||||
|
if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
|
||||||
|
!= '\0')
|
||||||
|
return -EINVAL; /* phy name should be null-terminated */
|
||||||
|
} else {
|
||||||
|
devname = "wpan%d";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(devname) >= IFNAMSIZ)
|
||||||
|
return -ENAMETOOLONG;
|
||||||
|
|
||||||
|
phy = wpan_phy_find(name);
|
||||||
|
if (!phy)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE);
|
||||||
|
if (!msg)
|
||||||
|
goto out_dev;
|
||||||
|
|
||||||
|
if (!phy->add_iface) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = phy->add_iface(phy, devname);
|
||||||
|
if (IS_ERR(dev)) {
|
||||||
|
rc = PTR_ERR(dev);
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
|
||||||
|
NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
|
||||||
|
|
||||||
|
dev_put(dev);
|
||||||
|
|
||||||
|
wpan_phy_put(phy);
|
||||||
|
|
||||||
|
return ieee802154_nl_reply(msg, info);
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
out_dev:
|
||||||
|
wpan_phy_put(phy);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ieee802154_del_iface(struct sk_buff *skb,
|
||||||
|
struct genl_info *info)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
struct wpan_phy *phy;
|
||||||
|
const char *name;
|
||||||
|
int rc;
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
pr_debug("%s\n", __func__);
|
||||||
|
|
||||||
|
if (!info->attrs[IEEE802154_ATTR_DEV_NAME])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
|
||||||
|
if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0')
|
||||||
|
return -EINVAL; /* name should be null-terminated */
|
||||||
|
|
||||||
|
dev = dev_get_by_name(genl_info_net(info), name);
|
||||||
|
if (!dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
phy = ieee802154_mlme_ops(dev)->get_phy(dev);
|
||||||
|
BUG_ON(!phy);
|
||||||
|
|
||||||
|
rc = -EINVAL;
|
||||||
|
/* phy name is optional, but should be checked if it's given */
|
||||||
|
if (info->attrs[IEEE802154_ATTR_PHY_NAME]) {
|
||||||
|
struct wpan_phy *phy2;
|
||||||
|
|
||||||
|
const char *pname =
|
||||||
|
nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
|
||||||
|
if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1]
|
||||||
|
!= '\0')
|
||||||
|
/* name should be null-terminated */
|
||||||
|
goto out_dev;
|
||||||
|
|
||||||
|
phy2 = wpan_phy_find(pname);
|
||||||
|
if (!phy2)
|
||||||
|
goto out_dev;
|
||||||
|
|
||||||
|
if (phy != phy2) {
|
||||||
|
wpan_phy_put(phy2);
|
||||||
|
goto out_dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = -ENOBUFS;
|
||||||
|
|
||||||
|
msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE);
|
||||||
|
if (!msg)
|
||||||
|
goto out_dev;
|
||||||
|
|
||||||
|
if (!phy->del_iface) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
phy->del_iface(phy, dev);
|
||||||
|
|
||||||
|
/* We don't have device anymore */
|
||||||
|
dev_put(dev);
|
||||||
|
dev = NULL;
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
|
|
||||||
|
NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
|
||||||
|
NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name);
|
||||||
|
|
||||||
|
wpan_phy_put(phy);
|
||||||
|
|
||||||
|
return ieee802154_nl_reply(msg, info);
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
out_dev:
|
||||||
|
wpan_phy_put(phy);
|
||||||
|
if (dev)
|
||||||
|
dev_put(dev);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static struct genl_ops ieee802154_phy_ops[] = {
|
static struct genl_ops ieee802154_phy_ops[] = {
|
||||||
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
|
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
|
||||||
ieee802154_dump_phy),
|
ieee802154_dump_phy),
|
||||||
|
IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
|
||||||
|
IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue