aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet')
-rw-r--r--net/phonet/af_phonet.c31
-rw-r--r--net/phonet/pn_dev.c119
-rw-r--r--net/phonet/pn_netlink.c24
3 files changed, 111 insertions, 63 deletions
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 13cb323f8c38..81795ea87794 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -275,8 +275,6 @@ static inline int can_respond(struct sk_buff *skb)
275 return 0; 275 return 0;
276 276
277 ph = pn_hdr(skb); 277 ph = pn_hdr(skb);
278 if (phonet_address_get(skb->dev, ph->pn_rdev) != ph->pn_rdev)
279 return 0; /* we are not the destination */
280 if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5)) 278 if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5))
281 return 0; 279 return 0;
282 if (ph->pn_res == PN_COMMGR) /* indications */ 280 if (ph->pn_res == PN_COMMGR) /* indications */
@@ -344,8 +342,8 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
344 struct packet_type *pkttype, 342 struct packet_type *pkttype,
345 struct net_device *orig_dev) 343 struct net_device *orig_dev)
346{ 344{
345 struct net *net = dev_net(dev);
347 struct phonethdr *ph; 346 struct phonethdr *ph;
348 struct sock *sk;
349 struct sockaddr_pn sa; 347 struct sockaddr_pn sa;
350 u16 len; 348 u16 len;
351 349
@@ -364,28 +362,28 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
364 skb_reset_transport_header(skb); 362 skb_reset_transport_header(skb);
365 363
366 pn_skb_get_dst_sockaddr(skb, &sa); 364 pn_skb_get_dst_sockaddr(skb, &sa);
367 if (pn_sockaddr_get_addr(&sa) == 0)
368 goto out; /* currently, we cannot be device 0 */
369 365
370 sk = pn_find_sock_by_sa(dev_net(dev), &sa); 366 /* check if we are the destination */
371 if (sk == NULL) { 367 if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
368 /* Phonet packet input */
369 struct sock *sk = pn_find_sock_by_sa(net, &sa);
370
371 if (sk)
372 return sk_receive_skb(sk, skb, 0);
373
372 if (can_respond(skb)) { 374 if (can_respond(skb)) {
373 send_obj_unreachable(skb); 375 send_obj_unreachable(skb);
374 send_reset_indications(skb); 376 send_reset_indications(skb);
375 } 377 }
376 goto out;
377 } 378 }
378 379
379 /* Push data to the socket (or other sockets connected to it). */
380 return sk_receive_skb(sk, skb, 0);
381
382out: 380out:
383 kfree_skb(skb); 381 kfree_skb(skb);
384 return NET_RX_DROP; 382 return NET_RX_DROP;
385} 383}
386 384
387static struct packet_type phonet_packet_type = { 385static struct packet_type phonet_packet_type = {
388 .type = __constant_htons(ETH_P_PHONET), 386 .type = cpu_to_be16(ETH_P_PHONET),
389 .dev = NULL, 387 .dev = NULL,
390 .func = phonet_rcv, 388 .func = phonet_rcv,
391}; 389};
@@ -428,16 +426,18 @@ static int __init phonet_init(void)
428{ 426{
429 int err; 427 int err;
430 428
429 err = phonet_device_init();
430 if (err)
431 return err;
432
431 err = sock_register(&phonet_proto_family); 433 err = sock_register(&phonet_proto_family);
432 if (err) { 434 if (err) {
433 printk(KERN_ALERT 435 printk(KERN_ALERT
434 "phonet protocol family initialization failed\n"); 436 "phonet protocol family initialization failed\n");
435 return err; 437 goto err_sock;
436 } 438 }
437 439
438 phonet_device_init();
439 dev_add_pack(&phonet_packet_type); 440 dev_add_pack(&phonet_packet_type);
440 phonet_netlink_register();
441 phonet_sysctl_init(); 441 phonet_sysctl_init();
442 442
443 err = isi_register(); 443 err = isi_register();
@@ -449,6 +449,7 @@ err:
449 phonet_sysctl_exit(); 449 phonet_sysctl_exit();
450 sock_unregister(PF_PHONET); 450 sock_unregister(PF_PHONET);
451 dev_remove_pack(&phonet_packet_type); 451 dev_remove_pack(&phonet_packet_type);
452err_sock:
452 phonet_device_exit(); 453 phonet_device_exit();
453 return err; 454 return err;
454} 455}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 5491bf5e354b..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,24 +202,52 @@ static struct notifier_block phonet_device_notifier = {
187 .priority = 0, 202 .priority = 0,
188}; 203};
189 204
190/* Initialize Phonet devices list */ 205/* Per-namespace Phonet devices handling */
191void phonet_device_init(void) 206static int phonet_init_net(struct net *net)
192{ 207{
193 register_netdevice_notifier(&phonet_device_notifier); 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;
194} 216}
195 217
196void phonet_device_exit(void) 218static void phonet_exit_net(struct net *net)
197{ 219{
220 struct phonet_net *pnn = net_generic(net, phonet_net_id);
198 struct phonet_device *pnd, *n; 221 struct phonet_device *pnd, *n;
199 222
200 rtnl_unregister_all(PF_PHONET); 223 list_for_each_entry_safe(pnd, n, &pnn->pndevs.list, list)
201 rtnl_lock();
202 spin_lock_bh(&pndevs.lock);
203
204 list_for_each_entry_safe(pnd, n, &pndevs.list, list)
205 __phonet_device_free(pnd); 224 __phonet_device_free(pnd);
206 225
207 spin_unlock_bh(&pndevs.lock); 226 kfree(pnn);
208 rtnl_unlock(); 227}
228
229static struct pernet_operations phonet_net_ops = {
230 .init = phonet_init_net,
231 .exit = phonet_exit_net,
232};
233
234/* Initialize Phonet devices list */
235int __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
248void phonet_device_exit(void)
249{
250 rtnl_unregister_all(PF_PHONET);
209 unregister_netdevice_notifier(&phonet_device_notifier); 251 unregister_netdevice_notifier(&phonet_device_notifier);
252 unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops);
210} 253}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 242fe8f8c322..1ceea1f92413 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -123,17 +123,16 @@ nla_put_failure:
123 123
124static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 124static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
125{ 125{
126 struct net *net = sock_net(skb->sk); 126 struct phonet_device_list *pndevs;
127 struct phonet_device *pnd; 127 struct phonet_device *pnd;
128 int dev_idx = 0, dev_start_idx = cb->args[0]; 128 int dev_idx = 0, dev_start_idx = cb->args[0];
129 int addr_idx = 0, addr_start_idx = cb->args[1]; 129 int addr_idx = 0, addr_start_idx = cb->args[1];
130 130
131 spin_lock_bh(&pndevs.lock); 131 pndevs = phonet_device_list(sock_net(skb->sk));
132 list_for_each_entry(pnd, &pndevs.list, list) { 132 spin_lock_bh(&pndevs->lock);
133 list_for_each_entry(pnd, &pndevs->list, list) {
133 u8 addr; 134 u8 addr;
134 135
135 if (!net_eq(dev_net(pnd->netdev), net))
136 continue;
137 if (dev_idx > dev_start_idx) 136 if (dev_idx > dev_start_idx)
138 addr_start_idx = 0; 137 addr_start_idx = 0;
139 if (dev_idx++ < dev_start_idx) 138 if (dev_idx++ < dev_start_idx)
@@ -153,16 +152,21 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
153 } 152 }
154 153
155out: 154out:
156 spin_unlock_bh(&pndevs.lock); 155 spin_unlock_bh(&pndevs->lock);
157 cb->args[0] = dev_idx; 156 cb->args[0] = dev_idx;
158 cb->args[1] = addr_idx; 157 cb->args[1] = addr_idx;
159 158
160 return skb->len; 159 return skb->len;
161} 160}
162 161
163void __init phonet_netlink_register(void) 162int __init phonet_netlink_register(void)
164{ 163{
165 rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL); 164 int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
166 rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL); 165 if (err)
167 rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit); 166 return err;
167
168 /* Further __rtnl_register() cannot fail */
169 __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
170 __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
171 return 0;
168} 172}