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_free(struct phonet_device *pnd) 73 { 74 list_del(&pnd->list); 75 kfree(pnd); 76 } 77 78 struct net_device *phonet_device_get(struct net *net) 79 { 80 struct phonet_device_list *pndevs = phonet_device_list(net); 81 struct phonet_device *pnd; 82 struct net_device *dev; 83 84 spin_lock_bh(&pndevs->lock); 85 list_for_each_entry(pnd, &pndevs->list, list) { 86 dev = pnd->netdev; 87 BUG_ON(!dev); 88 89 if ((dev->reg_state == NETREG_REGISTERED) && 90 ((pnd->netdev->flags & IFF_UP)) == IFF_UP) 91 break; 92 dev = NULL; 93 } 94 if (dev) 95 dev_hold(dev); 96 spin_unlock_bh(&pndevs->lock); 97 return dev; 98 } 99 100 int phonet_address_add(struct net_device *dev, u8 addr) 101 { 102 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 103 struct phonet_device *pnd; 104 int err = 0; 105 106 spin_lock_bh(&pndevs->lock); 107 /* Find or create Phonet-specific device data */ 108 pnd = __phonet_get(dev); 109 if (pnd == NULL) 110 pnd = __phonet_device_alloc(dev); 111 if (unlikely(pnd == NULL)) 112 err = -ENOMEM; 113 else if (test_and_set_bit(addr >> 2, pnd->addrs)) 114 err = -EEXIST; 115 spin_unlock_bh(&pndevs->lock); 116 return err; 117 } 118 119 int phonet_address_del(struct net_device *dev, u8 addr) 120 { 121 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 122 struct phonet_device *pnd; 123 int err = 0; 124 125 spin_lock_bh(&pndevs->lock); 126 pnd = __phonet_get(dev); 127 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) 128 err = -EADDRNOTAVAIL; 129 else if (bitmap_empty(pnd->addrs, 64)) 130 __phonet_device_free(pnd); 131 spin_unlock_bh(&pndevs->lock); 132 return err; 133 } 134 135 /* Gets a source address toward a destination, through a interface. */ 136 u8 phonet_address_get(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 141 spin_lock_bh(&pndevs->lock); 142 pnd = __phonet_get(dev); 143 if (pnd) { 144 BUG_ON(bitmap_empty(pnd->addrs, 64)); 145 146 /* Use same source address as destination, if possible */ 147 if (!test_bit(addr >> 2, pnd->addrs)) 148 addr = find_first_bit(pnd->addrs, 64) << 2; 149 } else 150 addr = PN_NO_ADDR; 151 spin_unlock_bh(&pndevs->lock); 152 return addr; 153 } 154 155 int phonet_address_lookup(struct net *net, u8 addr) 156 { 157 struct phonet_device_list *pndevs = phonet_device_list(net); 158 struct phonet_device *pnd; 159 int err = -EADDRNOTAVAIL; 160 161 spin_lock_bh(&pndevs->lock); 162 list_for_each_entry(pnd, &pndevs->list, list) { 163 /* Don't allow unregistering devices! */ 164 if ((pnd->netdev->reg_state != NETREG_REGISTERED) || 165 ((pnd->netdev->flags & IFF_UP)) != IFF_UP) 166 continue; 167 168 if (test_bit(addr >> 2, pnd->addrs)) { 169 err = 0; 170 goto found; 171 } 172 } 173 found: 174 spin_unlock_bh(&pndevs->lock); 175 return err; 176 } 177 178 /* notify Phonet of device events */ 179 static int phonet_device_notify(struct notifier_block *me, unsigned long what, 180 void *arg) 181 { 182 struct net_device *dev = arg; 183 184 if (what == NETDEV_UNREGISTER) { 185 struct phonet_device_list *pndevs; 186 struct phonet_device *pnd; 187 188 /* Destroy phonet-specific device data */ 189 pndevs = phonet_device_list(dev_net(dev)); 190 spin_lock_bh(&pndevs->lock); 191 pnd = __phonet_get(dev); 192 if (pnd) 193 __phonet_device_free(pnd); 194 spin_unlock_bh(&pndevs->lock); 195 } 196 return 0; 197 198 } 199 200 static struct notifier_block phonet_device_notifier = { 201 .notifier_call = phonet_device_notify, 202 .priority = 0, 203 }; 204 205 /* Per-namespace Phonet devices handling */ 206 static int phonet_init_net(struct net *net) 207 { 208 struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL); 209 if (!pnn) 210 return -ENOMEM; 211 212 INIT_LIST_HEAD(&pnn->pndevs.list); 213 spin_lock_init(&pnn->pndevs.lock); 214 net_assign_generic(net, phonet_net_id, pnn); 215 return 0; 216 } 217 218 static void phonet_exit_net(struct net *net) 219 { 220 struct phonet_net *pnn = net_generic(net, phonet_net_id); 221 struct phonet_device *pnd, *n; 222 223 list_for_each_entry_safe(pnd, n, &pnn->pndevs.list, list) 224 __phonet_device_free(pnd); 225 226 kfree(pnn); 227 } 228 229 static struct pernet_operations phonet_net_ops = { 230 .init = phonet_init_net, 231 .exit = phonet_exit_net, 232 }; 233 234 /* Initialize Phonet devices list */ 235 int __init phonet_device_init(void) 236 { 237 int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops); 238 if (err) 239 return err; 240 241 register_netdevice_notifier(&phonet_device_notifier); 242 err = phonet_netlink_register(); 243 if (err) 244 phonet_device_exit(); 245 return err; 246 } 247 248 void phonet_device_exit(void) 249 { 250 rtnl_unregister_all(PF_PHONET); 251 unregister_netdevice_notifier(&phonet_device_notifier); 252 unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); 253 } 254