aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/pep.c
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2011-03-08 17:44:10 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-09 14:59:32 -0500
commitf7ae8d59f66154df0424fd94035c89981fed3379 (patch)
tree829e2a3e2188a30b48afbd200675bf8d0a21cb0d /net/phonet/pep.c
parent44c9ab16d29a50af6ed9ae084b75774570de512a (diff)
Phonet: allocate sock from accept syscall rather than soft IRQ
This moves most of the accept logic to process context like other socket stacks do. Then we can use a few more common socket helpers and simplify a bit. Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r--net/phonet/pep.c284
1 files changed, 117 insertions, 167 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 610794a416e..c0fab4cfcef 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -42,7 +42,7 @@
42 * TCP_ESTABLISHED connected pipe in enabled state 42 * TCP_ESTABLISHED connected pipe in enabled state
43 * 43 *
44 * pep_sock locking: 44 * pep_sock locking:
45 * - sk_state, ackq, hlist: sock lock needed 45 * - sk_state, hlist: sock lock needed
46 * - listener: read only 46 * - listener: read only
47 * - pipe_handle: read only 47 * - pipe_handle: read only
48 */ 48 */
@@ -202,11 +202,12 @@ static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
202 GFP_KERNEL); 202 GFP_KERNEL);
203} 203}
204 204
205static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code) 205static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code,
206 gfp_t priority)
206{ 207{
207 static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; 208 static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ };
208 WARN_ON(code == PN_PIPE_NO_ERROR); 209 WARN_ON(code == PN_PIPE_NO_ERROR);
209 return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC); 210 return pep_reply(sk, skb, code, data, sizeof(data), priority);
210} 211}
211 212
212/* Control requests are not sent by the pipe service and have a specific 213/* Control requests are not sent by the pipe service and have a specific
@@ -365,7 +366,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
365 366
366 switch (hdr->message_id) { 367 switch (hdr->message_id) {
367 case PNS_PEP_CONNECT_REQ: 368 case PNS_PEP_CONNECT_REQ:
368 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 369 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_ATOMIC);
369 break; 370 break;
370 371
371 case PNS_PEP_DISCONNECT_REQ: 372 case PNS_PEP_DISCONNECT_REQ:
@@ -574,7 +575,6 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
574 575
575 sk->sk_state = TCP_SYN_RECV; 576 sk->sk_state = TCP_SYN_RECV;
576 sk->sk_backlog_rcv = pipe_do_rcv; 577 sk->sk_backlog_rcv = pipe_do_rcv;
577 sk->sk_destruct = pipe_destruct;
578 pn->rx_credits = 0; 578 pn->rx_credits = 0;
579 sk->sk_state_change(sk); 579 sk->sk_state_change(sk);
580 580
@@ -582,96 +582,6 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
582} 582}
583#endif 583#endif
584 584
585static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
586{
587 struct sock *newsk;
588 struct pep_sock *newpn, *pn = pep_sk(sk);
589 struct pnpipehdr *hdr;
590 struct sockaddr_pn dst, src;
591 u16 peer_type;
592 u8 pipe_handle, enabled, n_sb;
593 u8 aligned = 0;
594
595 if (!pskb_pull(skb, sizeof(*hdr) + 4))
596 return -EINVAL;
597
598 hdr = pnp_hdr(skb);
599 pipe_handle = hdr->pipe_handle;
600 switch (hdr->state_after_connect) {
601 case PN_PIPE_DISABLE:
602 enabled = 0;
603 break;
604 case PN_PIPE_ENABLE:
605 enabled = 1;
606 break;
607 default:
608 pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM);
609 return -EINVAL;
610 }
611 peer_type = hdr->other_pep_type << 8;
612
613 /* Parse sub-blocks (options) */
614 n_sb = hdr->data[4];
615 while (n_sb > 0) {
616 u8 type, buf[1], len = sizeof(buf);
617 const u8 *data = pep_get_sb(skb, &type, &len, buf);
618
619 if (data == NULL)
620 return -EINVAL;
621 switch (type) {
622 case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
623 if (len < 1)
624 return -EINVAL;
625 peer_type = (peer_type & 0xff00) | data[0];
626 break;
627 case PN_PIPE_SB_ALIGNED_DATA:
628 aligned = data[0] != 0;
629 break;
630 }
631 n_sb--;
632 }
633
634 skb = skb_clone(skb, GFP_ATOMIC);
635 if (!skb)
636 return -ENOMEM;
637
638 /* Create a new to-be-accepted sock */
639 newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot);
640 if (!newsk) {
641 kfree_skb(skb);
642 return -ENOMEM;
643 }
644 sock_init_data(NULL, newsk);
645 newsk->sk_state = TCP_SYN_RECV;
646 newsk->sk_backlog_rcv = pipe_do_rcv;
647 newsk->sk_protocol = sk->sk_protocol;
648 newsk->sk_destruct = pipe_destruct;
649
650 newpn = pep_sk(newsk);
651 pn_skb_get_dst_sockaddr(skb, &dst);
652 pn_skb_get_src_sockaddr(skb, &src);
653 newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
654 newpn->pn_sk.dobject = pn_sockaddr_get_object(&src);
655 newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst);
656 skb_queue_head_init(&newpn->ctrlreq_queue);
657 newpn->pipe_handle = pipe_handle;
658 atomic_set(&newpn->tx_credits, 0);
659 newpn->peer_type = peer_type;
660 newpn->rx_credits = 0;
661 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
662 newpn->init_enable = enabled;
663 newpn->aligned = aligned;
664
665 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
666 skb_queue_head(&newsk->sk_receive_queue, skb);
667 if (!sock_flag(sk, SOCK_DEAD))
668 sk->sk_data_ready(sk, 0);
669
670 sk_acceptq_added(sk);
671 sk_add_node(newsk, &pn->ackq);
672 return 0;
673}
674
675/* Listening sock must be locked */ 585/* Listening sock must be locked */
676static struct sock *pep_find_pipe(const struct hlist_head *hlist, 586static struct sock *pep_find_pipe(const struct hlist_head *hlist,
677 const struct sockaddr_pn *dst, 587 const struct sockaddr_pn *dst,
@@ -726,22 +636,18 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
726 if (sknode) 636 if (sknode)
727 return sk_receive_skb(sknode, skb, 1); 637 return sk_receive_skb(sknode, skb, 1);
728 638
729 /* Look for a pipe handle pending accept */
730 sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle);
731 if (sknode) {
732 sock_put(sknode);
733 if (net_ratelimit())
734 printk(KERN_WARNING"Phonet unconnected PEP ignored");
735 goto drop;
736 }
737
738 switch (hdr->message_id) { 639 switch (hdr->message_id) {
739 case PNS_PEP_CONNECT_REQ: 640 case PNS_PEP_CONNECT_REQ:
740 if (sk->sk_state == TCP_LISTEN && !sk_acceptq_is_full(sk)) 641 if (sk->sk_state != TCP_LISTEN || sk_acceptq_is_full(sk)) {
741 pep_connreq_rcv(sk, skb); 642 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE,
742 else 643 GFP_ATOMIC);
743 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 644 break;
744 break; 645 }
646 skb_queue_head(&sk->sk_receive_queue, skb);
647 sk_acceptq_added(sk);
648 if (!sock_flag(sk, SOCK_DEAD))
649 sk->sk_data_ready(sk, 0);
650 return NET_RX_SUCCESS;
745 651
746#ifdef CONFIG_PHONET_PIPECTRLR 652#ifdef CONFIG_PHONET_PIPECTRLR
747 case PNS_PEP_CONNECT_RESP: 653 case PNS_PEP_CONNECT_RESP:
@@ -799,24 +705,16 @@ static void pep_sock_close(struct sock *sk, long timeout)
799 sk_common_release(sk); 705 sk_common_release(sk);
800 706
801 lock_sock(sk); 707 lock_sock(sk);
802 if (sk->sk_state == TCP_LISTEN) { 708 if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) {
803 /* Destroy the listen queue */
804 struct sock *sknode;
805 struct hlist_node *p, *n;
806
807 sk_for_each_safe(sknode, p, n, &pn->ackq)
808 sk_del_node_init(sknode);
809 sk->sk_state = TCP_CLOSE;
810 } else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) {
811#ifndef CONFIG_PHONET_PIPECTRLR 709#ifndef CONFIG_PHONET_PIPECTRLR
812 /* Forcefully remove dangling Phonet pipe */ 710 /* Forcefully remove dangling Phonet pipe */
813 pipe_do_remove(sk); 711 pipe_do_remove(sk);
814#else 712#else
815 /* send pep disconnect request */ 713 /* send pep disconnect request */
816 pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, NULL, 0); 714 pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, NULL, 0);
817 sk->sk_state = TCP_CLOSE;
818#endif 715#endif
819 } 716 }
717 sk->sk_state = TCP_CLOSE;
820 718
821 ifindex = pn->ifindex; 719 ifindex = pn->ifindex;
822 pn->ifindex = 0; 720 pn->ifindex = 0;
@@ -827,69 +725,121 @@ static void pep_sock_close(struct sock *sk, long timeout)
827 sock_put(sk); 725 sock_put(sk);
828} 726}
829 727
830static int pep_wait_connreq(struct sock *sk, int noblock) 728static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
831{ 729{
832 struct task_struct *tsk = current; 730 struct pep_sock *pn = pep_sk(sk), *newpn;
833 struct pep_sock *pn = pep_sk(sk); 731 struct sock *newsk = NULL;
834 long timeo = sock_rcvtimeo(sk, noblock); 732 struct sk_buff *skb;
835 733 struct pnpipehdr *hdr;
836 for (;;) { 734 struct sockaddr_pn dst, src;
837 DEFINE_WAIT(wait); 735 int err;
736 u16 peer_type;
737 u8 pipe_handle, enabled, n_sb;
738 u8 aligned = 0;
838 739
839 if (sk->sk_state != TCP_LISTEN) 740 skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp);
840 return -EINVAL; 741 if (!skb)
841 if (!hlist_empty(&pn->ackq)) 742 return NULL;
842 break;
843 if (!timeo)
844 return -EWOULDBLOCK;
845 if (signal_pending(tsk))
846 return sock_intr_errno(timeo);
847 743
848 prepare_to_wait_exclusive(sk_sleep(sk), &wait, 744 lock_sock(sk);
849 TASK_INTERRUPTIBLE); 745 if (sk->sk_state != TCP_LISTEN) {
850 release_sock(sk); 746 err = -EINVAL;
851 timeo = schedule_timeout(timeo); 747 goto drop;
852 lock_sock(sk);
853 finish_wait(sk_sleep(sk), &wait);
854 } 748 }
749 sk_acceptq_removed(sk);
855 750
856 return 0; 751 err = -EPROTO;
857} 752 if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
753 goto drop;
858 754
859static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) 755 hdr = pnp_hdr(skb);
860{ 756 pipe_handle = hdr->pipe_handle;
861 struct pep_sock *pn = pep_sk(sk); 757 switch (hdr->state_after_connect) {
862 struct sock *newsk = NULL; 758 case PN_PIPE_DISABLE:
863 struct sk_buff *oskb; 759 enabled = 0;
864 int err; 760 break;
761 case PN_PIPE_ENABLE:
762 enabled = 1;
763 break;
764 default:
765 pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM,
766 GFP_KERNEL);
767 goto drop;
768 }
769 peer_type = hdr->other_pep_type << 8;
865 770
866 lock_sock(sk); 771 /* Parse sub-blocks (options) */
867 err = pep_wait_connreq(sk, flags & O_NONBLOCK); 772 n_sb = hdr->data[4];
868 if (err) 773 while (n_sb > 0) {
869 goto out; 774 u8 type, buf[1], len = sizeof(buf);
775 const u8 *data = pep_get_sb(skb, &type, &len, buf);
870 776
871 newsk = __sk_head(&pn->ackq); 777 if (data == NULL)
778 goto drop;
779 switch (type) {
780 case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
781 if (len < 1)
782 goto drop;
783 peer_type = (peer_type & 0xff00) | data[0];
784 break;
785 case PN_PIPE_SB_ALIGNED_DATA:
786 aligned = data[0] != 0;
787 break;
788 }
789 n_sb--;
790 }
872 791
873 oskb = skb_dequeue(&newsk->sk_receive_queue); 792 /* Check for duplicate pipe handle */
874 err = pep_accept_conn(newsk, oskb); 793 newsk = pep_find_pipe(&pn->hlist, &dst, pipe_handle);
875 if (err) { 794 if (unlikely(newsk)) {
876 skb_queue_head(&newsk->sk_receive_queue, oskb); 795 __sock_put(newsk);
877 newsk = NULL; 796 newsk = NULL;
878 goto out; 797 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_KERNEL);
798 goto drop;
799 }
800
801 /* Create a new to-be-accepted sock */
802 newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot);
803 if (!newsk) {
804 pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL);
805 err = -ENOBUFS;
806 goto drop;
879 } 807 }
880 kfree_skb(oskb);
881 808
809 sock_init_data(NULL, newsk);
810 newsk->sk_state = TCP_SYN_RECV;
811 newsk->sk_backlog_rcv = pipe_do_rcv;
812 newsk->sk_protocol = sk->sk_protocol;
813 newsk->sk_destruct = pipe_destruct;
814
815 newpn = pep_sk(newsk);
816 pn_skb_get_dst_sockaddr(skb, &dst);
817 pn_skb_get_src_sockaddr(skb, &src);
818 newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
819 newpn->pn_sk.dobject = pn_sockaddr_get_object(&src);
820 newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst);
882 sock_hold(sk); 821 sock_hold(sk);
883 pep_sk(newsk)->listener = sk; 822 newpn->listener = sk;
823 skb_queue_head_init(&newpn->ctrlreq_queue);
824 newpn->pipe_handle = pipe_handle;
825 atomic_set(&newpn->tx_credits, 0);
826 newpn->ifindex = 0;
827 newpn->peer_type = peer_type;
828 newpn->rx_credits = 0;
829 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
830 newpn->init_enable = enabled;
831 newpn->aligned = aligned;
884 832
885 sock_hold(newsk); 833 err = pep_accept_conn(newsk, skb);
886 sk_del_node_init(newsk); 834 if (err) {
887 sk_acceptq_removed(sk); 835 sock_put(newsk);
836 newsk = NULL;
837 goto drop;
838 }
888 sk_add_node(newsk, &pn->hlist); 839 sk_add_node(newsk, &pn->hlist);
889 __sock_put(newsk); 840drop:
890
891out:
892 release_sock(sk); 841 release_sock(sk);
842 kfree_skb(skb);
893 *errp = err; 843 *errp = err;
894 return newsk; 844 return newsk;
895} 845}
@@ -937,7 +887,7 @@ static int pep_init(struct sock *sk)
937{ 887{
938 struct pep_sock *pn = pep_sk(sk); 888 struct pep_sock *pn = pep_sk(sk);
939 889
940 INIT_HLIST_HEAD(&pn->ackq); 890 sk->sk_destruct = pipe_destruct;
941 INIT_HLIST_HEAD(&pn->hlist); 891 INIT_HLIST_HEAD(&pn->hlist);
942 skb_queue_head_init(&pn->ctrlreq_queue); 892 skb_queue_head_init(&pn->ctrlreq_queue);
943 pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 893 pn->pipe_handle = PN_PIPE_INVALID_HANDLE;