forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nl802154: add support for dumping WPAN interface information
Signed-off-by: Dmitry Eremin-Solenikov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
- Loading branch information
Showing
2 changed files
with
106 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,13 +19,15 @@ | |
* Written by: | ||
* Sergey Lapin <[email protected]> | ||
* Dmitry Eremin-Solenikov <[email protected]> | ||
* Maxim Osipov <[email protected]> | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/if_arp.h> | ||
#include <linux/netdevice.h> | ||
#include <net/netlink.h> | ||
#include <net/genetlink.h> | ||
#include <net/sock.h> | ||
#include <linux/nl802154.h> | ||
#include <net/af_ieee802154.h> | ||
#include <net/nl802154.h> | ||
|
@@ -73,7 +75,7 @@ static int ieee802154_nl_finish(struct sk_buff *msg) | |
/* XXX: nlh is right at the start of msg */ | ||
void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); | ||
|
||
if (!genlmsg_end(msg, hdr)) | ||
if (genlmsg_end(msg, hdr) < 0) | ||
goto out; | ||
|
||
return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, | ||
|
@@ -260,6 +262,35 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, | |
} | ||
EXPORT_SYMBOL(ieee802154_nl_scan_confirm); | ||
|
||
static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, | ||
u32 seq, int flags, struct net_device *dev) | ||
{ | ||
void *hdr; | ||
|
||
pr_debug("%s\n", __func__); | ||
|
||
hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, | ||
IEEE802154_LIST_IFACE); | ||
if (!hdr) | ||
goto out; | ||
|
||
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_U16(msg, IEEE802154_ATTR_SHORT_ADDR, | ||
ieee802154_mlme_ops(dev)->get_short_addr(dev)); | ||
NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, | ||
ieee802154_mlme_ops(dev)->get_pan_id(dev)); | ||
return genlmsg_end(msg, hdr); | ||
|
||
nla_put_failure: | ||
genlmsg_cancel(msg, hdr); | ||
out: | ||
return -EMSGSIZE; | ||
} | ||
|
||
/* Requests from userspace */ | ||
static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) | ||
{ | ||
|
@@ -272,7 +303,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) | |
dev = dev_get_by_name(&init_net, name); | ||
} else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) | ||
dev = dev_get_by_index(&init_net, | ||
nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); | ||
nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); | ||
else | ||
return NULL; | ||
|
||
|
@@ -466,6 +497,67 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |
return ret; | ||
} | ||
|
||
static int ieee802154_list_iface(struct sk_buff *skb, | ||
struct genl_info *info) | ||
{ | ||
/* Request for interface name, index, type, IEEE address, | ||
PAN Id, short address */ | ||
struct sk_buff *msg; | ||
struct net_device *dev = NULL; | ||
int rc = -ENOBUFS; | ||
|
||
pr_debug("%s\n", __func__); | ||
|
||
dev = ieee802154_nl_get_dev(info); | ||
if (!dev) | ||
return -ENODEV; | ||
|
||
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
if (!msg) | ||
goto out_dev; | ||
|
||
rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, | ||
0, dev); | ||
if (rc < 0) | ||
goto out_free; | ||
|
||
dev_put(dev); | ||
|
||
return genlmsg_unicast(&init_net, msg, info->snd_pid); | ||
out_free: | ||
nlmsg_free(msg); | ||
out_dev: | ||
dev_put(dev); | ||
return rc; | ||
|
||
} | ||
|
||
static int ieee802154_dump_iface(struct sk_buff *skb, | ||
struct netlink_callback *cb) | ||
{ | ||
struct net *net = sock_net(skb->sk); | ||
struct net_device *dev; | ||
int idx; | ||
int s_idx = cb->args[0]; | ||
|
||
pr_debug("%s\n", __func__); | ||
|
||
idx = 0; | ||
for_each_netdev(net, dev) { | ||
if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) | ||
goto cont; | ||
|
||
if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, | ||
cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) | ||
break; | ||
cont: | ||
idx++; | ||
} | ||
cb->args[0] = idx; | ||
|
||
return skb->len; | ||
} | ||
|
||
#define IEEE802154_OP(_cmd, _func) \ | ||
{ \ | ||
.cmd = _cmd, \ | ||
|
@@ -475,12 +567,22 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |
.flags = GENL_ADMIN_PERM, \ | ||
} | ||
|
||
#define IEEE802154_DUMP(_cmd, _func, _dump) \ | ||
{ \ | ||
.cmd = _cmd, \ | ||
.policy = ieee802154_policy, \ | ||
.doit = _func, \ | ||
.dumpit = _dump, \ | ||
} | ||
|
||
static struct genl_ops ieee802154_coordinator_ops[] = { | ||
IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), | ||
IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), | ||
IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), | ||
IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), | ||
IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), | ||
IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, | ||
ieee802154_dump_iface), | ||
}; | ||
|
||
static int __init ieee802154_nl_init(void) | ||
|