Blame view
net/phonet/pn_netlink.c
7.53 KB
8fb397406 Phonet: Netlink i... |
1 2 3 4 5 6 7 |
/* * File: pn_netlink.c * * Phonet netlink interface * * Copyright (C) 2008 Nokia Corporation. * |
31fdc5553 net: remove my fu... |
8 9 |
* Authors: Sakari Ailus <sakari.ailus@nokia.com> * Remi Denis-Courmont |
8fb397406 Phonet: Netlink i... |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #include <linux/kernel.h> #include <linux/netlink.h> #include <linux/phonet.h> |
5a0e3ad6a include cleanup: ... |
29 |
#include <linux/slab.h> |
8fb397406 Phonet: Netlink i... |
30 31 |
#include <net/sock.h> #include <net/phonet/pn_dev.h> |
f062f41d0 Phonet: routing t... |
32 |
/* Device address handling */ |
8fb397406 Phonet: Netlink i... |
33 |
static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr, |
15e473046 netlink: Rename p... |
34 |
u32 portid, u32 seq, int event); |
8fb397406 Phonet: Netlink i... |
35 |
|
c7a1a4c80 Phonet: publicize... |
36 |
void phonet_address_notify(int event, struct net_device *dev, u8 addr) |
8fb397406 Phonet: Netlink i... |
37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
{ struct sk_buff *skb; int err = -ENOBUFS; skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + nla_total_size(1), GFP_KERNEL); if (skb == NULL) goto errout; err = fill_addr(skb, dev, addr, 0, 0, event); if (err < 0) { WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } |
1ce85fe40 netlink: change n... |
51 52 53 |
rtnl_notify(skb, dev_net(dev), 0, RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL); return; |
8fb397406 Phonet: Netlink i... |
54 |
errout: |
4b7673a04 Phonet: remove ta... |
55 |
rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err); |
8fb397406 Phonet: Netlink i... |
56 |
} |
8980713b9 Phonet: Netlink f... |
57 58 59 |
static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = { [IFA_LOCAL] = { .type = NLA_U8 }, }; |
c21ef3e34 net: rtnetlink: p... |
60 61 |
static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) |
8fb397406 Phonet: Netlink i... |
62 |
{ |
8980713b9 Phonet: Netlink f... |
63 64 |
struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; |
8fb397406 Phonet: Netlink i... |
65 |
struct net_device *dev; |
8980713b9 Phonet: Netlink f... |
66 |
struct ifaddrmsg *ifm; |
8fb397406 Phonet: Netlink i... |
67 68 |
int err; u8 pnaddr; |
90f62cf30 net: Use netlink_... |
69 |
if (!netlink_capable(skb, CAP_NET_ADMIN)) |
dfc47ef86 net: Push capable... |
70 |
return -EPERM; |
90f62cf30 net: Use netlink_... |
71 |
if (!netlink_capable(skb, CAP_SYS_ADMIN)) |
8fb397406 Phonet: Netlink i... |
72 73 74 |
return -EPERM; ASSERT_RTNL(); |
fceb6435e netlink: pass ext... |
75 |
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_phonet_policy, |
c21ef3e34 net: rtnetlink: p... |
76 |
extack); |
8980713b9 Phonet: Netlink f... |
77 78 |
if (err < 0) return err; |
8fb397406 Phonet: Netlink i... |
79 |
|
8980713b9 Phonet: Netlink f... |
80 81 |
ifm = nlmsg_data(nlh); if (tb[IFA_LOCAL] == NULL) |
8fb397406 Phonet: Netlink i... |
82 |
return -EINVAL; |
8980713b9 Phonet: Netlink f... |
83 84 85 |
pnaddr = nla_get_u8(tb[IFA_LOCAL]); if (pnaddr & 3) /* Phonet addresses only have 6 high-order bits */ |
8fb397406 Phonet: Netlink i... |
86 |
return -EINVAL; |
8980713b9 Phonet: Netlink f... |
87 |
dev = __dev_get_by_index(net, ifm->ifa_index); |
8fb397406 Phonet: Netlink i... |
88 89 |
if (dev == NULL) return -ENODEV; |
8980713b9 Phonet: Netlink f... |
90 91 92 93 |
if (nlh->nlmsg_type == RTM_NEWADDR) err = phonet_address_add(dev, pnaddr); else err = phonet_address_del(dev, pnaddr); |
8fb397406 Phonet: Netlink i... |
94 |
if (!err) |
c7a1a4c80 Phonet: publicize... |
95 |
phonet_address_notify(nlh->nlmsg_type, dev, pnaddr); |
8fb397406 Phonet: Netlink i... |
96 97 98 99 |
return err; } static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr, |
15e473046 netlink: Rename p... |
100 |
u32 portid, u32 seq, int event) |
8fb397406 Phonet: Netlink i... |
101 102 103 |
{ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; |
8fb397406 Phonet: Netlink i... |
104 |
|
15e473046 netlink: Rename p... |
105 |
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), 0); |
8980713b9 Phonet: Netlink f... |
106 107 108 109 |
if (nlh == NULL) return -EMSGSIZE; ifm = nlmsg_data(nlh); |
8fb397406 Phonet: Netlink i... |
110 111 112 |
ifm->ifa_family = AF_PHONET; ifm->ifa_prefixlen = 0; ifm->ifa_flags = IFA_F_PERMANENT; |
8980713b9 Phonet: Netlink f... |
113 |
ifm->ifa_scope = RT_SCOPE_LINK; |
8fb397406 Phonet: Netlink i... |
114 |
ifm->ifa_index = dev->ifindex; |
7f116b5b6 phonet: Stop usin... |
115 116 |
if (nla_put_u8(skb, IFA_LOCAL, addr)) goto nla_put_failure; |
053c095a8 netlink: make nlm... |
117 118 |
nlmsg_end(skb, nlh); return 0; |
8fb397406 Phonet: Netlink i... |
119 |
|
8980713b9 Phonet: Netlink f... |
120 121 122 |
nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; |
8fb397406 Phonet: Netlink i... |
123 124 125 126 |
} static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { |
9a3b7a42b Phonet: use per-n... |
127 |
struct phonet_device_list *pndevs; |
8fb397406 Phonet: Netlink i... |
128 129 130 |
struct phonet_device *pnd; int dev_idx = 0, dev_start_idx = cb->args[0]; int addr_idx = 0, addr_start_idx = cb->args[1]; |
9a3b7a42b Phonet: use per-n... |
131 |
pndevs = phonet_device_list(sock_net(skb->sk)); |
eeb74a9d4 Phonet: convert d... |
132 133 |
rcu_read_lock(); list_for_each_entry_rcu(pnd, &pndevs->list, list) { |
8fb397406 Phonet: Netlink i... |
134 135 136 137 138 139 140 141 |
u8 addr; if (dev_idx > dev_start_idx) addr_start_idx = 0; if (dev_idx++ < dev_start_idx) continue; addr_idx = 0; |
a1ca14ac5 phonet: use for_e... |
142 |
for_each_set_bit(addr, pnd->addrs, 64) { |
8fb397406 Phonet: Netlink i... |
143 144 145 146 |
if (addr_idx++ < addr_start_idx) continue; if (fill_addr(skb, pnd->netdev, addr << 2, |
15e473046 netlink: Rename p... |
147 |
NETLINK_CB(cb->skb).portid, |
998ec759e Phonet: fix netli... |
148 |
cb->nlh->nlmsg_seq, RTM_NEWADDR) < 0) |
8fb397406 Phonet: Netlink i... |
149 150 151 152 153 |
goto out; } } out: |
eeb74a9d4 Phonet: convert d... |
154 |
rcu_read_unlock(); |
8fb397406 Phonet: Netlink i... |
155 156 157 158 159 |
cb->args[0] = dev_idx; cb->args[1] = addr_idx; return skb->len; } |
f062f41d0 Phonet: routing t... |
160 161 162 |
/* Routes handling */ static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst, |
15e473046 netlink: Rename p... |
163 |
u32 portid, u32 seq, int event) |
f062f41d0 Phonet: routing t... |
164 165 166 |
{ struct rtmsg *rtm; struct nlmsghdr *nlh; |
15e473046 netlink: Rename p... |
167 |
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), 0); |
f062f41d0 Phonet: routing t... |
168 169 170 171 172 173 174 175 176 177 178 179 180 |
if (nlh == NULL) return -EMSGSIZE; rtm = nlmsg_data(nlh); rtm->rtm_family = AF_PHONET; rtm->rtm_dst_len = 6; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; rtm->rtm_table = RT_TABLE_MAIN; rtm->rtm_protocol = RTPROT_STATIC; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; |
7f116b5b6 phonet: Stop usin... |
181 182 183 |
if (nla_put_u8(skb, RTA_DST, dst) || nla_put_u32(skb, RTA_OIF, dev->ifindex)) goto nla_put_failure; |
053c095a8 netlink: make nlm... |
184 185 |
nlmsg_end(skb, nlh); return 0; |
f062f41d0 Phonet: routing t... |
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; } void rtm_phonet_notify(int event, struct net_device *dev, u8 dst) { struct sk_buff *skb; int err = -ENOBUFS; skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + nla_total_size(1) + nla_total_size(4), GFP_KERNEL); if (skb == NULL) goto errout; err = fill_route(skb, dev, dst, 0, 0, event); if (err < 0) { WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } rtnl_notify(skb, dev_net(dev), 0, RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL); return; errout: |
4b7673a04 Phonet: remove ta... |
211 |
rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err); |
f062f41d0 Phonet: routing t... |
212 213 214 215 216 217 |
} static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = { [RTA_DST] = { .type = NLA_U8 }, [RTA_OIF] = { .type = NLA_U32 }, }; |
c21ef3e34 net: rtnetlink: p... |
218 219 |
static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) |
f062f41d0 Phonet: routing t... |
220 221 222 223 224 225 226 |
{ struct net *net = sock_net(skb->sk); struct nlattr *tb[RTA_MAX+1]; struct net_device *dev; struct rtmsg *rtm; int err; u8 dst; |
90f62cf30 net: Use netlink_... |
227 |
if (!netlink_capable(skb, CAP_NET_ADMIN)) |
dfc47ef86 net: Push capable... |
228 |
return -EPERM; |
90f62cf30 net: Use netlink_... |
229 |
if (!netlink_capable(skb, CAP_SYS_ADMIN)) |
f062f41d0 Phonet: routing t... |
230 231 232 |
return -EPERM; ASSERT_RTNL(); |
fceb6435e netlink: pass ext... |
233 |
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_phonet_policy, |
c21ef3e34 net: rtnetlink: p... |
234 |
extack); |
f062f41d0 Phonet: routing t... |
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
if (err < 0) return err; rtm = nlmsg_data(nlh); if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_type != RTN_UNICAST) return -EINVAL; if (tb[RTA_DST] == NULL || tb[RTA_OIF] == NULL) return -EINVAL; dst = nla_get_u8(tb[RTA_DST]); if (dst & 3) /* Phonet addresses only have 6 high-order bits */ return -EINVAL; dev = __dev_get_by_index(net, nla_get_u32(tb[RTA_OIF])); if (dev == NULL) return -ENODEV; if (nlh->nlmsg_type == RTM_NEWROUTE) err = phonet_route_add(dev, dst); else err = phonet_route_del(dev, dst); if (!err) rtm_phonet_notify(nlh->nlmsg_type, dev, dst); return err; } static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); |
926e9878a phonet netlink: a... |
263 |
u8 addr; |
f062f41d0 Phonet: routing t... |
264 |
|
e67f88dd1 net: dont hold rt... |
265 |
rcu_read_lock(); |
926e9878a phonet netlink: a... |
266 267 |
for (addr = cb->args[0]; addr < 64; addr++) { struct net_device *dev = phonet_route_get_rcu(net, addr << 2); |
f062f41d0 Phonet: routing t... |
268 |
|
f062f41d0 Phonet: routing t... |
269 270 |
if (!dev) continue; |
926e9878a phonet netlink: a... |
271 272 273 |
if (fill_route(skb, dev, addr << 2, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWROUTE) < 0) goto out; |
f062f41d0 Phonet: routing t... |
274 275 276 |
} out: |
e67f88dd1 net: dont hold rt... |
277 |
rcu_read_unlock(); |
926e9878a phonet netlink: a... |
278 |
cb->args[0] = addr; |
f062f41d0 Phonet: routing t... |
279 280 281 |
return skb->len; } |
660f706d9 Phonet: handle rt... |
282 |
int __init phonet_netlink_register(void) |
8fb397406 Phonet: Netlink i... |
283 |
{ |
c7ac8679b rtnetlink: Comput... |
284 |
int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, |
b97bac64a rtnetlink: make r... |
285 |
NULL, 0); |
660f706d9 Phonet: handle rt... |
286 287 288 289 |
if (err) return err; /* Further __rtnl_register() cannot fail */ |
b97bac64a rtnetlink: make r... |
290 291 292 293 294 |
__rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL, 0); __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit, 0); __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL, 0); __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL, 0); __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit, 0); |
660f706d9 Phonet: handle rt... |
295 |
return 0; |
8fb397406 Phonet: Netlink i... |
296 |
} |