aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/pn_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet/pn_dev.c')
-rw-r--r--net/phonet/pn_dev.c108
1 files changed, 75 insertions, 33 deletions
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 3e24c0522ee3..80a322d77909 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -28,32 +28,41 @@
28#include <linux/netdevice.h> 28#include <linux/netdevice.h>
29#include <linux/phonet.h> 29#include <linux/phonet.h>
30#include <net/sock.h> 30#include <net/sock.h>
31#include <net/netns/generic.h>
31#include <net/phonet/pn_dev.h> 32#include <net/phonet/pn_dev.h>
32 33
33/* when accessing, remember to lock with spin_lock(&pndevs.lock); */ 34struct phonet_net {
34struct phonet_device_list pndevs = { 35 struct phonet_device_list pndevs;
35 .list = LIST_HEAD_INIT(pndevs.list),
36 .lock = __SPIN_LOCK_UNLOCKED(pndevs.lock),
37}; 36};
38 37
38int phonet_net_id;
39
40struct 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
39/* Allocate new Phonet device. */ 46/* Allocate new Phonet device. */
40static struct phonet_device *__phonet_device_alloc(struct net_device *dev) 47static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
41{ 48{
49 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
42 struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC); 50 struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC);
43 if (pnd == NULL) 51 if (pnd == NULL)
44 return NULL; 52 return NULL;
45 pnd->netdev = dev; 53 pnd->netdev = dev;
46 bitmap_zero(pnd->addrs, 64); 54 bitmap_zero(pnd->addrs, 64);
47 55
48 list_add(&pnd->list, &pndevs.list); 56 list_add(&pnd->list, &pndevs->list);
49 return pnd; 57 return pnd;
50} 58}
51 59
52static struct phonet_device *__phonet_get(struct net_device *dev) 60static struct phonet_device *__phonet_get(struct net_device *dev)
53{ 61{
62 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
54 struct phonet_device *pnd; 63 struct phonet_device *pnd;
55 64
56 list_for_each_entry(pnd, &pndevs.list, list) { 65 list_for_each_entry(pnd, &pndevs->list, list) {
57 if (pnd->netdev == dev) 66 if (pnd->netdev == dev)
58 return pnd; 67 return pnd;
59 } 68 }
@@ -68,32 +77,33 @@ static void __phonet_device_free(struct phonet_device *pnd)
68 77
69struct net_device *phonet_device_get(struct net *net) 78struct net_device *phonet_device_get(struct net *net)
70{ 79{
80 struct phonet_device_list *pndevs = phonet_device_list(net);
71 struct phonet_device *pnd; 81 struct phonet_device *pnd;
72 struct net_device *dev; 82 struct net_device *dev;
73 83
74 spin_lock_bh(&pndevs.lock); 84 spin_lock_bh(&pndevs->lock);
75 list_for_each_entry(pnd, &pndevs.list, list) { 85 list_for_each_entry(pnd, &pndevs->list, list) {
76 dev = pnd->netdev; 86 dev = pnd->netdev;
77 BUG_ON(!dev); 87 BUG_ON(!dev);
78 88
79 if (net_eq(dev_net(dev), net) && 89 if ((dev->reg_state == NETREG_REGISTERED) &&
80 (dev->reg_state == NETREG_REGISTERED) &&
81 ((pnd->netdev->flags & IFF_UP)) == IFF_UP) 90 ((pnd->netdev->flags & IFF_UP)) == IFF_UP)
82 break; 91 break;
83 dev = NULL; 92 dev = NULL;
84 } 93 }
85 if (dev) 94 if (dev)
86 dev_hold(dev); 95 dev_hold(dev);
87 spin_unlock_bh(&pndevs.lock); 96 spin_unlock_bh(&pndevs->lock);
88 return dev; 97 return dev;
89} 98}
90 99
91int phonet_address_add(struct net_device *dev, u8 addr) 100int phonet_address_add(struct net_device *dev, u8 addr)
92{ 101{
102 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
93 struct phonet_device *pnd; 103 struct phonet_device *pnd;
94 int err = 0; 104 int err = 0;
95 105
96 spin_lock_bh(&pndevs.lock); 106 spin_lock_bh(&pndevs->lock);
97 /* Find or create Phonet-specific device data */ 107 /* Find or create Phonet-specific device data */
98 pnd = __phonet_get(dev); 108 pnd = __phonet_get(dev);
99 if (pnd == NULL) 109 if (pnd == NULL)
@@ -102,31 +112,33 @@ int phonet_address_add(struct net_device *dev, u8 addr)
102 err = -ENOMEM; 112 err = -ENOMEM;
103 else if (test_and_set_bit(addr >> 2, pnd->addrs)) 113 else if (test_and_set_bit(addr >> 2, pnd->addrs))
104 err = -EEXIST; 114 err = -EEXIST;
105 spin_unlock_bh(&pndevs.lock); 115 spin_unlock_bh(&pndevs->lock);
106 return err; 116 return err;
107} 117}
108 118
109int phonet_address_del(struct net_device *dev, u8 addr) 119int phonet_address_del(struct net_device *dev, u8 addr)
110{ 120{
121 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
111 struct phonet_device *pnd; 122 struct phonet_device *pnd;
112 int err = 0; 123 int err = 0;
113 124
114 spin_lock_bh(&pndevs.lock); 125 spin_lock_bh(&pndevs->lock);
115 pnd = __phonet_get(dev); 126 pnd = __phonet_get(dev);
116 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) 127 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs))
117 err = -EADDRNOTAVAIL; 128 err = -EADDRNOTAVAIL;
118 else if (bitmap_empty(pnd->addrs, 64)) 129 else if (bitmap_empty(pnd->addrs, 64))
119 __phonet_device_free(pnd); 130 __phonet_device_free(pnd);
120 spin_unlock_bh(&pndevs.lock); 131 spin_unlock_bh(&pndevs->lock);
121 return err; 132 return err;
122} 133}
123 134
124/* Gets a source address toward a destination, through a interface. */ 135/* Gets a source address toward a destination, through a interface. */
125u8 phonet_address_get(struct net_device *dev, u8 addr) 136u8 phonet_address_get(struct net_device *dev, u8 addr)
126{ 137{
138 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
127 struct phonet_device *pnd; 139 struct phonet_device *pnd;
128 140
129 spin_lock_bh(&pndevs.lock); 141 spin_lock_bh(&pndevs->lock);
130 pnd = __phonet_get(dev); 142 pnd = __phonet_get(dev);
131 if (pnd) { 143 if (pnd) {
132 BUG_ON(bitmap_empty(pnd->addrs, 64)); 144 BUG_ON(bitmap_empty(pnd->addrs, 64));
@@ -136,30 +148,31 @@ u8 phonet_address_get(struct net_device *dev, u8 addr)
136 addr = find_first_bit(pnd->addrs, 64) << 2; 148 addr = find_first_bit(pnd->addrs, 64) << 2;
137 } else 149 } else
138 addr = PN_NO_ADDR; 150 addr = PN_NO_ADDR;
139 spin_unlock_bh(&pndevs.lock); 151 spin_unlock_bh(&pndevs->lock);
140 return addr; 152 return addr;
141} 153}
142 154
143int phonet_address_lookup(struct net *net, u8 addr) 155int phonet_address_lookup(struct net *net, u8 addr)
144{ 156{
157 struct phonet_device_list *pndevs = phonet_device_list(net);
145 struct phonet_device *pnd; 158 struct phonet_device *pnd;
159 int err = -EADDRNOTAVAIL;
146 160
147 spin_lock_bh(&pndevs.lock); 161 spin_lock_bh(&pndevs->lock);
148 list_for_each_entry(pnd, &pndevs.list, list) { 162 list_for_each_entry(pnd, &pndevs->list, list) {
149 if (!net_eq(dev_net(pnd->netdev), net))
150 continue;
151 /* Don't allow unregistering devices! */ 163 /* Don't allow unregistering devices! */
152 if ((pnd->netdev->reg_state != NETREG_REGISTERED) || 164 if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
153 ((pnd->netdev->flags & IFF_UP)) != IFF_UP) 165 ((pnd->netdev->flags & IFF_UP)) != IFF_UP)
154 continue; 166 continue;
155 167
156 if (test_bit(addr >> 2, pnd->addrs)) { 168 if (test_bit(addr >> 2, pnd->addrs)) {
157 spin_unlock_bh(&pndevs.lock); 169 err = 0;
158 return 0; 170 goto found;
159 } 171 }
160 } 172 }
161 spin_unlock_bh(&pndevs.lock); 173found:
162 return -EADDRNOTAVAIL; 174 spin_unlock_bh(&pndevs->lock);
175 return err;
163} 176}
164 177
165/* notify Phonet of device events */ 178/* notify Phonet of device events */
@@ -169,14 +182,16 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
169 struct net_device *dev = arg; 182 struct net_device *dev = arg;
170 183
171 if (what == NETDEV_UNREGISTER) { 184 if (what == NETDEV_UNREGISTER) {
185 struct phonet_device_list *pndevs;
172 struct phonet_device *pnd; 186 struct phonet_device *pnd;
173 187
174 /* Destroy phonet-specific device data */ 188 /* Destroy phonet-specific device data */
175 spin_lock_bh(&pndevs.lock); 189 pndevs = phonet_device_list(dev_net(dev));
190 spin_lock_bh(&pndevs->lock);
176 pnd = __phonet_get(dev); 191 pnd = __phonet_get(dev);
177 if (pnd) 192 if (pnd)
178 __phonet_device_free(pnd); 193 __phonet_device_free(pnd);
179 spin_unlock_bh(&pndevs.lock); 194 spin_unlock_bh(&pndevs->lock);
180 } 195 }
181 return 0; 196 return 0;
182 197
@@ -187,10 +202,41 @@ static struct notifier_block phonet_device_notifier = {
187 .priority = 0, 202 .priority = 0,
188}; 203};
189 204
205/* Per-namespace Phonet devices handling */
206static 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
218static 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
229static struct pernet_operations phonet_net_ops = {
230 .init = phonet_init_net,
231 .exit = phonet_exit_net,
232};
233
190/* Initialize Phonet devices list */ 234/* Initialize Phonet devices list */
191int __init phonet_device_init(void) 235int __init phonet_device_init(void)
192{ 236{
193 int err; 237 int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops);
238 if (err)
239 return err;
194 240
195 register_netdevice_notifier(&phonet_device_notifier); 241 register_netdevice_notifier(&phonet_device_notifier);
196 err = phonet_netlink_register(); 242 err = phonet_netlink_register();
@@ -201,11 +247,7 @@ int __init phonet_device_init(void)
201 247
202void phonet_device_exit(void) 248void phonet_device_exit(void)
203{ 249{
204 struct phonet_device *pnd, *n;
205
206 rtnl_unregister_all(PF_PHONET); 250 rtnl_unregister_all(PF_PHONET);
207 unregister_netdevice_notifier(&phonet_device_notifier); 251 unregister_netdevice_notifier(&phonet_device_notifier);
208 252 unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops);
209 list_for_each_entry_safe(pnd, n, &pndevs.list, list)
210 __phonet_device_free(pnd);
211} 253}