aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/pep.c
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2008-10-05 14:16:16 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-05 14:16:16 -0400
commit02a47617cdce440f60c71a51f3a93f9f5fcc5a7a (patch)
tree2f65d9978345b8eafdaf926a3342424a21c6e57a /net/phonet/pep.c
parentc41bd97f815720f9404f97da0c4f4400b52c243d (diff)
Phonet: implement GPRS virtual interface over PEP socket
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.c161
1 files changed, 150 insertions, 11 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index d564d07cb79..bc6d50f8324 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:
612static void pep_sock_close(struct sock *sk, long timeout) 613static 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
631static int pep_wait_connreq(struct sock *sk, int noblock) 638static 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
740static 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
785out_norel:
786 return err;
787}
788
789static 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
819static 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
733static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 836static 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
916int 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
923int 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
951struct 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
823static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, 960static 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,