]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/batman-adv/netlink.c
batman-adv: add netlink command to query generic mesh information files
[mirror_ubuntu-jammy-kernel.git] / net / batman-adv / netlink.c
CommitLineData
09748a22
MS
1/* Copyright (C) 2016 B.A.T.M.A.N. contributors:
2 *
3 * Matthias Schiffer
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "netlink.h"
19#include "main.h"
20
5da0aef5
MS
21#include <linux/errno.h>
22#include <linux/fs.h>
09748a22 23#include <linux/genetlink.h>
5da0aef5 24#include <linux/if_ether.h>
09748a22 25#include <linux/init.h>
5da0aef5
MS
26#include <linux/netdevice.h>
27#include <linux/netlink.h>
09748a22 28#include <linux/printk.h>
5da0aef5 29#include <linux/stddef.h>
09748a22 30#include <net/genetlink.h>
5da0aef5 31#include <net/netlink.h>
09748a22
MS
32#include <uapi/linux/batman_adv.h>
33
5da0aef5
MS
34#include "hard-interface.h"
35#include "soft-interface.h"
36
37struct sk_buff;
38
09748a22
MS
39static struct genl_family batadv_netlink_family = {
40 .id = GENL_ID_GENERATE,
41 .hdrsize = 0,
42 .name = BATADV_NL_NAME,
43 .version = 1,
44 .maxattr = BATADV_ATTR_MAX,
45};
46
5da0aef5
MS
47static struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
48 [BATADV_ATTR_VERSION] = { .type = NLA_STRING },
49 [BATADV_ATTR_ALGO_NAME] = { .type = NLA_STRING },
50 [BATADV_ATTR_MESH_IFINDEX] = { .type = NLA_U32 },
51 [BATADV_ATTR_MESH_IFNAME] = { .type = NLA_STRING },
52 [BATADV_ATTR_MESH_ADDRESS] = { .len = ETH_ALEN },
53 [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 },
54 [BATADV_ATTR_HARD_IFNAME] = { .type = NLA_STRING },
55 [BATADV_ATTR_HARD_ADDRESS] = { .len = ETH_ALEN },
56};
57
58/**
59 * batadv_netlink_mesh_info_put - fill in generic information about mesh
60 * interface
61 * @msg: netlink message to be sent back
62 * @soft_iface: interface for which the data should be taken
63 *
64 * Return: 0 on success, < 0 on error
65 */
66static int
67batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface)
68{
69 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
70 struct batadv_hard_iface *primary_if = NULL;
71 struct net_device *hard_iface;
72 int ret = -ENOBUFS;
73
74 if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) ||
75 nla_put_string(msg, BATADV_ATTR_ALGO_NAME,
76 bat_priv->bat_algo_ops->name) ||
77 nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) ||
78 nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) ||
79 nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN,
80 soft_iface->dev_addr))
81 goto out;
82
83 primary_if = batadv_primary_if_get_selected(bat_priv);
84 if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) {
85 hard_iface = primary_if->net_dev;
86
87 if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
88 hard_iface->ifindex) ||
89 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
90 hard_iface->name) ||
91 nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
92 hard_iface->dev_addr))
93 goto out;
94 }
95
96 ret = 0;
97
98 out:
99 if (primary_if)
100 batadv_hardif_put(primary_if);
101
102 return ret;
103}
104
105/**
106 * batadv_netlink_get_mesh_info - handle incoming BATADV_CMD_GET_MESH_INFO
107 * netlink request
108 * @skb: received netlink message
109 * @info: receiver information
110 *
111 * Return: 0 on success, < 0 on error
112 */
113static int
114batadv_netlink_get_mesh_info(struct sk_buff *skb, struct genl_info *info)
115{
116 struct net *net = genl_info_net(info);
117 struct net_device *soft_iface;
118 struct sk_buff *msg = NULL;
119 void *msg_head;
120 int ifindex;
121 int ret;
122
123 if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
124 return -EINVAL;
125
126 ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
127 if (!ifindex)
128 return -EINVAL;
129
130 soft_iface = dev_get_by_index(net, ifindex);
131 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
132 ret = -ENODEV;
133 goto out;
134 }
135
136 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
137 if (!msg) {
138 ret = -ENOMEM;
139 goto out;
140 }
141
142 msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq,
143 &batadv_netlink_family, 0,
144 BATADV_CMD_GET_MESH_INFO);
145 if (!msg_head) {
146 ret = -ENOBUFS;
147 goto out;
148 }
149
150 ret = batadv_netlink_mesh_info_put(msg, soft_iface);
151
152 out:
153 if (soft_iface)
154 dev_put(soft_iface);
155
156 if (ret) {
157 if (msg)
158 nlmsg_free(msg);
159 return ret;
160 }
161
162 genlmsg_end(msg, msg_head);
163 return genlmsg_reply(msg, info);
164}
165
09748a22 166static struct genl_ops batadv_netlink_ops[] = {
5da0aef5
MS
167 {
168 .cmd = BATADV_CMD_GET_MESH_INFO,
169 .flags = GENL_ADMIN_PERM,
170 .policy = batadv_netlink_policy,
171 .doit = batadv_netlink_get_mesh_info,
172 },
09748a22
MS
173};
174
175/**
176 * batadv_netlink_register - register batadv genl netlink family
177 */
178void __init batadv_netlink_register(void)
179{
180 int ret;
181
182 ret = genl_register_family_with_ops(&batadv_netlink_family,
183 batadv_netlink_ops);
184 if (ret)
185 pr_warn("unable to register netlink family");
186}
187
188/**
189 * batadv_netlink_unregister - unregister batadv genl netlink family
190 */
191void batadv_netlink_unregister(void)
192{
193 genl_unregister_family(&batadv_netlink_family);
194}