diff options
Diffstat (limited to 'net/phonet/af_phonet.c')
-rw-r--r-- | net/phonet/af_phonet.c | 84 |
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 */ |
37 | static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly; | 38 | static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly; |
38 | static DEFINE_SPINLOCK(proto_tab_lock); | ||
39 | 39 | ||
40 | static struct phonet_protocol *phonet_proto_get(int protocol) | 40 | static 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 | ||
63 | static int pn_socket_create(struct net *net, struct socket *sock, int protocol) | 63 | static 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 | ||
121 | static struct net_proto_family phonet_proto_family = { | 122 | static 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, | |||
235 | int pn_skb_send(struct sock *sk, struct sk_buff *skb, | 238 | int 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; | ||
428 | out_dev: | ||
429 | dev_put(out_dev); | ||
384 | } | 430 | } |
385 | 431 | ||
386 | out: | 432 | out: |
@@ -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 | ||
442 | static DEFINE_MUTEX(proto_tab_lock); | ||
443 | |||
396 | int __init_or_module phonet_proto_register(int protocol, | 444 | int __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 | ||
419 | void phonet_proto_unregister(int protocol, struct phonet_protocol *pp) | 467 | void 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 | } |
427 | EXPORT_SYMBOL(phonet_proto_unregister); | 476 | EXPORT_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 |