diff options
-rw-r--r-- | include/linux/phonet.h | 2 | ||||
-rw-r--r-- | net/phonet/pep.c | 106 |
2 files changed, 97 insertions, 11 deletions
diff --git a/include/linux/phonet.h b/include/linux/phonet.h index f53a4167c5f4..f48bfc80cb4b 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define PNPIPE_ENCAP 1 | 38 | #define PNPIPE_ENCAP 1 |
39 | #define PNPIPE_IFINDEX 2 | 39 | #define PNPIPE_IFINDEX 2 |
40 | #define PNPIPE_HANDLE 3 | 40 | #define PNPIPE_HANDLE 3 |
41 | #define PNPIPE_INITSTATE 4 | ||
41 | 42 | ||
42 | #define PNADDR_ANY 0 | 43 | #define PNADDR_ANY 0 |
43 | #define PNADDR_BROADCAST 0xFC | 44 | #define PNADDR_BROADCAST 0xFC |
@@ -49,6 +50,7 @@ | |||
49 | 50 | ||
50 | /* ioctls */ | 51 | /* ioctls */ |
51 | #define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0) | 52 | #define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0) |
53 | #define SIOCPNENABLEPIPE (SIOCPROTOPRIVATE + 13) | ||
52 | #define SIOCPNADDRESOURCE (SIOCPROTOPRIVATE + 14) | 54 | #define SIOCPNADDRESOURCE (SIOCPROTOPRIVATE + 14) |
53 | #define SIOCPNDELRESOURCE (SIOCPROTOPRIVATE + 15) | 55 | #define SIOCPNDELRESOURCE (SIOCPROTOPRIVATE + 15) |
54 | 56 | ||
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 2ba6e9fb4cbc..9f60008740e3 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -534,6 +534,29 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | |||
534 | return pipe_handler_send_created_ind(sk); | 534 | return pipe_handler_send_created_ind(sk); |
535 | } | 535 | } |
536 | 536 | ||
537 | static int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb) | ||
538 | { | ||
539 | struct pnpipehdr *hdr = pnp_hdr(skb); | ||
540 | |||
541 | if (hdr->error_code != PN_PIPE_NO_ERROR) | ||
542 | return -ECONNREFUSED; | ||
543 | |||
544 | return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */, | ||
545 | NULL, 0, GFP_ATOMIC); | ||
546 | |||
547 | } | ||
548 | |||
549 | static void pipe_start_flow_control(struct sock *sk) | ||
550 | { | ||
551 | struct pep_sock *pn = pep_sk(sk); | ||
552 | |||
553 | if (!pn_flow_safe(pn->tx_fc)) { | ||
554 | atomic_set(&pn->tx_credits, 1); | ||
555 | sk->sk_write_space(sk); | ||
556 | } | ||
557 | pipe_grant_credits(sk, GFP_ATOMIC); | ||
558 | } | ||
559 | |||
537 | /* Queue an skb to an actively connected sock. | 560 | /* Queue an skb to an actively connected sock. |
538 | * Socket lock must be held. */ | 561 | * Socket lock must be held. */ |
539 | static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) | 562 | static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) |
@@ -579,13 +602,25 @@ static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
579 | sk->sk_state = TCP_CLOSE_WAIT; | 602 | sk->sk_state = TCP_CLOSE_WAIT; |
580 | break; | 603 | break; |
581 | } | 604 | } |
605 | if (pn->init_enable == PN_PIPE_DISABLE) | ||
606 | sk->sk_state = TCP_SYN_RECV; | ||
607 | else { | ||
608 | sk->sk_state = TCP_ESTABLISHED; | ||
609 | pipe_start_flow_control(sk); | ||
610 | } | ||
611 | break; | ||
582 | 612 | ||
583 | sk->sk_state = TCP_ESTABLISHED; | 613 | case PNS_PEP_ENABLE_RESP: |
584 | if (!pn_flow_safe(pn->tx_fc)) { | 614 | if (sk->sk_state != TCP_SYN_SENT) |
585 | atomic_set(&pn->tx_credits, 1); | 615 | break; |
586 | sk->sk_write_space(sk); | 616 | |
617 | if (pep_enableresp_rcv(sk, skb)) { | ||
618 | sk->sk_state = TCP_CLOSE_WAIT; | ||
619 | break; | ||
587 | } | 620 | } |
588 | pipe_grant_credits(sk, GFP_ATOMIC); | 621 | |
622 | sk->sk_state = TCP_ESTABLISHED; | ||
623 | pipe_start_flow_control(sk); | ||
589 | break; | 624 | break; |
590 | 625 | ||
591 | case PNS_PEP_DISCONNECT_RESP: | 626 | case PNS_PEP_DISCONNECT_RESP: |
@@ -864,14 +899,32 @@ static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) | |||
864 | int err; | 899 | int err; |
865 | u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; | 900 | u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; |
866 | 901 | ||
867 | pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ | 902 | if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE) |
903 | pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ | ||
904 | |||
868 | err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, | 905 | err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, |
869 | PN_PIPE_ENABLE, data, 4); | 906 | pn->init_enable, data, 4); |
870 | if (err) { | 907 | if (err) { |
871 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | 908 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; |
872 | return err; | 909 | return err; |
873 | } | 910 | } |
911 | |||
874 | sk->sk_state = TCP_SYN_SENT; | 912 | sk->sk_state = TCP_SYN_SENT; |
913 | |||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) | ||
918 | { | ||
919 | int err; | ||
920 | |||
921 | err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD, | ||
922 | NULL, 0); | ||
923 | if (err) | ||
924 | return err; | ||
925 | |||
926 | sk->sk_state = TCP_SYN_SENT; | ||
927 | |||
875 | return 0; | 928 | return 0; |
876 | } | 929 | } |
877 | 930 | ||
@@ -879,11 +932,14 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
879 | { | 932 | { |
880 | struct pep_sock *pn = pep_sk(sk); | 933 | struct pep_sock *pn = pep_sk(sk); |
881 | int answ; | 934 | int answ; |
935 | int ret = -ENOIOCTLCMD; | ||
882 | 936 | ||
883 | switch (cmd) { | 937 | switch (cmd) { |
884 | case SIOCINQ: | 938 | case SIOCINQ: |
885 | if (sk->sk_state == TCP_LISTEN) | 939 | if (sk->sk_state == TCP_LISTEN) { |
886 | return -EINVAL; | 940 | ret = -EINVAL; |
941 | break; | ||
942 | } | ||
887 | 943 | ||
888 | lock_sock(sk); | 944 | lock_sock(sk); |
889 | if (sock_flag(sk, SOCK_URGINLINE) && | 945 | if (sock_flag(sk, SOCK_URGINLINE) && |
@@ -894,10 +950,22 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
894 | else | 950 | else |
895 | answ = 0; | 951 | answ = 0; |
896 | release_sock(sk); | 952 | release_sock(sk); |
897 | return put_user(answ, (int __user *)arg); | 953 | ret = put_user(answ, (int __user *)arg); |
954 | break; | ||
955 | |||
956 | case SIOCPNENABLEPIPE: | ||
957 | lock_sock(sk); | ||
958 | if (sk->sk_state == TCP_SYN_SENT) | ||
959 | ret = -EBUSY; | ||
960 | else if (sk->sk_state == TCP_ESTABLISHED) | ||
961 | ret = -EISCONN; | ||
962 | else | ||
963 | ret = pep_sock_enable(sk, NULL, 0); | ||
964 | release_sock(sk); | ||
965 | break; | ||
898 | } | 966 | } |
899 | 967 | ||
900 | return -ENOIOCTLCMD; | 968 | return ret; |
901 | } | 969 | } |
902 | 970 | ||
903 | static int pep_init(struct sock *sk) | 971 | static int pep_init(struct sock *sk) |
@@ -960,6 +1028,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, | |||
960 | } | 1028 | } |
961 | goto out_norel; | 1029 | goto out_norel; |
962 | 1030 | ||
1031 | case PNPIPE_HANDLE: | ||
1032 | if ((sk->sk_state == TCP_CLOSE) && | ||
1033 | (val >= 0) && (val < PN_PIPE_INVALID_HANDLE)) | ||
1034 | pn->pipe_handle = val; | ||
1035 | else | ||
1036 | err = -EINVAL; | ||
1037 | break; | ||
1038 | |||
1039 | case PNPIPE_INITSTATE: | ||
1040 | pn->init_enable = !!val; | ||
1041 | break; | ||
1042 | |||
963 | default: | 1043 | default: |
964 | err = -ENOPROTOOPT; | 1044 | err = -ENOPROTOOPT; |
965 | } | 1045 | } |
@@ -995,6 +1075,10 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, | |||
995 | return -EINVAL; | 1075 | return -EINVAL; |
996 | break; | 1076 | break; |
997 | 1077 | ||
1078 | case PNPIPE_INITSTATE: | ||
1079 | val = pn->init_enable; | ||
1080 | break; | ||
1081 | |||
998 | default: | 1082 | default: |
999 | return -ENOPROTOOPT; | 1083 | return -ENOPROTOOPT; |
1000 | } | 1084 | } |