at v2.6.39 11 kB view raw
1/* 2 * File: pn_dev.c 3 * 4 * Phonet network device 5 * 6 * Copyright (C) 2008 Nokia Corporation. 7 * 8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com> 9 * Original author: Sakari Ailus <sakari.ailus@nokia.com> 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/net.h> 28#include <linux/slab.h> 29#include <linux/netdevice.h> 30#include <linux/phonet.h> 31#include <linux/proc_fs.h> 32#include <linux/if_arp.h> 33#include <net/sock.h> 34#include <net/netns/generic.h> 35#include <net/phonet/pn_dev.h> 36 37struct phonet_routes { 38 struct mutex lock; 39 struct net_device *table[64]; 40}; 41 42struct phonet_net { 43 struct phonet_device_list pndevs; 44 struct phonet_routes routes; 45}; 46 47int phonet_net_id __read_mostly; 48 49static struct phonet_net *phonet_pernet(struct net *net) 50{ 51 BUG_ON(!net); 52 53 return net_generic(net, phonet_net_id); 54} 55 56struct phonet_device_list *phonet_device_list(struct net *net) 57{ 58 struct phonet_net *pnn = phonet_pernet(net); 59 return &pnn->pndevs; 60} 61 62/* Allocate new Phonet device. */ 63static struct phonet_device *__phonet_device_alloc(struct net_device *dev) 64{ 65 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 66 struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC); 67 if (pnd == NULL) 68 return NULL; 69 pnd->netdev = dev; 70 bitmap_zero(pnd->addrs, 64); 71 72 BUG_ON(!mutex_is_locked(&pndevs->lock)); 73 list_add_rcu(&pnd->list, &pndevs->list); 74 return pnd; 75} 76 77static struct phonet_device *__phonet_get(struct net_device *dev) 78{ 79 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 80 struct phonet_device *pnd; 81 82 BUG_ON(!mutex_is_locked(&pndevs->lock)); 83 list_for_each_entry(pnd, &pndevs->list, list) { 84 if (pnd->netdev == dev) 85 return pnd; 86 } 87 return NULL; 88} 89 90static struct phonet_device *__phonet_get_rcu(struct net_device *dev) 91{ 92 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 93 struct phonet_device *pnd; 94 95 list_for_each_entry_rcu(pnd, &pndevs->list, list) { 96 if (pnd->netdev == dev) 97 return pnd; 98 } 99 return NULL; 100} 101 102static void phonet_device_destroy(struct net_device *dev) 103{ 104 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 105 struct phonet_device *pnd; 106 107 ASSERT_RTNL(); 108 109 mutex_lock(&pndevs->lock); 110 pnd = __phonet_get(dev); 111 if (pnd) 112 list_del_rcu(&pnd->list); 113 mutex_unlock(&pndevs->lock); 114 115 if (pnd) { 116 u8 addr; 117 118 for_each_set_bit(addr, pnd->addrs, 64) 119 phonet_address_notify(RTM_DELADDR, dev, addr); 120 kfree(pnd); 121 } 122} 123 124struct net_device *phonet_device_get(struct net *net) 125{ 126 struct phonet_device_list *pndevs = phonet_device_list(net); 127 struct phonet_device *pnd; 128 struct net_device *dev = NULL; 129 130 rcu_read_lock(); 131 list_for_each_entry_rcu(pnd, &pndevs->list, list) { 132 dev = pnd->netdev; 133 BUG_ON(!dev); 134 135 if ((dev->reg_state == NETREG_REGISTERED) && 136 ((pnd->netdev->flags & IFF_UP)) == IFF_UP) 137 break; 138 dev = NULL; 139 } 140 if (dev) 141 dev_hold(dev); 142 rcu_read_unlock(); 143 return dev; 144} 145 146int phonet_address_add(struct net_device *dev, u8 addr) 147{ 148 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 149 struct phonet_device *pnd; 150 int err = 0; 151 152 mutex_lock(&pndevs->lock); 153 /* Find or create Phonet-specific device data */ 154 pnd = __phonet_get(dev); 155 if (pnd == NULL) 156 pnd = __phonet_device_alloc(dev); 157 if (unlikely(pnd == NULL)) 158 err = -ENOMEM; 159 else if (test_and_set_bit(addr >> 2, pnd->addrs)) 160 err = -EEXIST; 161 mutex_unlock(&pndevs->lock); 162 return err; 163} 164 165static void phonet_device_rcu_free(struct rcu_head *head) 166{ 167 struct phonet_device *pnd; 168 169 pnd = container_of(head, struct phonet_device, rcu); 170 kfree(pnd); 171} 172 173int phonet_address_del(struct net_device *dev, u8 addr) 174{ 175 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 176 struct phonet_device *pnd; 177 int err = 0; 178 179 mutex_lock(&pndevs->lock); 180 pnd = __phonet_get(dev); 181 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) { 182 err = -EADDRNOTAVAIL; 183 pnd = NULL; 184 } else if (bitmap_empty(pnd->addrs, 64)) 185 list_del_rcu(&pnd->list); 186 else 187 pnd = NULL; 188 mutex_unlock(&pndevs->lock); 189 190 if (pnd) 191 call_rcu(&pnd->rcu, phonet_device_rcu_free); 192 193 return err; 194} 195 196/* Gets a source address toward a destination, through a interface. */ 197u8 phonet_address_get(struct net_device *dev, u8 daddr) 198{ 199 struct phonet_device *pnd; 200 u8 saddr; 201 202 rcu_read_lock(); 203 pnd = __phonet_get_rcu(dev); 204 if (pnd) { 205 BUG_ON(bitmap_empty(pnd->addrs, 64)); 206 207 /* Use same source address as destination, if possible */ 208 if (test_bit(daddr >> 2, pnd->addrs)) 209 saddr = daddr; 210 else 211 saddr = find_first_bit(pnd->addrs, 64) << 2; 212 } else 213 saddr = PN_NO_ADDR; 214 rcu_read_unlock(); 215 216 if (saddr == PN_NO_ADDR) { 217 /* Fallback to another device */ 218 struct net_device *def_dev; 219 220 def_dev = phonet_device_get(dev_net(dev)); 221 if (def_dev) { 222 if (def_dev != dev) 223 saddr = phonet_address_get(def_dev, daddr); 224 dev_put(def_dev); 225 } 226 } 227 return saddr; 228} 229 230int phonet_address_lookup(struct net *net, u8 addr) 231{ 232 struct phonet_device_list *pndevs = phonet_device_list(net); 233 struct phonet_device *pnd; 234 int err = -EADDRNOTAVAIL; 235 236 rcu_read_lock(); 237 list_for_each_entry_rcu(pnd, &pndevs->list, list) { 238 /* Don't allow unregistering devices! */ 239 if ((pnd->netdev->reg_state != NETREG_REGISTERED) || 240 ((pnd->netdev->flags & IFF_UP)) != IFF_UP) 241 continue; 242 243 if (test_bit(addr >> 2, pnd->addrs)) { 244 err = 0; 245 goto found; 246 } 247 } 248found: 249 rcu_read_unlock(); 250 return err; 251} 252 253/* automatically configure a Phonet device, if supported */ 254static int phonet_device_autoconf(struct net_device *dev) 255{ 256 struct if_phonet_req req; 257 int ret; 258 259 if (!dev->netdev_ops->ndo_do_ioctl) 260 return -EOPNOTSUPP; 261 262 ret = dev->netdev_ops->ndo_do_ioctl(dev, (struct ifreq *)&req, 263 SIOCPNGAUTOCONF); 264 if (ret < 0) 265 return ret; 266 267 ASSERT_RTNL(); 268 ret = phonet_address_add(dev, req.ifr_phonet_autoconf.device); 269 if (ret) 270 return ret; 271 phonet_address_notify(RTM_NEWADDR, dev, 272 req.ifr_phonet_autoconf.device); 273 return 0; 274} 275 276static void phonet_route_autodel(struct net_device *dev) 277{ 278 struct phonet_net *pnn = phonet_pernet(dev_net(dev)); 279 unsigned i; 280 DECLARE_BITMAP(deleted, 64); 281 282 /* Remove left-over Phonet routes */ 283 bitmap_zero(deleted, 64); 284 mutex_lock(&pnn->routes.lock); 285 for (i = 0; i < 64; i++) 286 if (dev == pnn->routes.table[i]) { 287 rcu_assign_pointer(pnn->routes.table[i], NULL); 288 set_bit(i, deleted); 289 } 290 mutex_unlock(&pnn->routes.lock); 291 292 if (bitmap_empty(deleted, 64)) 293 return; /* short-circuit RCU */ 294 synchronize_rcu(); 295 for_each_set_bit(i, deleted, 64) { 296 rtm_phonet_notify(RTM_DELROUTE, dev, i); 297 dev_put(dev); 298 } 299} 300 301/* notify Phonet of device events */ 302static int phonet_device_notify(struct notifier_block *me, unsigned long what, 303 void *arg) 304{ 305 struct net_device *dev = arg; 306 307 switch (what) { 308 case NETDEV_REGISTER: 309 if (dev->type == ARPHRD_PHONET) 310 phonet_device_autoconf(dev); 311 break; 312 case NETDEV_UNREGISTER: 313 phonet_device_destroy(dev); 314 phonet_route_autodel(dev); 315 break; 316 } 317 return 0; 318 319} 320 321static struct notifier_block phonet_device_notifier = { 322 .notifier_call = phonet_device_notify, 323 .priority = 0, 324}; 325 326/* Per-namespace Phonet devices handling */ 327static int __net_init phonet_init_net(struct net *net) 328{ 329 struct phonet_net *pnn = phonet_pernet(net); 330 331 if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) 332 return -ENOMEM; 333 334 INIT_LIST_HEAD(&pnn->pndevs.list); 335 mutex_init(&pnn->pndevs.lock); 336 mutex_init(&pnn->routes.lock); 337 return 0; 338} 339 340static void __net_exit phonet_exit_net(struct net *net) 341{ 342 struct phonet_net *pnn = phonet_pernet(net); 343 struct net_device *dev; 344 unsigned i; 345 346 rtnl_lock(); 347 for_each_netdev(net, dev) 348 phonet_device_destroy(dev); 349 350 for (i = 0; i < 64; i++) { 351 dev = pnn->routes.table[i]; 352 if (dev) { 353 rtm_phonet_notify(RTM_DELROUTE, dev, i); 354 dev_put(dev); 355 } 356 } 357 rtnl_unlock(); 358 359 proc_net_remove(net, "phonet"); 360} 361 362static struct pernet_operations phonet_net_ops = { 363 .init = phonet_init_net, 364 .exit = phonet_exit_net, 365 .id = &phonet_net_id, 366 .size = sizeof(struct phonet_net), 367}; 368 369/* Initialize Phonet devices list */ 370int __init phonet_device_init(void) 371{ 372 int err = register_pernet_device(&phonet_net_ops); 373 if (err) 374 return err; 375 376 proc_net_fops_create(&init_net, "pnresource", 0, &pn_res_seq_fops); 377 register_netdevice_notifier(&phonet_device_notifier); 378 err = phonet_netlink_register(); 379 if (err) 380 phonet_device_exit(); 381 return err; 382} 383 384void phonet_device_exit(void) 385{ 386 rtnl_unregister_all(PF_PHONET); 387 unregister_netdevice_notifier(&phonet_device_notifier); 388 unregister_pernet_device(&phonet_net_ops); 389 proc_net_remove(&init_net, "pnresource"); 390} 391 392int phonet_route_add(struct net_device *dev, u8 daddr) 393{ 394 struct phonet_net *pnn = phonet_pernet(dev_net(dev)); 395 struct phonet_routes *routes = &pnn->routes; 396 int err = -EEXIST; 397 398 daddr = daddr >> 2; 399 mutex_lock(&routes->lock); 400 if (routes->table[daddr] == NULL) { 401 rcu_assign_pointer(routes->table[daddr], dev); 402 dev_hold(dev); 403 err = 0; 404 } 405 mutex_unlock(&routes->lock); 406 return err; 407} 408 409int phonet_route_del(struct net_device *dev, u8 daddr) 410{ 411 struct phonet_net *pnn = phonet_pernet(dev_net(dev)); 412 struct phonet_routes *routes = &pnn->routes; 413 414 daddr = daddr >> 2; 415 mutex_lock(&routes->lock); 416 if (dev == routes->table[daddr]) 417 rcu_assign_pointer(routes->table[daddr], NULL); 418 else 419 dev = NULL; 420 mutex_unlock(&routes->lock); 421 422 if (!dev) 423 return -ENOENT; 424 synchronize_rcu(); 425 dev_put(dev); 426 return 0; 427} 428 429struct net_device *phonet_route_get(struct net *net, u8 daddr) 430{ 431 struct phonet_net *pnn = phonet_pernet(net); 432 struct phonet_routes *routes = &pnn->routes; 433 struct net_device *dev; 434 435 ASSERT_RTNL(); /* no need to hold the device */ 436 437 daddr >>= 2; 438 rcu_read_lock(); 439 dev = rcu_dereference(routes->table[daddr]); 440 rcu_read_unlock(); 441 return dev; 442} 443 444struct net_device *phonet_route_output(struct net *net, u8 daddr) 445{ 446 struct phonet_net *pnn = phonet_pernet(net); 447 struct phonet_routes *routes = &pnn->routes; 448 struct net_device *dev; 449 450 daddr >>= 2; 451 rcu_read_lock(); 452 dev = rcu_dereference(routes->table[daddr]); 453 if (dev) 454 dev_hold(dev); 455 rcu_read_unlock(); 456 457 if (!dev) 458 dev = phonet_device_get(net); /* Default route */ 459 return dev; 460}