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/netdevice.h> 29 #include <linux/phonet.h> 30 #include <net/sock.h> 31 #include <net/netns/generic.h> 32 #include <net/phonet/pn_dev.h> 33 34 struct phonet_net { 35 struct phonet_device_list pndevs; 36 }; 37 38 int phonet_net_id; 39 40 struct phonet_device_list *phonet_device_list(struct net *net) 41 { 42 struct phonet_net *pnn = net_generic(net, phonet_net_id); 43 return &pnn->pndevs; 44 } 45 46 /* Allocate new Phonet device. */ 47 static struct phonet_device *__phonet_device_alloc(struct net_device *dev) 48 { 49 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 50 struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC); 51 if (pnd == NULL) 52 return NULL; 53 pnd->netdev = dev; 54 bitmap_zero(pnd->addrs, 64); 55 56 list_add(&pnd->list, &pndevs->list); 57 return pnd; 58 } 59 60 static struct phonet_device *__phonet_get(struct net_device *dev) 61 { 62 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 63 struct phonet_device *pnd; 64 65 list_for_each_entry(pnd, &pndevs->list, list) { 66 if (pnd->netdev == dev) 67 return pnd; 68 } 69 return NULL; 70 } 71 72 static void phonet_device_destroy(struct net_device *dev) 73 { 74 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 75 struct phonet_device *pnd; 76 77 ASSERT_RTNL(); 78 79 spin_lock_bh(&pndevs->lock); 80 pnd = __phonet_get(dev); 81 if (pnd) 82 list_del(&pnd->list); 83 spin_unlock_bh(&pndevs->lock); 84 85 if (pnd) { 86 u8 addr; 87 88 for (addr = find_first_bit(pnd->addrs, 64); addr < 64; 89 addr = find_next_bit(pnd->addrs, 64, 1+addr)) 90 phonet_address_notify(RTM_DELADDR, dev, addr); 91 kfree(pnd); 92 } 93 } 94 95 struct net_device *phonet_device_get(struct net *net) 96 { 97 struct phonet_device_list *pndevs = phonet_device_list(net); 98 struct phonet_device *pnd; 99 struct net_device *dev; 100 101 spin_lock_bh(&pndevs->lock); 102 list_for_each_entry(pnd, &pndevs->list, list) { 103 dev = pnd->netdev; 104 BUG_ON(!dev); 105 106 if ((dev->reg_state == NETREG_REGISTERED) && 107 ((pnd->netdev->flags & IFF_UP)) == IFF_UP) 108 break; 109 dev = NULL; 110 } 111 if (dev) 112 dev_hold(dev); 113 spin_unlock_bh(&pndevs->lock); 114 return dev; 115 } 116 117 int phonet_address_add(struct net_device *dev, u8 addr) 118 { 119 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 120 struct phonet_device *pnd; 121 int err = 0; 122 123 spin_lock_bh(&pndevs->lock); 124 /* Find or create Phonet-specific device data */ 125 pnd = __phonet_get(dev); 126 if (pnd == NULL) 127 pnd = __phonet_device_alloc(dev); 128 if (unlikely(pnd == NULL)) 129 err = -ENOMEM; 130 else if (test_and_set_bit(addr >> 2, pnd->addrs)) 131 err = -EEXIST; 132 spin_unlock_bh(&pndevs->lock); 133 return err; 134 } 135 136 int phonet_address_del(struct net_device *dev, u8 addr) 137 { 138 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 139 struct phonet_device *pnd; 140 int err = 0; 141 142 spin_lock_bh(&pndevs->lock); 143 pnd = __phonet_get(dev); 144 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) 145 err = -EADDRNOTAVAIL; 146 else if (bitmap_empty(pnd->addrs, 64)) { 147 list_del(&pnd->list); 148 kfree(pnd); 149 } 150 spin_unlock_bh(&pndevs->lock); 151 return err; 152 } 153 154 /* Gets a source address toward a destination, through a interface. */ 155 u8 phonet_address_get(struct net_device *dev, u8 addr) 156 { 157 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 158 struct phonet_device *pnd; 159 160 spin_lock_bh(&pndevs->lock); 161 pnd = __phonet_get(dev); 162 if (pnd) { 163 BUG_ON(bitmap_empty(pnd->addrs, 64)); 164 165 /* Use same source address as destination, if possible */ 166 if (!test_bit(addr >> 2, pnd->addrs)) 167 addr = find_first_bit(pnd->addrs, 64) << 2; 168 } else 169 addr = PN_NO_ADDR; 170 spin_unlock_bh(&pndevs->lock); 171 return addr; 172 } 173 174 int phonet_address_lookup(struct net *net, u8 addr) 175 { 176 struct phonet_device_list *pndevs = phonet_device_list(net); 177 struct phonet_device *pnd; 178 int err = -EADDRNOTAVAIL; 179 180 spin_lock_bh(&pndevs->lock); 181 list_for_each_entry(pnd, &pndevs->list, list) { 182 /* Don't allow unregistering devices! */ 183 if ((pnd->netdev->reg_state != NETREG_REGISTERED) || 184 ((pnd->netdev->flags & IFF_UP)) != IFF_UP) 185 continue; 186 187 if (test_bit(addr >> 2, pnd->addrs)) { 188 err = 0; 189 goto found; 190 } 191 } 192 found: 193 spin_unlock_bh(&pndevs->lock); 194 return err; 195 } 196 197 /* notify Phonet of device events */ 198 static int phonet_device_notify(struct notifier_block *me, unsigned long what, 199 void *arg) 200 { 201 struct net_device *dev = arg; 202 203 if (what == NETDEV_UNREGISTER) 204 phonet_device_destroy(dev); 205 return 0; 206 207 } 208 209 static struct notifier_block phonet_device_notifier = { 210 .notifier_call = phonet_device_notify, 211 .priority = 0, 212 }; 213 214 /* Per-namespace Phonet devices handling */ 215 static int phonet_init_net(struct net *net) 216 { 217 struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL); 218 if (!pnn) 219 return -ENOMEM; 220 221 if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) { 222 kfree(pnn); 223 return -ENOMEM; 224 } 225 226 INIT_LIST_HEAD(&pnn->pndevs.list); 227 spin_lock_init(&pnn->pndevs.lock); 228 net_assign_generic(net, phonet_net_id, pnn); 229 return 0; 230 } 231 232 static void phonet_exit_net(struct net *net) 233 { 234 struct phonet_net *pnn = net_generic(net, phonet_net_id); 235 struct net_device *dev; 236 237 rtnl_lock(); 238 for_each_netdev(net, dev) 239 phonet_device_destroy(dev); 240 rtnl_unlock(); 241 242 proc_net_remove(net, "phonet"); 243 kfree(pnn); 244 } 245 246 static struct pernet_operations phonet_net_ops = { 247 .init = phonet_init_net, 248 .exit = phonet_exit_net, 249 }; 250 251 /* Initialize Phonet devices list */ 252 int __init phonet_device_init(void) 253 { 254 int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops); 255 if (err) 256 return err; 257 258 register_netdevice_notifier(&phonet_device_notifier); 259 err = phonet_netlink_register(); 260 if (err) 261 phonet_device_exit(); 262 return err; 263 } 264 265 void phonet_device_exit(void) 266 { 267 rtnl_unregister_all(PF_PHONET); 268 unregister_netdevice_notifier(&phonet_device_notifier); 269 unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); 270 } 271