1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * File: pn_netlink.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Phonet netlink interface
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2008 Nokia Corporation.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Authors: Sakari Ailus <sakari.ailus@nokia.com>
10*4882a593Smuzhiyun * Remi Denis-Courmont
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/netlink.h>
15*4882a593Smuzhiyun #include <linux/phonet.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <net/sock.h>
18*4882a593Smuzhiyun #include <net/phonet/pn_dev.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* Device address handling */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
23*4882a593Smuzhiyun u32 portid, u32 seq, int event);
24*4882a593Smuzhiyun
phonet_address_notify(int event,struct net_device * dev,u8 addr)25*4882a593Smuzhiyun void phonet_address_notify(int event, struct net_device *dev, u8 addr)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun struct sk_buff *skb;
28*4882a593Smuzhiyun int err = -ENOBUFS;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
31*4882a593Smuzhiyun nla_total_size(1), GFP_KERNEL);
32*4882a593Smuzhiyun if (skb == NULL)
33*4882a593Smuzhiyun goto errout;
34*4882a593Smuzhiyun err = fill_addr(skb, dev, addr, 0, 0, event);
35*4882a593Smuzhiyun if (err < 0) {
36*4882a593Smuzhiyun WARN_ON(err == -EMSGSIZE);
37*4882a593Smuzhiyun kfree_skb(skb);
38*4882a593Smuzhiyun goto errout;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun rtnl_notify(skb, dev_net(dev), 0,
41*4882a593Smuzhiyun RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
42*4882a593Smuzhiyun return;
43*4882a593Smuzhiyun errout:
44*4882a593Smuzhiyun rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = {
48*4882a593Smuzhiyun [IFA_LOCAL] = { .type = NLA_U8 },
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
addr_doit(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)51*4882a593Smuzhiyun static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
52*4882a593Smuzhiyun struct netlink_ext_ack *extack)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun struct net *net = sock_net(skb->sk);
55*4882a593Smuzhiyun struct nlattr *tb[IFA_MAX+1];
56*4882a593Smuzhiyun struct net_device *dev;
57*4882a593Smuzhiyun struct ifaddrmsg *ifm;
58*4882a593Smuzhiyun int err;
59*4882a593Smuzhiyun u8 pnaddr;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (!netlink_capable(skb, CAP_NET_ADMIN))
62*4882a593Smuzhiyun return -EPERM;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (!netlink_capable(skb, CAP_SYS_ADMIN))
65*4882a593Smuzhiyun return -EPERM;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun ASSERT_RTNL();
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
70*4882a593Smuzhiyun ifa_phonet_policy, extack);
71*4882a593Smuzhiyun if (err < 0)
72*4882a593Smuzhiyun return err;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ifm = nlmsg_data(nlh);
75*4882a593Smuzhiyun if (tb[IFA_LOCAL] == NULL)
76*4882a593Smuzhiyun return -EINVAL;
77*4882a593Smuzhiyun pnaddr = nla_get_u8(tb[IFA_LOCAL]);
78*4882a593Smuzhiyun if (pnaddr & 3)
79*4882a593Smuzhiyun /* Phonet addresses only have 6 high-order bits */
80*4882a593Smuzhiyun return -EINVAL;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun dev = __dev_get_by_index(net, ifm->ifa_index);
83*4882a593Smuzhiyun if (dev == NULL)
84*4882a593Smuzhiyun return -ENODEV;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun if (nlh->nlmsg_type == RTM_NEWADDR)
87*4882a593Smuzhiyun err = phonet_address_add(dev, pnaddr);
88*4882a593Smuzhiyun else
89*4882a593Smuzhiyun err = phonet_address_del(dev, pnaddr);
90*4882a593Smuzhiyun if (!err)
91*4882a593Smuzhiyun phonet_address_notify(nlh->nlmsg_type, dev, pnaddr);
92*4882a593Smuzhiyun return err;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
fill_addr(struct sk_buff * skb,struct net_device * dev,u8 addr,u32 portid,u32 seq,int event)95*4882a593Smuzhiyun static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
96*4882a593Smuzhiyun u32 portid, u32 seq, int event)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct ifaddrmsg *ifm;
99*4882a593Smuzhiyun struct nlmsghdr *nlh;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), 0);
102*4882a593Smuzhiyun if (nlh == NULL)
103*4882a593Smuzhiyun return -EMSGSIZE;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun ifm = nlmsg_data(nlh);
106*4882a593Smuzhiyun ifm->ifa_family = AF_PHONET;
107*4882a593Smuzhiyun ifm->ifa_prefixlen = 0;
108*4882a593Smuzhiyun ifm->ifa_flags = IFA_F_PERMANENT;
109*4882a593Smuzhiyun ifm->ifa_scope = RT_SCOPE_LINK;
110*4882a593Smuzhiyun ifm->ifa_index = dev->ifindex;
111*4882a593Smuzhiyun if (nla_put_u8(skb, IFA_LOCAL, addr))
112*4882a593Smuzhiyun goto nla_put_failure;
113*4882a593Smuzhiyun nlmsg_end(skb, nlh);
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun nla_put_failure:
117*4882a593Smuzhiyun nlmsg_cancel(skb, nlh);
118*4882a593Smuzhiyun return -EMSGSIZE;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
getaddr_dumpit(struct sk_buff * skb,struct netlink_callback * cb)121*4882a593Smuzhiyun static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct phonet_device_list *pndevs;
124*4882a593Smuzhiyun struct phonet_device *pnd;
125*4882a593Smuzhiyun int dev_idx = 0, dev_start_idx = cb->args[0];
126*4882a593Smuzhiyun int addr_idx = 0, addr_start_idx = cb->args[1];
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun pndevs = phonet_device_list(sock_net(skb->sk));
129*4882a593Smuzhiyun rcu_read_lock();
130*4882a593Smuzhiyun list_for_each_entry_rcu(pnd, &pndevs->list, list) {
131*4882a593Smuzhiyun u8 addr;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (dev_idx > dev_start_idx)
134*4882a593Smuzhiyun addr_start_idx = 0;
135*4882a593Smuzhiyun if (dev_idx++ < dev_start_idx)
136*4882a593Smuzhiyun continue;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun addr_idx = 0;
139*4882a593Smuzhiyun for_each_set_bit(addr, pnd->addrs, 64) {
140*4882a593Smuzhiyun if (addr_idx++ < addr_start_idx)
141*4882a593Smuzhiyun continue;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (fill_addr(skb, pnd->netdev, addr << 2,
144*4882a593Smuzhiyun NETLINK_CB(cb->skb).portid,
145*4882a593Smuzhiyun cb->nlh->nlmsg_seq, RTM_NEWADDR) < 0)
146*4882a593Smuzhiyun goto out;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun out:
151*4882a593Smuzhiyun rcu_read_unlock();
152*4882a593Smuzhiyun cb->args[0] = dev_idx;
153*4882a593Smuzhiyun cb->args[1] = addr_idx;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return skb->len;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Routes handling */
159*4882a593Smuzhiyun
fill_route(struct sk_buff * skb,struct net_device * dev,u8 dst,u32 portid,u32 seq,int event)160*4882a593Smuzhiyun static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst,
161*4882a593Smuzhiyun u32 portid, u32 seq, int event)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct rtmsg *rtm;
164*4882a593Smuzhiyun struct nlmsghdr *nlh;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), 0);
167*4882a593Smuzhiyun if (nlh == NULL)
168*4882a593Smuzhiyun return -EMSGSIZE;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun rtm = nlmsg_data(nlh);
171*4882a593Smuzhiyun rtm->rtm_family = AF_PHONET;
172*4882a593Smuzhiyun rtm->rtm_dst_len = 6;
173*4882a593Smuzhiyun rtm->rtm_src_len = 0;
174*4882a593Smuzhiyun rtm->rtm_tos = 0;
175*4882a593Smuzhiyun rtm->rtm_table = RT_TABLE_MAIN;
176*4882a593Smuzhiyun rtm->rtm_protocol = RTPROT_STATIC;
177*4882a593Smuzhiyun rtm->rtm_scope = RT_SCOPE_UNIVERSE;
178*4882a593Smuzhiyun rtm->rtm_type = RTN_UNICAST;
179*4882a593Smuzhiyun rtm->rtm_flags = 0;
180*4882a593Smuzhiyun if (nla_put_u8(skb, RTA_DST, dst) ||
181*4882a593Smuzhiyun nla_put_u32(skb, RTA_OIF, dev->ifindex))
182*4882a593Smuzhiyun goto nla_put_failure;
183*4882a593Smuzhiyun nlmsg_end(skb, nlh);
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun nla_put_failure:
187*4882a593Smuzhiyun nlmsg_cancel(skb, nlh);
188*4882a593Smuzhiyun return -EMSGSIZE;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
rtm_phonet_notify(int event,struct net_device * dev,u8 dst)191*4882a593Smuzhiyun void rtm_phonet_notify(int event, struct net_device *dev, u8 dst)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun struct sk_buff *skb;
194*4882a593Smuzhiyun int err = -ENOBUFS;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
197*4882a593Smuzhiyun nla_total_size(1) + nla_total_size(4), GFP_KERNEL);
198*4882a593Smuzhiyun if (skb == NULL)
199*4882a593Smuzhiyun goto errout;
200*4882a593Smuzhiyun err = fill_route(skb, dev, dst, 0, 0, event);
201*4882a593Smuzhiyun if (err < 0) {
202*4882a593Smuzhiyun WARN_ON(err == -EMSGSIZE);
203*4882a593Smuzhiyun kfree_skb(skb);
204*4882a593Smuzhiyun goto errout;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun rtnl_notify(skb, dev_net(dev), 0,
207*4882a593Smuzhiyun RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL);
208*4882a593Smuzhiyun return;
209*4882a593Smuzhiyun errout:
210*4882a593Smuzhiyun rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = {
214*4882a593Smuzhiyun [RTA_DST] = { .type = NLA_U8 },
215*4882a593Smuzhiyun [RTA_OIF] = { .type = NLA_U32 },
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun
route_doit(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)218*4882a593Smuzhiyun static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
219*4882a593Smuzhiyun struct netlink_ext_ack *extack)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct net *net = sock_net(skb->sk);
222*4882a593Smuzhiyun struct nlattr *tb[RTA_MAX+1];
223*4882a593Smuzhiyun struct net_device *dev;
224*4882a593Smuzhiyun struct rtmsg *rtm;
225*4882a593Smuzhiyun int err;
226*4882a593Smuzhiyun u8 dst;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (!netlink_capable(skb, CAP_NET_ADMIN))
229*4882a593Smuzhiyun return -EPERM;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (!netlink_capable(skb, CAP_SYS_ADMIN))
232*4882a593Smuzhiyun return -EPERM;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ASSERT_RTNL();
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun err = nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
237*4882a593Smuzhiyun rtm_phonet_policy, extack);
238*4882a593Smuzhiyun if (err < 0)
239*4882a593Smuzhiyun return err;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun rtm = nlmsg_data(nlh);
242*4882a593Smuzhiyun if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_type != RTN_UNICAST)
243*4882a593Smuzhiyun return -EINVAL;
244*4882a593Smuzhiyun if (tb[RTA_DST] == NULL || tb[RTA_OIF] == NULL)
245*4882a593Smuzhiyun return -EINVAL;
246*4882a593Smuzhiyun dst = nla_get_u8(tb[RTA_DST]);
247*4882a593Smuzhiyun if (dst & 3) /* Phonet addresses only have 6 high-order bits */
248*4882a593Smuzhiyun return -EINVAL;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun dev = __dev_get_by_index(net, nla_get_u32(tb[RTA_OIF]));
251*4882a593Smuzhiyun if (dev == NULL)
252*4882a593Smuzhiyun return -ENODEV;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if (nlh->nlmsg_type == RTM_NEWROUTE)
255*4882a593Smuzhiyun err = phonet_route_add(dev, dst);
256*4882a593Smuzhiyun else
257*4882a593Smuzhiyun err = phonet_route_del(dev, dst);
258*4882a593Smuzhiyun if (!err)
259*4882a593Smuzhiyun rtm_phonet_notify(nlh->nlmsg_type, dev, dst);
260*4882a593Smuzhiyun return err;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
route_dumpit(struct sk_buff * skb,struct netlink_callback * cb)263*4882a593Smuzhiyun static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun struct net *net = sock_net(skb->sk);
266*4882a593Smuzhiyun u8 addr;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun rcu_read_lock();
269*4882a593Smuzhiyun for (addr = cb->args[0]; addr < 64; addr++) {
270*4882a593Smuzhiyun struct net_device *dev = phonet_route_get_rcu(net, addr << 2);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (!dev)
273*4882a593Smuzhiyun continue;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (fill_route(skb, dev, addr << 2, NETLINK_CB(cb->skb).portid,
276*4882a593Smuzhiyun cb->nlh->nlmsg_seq, RTM_NEWROUTE) < 0)
277*4882a593Smuzhiyun goto out;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun out:
281*4882a593Smuzhiyun rcu_read_unlock();
282*4882a593Smuzhiyun cb->args[0] = addr;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return skb->len;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
phonet_netlink_register(void)287*4882a593Smuzhiyun int __init phonet_netlink_register(void)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int err = rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_NEWADDR,
290*4882a593Smuzhiyun addr_doit, NULL, 0);
291*4882a593Smuzhiyun if (err)
292*4882a593Smuzhiyun return err;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /* Further rtnl_register_module() cannot fail */
295*4882a593Smuzhiyun rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_DELADDR,
296*4882a593Smuzhiyun addr_doit, NULL, 0);
297*4882a593Smuzhiyun rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_GETADDR,
298*4882a593Smuzhiyun NULL, getaddr_dumpit, 0);
299*4882a593Smuzhiyun rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_NEWROUTE,
300*4882a593Smuzhiyun route_doit, NULL, 0);
301*4882a593Smuzhiyun rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_DELROUTE,
302*4882a593Smuzhiyun route_doit, NULL, 0);
303*4882a593Smuzhiyun rtnl_register_module(THIS_MODULE, PF_PHONET, RTM_GETROUTE,
304*4882a593Smuzhiyun NULL, route_dumpit, 0);
305*4882a593Smuzhiyun return 0;
306*4882a593Smuzhiyun }
307