aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/af_phonet.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet/af_phonet.c')
-rw-r--r--net/phonet/af_phonet.c84
1 files changed, 67 insertions, 17 deletions
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index f60c0c2aacba..73aee7f2fcdc 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -25,6 +25,7 @@
25 25
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/slab.h>
28#include <asm/unaligned.h> 29#include <asm/unaligned.h>
29#include <net/sock.h> 30#include <net/sock.h>
30 31
@@ -35,7 +36,6 @@
35 36
36/* Transport protocol registration */ 37/* Transport protocol registration */
37static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly; 38static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly;
38static DEFINE_SPINLOCK(proto_tab_lock);
39 39
40static struct phonet_protocol *phonet_proto_get(int protocol) 40static struct phonet_protocol *phonet_proto_get(int protocol)
41{ 41{
@@ -44,11 +44,11 @@ static struct phonet_protocol *phonet_proto_get(int protocol)
44 if (protocol >= PHONET_NPROTO) 44 if (protocol >= PHONET_NPROTO)
45 return NULL; 45 return NULL;
46 46
47 spin_lock(&proto_tab_lock); 47 rcu_read_lock();
48 pp = proto_tab[protocol]; 48 pp = rcu_dereference(proto_tab[protocol]);
49 if (pp && !try_module_get(pp->prot->owner)) 49 if (pp && !try_module_get(pp->prot->owner))
50 pp = NULL; 50 pp = NULL;
51 spin_unlock(&proto_tab_lock); 51 rcu_read_unlock();
52 52
53 return pp; 53 return pp;
54} 54}
@@ -60,7 +60,8 @@ static inline void phonet_proto_put(struct phonet_protocol *pp)
60 60
61/* protocol family functions */ 61/* protocol family functions */
62 62
63static int pn_socket_create(struct net *net, struct socket *sock, int protocol) 63static int pn_socket_create(struct net *net, struct socket *sock, int protocol,
64 int kern)
64{ 65{
65 struct sock *sk; 66 struct sock *sk;
66 struct pn_sock *pn; 67 struct pn_sock *pn;
@@ -118,7 +119,7 @@ out:
118 return err; 119 return err;
119} 120}
120 121
121static struct net_proto_family phonet_proto_family = { 122static const struct net_proto_family phonet_proto_family = {
122 .family = PF_PHONET, 123 .family = PF_PHONET,
123 .create = pn_socket_create, 124 .create = pn_socket_create,
124 .owner = THIS_MODULE, 125 .owner = THIS_MODULE,
@@ -190,9 +191,8 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev,
190 skb->priority = 0; 191 skb->priority = 0;
191 skb->dev = dev; 192 skb->dev = dev;
192 193
193 if (pn_addr(src) == pn_addr(dst)) { 194 if (skb->pkt_type == PACKET_LOOPBACK) {
194 skb_reset_mac_header(skb); 195 skb_reset_mac_header(skb);
195 skb->pkt_type = PACKET_LOOPBACK;
196 skb_orphan(skb); 196 skb_orphan(skb);
197 if (irq) 197 if (irq)
198 netif_rx(skb); 198 netif_rx(skb);
@@ -222,6 +222,9 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev,
222 if (skb == NULL) 222 if (skb == NULL)
223 return -ENOMEM; 223 return -ENOMEM;
224 224
225 if (phonet_address_lookup(dev_net(dev), pn_addr(dst)) == 0)
226 skb->pkt_type = PACKET_LOOPBACK;
227
225 skb_reserve(skb, MAX_PHONET_HEADER); 228 skb_reserve(skb, MAX_PHONET_HEADER);
226 __skb_put(skb, len); 229 __skb_put(skb, len);
227 skb_copy_to_linear_data(skb, data, len); 230 skb_copy_to_linear_data(skb, data, len);
@@ -235,6 +238,7 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev,
235int pn_skb_send(struct sock *sk, struct sk_buff *skb, 238int pn_skb_send(struct sock *sk, struct sk_buff *skb,
236 const struct sockaddr_pn *target) 239 const struct sockaddr_pn *target)
237{ 240{
241 struct net *net = sock_net(sk);
238 struct net_device *dev; 242 struct net_device *dev;
239 struct pn_sock *pn = pn_sk(sk); 243 struct pn_sock *pn = pn_sk(sk);
240 int err; 244 int err;
@@ -243,9 +247,13 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb,
243 247
244 err = -EHOSTUNREACH; 248 err = -EHOSTUNREACH;
245 if (sk->sk_bound_dev_if) 249 if (sk->sk_bound_dev_if)
246 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); 250 dev = dev_get_by_index(net, sk->sk_bound_dev_if);
247 else 251 else if (phonet_address_lookup(net, daddr) == 0) {
248 dev = phonet_device_get(sock_net(sk)); 252 dev = phonet_device_get(net);
253 skb->pkt_type = PACKET_LOOPBACK;
254 } else
255 dev = phonet_route_output(net, daddr);
256
249 if (!dev || !(dev->flags & IFF_UP)) 257 if (!dev || !(dev->flags & IFF_UP))
250 goto drop; 258 goto drop;
251 259
@@ -369,6 +377,12 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
369 377
370 pn_skb_get_dst_sockaddr(skb, &sa); 378 pn_skb_get_dst_sockaddr(skb, &sa);
371 379
380 /* check if this is broadcasted */
381 if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
382 pn_deliver_sock_broadcast(net, skb);
383 goto out;
384 }
385
372 /* check if we are the destination */ 386 /* check if we are the destination */
373 if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) { 387 if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
374 /* Phonet packet input */ 388 /* Phonet packet input */
@@ -381,6 +395,38 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
381 send_obj_unreachable(skb); 395 send_obj_unreachable(skb);
382 send_reset_indications(skb); 396 send_reset_indications(skb);
383 } 397 }
398 } else if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
399 goto out; /* Race between address deletion and loopback */
400 else {
401 /* Phonet packet routing */
402 struct net_device *out_dev;
403
404 out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
405 if (!out_dev) {
406 LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n",
407 pn_sockaddr_get_addr(&sa));
408 goto out;
409 }
410
411 __skb_push(skb, sizeof(struct phonethdr));
412 skb->dev = out_dev;
413 if (out_dev == dev) {
414 LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n",
415 pn_sockaddr_get_addr(&sa), dev->name);
416 goto out_dev;
417 }
418 /* Some drivers (e.g. TUN) do not allocate HW header space */
419 if (skb_cow_head(skb, out_dev->hard_header_len))
420 goto out_dev;
421
422 if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL,
423 skb->len) < 0)
424 goto out_dev;
425 dev_queue_xmit(skb);
426 dev_put(out_dev);
427 return NET_RX_SUCCESS;
428out_dev:
429 dev_put(out_dev);
384 } 430 }
385 431
386out: 432out:
@@ -393,6 +439,8 @@ static struct packet_type phonet_packet_type __read_mostly = {
393 .func = phonet_rcv, 439 .func = phonet_rcv,
394}; 440};
395 441
442static DEFINE_MUTEX(proto_tab_lock);
443
396int __init_or_module phonet_proto_register(int protocol, 444int __init_or_module phonet_proto_register(int protocol,
397 struct phonet_protocol *pp) 445 struct phonet_protocol *pp)
398{ 446{
@@ -405,12 +453,12 @@ int __init_or_module phonet_proto_register(int protocol,
405 if (err) 453 if (err)
406 return err; 454 return err;
407 455
408 spin_lock(&proto_tab_lock); 456 mutex_lock(&proto_tab_lock);
409 if (proto_tab[protocol]) 457 if (proto_tab[protocol])
410 err = -EBUSY; 458 err = -EBUSY;
411 else 459 else
412 proto_tab[protocol] = pp; 460 rcu_assign_pointer(proto_tab[protocol], pp);
413 spin_unlock(&proto_tab_lock); 461 mutex_unlock(&proto_tab_lock);
414 462
415 return err; 463 return err;
416} 464}
@@ -418,10 +466,11 @@ EXPORT_SYMBOL(phonet_proto_register);
418 466
419void phonet_proto_unregister(int protocol, struct phonet_protocol *pp) 467void phonet_proto_unregister(int protocol, struct phonet_protocol *pp)
420{ 468{
421 spin_lock(&proto_tab_lock); 469 mutex_lock(&proto_tab_lock);
422 BUG_ON(proto_tab[protocol] != pp); 470 BUG_ON(proto_tab[protocol] != pp);
423 proto_tab[protocol] = NULL; 471 rcu_assign_pointer(proto_tab[protocol], NULL);
424 spin_unlock(&proto_tab_lock); 472 mutex_unlock(&proto_tab_lock);
473 synchronize_rcu();
425 proto_unregister(pp->prot); 474 proto_unregister(pp->prot);
426} 475}
427EXPORT_SYMBOL(phonet_proto_unregister); 476EXPORT_SYMBOL(phonet_proto_unregister);
@@ -435,6 +484,7 @@ static int __init phonet_init(void)
435 if (err) 484 if (err)
436 return err; 485 return err;
437 486
487 pn_sock_init();
438 err = sock_register(&phonet_proto_family); 488 err = sock_register(&phonet_proto_family);
439 if (err) { 489 if (err) {
440 printk(KERN_ALERT 490 printk(KERN_ALERT