aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /net/phonet
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'net/phonet')
-rw-r--r--net/phonet/af_phonet.c84
-rw-r--r--net/phonet/datagram.c13
-rw-r--r--net/phonet/pep-gprs.c4
-rw-r--r--net/phonet/pep.c65
-rw-r--r--net/phonet/pn_dev.c227
-rw-r--r--net/phonet/pn_netlink.c142
-rw-r--r--net/phonet/socket.c83
-rw-r--r--net/phonet/sysctl.c8
8 files changed, 508 insertions, 118 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
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index ef5c75c372e4..1bd38db4fe1e 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -24,6 +24,7 @@
24 */ 24 */
25 25
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/slab.h>
27#include <linux/socket.h> 28#include <linux/socket.h>
28#include <asm/ioctls.h> 29#include <asm/ioctls.h>
29#include <net/sock.h> 30#include <net/sock.h>
@@ -75,7 +76,8 @@ static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
75 struct sk_buff *skb; 76 struct sk_buff *skb;
76 int err; 77 int err;
77 78
78 if (msg->msg_flags & MSG_OOB) 79 if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
80 MSG_CMSG_COMPAT))
79 return -EOPNOTSUPP; 81 return -EOPNOTSUPP;
80 82
81 if (msg->msg_name == NULL) 83 if (msg->msg_name == NULL)
@@ -119,7 +121,8 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
119 int rval = -EOPNOTSUPP; 121 int rval = -EOPNOTSUPP;
120 int copylen; 122 int copylen;
121 123
122 if (flags & MSG_OOB) 124 if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
125 MSG_CMSG_COMPAT))
123 goto out_nofree; 126 goto out_nofree;
124 127
125 if (addr_len) 128 if (addr_len)
@@ -159,11 +162,9 @@ out_nofree:
159static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb) 162static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
160{ 163{
161 int err = sock_queue_rcv_skb(sk, skb); 164 int err = sock_queue_rcv_skb(sk, skb);
162 if (err < 0) { 165
166 if (err < 0)
163 kfree_skb(skb); 167 kfree_skb(skb);
164 if (err == -ENOMEM)
165 atomic_inc(&sk->sk_drops);
166 }
167 return err ? NET_RX_DROP : NET_RX_SUCCESS; 168 return err ? NET_RX_DROP : NET_RX_SUCCESS;
168} 169}
169 170
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c
index d183509d3fa6..d01208968c83 100644
--- a/net/phonet/pep-gprs.c
+++ b/net/phonet/pep-gprs.c
@@ -96,11 +96,11 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
96 goto drop; 96 goto drop;
97 } 97 }
98 98
99 if (likely(skb_headroom(skb) & 3)) { 99 if (skb_headroom(skb) & 3) {
100 struct sk_buff *rskb, *fs; 100 struct sk_buff *rskb, *fs;
101 int flen = 0; 101 int flen = 0;
102 102
103 /* Phonet Pipe data header is misaligned (3 bytes), 103 /* Phonet Pipe data header may be misaligned (3 bytes),
104 * so wrap the IP packet as a single fragment of an head-less 104 * so wrap the IP packet as a single fragment of an head-less
105 * socket buffer. The network stack will pull what it needs, 105 * socket buffer. The network stack will pull what it needs,
106 * but at least, the whole IP payload is not memcpy'd. */ 106 * but at least, the whole IP payload is not memcpy'd. */
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 5f32d217535b..e2a95762abd3 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/slab.h>
26#include <linux/socket.h> 27#include <linux/socket.h>
27#include <net/sock.h> 28#include <net/sock.h>
28#include <net/tcp_states.h> 29#include <net/tcp_states.h>
@@ -354,14 +355,15 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
354 queue = &pn->ctrlreq_queue; 355 queue = &pn->ctrlreq_queue;
355 goto queue; 356 goto queue;
356 357
358 case PNS_PIPE_ALIGNED_DATA:
359 __skb_pull(skb, 1);
360 /* fall through */
357 case PNS_PIPE_DATA: 361 case PNS_PIPE_DATA:
358 __skb_pull(skb, 3); /* Pipe data header */ 362 __skb_pull(skb, 3); /* Pipe data header */
359 if (!pn_flow_safe(pn->rx_fc)) { 363 if (!pn_flow_safe(pn->rx_fc)) {
360 err = sock_queue_rcv_skb(sk, skb); 364 err = sock_queue_rcv_skb(sk, skb);
361 if (!err) 365 if (!err)
362 return 0; 366 return 0;
363 if (err == -ENOMEM)
364 atomic_inc(&sk->sk_drops);
365 break; 367 break;
366 } 368 }
367 369
@@ -443,6 +445,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
443 struct sockaddr_pn dst; 445 struct sockaddr_pn dst;
444 u16 peer_type; 446 u16 peer_type;
445 u8 pipe_handle, enabled, n_sb; 447 u8 pipe_handle, enabled, n_sb;
448 u8 aligned = 0;
446 449
447 if (!pskb_pull(skb, sizeof(*hdr) + 4)) 450 if (!pskb_pull(skb, sizeof(*hdr) + 4))
448 return -EINVAL; 451 return -EINVAL;
@@ -481,6 +484,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
481 return -EINVAL; 484 return -EINVAL;
482 peer_type = (peer_type & 0xff00) | data[0]; 485 peer_type = (peer_type & 0xff00) | data[0];
483 break; 486 break;
487 case PN_PIPE_SB_ALIGNED_DATA:
488 aligned = data[0] != 0;
489 break;
484 } 490 }
485 n_sb--; 491 n_sb--;
486 } 492 }
@@ -512,6 +518,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
512 newpn->rx_credits = 0; 518 newpn->rx_credits = 0;
513 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 519 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
514 newpn->init_enable = enabled; 520 newpn->init_enable = enabled;
521 newpn->aligned = aligned;
515 522
516 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); 523 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
517 skb_queue_head(&newsk->sk_receive_queue, skb); 524 skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -716,8 +723,8 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
716 return -EINVAL; 723 return -EINVAL;
717 724
718 lock_sock(sk); 725 lock_sock(sk);
719 if (sock_flag(sk, SOCK_URGINLINE) 726 if (sock_flag(sk, SOCK_URGINLINE) &&
720 && !skb_queue_empty(&pn->ctrlreq_queue)) 727 !skb_queue_empty(&pn->ctrlreq_queue))
721 answ = skb_peek(&pn->ctrlreq_queue)->len; 728 answ = skb_peek(&pn->ctrlreq_queue)->len;
722 else if (!skb_queue_empty(&sk->sk_receive_queue)) 729 else if (!skb_queue_empty(&sk->sk_receive_queue))
723 answ = skb_peek(&sk->sk_receive_queue)->len; 730 answ = skb_peek(&sk->sk_receive_queue)->len;
@@ -831,11 +838,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
831 return -ENOBUFS; 838 return -ENOBUFS;
832 } 839 }
833 840
834 skb_push(skb, 3); 841 skb_push(skb, 3 + pn->aligned);
835 skb_reset_transport_header(skb); 842 skb_reset_transport_header(skb);
836 ph = pnp_hdr(skb); 843 ph = pnp_hdr(skb);
837 ph->utid = 0; 844 ph->utid = 0;
838 ph->message_id = PNS_PIPE_DATA; 845 if (pn->aligned) {
846 ph->message_id = PNS_PIPE_ALIGNED_DATA;
847 ph->data[0] = 0; /* padding */
848 } else
849 ph->message_id = PNS_PIPE_DATA;
839 ph->pipe_handle = pn->pipe_handle; 850 ph->pipe_handle = pn->pipe_handle;
840 851
841 return pn_skb_send(sk, skb, &pipe_srv); 852 return pn_skb_send(sk, skb, &pipe_srv);
@@ -845,14 +856,26 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
845 struct msghdr *msg, size_t len) 856 struct msghdr *msg, size_t len)
846{ 857{
847 struct pep_sock *pn = pep_sk(sk); 858 struct pep_sock *pn = pep_sk(sk);
848 struct sk_buff *skb = NULL; 859 struct sk_buff *skb;
849 long timeo; 860 long timeo;
850 int flags = msg->msg_flags; 861 int flags = msg->msg_flags;
851 int err, done; 862 int err, done;
852 863
853 if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR)) 864 if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
865 MSG_CMSG_COMPAT)) ||
866 !(msg->msg_flags & MSG_EOR))
854 return -EOPNOTSUPP; 867 return -EOPNOTSUPP;
855 868
869 skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
870 flags & MSG_DONTWAIT, &err);
871 if (!skb)
872 return -ENOBUFS;
873
874 skb_reserve(skb, MAX_PHONET_HEADER + 3);
875 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
876 if (err < 0)
877 goto outfree;
878
856 lock_sock(sk); 879 lock_sock(sk);
857 timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 880 timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
858 if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { 881 if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) {
@@ -896,28 +919,13 @@ disabled:
896 goto disabled; 919 goto disabled;
897 } 920 }
898 921
899 if (!skb) {
900 skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
901 flags & MSG_DONTWAIT, &err);
902 if (skb == NULL)
903 goto out;
904 skb_reserve(skb, MAX_PHONET_HEADER + 3);
905
906 if (sk->sk_state != TCP_ESTABLISHED ||
907 !atomic_read(&pn->tx_credits))
908 goto disabled; /* sock_alloc_send_skb might sleep */
909 }
910
911 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
912 if (err < 0)
913 goto out;
914
915 err = pipe_skb_send(sk, skb); 922 err = pipe_skb_send(sk, skb);
916 if (err >= 0) 923 if (err >= 0)
917 err = len; /* success! */ 924 err = len; /* success! */
918 skb = NULL; 925 skb = NULL;
919out: 926out:
920 release_sock(sk); 927 release_sock(sk);
928outfree:
921 kfree_skb(skb); 929 kfree_skb(skb);
922 return err; 930 return err;
923} 931}
@@ -934,6 +942,9 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
934 struct sk_buff *rskb, *fs; 942 struct sk_buff *rskb, *fs;
935 int flen = 0; 943 int flen = 0;
936 944
945 if (pep_sk(sk)->aligned)
946 return pipe_skb_send(sk, skb);
947
937 rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 948 rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
938 if (!rskb) { 949 if (!rskb) {
939 kfree_skb(skb); 950 kfree_skb(skb);
@@ -973,6 +984,10 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
973 struct sk_buff *skb; 984 struct sk_buff *skb;
974 int err; 985 int err;
975 986
987 if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL|
988 MSG_NOSIGNAL|MSG_CMSG_COMPAT))
989 return -EOPNOTSUPP;
990
976 if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) 991 if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE)))
977 return -ENOTCONN; 992 return -ENOTCONN;
978 993
@@ -980,6 +995,8 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
980 /* Dequeue and acknowledge control request */ 995 /* Dequeue and acknowledge control request */
981 struct pep_sock *pn = pep_sk(sk); 996 struct pep_sock *pn = pep_sk(sk);
982 997
998 if (flags & MSG_PEEK)
999 return -EOPNOTSUPP;
983 skb = skb_dequeue(&pn->ctrlreq_queue); 1000 skb = skb_dequeue(&pn->ctrlreq_queue);
984 if (skb) { 1001 if (skb) {
985 pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, 1002 pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR,
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 5f42f30dd168..9b4ced6e0968 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -25,6 +25,7 @@
25 25
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/net.h> 27#include <linux/net.h>
28#include <linux/slab.h>
28#include <linux/netdevice.h> 29#include <linux/netdevice.h>
29#include <linux/phonet.h> 30#include <linux/phonet.h>
30#include <linux/proc_fs.h> 31#include <linux/proc_fs.h>
@@ -33,11 +34,17 @@
33#include <net/netns/generic.h> 34#include <net/netns/generic.h>
34#include <net/phonet/pn_dev.h> 35#include <net/phonet/pn_dev.h>
35 36
37struct phonet_routes {
38 struct mutex lock;
39 struct net_device *table[64];
40};
41
36struct phonet_net { 42struct phonet_net {
37 struct phonet_device_list pndevs; 43 struct phonet_device_list pndevs;
44 struct phonet_routes routes;
38}; 45};
39 46
40int phonet_net_id; 47int phonet_net_id __read_mostly;
41 48
42struct phonet_device_list *phonet_device_list(struct net *net) 49struct phonet_device_list *phonet_device_list(struct net *net)
43{ 50{
@@ -55,7 +62,8 @@ static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
55 pnd->netdev = dev; 62 pnd->netdev = dev;
56 bitmap_zero(pnd->addrs, 64); 63 bitmap_zero(pnd->addrs, 64);
57 64
58 list_add(&pnd->list, &pndevs->list); 65 BUG_ON(!mutex_is_locked(&pndevs->lock));
66 list_add_rcu(&pnd->list, &pndevs->list);
59 return pnd; 67 return pnd;
60} 68}
61 69
@@ -64,6 +72,7 @@ static struct phonet_device *__phonet_get(struct net_device *dev)
64 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 72 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
65 struct phonet_device *pnd; 73 struct phonet_device *pnd;
66 74
75 BUG_ON(!mutex_is_locked(&pndevs->lock));
67 list_for_each_entry(pnd, &pndevs->list, list) { 76 list_for_each_entry(pnd, &pndevs->list, list) {
68 if (pnd->netdev == dev) 77 if (pnd->netdev == dev)
69 return pnd; 78 return pnd;
@@ -71,6 +80,18 @@ static struct phonet_device *__phonet_get(struct net_device *dev)
71 return NULL; 80 return NULL;
72} 81}
73 82
83static struct phonet_device *__phonet_get_rcu(struct net_device *dev)
84{
85 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
86 struct phonet_device *pnd;
87
88 list_for_each_entry_rcu(pnd, &pndevs->list, list) {
89 if (pnd->netdev == dev)
90 return pnd;
91 }
92 return NULL;
93}
94
74static void phonet_device_destroy(struct net_device *dev) 95static void phonet_device_destroy(struct net_device *dev)
75{ 96{
76 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); 97 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
@@ -78,17 +99,16 @@ static void phonet_device_destroy(struct net_device *dev)
78 99
79 ASSERT_RTNL(); 100 ASSERT_RTNL();
80 101
81 spin_lock_bh(&pndevs->lock); 102 mutex_lock(&pndevs->lock);
82 pnd = __phonet_get(dev); 103 pnd = __phonet_get(dev);
83 if (pnd) 104 if (pnd)
84 list_del(&pnd->list); 105 list_del_rcu(&pnd->list);
85 spin_unlock_bh(&pndevs->lock); 106 mutex_unlock(&pndevs->lock);
86 107
87 if (pnd) { 108 if (pnd) {
88 u8 addr; 109 u8 addr;
89 110
90 for (addr = find_first_bit(pnd->addrs, 64); addr < 64; 111 for_each_set_bit(addr, pnd->addrs, 64)
91 addr = find_next_bit(pnd->addrs, 64, 1+addr))
92 phonet_address_notify(RTM_DELADDR, dev, addr); 112 phonet_address_notify(RTM_DELADDR, dev, addr);
93 kfree(pnd); 113 kfree(pnd);
94 } 114 }
@@ -100,8 +120,8 @@ struct net_device *phonet_device_get(struct net *net)
100 struct phonet_device *pnd; 120 struct phonet_device *pnd;
101 struct net_device *dev = NULL; 121 struct net_device *dev = NULL;
102 122
103 spin_lock_bh(&pndevs->lock); 123 rcu_read_lock();
104 list_for_each_entry(pnd, &pndevs->list, list) { 124 list_for_each_entry_rcu(pnd, &pndevs->list, list) {
105 dev = pnd->netdev; 125 dev = pnd->netdev;
106 BUG_ON(!dev); 126 BUG_ON(!dev);
107 127
@@ -112,7 +132,7 @@ struct net_device *phonet_device_get(struct net *net)
112 } 132 }
113 if (dev) 133 if (dev)
114 dev_hold(dev); 134 dev_hold(dev);
115 spin_unlock_bh(&pndevs->lock); 135 rcu_read_unlock();
116 return dev; 136 return dev;
117} 137}
118 138
@@ -122,7 +142,7 @@ int phonet_address_add(struct net_device *dev, u8 addr)
122 struct phonet_device *pnd; 142 struct phonet_device *pnd;
123 int err = 0; 143 int err = 0;
124 144
125 spin_lock_bh(&pndevs->lock); 145 mutex_lock(&pndevs->lock);
126 /* Find or create Phonet-specific device data */ 146 /* Find or create Phonet-specific device data */
127 pnd = __phonet_get(dev); 147 pnd = __phonet_get(dev);
128 if (pnd == NULL) 148 if (pnd == NULL)
@@ -131,7 +151,7 @@ int phonet_address_add(struct net_device *dev, u8 addr)
131 err = -ENOMEM; 151 err = -ENOMEM;
132 else if (test_and_set_bit(addr >> 2, pnd->addrs)) 152 else if (test_and_set_bit(addr >> 2, pnd->addrs))
133 err = -EEXIST; 153 err = -EEXIST;
134 spin_unlock_bh(&pndevs->lock); 154 mutex_unlock(&pndevs->lock);
135 return err; 155 return err;
136} 156}
137 157
@@ -141,36 +161,56 @@ int phonet_address_del(struct net_device *dev, u8 addr)
141 struct phonet_device *pnd; 161 struct phonet_device *pnd;
142 int err = 0; 162 int err = 0;
143 163
144 spin_lock_bh(&pndevs->lock); 164 mutex_lock(&pndevs->lock);
145 pnd = __phonet_get(dev); 165 pnd = __phonet_get(dev);
146 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) 166 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) {
147 err = -EADDRNOTAVAIL; 167 err = -EADDRNOTAVAIL;
148 else if (bitmap_empty(pnd->addrs, 64)) { 168 pnd = NULL;
149 list_del(&pnd->list); 169 } else if (bitmap_empty(pnd->addrs, 64))
170 list_del_rcu(&pnd->list);
171 else
172 pnd = NULL;
173 mutex_unlock(&pndevs->lock);
174
175 if (pnd) {
176 synchronize_rcu();
150 kfree(pnd); 177 kfree(pnd);
151 } 178 }
152 spin_unlock_bh(&pndevs->lock);
153 return err; 179 return err;
154} 180}
155 181
156/* Gets a source address toward a destination, through a interface. */ 182/* Gets a source address toward a destination, through a interface. */
157u8 phonet_address_get(struct net_device *dev, u8 addr) 183u8 phonet_address_get(struct net_device *dev, u8 daddr)
158{ 184{
159 struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
160 struct phonet_device *pnd; 185 struct phonet_device *pnd;
186 u8 saddr;
161 187
162 spin_lock_bh(&pndevs->lock); 188 rcu_read_lock();
163 pnd = __phonet_get(dev); 189 pnd = __phonet_get_rcu(dev);
164 if (pnd) { 190 if (pnd) {
165 BUG_ON(bitmap_empty(pnd->addrs, 64)); 191 BUG_ON(bitmap_empty(pnd->addrs, 64));
166 192
167 /* Use same source address as destination, if possible */ 193 /* Use same source address as destination, if possible */
168 if (!test_bit(addr >> 2, pnd->addrs)) 194 if (test_bit(daddr >> 2, pnd->addrs))
169 addr = find_first_bit(pnd->addrs, 64) << 2; 195 saddr = daddr;
196 else
197 saddr = find_first_bit(pnd->addrs, 64) << 2;
170 } else 198 } else
171 addr = PN_NO_ADDR; 199 saddr = PN_NO_ADDR;
172 spin_unlock_bh(&pndevs->lock); 200 rcu_read_unlock();
173 return addr; 201
202 if (saddr == PN_NO_ADDR) {
203 /* Fallback to another device */
204 struct net_device *def_dev;
205
206 def_dev = phonet_device_get(dev_net(dev));
207 if (def_dev) {
208 if (def_dev != dev)
209 saddr = phonet_address_get(def_dev, daddr);
210 dev_put(def_dev);
211 }
212 }
213 return saddr;
174} 214}
175 215
176int phonet_address_lookup(struct net *net, u8 addr) 216int phonet_address_lookup(struct net *net, u8 addr)
@@ -179,8 +219,8 @@ int phonet_address_lookup(struct net *net, u8 addr)
179 struct phonet_device *pnd; 219 struct phonet_device *pnd;
180 int err = -EADDRNOTAVAIL; 220 int err = -EADDRNOTAVAIL;
181 221
182 spin_lock_bh(&pndevs->lock); 222 rcu_read_lock();
183 list_for_each_entry(pnd, &pndevs->list, list) { 223 list_for_each_entry_rcu(pnd, &pndevs->list, list) {
184 /* Don't allow unregistering devices! */ 224 /* Don't allow unregistering devices! */
185 if ((pnd->netdev->reg_state != NETREG_REGISTERED) || 225 if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
186 ((pnd->netdev->flags & IFF_UP)) != IFF_UP) 226 ((pnd->netdev->flags & IFF_UP)) != IFF_UP)
@@ -192,7 +232,7 @@ int phonet_address_lookup(struct net *net, u8 addr)
192 } 232 }
193 } 233 }
194found: 234found:
195 spin_unlock_bh(&pndevs->lock); 235 rcu_read_unlock();
196 return err; 236 return err;
197} 237}
198 238
@@ -219,6 +259,32 @@ static int phonet_device_autoconf(struct net_device *dev)
219 return 0; 259 return 0;
220} 260}
221 261
262static void phonet_route_autodel(struct net_device *dev)
263{
264 struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
265 unsigned i;
266 DECLARE_BITMAP(deleted, 64);
267
268 /* Remove left-over Phonet routes */
269 bitmap_zero(deleted, 64);
270 mutex_lock(&pnn->routes.lock);
271 for (i = 0; i < 64; i++)
272 if (dev == pnn->routes.table[i]) {
273 rcu_assign_pointer(pnn->routes.table[i], NULL);
274 set_bit(i, deleted);
275 }
276 mutex_unlock(&pnn->routes.lock);
277
278 if (bitmap_empty(deleted, 64))
279 return; /* short-circuit RCU */
280 synchronize_rcu();
281 for (i = find_first_bit(deleted, 64); i < 64;
282 i = find_next_bit(deleted, 64, i + 1)) {
283 rtm_phonet_notify(RTM_DELROUTE, dev, i);
284 dev_put(dev);
285 }
286}
287
222/* notify Phonet of device events */ 288/* notify Phonet of device events */
223static int phonet_device_notify(struct notifier_block *me, unsigned long what, 289static int phonet_device_notify(struct notifier_block *me, unsigned long what,
224 void *arg) 290 void *arg)
@@ -232,6 +298,7 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
232 break; 298 break;
233 case NETDEV_UNREGISTER: 299 case NETDEV_UNREGISTER:
234 phonet_device_destroy(dev); 300 phonet_device_destroy(dev);
301 phonet_route_autodel(dev);
235 break; 302 break;
236 } 303 }
237 return 0; 304 return 0;
@@ -244,46 +311,52 @@ static struct notifier_block phonet_device_notifier = {
244}; 311};
245 312
246/* Per-namespace Phonet devices handling */ 313/* Per-namespace Phonet devices handling */
247static int phonet_init_net(struct net *net) 314static int __net_init phonet_init_net(struct net *net)
248{ 315{
249 struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL); 316 struct phonet_net *pnn = net_generic(net, phonet_net_id);
250 if (!pnn)
251 return -ENOMEM;
252 317
253 if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) { 318 if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops))
254 kfree(pnn);
255 return -ENOMEM; 319 return -ENOMEM;
256 }
257 320
258 INIT_LIST_HEAD(&pnn->pndevs.list); 321 INIT_LIST_HEAD(&pnn->pndevs.list);
259 spin_lock_init(&pnn->pndevs.lock); 322 mutex_init(&pnn->pndevs.lock);
260 net_assign_generic(net, phonet_net_id, pnn); 323 mutex_init(&pnn->routes.lock);
261 return 0; 324 return 0;
262} 325}
263 326
264static void phonet_exit_net(struct net *net) 327static void __net_exit phonet_exit_net(struct net *net)
265{ 328{
266 struct phonet_net *pnn = net_generic(net, phonet_net_id); 329 struct phonet_net *pnn = net_generic(net, phonet_net_id);
267 struct net_device *dev; 330 struct net_device *dev;
331 unsigned i;
268 332
269 rtnl_lock(); 333 rtnl_lock();
270 for_each_netdev(net, dev) 334 for_each_netdev(net, dev)
271 phonet_device_destroy(dev); 335 phonet_device_destroy(dev);
336
337 for (i = 0; i < 64; i++) {
338 dev = pnn->routes.table[i];
339 if (dev) {
340 rtm_phonet_notify(RTM_DELROUTE, dev, i);
341 dev_put(dev);
342 }
343 }
272 rtnl_unlock(); 344 rtnl_unlock();
273 345
274 proc_net_remove(net, "phonet"); 346 proc_net_remove(net, "phonet");
275 kfree(pnn);
276} 347}
277 348
278static struct pernet_operations phonet_net_ops = { 349static struct pernet_operations phonet_net_ops = {
279 .init = phonet_init_net, 350 .init = phonet_init_net,
280 .exit = phonet_exit_net, 351 .exit = phonet_exit_net,
352 .id = &phonet_net_id,
353 .size = sizeof(struct phonet_net),
281}; 354};
282 355
283/* Initialize Phonet devices list */ 356/* Initialize Phonet devices list */
284int __init phonet_device_init(void) 357int __init phonet_device_init(void)
285{ 358{
286 int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops); 359 int err = register_pernet_device(&phonet_net_ops);
287 if (err) 360 if (err)
288 return err; 361 return err;
289 362
@@ -298,5 +371,75 @@ void phonet_device_exit(void)
298{ 371{
299 rtnl_unregister_all(PF_PHONET); 372 rtnl_unregister_all(PF_PHONET);
300 unregister_netdevice_notifier(&phonet_device_notifier); 373 unregister_netdevice_notifier(&phonet_device_notifier);
301 unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); 374 unregister_pernet_device(&phonet_net_ops);
375}
376
377int phonet_route_add(struct net_device *dev, u8 daddr)
378{
379 struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
380 struct phonet_routes *routes = &pnn->routes;
381 int err = -EEXIST;
382
383 daddr = daddr >> 2;
384 mutex_lock(&routes->lock);
385 if (routes->table[daddr] == NULL) {
386 rcu_assign_pointer(routes->table[daddr], dev);
387 dev_hold(dev);
388 err = 0;
389 }
390 mutex_unlock(&routes->lock);
391 return err;
392}
393
394int phonet_route_del(struct net_device *dev, u8 daddr)
395{
396 struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
397 struct phonet_routes *routes = &pnn->routes;
398
399 daddr = daddr >> 2;
400 mutex_lock(&routes->lock);
401 if (dev == routes->table[daddr])
402 rcu_assign_pointer(routes->table[daddr], NULL);
403 else
404 dev = NULL;
405 mutex_unlock(&routes->lock);
406
407 if (!dev)
408 return -ENOENT;
409 synchronize_rcu();
410 dev_put(dev);
411 return 0;
412}
413
414struct net_device *phonet_route_get(struct net *net, u8 daddr)
415{
416 struct phonet_net *pnn = net_generic(net, phonet_net_id);
417 struct phonet_routes *routes = &pnn->routes;
418 struct net_device *dev;
419
420 ASSERT_RTNL(); /* no need to hold the device */
421
422 daddr >>= 2;
423 rcu_read_lock();
424 dev = rcu_dereference(routes->table[daddr]);
425 rcu_read_unlock();
426 return dev;
427}
428
429struct net_device *phonet_route_output(struct net *net, u8 daddr)
430{
431 struct phonet_net *pnn = net_generic(net, phonet_net_id);
432 struct phonet_routes *routes = &pnn->routes;
433 struct net_device *dev;
434
435 daddr >>= 2;
436 rcu_read_lock();
437 dev = rcu_dereference(routes->table[daddr]);
438 if (dev)
439 dev_hold(dev);
440 rcu_read_unlock();
441
442 if (!dev)
443 dev = phonet_device_get(net); /* Default route */
444 return dev;
302} 445}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index d21fd3576610..58b3b1f991ed 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -26,9 +26,12 @@
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/netlink.h> 27#include <linux/netlink.h>
28#include <linux/phonet.h> 28#include <linux/phonet.h>
29#include <linux/slab.h>
29#include <net/sock.h> 30#include <net/sock.h>
30#include <net/phonet/pn_dev.h> 31#include <net/phonet/pn_dev.h>
31 32
33/* Device address handling */
34
32static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr, 35static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
33 u32 pid, u32 seq, int event); 36 u32 pid, u32 seq, int event);
34 37
@@ -51,8 +54,7 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr)
51 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL); 54 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
52 return; 55 return;
53errout: 56errout:
54 if (err < 0) 57 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
55 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
56} 58}
57 59
58static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = { 60static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = {
@@ -130,8 +132,8 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
130 int addr_idx = 0, addr_start_idx = cb->args[1]; 132 int addr_idx = 0, addr_start_idx = cb->args[1];
131 133
132 pndevs = phonet_device_list(sock_net(skb->sk)); 134 pndevs = phonet_device_list(sock_net(skb->sk));
133 spin_lock_bh(&pndevs->lock); 135 rcu_read_lock();
134 list_for_each_entry(pnd, &pndevs->list, list) { 136 list_for_each_entry_rcu(pnd, &pndevs->list, list) {
135 u8 addr; 137 u8 addr;
136 138
137 if (dev_idx > dev_start_idx) 139 if (dev_idx > dev_start_idx)
@@ -140,8 +142,7 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
140 continue; 142 continue;
141 143
142 addr_idx = 0; 144 addr_idx = 0;
143 for (addr = find_first_bit(pnd->addrs, 64); addr < 64; 145 for_each_set_bit(addr, pnd->addrs, 64) {
144 addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
145 if (addr_idx++ < addr_start_idx) 146 if (addr_idx++ < addr_start_idx)
146 continue; 147 continue;
147 148
@@ -153,13 +154,137 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
153 } 154 }
154 155
155out: 156out:
156 spin_unlock_bh(&pndevs->lock); 157 rcu_read_unlock();
157 cb->args[0] = dev_idx; 158 cb->args[0] = dev_idx;
158 cb->args[1] = addr_idx; 159 cb->args[1] = addr_idx;
159 160
160 return skb->len; 161 return skb->len;
161} 162}
162 163
164/* Routes handling */
165
166static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst,
167 u32 pid, u32 seq, int event)
168{
169 struct rtmsg *rtm;
170 struct nlmsghdr *nlh;
171
172 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), 0);
173 if (nlh == NULL)
174 return -EMSGSIZE;
175
176 rtm = nlmsg_data(nlh);
177 rtm->rtm_family = AF_PHONET;
178 rtm->rtm_dst_len = 6;
179 rtm->rtm_src_len = 0;
180 rtm->rtm_tos = 0;
181 rtm->rtm_table = RT_TABLE_MAIN;
182 rtm->rtm_protocol = RTPROT_STATIC;
183 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
184 rtm->rtm_type = RTN_UNICAST;
185 rtm->rtm_flags = 0;
186 NLA_PUT_U8(skb, RTA_DST, dst);
187 NLA_PUT_U32(skb, RTA_OIF, dev->ifindex);
188 return nlmsg_end(skb, nlh);
189
190nla_put_failure:
191 nlmsg_cancel(skb, nlh);
192 return -EMSGSIZE;
193}
194
195void rtm_phonet_notify(int event, struct net_device *dev, u8 dst)
196{
197 struct sk_buff *skb;
198 int err = -ENOBUFS;
199
200 skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
201 nla_total_size(1) + nla_total_size(4), GFP_KERNEL);
202 if (skb == NULL)
203 goto errout;
204 err = fill_route(skb, dev, dst, 0, 0, event);
205 if (err < 0) {
206 WARN_ON(err == -EMSGSIZE);
207 kfree_skb(skb);
208 goto errout;
209 }
210 rtnl_notify(skb, dev_net(dev), 0,
211 RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL);
212 return;
213errout:
214 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err);
215}
216
217static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = {
218 [RTA_DST] = { .type = NLA_U8 },
219 [RTA_OIF] = { .type = NLA_U32 },
220};
221
222static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
223{
224 struct net *net = sock_net(skb->sk);
225 struct nlattr *tb[RTA_MAX+1];
226 struct net_device *dev;
227 struct rtmsg *rtm;
228 int err;
229 u8 dst;
230
231 if (!capable(CAP_SYS_ADMIN))
232 return -EPERM;
233
234 ASSERT_RTNL();
235
236 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_phonet_policy);
237 if (err < 0)
238 return err;
239
240 rtm = nlmsg_data(nlh);
241 if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_type != RTN_UNICAST)
242 return -EINVAL;
243 if (tb[RTA_DST] == NULL || tb[RTA_OIF] == NULL)
244 return -EINVAL;
245 dst = nla_get_u8(tb[RTA_DST]);
246 if (dst & 3) /* Phonet addresses only have 6 high-order bits */
247 return -EINVAL;
248
249 dev = __dev_get_by_index(net, nla_get_u32(tb[RTA_OIF]));
250 if (dev == NULL)
251 return -ENODEV;
252
253 if (nlh->nlmsg_type == RTM_NEWROUTE)
254 err = phonet_route_add(dev, dst);
255 else
256 err = phonet_route_del(dev, dst);
257 if (!err)
258 rtm_phonet_notify(nlh->nlmsg_type, dev, dst);
259 return err;
260}
261
262static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
263{
264 struct net *net = sock_net(skb->sk);
265 u8 addr, addr_idx = 0, addr_start_idx = cb->args[0];
266
267 for (addr = 0; addr < 64; addr++) {
268 struct net_device *dev;
269
270 dev = phonet_route_get(net, addr << 2);
271 if (!dev)
272 continue;
273
274 if (addr_idx++ < addr_start_idx)
275 continue;
276 if (fill_route(skb, dev, addr << 2, NETLINK_CB(cb->skb).pid,
277 cb->nlh->nlmsg_seq, RTM_NEWROUTE))
278 goto out;
279 }
280
281out:
282 cb->args[0] = addr_idx;
283 cb->args[1] = 0;
284
285 return skb->len;
286}
287
163int __init phonet_netlink_register(void) 288int __init phonet_netlink_register(void)
164{ 289{
165 int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL); 290 int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
@@ -169,5 +294,8 @@ int __init phonet_netlink_register(void)
169 /* Further __rtnl_register() cannot fail */ 294 /* Further __rtnl_register() cannot fail */
170 __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL); 295 __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
171 __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit); 296 __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
297 __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL);
298 __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL);
299 __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit);
172 return 0; 300 return 0;
173} 301}
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index aa5b5a972bff..c785bfd0744f 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -23,6 +23,7 @@
23 * 02110-1301 USA 23 * 02110-1301 USA
24 */ 24 */
25 25
26#include <linux/gfp.h>
26#include <linux/kernel.h> 27#include <linux/kernel.h>
27#include <linux/net.h> 28#include <linux/net.h>
28#include <linux/poll.h> 29#include <linux/poll.h>
@@ -45,13 +46,28 @@ static int pn_socket_release(struct socket *sock)
45 return 0; 46 return 0;
46} 47}
47 48
49#define PN_HASHSIZE 16
50#define PN_HASHMASK (PN_HASHSIZE-1)
51
52
48static struct { 53static struct {
49 struct hlist_head hlist; 54 struct hlist_head hlist[PN_HASHSIZE];
50 spinlock_t lock; 55 spinlock_t lock;
51} pnsocks = { 56} pnsocks;
52 .hlist = HLIST_HEAD_INIT, 57
53 .lock = __SPIN_LOCK_UNLOCKED(pnsocks.lock), 58void __init pn_sock_init(void)
54}; 59{
60 unsigned i;
61
62 for (i = 0; i < PN_HASHSIZE; i++)
63 INIT_HLIST_HEAD(pnsocks.hlist + i);
64 spin_lock_init(&pnsocks.lock);
65}
66
67static struct hlist_head *pn_hash_list(u16 obj)
68{
69 return pnsocks.hlist + (obj & PN_HASHMASK);
70}
55 71
56/* 72/*
57 * Find address based on socket address, match only certain fields. 73 * Find address based on socket address, match only certain fields.
@@ -64,10 +80,11 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
64 struct sock *rval = NULL; 80 struct sock *rval = NULL;
65 u16 obj = pn_sockaddr_get_object(spn); 81 u16 obj = pn_sockaddr_get_object(spn);
66 u8 res = spn->spn_resource; 82 u8 res = spn->spn_resource;
83 struct hlist_head *hlist = pn_hash_list(obj);
67 84
68 spin_lock_bh(&pnsocks.lock); 85 spin_lock_bh(&pnsocks.lock);
69 86
70 sk_for_each(sknode, node, &pnsocks.hlist) { 87 sk_for_each(sknode, node, hlist) {
71 struct pn_sock *pn = pn_sk(sknode); 88 struct pn_sock *pn = pn_sk(sknode);
72 BUG_ON(!pn->sobject); /* unbound socket */ 89 BUG_ON(!pn->sobject); /* unbound socket */
73 90
@@ -82,8 +99,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
82 if (pn->resource != res) 99 if (pn->resource != res)
83 continue; 100 continue;
84 } 101 }
85 if (pn_addr(pn->sobject) 102 if (pn_addr(pn->sobject) &&
86 && pn_addr(pn->sobject) != pn_addr(obj)) 103 pn_addr(pn->sobject) != pn_addr(obj))
87 continue; 104 continue;
88 105
89 rval = sknode; 106 rval = sknode;
@@ -94,13 +111,44 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
94 spin_unlock_bh(&pnsocks.lock); 111 spin_unlock_bh(&pnsocks.lock);
95 112
96 return rval; 113 return rval;
114}
115
116/* Deliver a broadcast packet (only in bottom-half) */
117void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
118{
119 struct hlist_head *hlist = pnsocks.hlist;
120 unsigned h;
121
122 spin_lock(&pnsocks.lock);
123 for (h = 0; h < PN_HASHSIZE; h++) {
124 struct hlist_node *node;
125 struct sock *sknode;
126
127 sk_for_each(sknode, node, hlist) {
128 struct sk_buff *clone;
129
130 if (!net_eq(sock_net(sknode), net))
131 continue;
132 if (!sock_flag(sknode, SOCK_BROADCAST))
133 continue;
97 134
135 clone = skb_clone(skb, GFP_ATOMIC);
136 if (clone) {
137 sock_hold(sknode);
138 sk_receive_skb(sknode, clone, 0);
139 }
140 }
141 hlist++;
142 }
143 spin_unlock(&pnsocks.lock);
98} 144}
99 145
100void pn_sock_hash(struct sock *sk) 146void pn_sock_hash(struct sock *sk)
101{ 147{
148 struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
149
102 spin_lock_bh(&pnsocks.lock); 150 spin_lock_bh(&pnsocks.lock);
103 sk_add_node(sk, &pnsocks.hlist); 151 sk_add_node(sk, hlist);
104 spin_unlock_bh(&pnsocks.lock); 152 spin_unlock_bh(&pnsocks.lock);
105} 153}
106EXPORT_SYMBOL(pn_sock_hash); 154EXPORT_SYMBOL(pn_sock_hash);
@@ -416,15 +464,20 @@ EXPORT_SYMBOL(pn_sock_get_port);
416static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) 464static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
417{ 465{
418 struct net *net = seq_file_net(seq); 466 struct net *net = seq_file_net(seq);
467 struct hlist_head *hlist = pnsocks.hlist;
419 struct hlist_node *node; 468 struct hlist_node *node;
420 struct sock *sknode; 469 struct sock *sknode;
470 unsigned h;
421 471
422 sk_for_each(sknode, node, &pnsocks.hlist) { 472 for (h = 0; h < PN_HASHSIZE; h++) {
423 if (!net_eq(net, sock_net(sknode))) 473 sk_for_each(sknode, node, hlist) {
424 continue; 474 if (!net_eq(net, sock_net(sknode)))
425 if (!pos) 475 continue;
426 return sknode; 476 if (!pos)
427 pos--; 477 return sknode;
478 pos--;
479 }
480 hlist++;
428 } 481 }
429 return NULL; 482 return NULL;
430} 483}
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
index 2220f3322326..cea1c7dbdae2 100644
--- a/net/phonet/sysctl.c
+++ b/net/phonet/sysctl.c
@@ -84,20 +84,18 @@ static int proc_local_port_range(ctl_table *table, int write,
84 84
85static struct ctl_table phonet_table[] = { 85static struct ctl_table phonet_table[] = {
86 { 86 {
87 .ctl_name = CTL_UNNUMBERED,
88 .procname = "local_port_range", 87 .procname = "local_port_range",
89 .data = &local_port_range, 88 .data = &local_port_range,
90 .maxlen = sizeof(local_port_range), 89 .maxlen = sizeof(local_port_range),
91 .mode = 0644, 90 .mode = 0644,
92 .proc_handler = proc_local_port_range, 91 .proc_handler = proc_local_port_range,
93 .strategy = NULL,
94 }, 92 },
95 { .ctl_name = 0 } 93 { }
96}; 94};
97 95
98static struct ctl_path phonet_ctl_path[] = { 96static struct ctl_path phonet_ctl_path[] = {
99 { .procname = "net", .ctl_name = CTL_NET, }, 97 { .procname = "net", },
100 { .procname = "phonet", .ctl_name = CTL_UNNUMBERED, }, 98 { .procname = "phonet", },
101 { }, 99 { },
102}; 100};
103 101