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