]>
Commit | Line | Data |
---|---|---|
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 | ||
37 | struct sk_buff; | |
38 | ||
09748a22 MS |
39 | static 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 |
47 | static 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 | */ | |
66 | static int | |
67 | batadv_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 | */ | |
113 | static int | |
114 | batadv_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 | 166 | static 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 | */ | |
178 | void __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 | */ | |
191 | void batadv_netlink_unregister(void) | |
192 | { | |
193 | genl_unregister_family(&batadv_netlink_family); | |
194 | } |