diff options
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r-- | net/phonet/pep.c | 161 |
1 files changed, 150 insertions, 11 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index d564d07cb797..bc6d50f83249 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/phonet.h> | 31 | #include <linux/phonet.h> |
32 | #include <net/phonet/phonet.h> | 32 | #include <net/phonet/phonet.h> |
33 | #include <net/phonet/pep.h> | 33 | #include <net/phonet/pep.h> |
34 | #include <net/phonet/gprs.h> | ||
34 | 35 | ||
35 | /* sk_state values: | 36 | /* sk_state values: |
36 | * TCP_CLOSE sock not in use yet | 37 | * TCP_CLOSE sock not in use yet |
@@ -612,6 +613,7 @@ drop: | |||
612 | static void pep_sock_close(struct sock *sk, long timeout) | 613 | static void pep_sock_close(struct sock *sk, long timeout) |
613 | { | 614 | { |
614 | struct pep_sock *pn = pep_sk(sk); | 615 | struct pep_sock *pn = pep_sk(sk); |
616 | int ifindex = 0; | ||
615 | 617 | ||
616 | sk_common_release(sk); | 618 | sk_common_release(sk); |
617 | 619 | ||
@@ -625,7 +627,12 @@ static void pep_sock_close(struct sock *sk, long timeout) | |||
625 | sk_del_node_init(sknode); | 627 | sk_del_node_init(sknode); |
626 | sk->sk_state = TCP_CLOSE; | 628 | sk->sk_state = TCP_CLOSE; |
627 | } | 629 | } |
630 | ifindex = pn->ifindex; | ||
631 | pn->ifindex = 0; | ||
628 | release_sock(sk); | 632 | release_sock(sk); |
633 | |||
634 | if (ifindex) | ||
635 | gprs_detach(sk); | ||
629 | } | 636 | } |
630 | 637 | ||
631 | static int pep_wait_connreq(struct sock *sk, int noblock) | 638 | static int pep_wait_connreq(struct sock *sk, int noblock) |
@@ -730,12 +737,107 @@ static int pep_init(struct sock *sk) | |||
730 | return 0; | 737 | return 0; |
731 | } | 738 | } |
732 | 739 | ||
740 | static int pep_setsockopt(struct sock *sk, int level, int optname, | ||
741 | char __user *optval, int optlen) | ||
742 | { | ||
743 | struct pep_sock *pn = pep_sk(sk); | ||
744 | int val = 0, err = 0; | ||
745 | |||
746 | if (level != SOL_PNPIPE) | ||
747 | return -ENOPROTOOPT; | ||
748 | if (optlen >= sizeof(int)) { | ||
749 | if (get_user(val, (int __user *) optval)) | ||
750 | return -EFAULT; | ||
751 | } | ||
752 | |||
753 | lock_sock(sk); | ||
754 | switch (optname) { | ||
755 | case PNPIPE_ENCAP: | ||
756 | if (val && val != PNPIPE_ENCAP_IP) { | ||
757 | err = -EINVAL; | ||
758 | break; | ||
759 | } | ||
760 | if (!pn->ifindex == !val) | ||
761 | break; /* Nothing to do! */ | ||
762 | if (!capable(CAP_NET_ADMIN)) { | ||
763 | err = -EPERM; | ||
764 | break; | ||
765 | } | ||
766 | if (val) { | ||
767 | release_sock(sk); | ||
768 | err = gprs_attach(sk); | ||
769 | if (err > 0) { | ||
770 | pn->ifindex = err; | ||
771 | err = 0; | ||
772 | } | ||
773 | } else { | ||
774 | pn->ifindex = 0; | ||
775 | release_sock(sk); | ||
776 | gprs_detach(sk); | ||
777 | err = 0; | ||
778 | } | ||
779 | goto out_norel; | ||
780 | default: | ||
781 | err = -ENOPROTOOPT; | ||
782 | } | ||
783 | release_sock(sk); | ||
784 | |||
785 | out_norel: | ||
786 | return err; | ||
787 | } | ||
788 | |||
789 | static int pep_getsockopt(struct sock *sk, int level, int optname, | ||
790 | char __user *optval, int __user *optlen) | ||
791 | { | ||
792 | struct pep_sock *pn = pep_sk(sk); | ||
793 | int len, val; | ||
794 | |||
795 | if (level != SOL_PNPIPE) | ||
796 | return -ENOPROTOOPT; | ||
797 | if (get_user(len, optlen)) | ||
798 | return -EFAULT; | ||
799 | |||
800 | switch (optname) { | ||
801 | case PNPIPE_ENCAP: | ||
802 | val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; | ||
803 | break; | ||
804 | case PNPIPE_IFINDEX: | ||
805 | val = pn->ifindex; | ||
806 | break; | ||
807 | default: | ||
808 | return -ENOPROTOOPT; | ||
809 | } | ||
810 | |||
811 | len = min_t(unsigned int, sizeof(int), len); | ||
812 | if (put_user(len, optlen)) | ||
813 | return -EFAULT; | ||
814 | if (put_user(val, (int __user *) optval)) | ||
815 | return -EFAULT; | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | ||
820 | { | ||
821 | struct pep_sock *pn = pep_sk(sk); | ||
822 | struct pnpipehdr *ph; | ||
823 | |||
824 | skb_push(skb, 3); | ||
825 | skb_reset_transport_header(skb); | ||
826 | ph = pnp_hdr(skb); | ||
827 | ph->utid = 0; | ||
828 | ph->message_id = PNS_PIPE_DATA; | ||
829 | ph->pipe_handle = pn->pipe_handle; | ||
830 | if (pn_flow_safe(pn->tx_fc) && pn->tx_credits) | ||
831 | pn->tx_credits--; | ||
832 | |||
833 | return pn_skb_send(sk, skb, &pipe_srv); | ||
834 | } | ||
835 | |||
733 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | 836 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, |
734 | struct msghdr *msg, size_t len) | 837 | struct msghdr *msg, size_t len) |
735 | { | 838 | { |
736 | struct pep_sock *pn = pep_sk(sk); | 839 | struct pep_sock *pn = pep_sk(sk); |
737 | struct sk_buff *skb = NULL; | 840 | struct sk_buff *skb = NULL; |
738 | struct pnpipehdr *ph; | ||
739 | long timeo; | 841 | long timeo; |
740 | int flags = msg->msg_flags; | 842 | int flags = msg->msg_flags; |
741 | int err, done; | 843 | int err, done; |
@@ -801,16 +903,7 @@ disabled: | |||
801 | if (err < 0) | 903 | if (err < 0) |
802 | goto out; | 904 | goto out; |
803 | 905 | ||
804 | __skb_push(skb, 3); | 906 | err = pipe_skb_send(sk, skb); |
805 | skb_reset_transport_header(skb); | ||
806 | ph = pnp_hdr(skb); | ||
807 | ph->utid = 0; | ||
808 | ph->message_id = PNS_PIPE_DATA; | ||
809 | ph->pipe_handle = pn->pipe_handle; | ||
810 | if (pn_flow_safe(pn->tx_fc)) /* credit-based flow control */ | ||
811 | pn->tx_credits--; | ||
812 | |||
813 | err = pn_skb_send(sk, skb, &pipe_srv); | ||
814 | if (err >= 0) | 907 | if (err >= 0) |
815 | err = len; /* success! */ | 908 | err = len; /* success! */ |
816 | skb = NULL; | 909 | skb = NULL; |
@@ -820,6 +913,50 @@ out: | |||
820 | return err; | 913 | return err; |
821 | } | 914 | } |
822 | 915 | ||
916 | int pep_writeable(struct sock *sk) | ||
917 | { | ||
918 | struct pep_sock *pn = pep_sk(sk); | ||
919 | |||
920 | return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0; | ||
921 | } | ||
922 | |||
923 | int pep_write(struct sock *sk, struct sk_buff *skb) | ||
924 | { | ||
925 | struct sk_buff *rskb, *fs; | ||
926 | int flen = 0; | ||
927 | |||
928 | rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); | ||
929 | if (!rskb) { | ||
930 | kfree_skb(skb); | ||
931 | return -ENOMEM; | ||
932 | } | ||
933 | skb_shinfo(rskb)->frag_list = skb; | ||
934 | rskb->len += skb->len; | ||
935 | rskb->data_len += rskb->len; | ||
936 | rskb->truesize += rskb->len; | ||
937 | |||
938 | /* Avoid nested fragments */ | ||
939 | for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) | ||
940 | flen += fs->len; | ||
941 | skb->next = skb_shinfo(skb)->frag_list; | ||
942 | skb_shinfo(skb)->frag_list = NULL; | ||
943 | skb->len -= flen; | ||
944 | skb->data_len -= flen; | ||
945 | skb->truesize -= flen; | ||
946 | |||
947 | skb_reserve(rskb, MAX_PHONET_HEADER + 3); | ||
948 | return pipe_skb_send(sk, rskb); | ||
949 | } | ||
950 | |||
951 | struct sk_buff *pep_read(struct sock *sk) | ||
952 | { | ||
953 | struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); | ||
954 | |||
955 | if (sk->sk_state == TCP_ESTABLISHED) | ||
956 | pipe_grant_credits(sk); | ||
957 | return skb; | ||
958 | } | ||
959 | |||
823 | static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, | 960 | static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, |
824 | struct msghdr *msg, size_t len, int noblock, | 961 | struct msghdr *msg, size_t len, int noblock, |
825 | int flags, int *addr_len) | 962 | int flags, int *addr_len) |
@@ -902,6 +1039,8 @@ static struct proto pep_proto = { | |||
902 | .accept = pep_sock_accept, | 1039 | .accept = pep_sock_accept, |
903 | .ioctl = pep_ioctl, | 1040 | .ioctl = pep_ioctl, |
904 | .init = pep_init, | 1041 | .init = pep_init, |
1042 | .setsockopt = pep_setsockopt, | ||
1043 | .getsockopt = pep_getsockopt, | ||
905 | .sendmsg = pep_sendmsg, | 1044 | .sendmsg = pep_sendmsg, |
906 | .recvmsg = pep_recvmsg, | 1045 | .recvmsg = pep_recvmsg, |
907 | .backlog_rcv = pep_do_rcv, | 1046 | .backlog_rcv = pep_do_rcv, |