diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2011-03-08 17:44:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-09 14:59:33 -0500 |
commit | 297edb6003268c1d60da8c21eb76bf39b6428213 (patch) | |
tree | b17c7544eed3430ed89a56e54a3de14fe9755c3c | |
parent | acaf7df610ff3faf1778ce40d601fc3dd4a41b40 (diff) |
Phonet: support active connection without pipe controller on modem
This provides support for newer ISI modems with no need for the
earlier experimental compile-time alternative choice. With this,
we can now use the same kernel and userspace with both types of
modems.
This also avoids confusing two different and incompatible state
machines, actively connected vs accepted sockets, and adds
connection response error handling (processing "SYN/RST" of sorts).
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/networking/phonet.txt | 53 | ||||
-rw-r--r-- | net/phonet/pep.c | 172 | ||||
-rw-r--r-- | net/phonet/socket.c | 102 |
3 files changed, 165 insertions, 162 deletions
diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt index cacac968c1c3..3d127791cb06 100644 --- a/Documentation/networking/phonet.txt +++ b/Documentation/networking/phonet.txt | |||
@@ -154,9 +154,28 @@ connections, one per accept()'d socket. | |||
154 | write(cfd, msg, msglen); | 154 | write(cfd, msg, msglen); |
155 | } | 155 | } |
156 | 156 | ||
157 | Connections are established between two endpoints by a "third party" | 157 | Connections are traditionally established between two endpoints by a |
158 | application. This means that both endpoints are passive; so connect() | 158 | "third party" application. This means that both endpoints are passive. |
159 | is not possible. | 159 | |
160 | |||
161 | As of Linux kernel version 2.6.39, it is also possible to connect | ||
162 | two endpoints directly, using connect() on the active side. This is | ||
163 | intended to support the newer Nokia Wireless Modem API, as found in | ||
164 | e.g. the Nokia Slim Modem in the ST-Ericsson U8500 platform: | ||
165 | |||
166 | struct sockaddr_spn spn; | ||
167 | int fd; | ||
168 | |||
169 | fd = socket(PF_PHONET, SOCK_SEQPACKET, PN_PROTO_PIPE); | ||
170 | memset(&spn, 0, sizeof(spn)); | ||
171 | spn.spn_family = AF_PHONET; | ||
172 | spn.spn_obj = ...; | ||
173 | spn.spn_dev = ...; | ||
174 | spn.spn_resource = 0xD9; | ||
175 | connect(fd, (struct sockaddr *)&spn, sizeof(spn)); | ||
176 | /* normal I/O here ... */ | ||
177 | close(fd); | ||
178 | |||
160 | 179 | ||
161 | WARNING: | 180 | WARNING: |
162 | When polling a connected pipe socket for writability, there is an | 181 | When polling a connected pipe socket for writability, there is an |
@@ -189,17 +208,8 @@ The pipe protocol provides two socket options at the SOL_PNPIPE level: | |||
189 | Phonet Pipe-controller Implementation | 208 | Phonet Pipe-controller Implementation |
190 | ------------------------------------- | 209 | ------------------------------------- |
191 | 210 | ||
192 | Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig | 211 | Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR |
193 | option. It is useful when communicating with those Nokia Modems which do not | 212 | Kconfig option. |
194 | implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson | ||
195 | U8500 platform. | ||
196 | |||
197 | The implementation is based on the Data Connection Establishment Sequence | ||
198 | depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf' | ||
199 | document. | ||
200 | |||
201 | It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection | ||
202 | between itself and a remote pipe-end point (e.g. modem). | ||
203 | 213 | ||
204 | The implementation adds socket options at SOL_PNPIPE level: | 214 | The implementation adds socket options at SOL_PNPIPE level: |
205 | 215 | ||
@@ -207,21 +217,6 @@ The implementation adds socket options at SOL_PNPIPE level: | |||
207 | is disabled. If the value is non-zero, the pipe is enabled. If the pipe | 217 | is disabled. If the value is non-zero, the pipe is enabled. If the pipe |
208 | is not (yet) connected, ENOTCONN is error is returned. | 218 | is not (yet) connected, ENOTCONN is error is returned. |
209 | 219 | ||
210 | The implementation also adds socket 'connect'. On calling the 'connect', pipe | ||
211 | will be created between the source socket and the destination, and the pipe | ||
212 | state will be set to PIPE_DISABLED. | ||
213 | |||
214 | After a pipe has been created and enabled successfully, the Pipe data can be | ||
215 | exchanged between the host-pep and remote-pep (modem). | ||
216 | |||
217 | User-space would typically follow below sequence with Pipe controller:- | ||
218 | -socket | ||
219 | -bind | ||
220 | -setsockopt for PNPIPE_PIPE_HANDLE | ||
221 | -connect | ||
222 | -setsockopt for PNPIPE_ENCAP_IP | ||
223 | -setsockopt for PNPIPE_ENABLE | ||
224 | |||
225 | 220 | ||
226 | Authors | 221 | Authors |
227 | ------- | 222 | ------- |
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index abfb795af142..671effb4ea15 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -136,7 +136,6 @@ static int pep_indicate(struct sock *sk, u8 id, u8 code, | |||
136 | 136 | ||
137 | #define PAD 0x00 | 137 | #define PAD 0x00 |
138 | 138 | ||
139 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
140 | static int pipe_handler_request(struct sock *sk, u8 id, u8 code, | 139 | static int pipe_handler_request(struct sock *sk, u8 id, u8 code, |
141 | const void *data, int len) | 140 | const void *data, int len) |
142 | { | 141 | { |
@@ -168,11 +167,7 @@ static int pipe_handler_send_created_ind(struct sock *sk) | |||
168 | data, 4, GFP_ATOMIC); | 167 | data, 4, GFP_ATOMIC); |
169 | } | 168 | } |
170 | 169 | ||
171 | static int pipe_handler_send_ind(struct sock *sk, u8 id) | 170 | #ifdef CONFIG_PHONET_PIPECTRLR |
172 | { | ||
173 | return pep_indicate(sk, id, PAD, NULL, 0, GFP_ATOMIC); | ||
174 | } | ||
175 | |||
176 | static int pipe_handler_enable_pipe(struct sock *sk, int enable) | 171 | static int pipe_handler_enable_pipe(struct sock *sk, int enable) |
177 | { | 172 | { |
178 | u8 id = enable ? PNS_PEP_ENABLE_REQ : PNS_PEP_DISABLE_REQ; | 173 | u8 id = enable ? PNS_PEP_ENABLE_REQ : PNS_PEP_DISABLE_REQ; |
@@ -376,32 +371,11 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
376 | sk->sk_state_change(sk); | 371 | sk->sk_state_change(sk); |
377 | break; | 372 | break; |
378 | 373 | ||
379 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
380 | case PNS_PEP_DISCONNECT_RESP: | ||
381 | sk->sk_state = TCP_CLOSE; | ||
382 | break; | ||
383 | #endif | ||
384 | |||
385 | case PNS_PEP_ENABLE_REQ: | 374 | case PNS_PEP_ENABLE_REQ: |
386 | /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ | 375 | /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ |
387 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 376 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
388 | break; | 377 | break; |
389 | 378 | ||
390 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
391 | case PNS_PEP_ENABLE_RESP: | ||
392 | pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND); | ||
393 | |||
394 | if (!pn_flow_safe(pn->tx_fc)) { | ||
395 | atomic_set(&pn->tx_credits, 1); | ||
396 | sk->sk_write_space(sk); | ||
397 | } | ||
398 | if (sk->sk_state == TCP_ESTABLISHED) | ||
399 | break; /* Nothing to do */ | ||
400 | sk->sk_state = TCP_ESTABLISHED; | ||
401 | pipe_grant_credits(sk, GFP_ATOMIC); | ||
402 | break; | ||
403 | #endif | ||
404 | |||
405 | case PNS_PEP_RESET_REQ: | 379 | case PNS_PEP_RESET_REQ: |
406 | switch (hdr->state_after_reset) { | 380 | switch (hdr->state_after_reset) { |
407 | case PN_PIPE_DISABLE: | 381 | case PN_PIPE_DISABLE: |
@@ -420,15 +394,6 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
420 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 394 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
421 | break; | 395 | break; |
422 | 396 | ||
423 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
424 | case PNS_PEP_DISABLE_RESP: | ||
425 | atomic_set(&pn->tx_credits, 0); | ||
426 | pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND); | ||
427 | sk->sk_state = TCP_SYN_RECV; | ||
428 | pn->rx_credits = 0; | ||
429 | break; | ||
430 | #endif | ||
431 | |||
432 | case PNS_PEP_CTRL_REQ: | 397 | case PNS_PEP_CTRL_REQ: |
433 | if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { | 398 | if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { |
434 | atomic_inc(&sk->sk_drops); | 399 | atomic_inc(&sk->sk_drops); |
@@ -521,7 +486,6 @@ static void pipe_destruct(struct sock *sk) | |||
521 | skb_queue_purge(&pn->ctrlreq_queue); | 486 | skb_queue_purge(&pn->ctrlreq_queue); |
522 | } | 487 | } |
523 | 488 | ||
524 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
525 | static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) | 489 | static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) |
526 | { | 490 | { |
527 | unsigned i; | 491 | unsigned i; |
@@ -546,6 +510,8 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | |||
546 | return -EINVAL; | 510 | return -EINVAL; |
547 | 511 | ||
548 | hdr = pnp_hdr(skb); | 512 | hdr = pnp_hdr(skb); |
513 | if (hdr->error_code != PN_PIPE_NO_ERROR) | ||
514 | return -ECONNREFUSED; | ||
549 | 515 | ||
550 | /* Parse sub-blocks */ | 516 | /* Parse sub-blocks */ |
551 | n_sb = hdr->data[4]; | 517 | n_sb = hdr->data[4]; |
@@ -573,14 +539,74 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | |||
573 | n_sb--; | 539 | n_sb--; |
574 | } | 540 | } |
575 | 541 | ||
576 | sk->sk_state = TCP_SYN_RECV; | ||
577 | sk->sk_backlog_rcv = pipe_do_rcv; | ||
578 | pn->rx_credits = 0; | ||
579 | sk->sk_state_change(sk); | ||
580 | |||
581 | return pipe_handler_send_created_ind(sk); | 542 | return pipe_handler_send_created_ind(sk); |
582 | } | 543 | } |
583 | #endif | 544 | |
545 | /* Queue an skb to an actively connected sock. | ||
546 | * Socket lock must be held. */ | ||
547 | static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) | ||
548 | { | ||
549 | struct pep_sock *pn = pep_sk(sk); | ||
550 | struct pnpipehdr *hdr = pnp_hdr(skb); | ||
551 | int err = NET_RX_SUCCESS; | ||
552 | |||
553 | switch (hdr->message_id) { | ||
554 | case PNS_PIPE_ALIGNED_DATA: | ||
555 | __skb_pull(skb, 1); | ||
556 | /* fall through */ | ||
557 | case PNS_PIPE_DATA: | ||
558 | __skb_pull(skb, 3); /* Pipe data header */ | ||
559 | if (!pn_flow_safe(pn->rx_fc)) { | ||
560 | err = sock_queue_rcv_skb(sk, skb); | ||
561 | if (!err) | ||
562 | return NET_RX_SUCCESS; | ||
563 | err = NET_RX_DROP; | ||
564 | break; | ||
565 | } | ||
566 | |||
567 | if (pn->rx_credits == 0) { | ||
568 | atomic_inc(&sk->sk_drops); | ||
569 | err = NET_RX_DROP; | ||
570 | break; | ||
571 | } | ||
572 | pn->rx_credits--; | ||
573 | skb->dev = NULL; | ||
574 | skb_set_owner_r(skb, sk); | ||
575 | err = skb->len; | ||
576 | skb_queue_tail(&sk->sk_receive_queue, skb); | ||
577 | if (!sock_flag(sk, SOCK_DEAD)) | ||
578 | sk->sk_data_ready(sk, err); | ||
579 | return NET_RX_SUCCESS; | ||
580 | |||
581 | case PNS_PEP_CONNECT_RESP: | ||
582 | if (sk->sk_state != TCP_SYN_SENT) | ||
583 | break; | ||
584 | if (!sock_flag(sk, SOCK_DEAD)) | ||
585 | sk->sk_state_change(sk); | ||
586 | if (pep_connresp_rcv(sk, skb)) { | ||
587 | sk->sk_state = TCP_CLOSE_WAIT; | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | sk->sk_state = TCP_ESTABLISHED; | ||
592 | if (!pn_flow_safe(pn->tx_fc)) { | ||
593 | atomic_set(&pn->tx_credits, 1); | ||
594 | sk->sk_write_space(sk); | ||
595 | } | ||
596 | pipe_grant_credits(sk, GFP_ATOMIC); | ||
597 | break; | ||
598 | |||
599 | case PNS_PEP_DISCONNECT_RESP: | ||
600 | /* sock should already be dead, nothing to do */ | ||
601 | break; | ||
602 | |||
603 | case PNS_PEP_STATUS_IND: | ||
604 | pipe_rcv_status(sk, skb); | ||
605 | break; | ||
606 | } | ||
607 | kfree_skb(skb); | ||
608 | return err; | ||
609 | } | ||
584 | 610 | ||
585 | /* Listening sock must be locked */ | 611 | /* Listening sock must be locked */ |
586 | static struct sock *pep_find_pipe(const struct hlist_head *hlist, | 612 | static struct sock *pep_find_pipe(const struct hlist_head *hlist, |
@@ -649,12 +675,6 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
649 | sk->sk_data_ready(sk, 0); | 675 | sk->sk_data_ready(sk, 0); |
650 | return NET_RX_SUCCESS; | 676 | return NET_RX_SUCCESS; |
651 | 677 | ||
652 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
653 | case PNS_PEP_CONNECT_RESP: | ||
654 | pep_connresp_rcv(sk, skb); | ||
655 | break; | ||
656 | #endif | ||
657 | |||
658 | case PNS_PEP_DISCONNECT_REQ: | 678 | case PNS_PEP_DISCONNECT_REQ: |
659 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 679 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
660 | break; | 680 | break; |
@@ -667,15 +687,19 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
667 | case PNS_PEP_ENABLE_REQ: | 687 | case PNS_PEP_ENABLE_REQ: |
668 | case PNS_PEP_DISABLE_REQ: | 688 | case PNS_PEP_DISABLE_REQ: |
669 | /* invalid handle is not even allowed here! */ | 689 | /* invalid handle is not even allowed here! */ |
670 | default: | ||
671 | break; | 690 | break; |
691 | |||
692 | default: | ||
693 | if ((1 << sk->sk_state) | ||
694 | & ~(TCPF_CLOSE|TCPF_LISTEN|TCPF_CLOSE_WAIT)) | ||
695 | /* actively connected socket */ | ||
696 | return pipe_handler_do_rcv(sk, skb); | ||
672 | } | 697 | } |
673 | drop: | 698 | drop: |
674 | kfree_skb(skb); | 699 | kfree_skb(skb); |
675 | return NET_RX_SUCCESS; | 700 | return NET_RX_SUCCESS; |
676 | } | 701 | } |
677 | 702 | ||
678 | #ifndef CONFIG_PHONET_PIPECTRLR | ||
679 | static int pipe_do_remove(struct sock *sk) | 703 | static int pipe_do_remove(struct sock *sk) |
680 | { | 704 | { |
681 | struct pep_sock *pn = pep_sk(sk); | 705 | struct pep_sock *pn = pep_sk(sk); |
@@ -693,7 +717,6 @@ static int pipe_do_remove(struct sock *sk) | |||
693 | ph->data[0] = PAD; | 717 | ph->data[0] = PAD; |
694 | return pn_skb_send(sk, skb, NULL); | 718 | return pn_skb_send(sk, skb, NULL); |
695 | } | 719 | } |
696 | #endif | ||
697 | 720 | ||
698 | /* associated socket ceases to exist */ | 721 | /* associated socket ceases to exist */ |
699 | static void pep_sock_close(struct sock *sk, long timeout) | 722 | static void pep_sock_close(struct sock *sk, long timeout) |
@@ -706,13 +729,12 @@ static void pep_sock_close(struct sock *sk, long timeout) | |||
706 | 729 | ||
707 | lock_sock(sk); | 730 | lock_sock(sk); |
708 | if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { | 731 | if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { |
709 | #ifndef CONFIG_PHONET_PIPECTRLR | 732 | if (sk->sk_backlog_rcv == pipe_do_rcv) |
710 | /* Forcefully remove dangling Phonet pipe */ | 733 | /* Forcefully remove dangling Phonet pipe */ |
711 | pipe_do_remove(sk); | 734 | pipe_do_remove(sk); |
712 | #else | 735 | else |
713 | /* send pep disconnect request */ | 736 | pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, |
714 | pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, NULL, 0); | 737 | NULL, 0); |
715 | #endif | ||
716 | } | 738 | } |
717 | sk->sk_state = TCP_CLOSE; | 739 | sk->sk_state = TCP_CLOSE; |
718 | 740 | ||
@@ -844,20 +866,22 @@ drop: | |||
844 | return newsk; | 866 | return newsk; |
845 | } | 867 | } |
846 | 868 | ||
847 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
848 | static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) | 869 | static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) |
849 | { | 870 | { |
850 | struct pep_sock *pn = pep_sk(sk); | 871 | struct pep_sock *pn = pep_sk(sk); |
851 | const struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; | 872 | int err; |
852 | u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; | 873 | u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; |
853 | 874 | ||
854 | pn->pn_sk.dobject = pn_sockaddr_get_object(spn); | ||
855 | pn->pn_sk.resource = pn_sockaddr_get_resource(spn); | ||
856 | pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ | 875 | pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ |
857 | return pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, | 876 | err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, |
858 | PN_PIPE_DISABLE, data, 4); | 877 | PN_PIPE_ENABLE, data, 4); |
878 | if (err) { | ||
879 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | ||
880 | return err; | ||
881 | } | ||
882 | sk->sk_state = TCP_SYN_SENT; | ||
883 | return 0; | ||
859 | } | 884 | } |
860 | #endif | ||
861 | 885 | ||
862 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | 886 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) |
863 | { | 887 | { |
@@ -890,8 +914,16 @@ static int pep_init(struct sock *sk) | |||
890 | 914 | ||
891 | sk->sk_destruct = pipe_destruct; | 915 | sk->sk_destruct = pipe_destruct; |
892 | INIT_HLIST_HEAD(&pn->hlist); | 916 | INIT_HLIST_HEAD(&pn->hlist); |
917 | pn->listener = NULL; | ||
893 | skb_queue_head_init(&pn->ctrlreq_queue); | 918 | skb_queue_head_init(&pn->ctrlreq_queue); |
919 | atomic_set(&pn->tx_credits, 0); | ||
920 | pn->ifindex = 0; | ||
921 | pn->peer_type = 0; | ||
894 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | 922 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; |
923 | pn->rx_credits = 0; | ||
924 | pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; | ||
925 | pn->init_enable = 1; | ||
926 | pn->aligned = 0; | ||
895 | return 0; | 927 | return 0; |
896 | } | 928 | } |
897 | 929 | ||
@@ -1219,9 +1251,9 @@ static void pep_sock_unhash(struct sock *sk) | |||
1219 | 1251 | ||
1220 | lock_sock(sk); | 1252 | lock_sock(sk); |
1221 | 1253 | ||
1222 | #ifndef CONFIG_PHONET_PIPECTRLR | 1254 | if (pn->listener != NULL) { |
1223 | if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { | ||
1224 | skparent = pn->listener; | 1255 | skparent = pn->listener; |
1256 | pn->listener = NULL; | ||
1225 | release_sock(sk); | 1257 | release_sock(sk); |
1226 | 1258 | ||
1227 | pn = pep_sk(skparent); | 1259 | pn = pep_sk(skparent); |
@@ -1229,7 +1261,7 @@ static void pep_sock_unhash(struct sock *sk) | |||
1229 | sk_del_node_init(sk); | 1261 | sk_del_node_init(sk); |
1230 | sk = skparent; | 1262 | sk = skparent; |
1231 | } | 1263 | } |
1232 | #endif | 1264 | |
1233 | /* Unhash a listening sock only when it is closed | 1265 | /* Unhash a listening sock only when it is closed |
1234 | * and all of its active connected pipes are closed. */ | 1266 | * and all of its active connected pipes are closed. */ |
1235 | if (hlist_empty(&pn->hlist)) | 1267 | if (hlist_empty(&pn->hlist)) |
@@ -1243,9 +1275,7 @@ static void pep_sock_unhash(struct sock *sk) | |||
1243 | static struct proto pep_proto = { | 1275 | static struct proto pep_proto = { |
1244 | .close = pep_sock_close, | 1276 | .close = pep_sock_close, |
1245 | .accept = pep_sock_accept, | 1277 | .accept = pep_sock_accept, |
1246 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1247 | .connect = pep_sock_connect, | 1278 | .connect = pep_sock_connect, |
1248 | #endif | ||
1249 | .ioctl = pep_ioctl, | 1279 | .ioctl = pep_ioctl, |
1250 | .init = pep_init, | 1280 | .init = pep_init, |
1251 | .setsockopt = pep_setsockopt, | 1281 | .setsockopt = pep_setsockopt, |
diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 1eccfc35bcc0..b1adafab377c 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c | |||
@@ -225,15 +225,18 @@ static int pn_socket_autobind(struct socket *sock) | |||
225 | return 0; /* socket was already bound */ | 225 | return 0; /* socket was already bound */ |
226 | } | 226 | } |
227 | 227 | ||
228 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
229 | static int pn_socket_connect(struct socket *sock, struct sockaddr *addr, | 228 | static int pn_socket_connect(struct socket *sock, struct sockaddr *addr, |
230 | int len, int flags) | 229 | int len, int flags) |
231 | { | 230 | { |
232 | struct sock *sk = sock->sk; | 231 | struct sock *sk = sock->sk; |
232 | struct pn_sock *pn = pn_sk(sk); | ||
233 | struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; | 233 | struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; |
234 | long timeo; | 234 | struct task_struct *tsk = current; |
235 | long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); | ||
235 | int err; | 236 | int err; |
236 | 237 | ||
238 | if (pn_socket_autobind(sock)) | ||
239 | return -ENOBUFS; | ||
237 | if (len < sizeof(struct sockaddr_pn)) | 240 | if (len < sizeof(struct sockaddr_pn)) |
238 | return -EINVAL; | 241 | return -EINVAL; |
239 | if (spn->spn_family != AF_PHONET) | 242 | if (spn->spn_family != AF_PHONET) |
@@ -243,82 +246,61 @@ static int pn_socket_connect(struct socket *sock, struct sockaddr *addr, | |||
243 | 246 | ||
244 | switch (sock->state) { | 247 | switch (sock->state) { |
245 | case SS_UNCONNECTED: | 248 | case SS_UNCONNECTED: |
246 | sk->sk_state = TCP_CLOSE; | 249 | if (sk->sk_state != TCP_CLOSE) { |
247 | break; | ||
248 | case SS_CONNECTING: | ||
249 | switch (sk->sk_state) { | ||
250 | case TCP_SYN_RECV: | ||
251 | sock->state = SS_CONNECTED; | ||
252 | err = -EISCONN; | ||
253 | goto out; | ||
254 | case TCP_CLOSE: | ||
255 | err = -EALREADY; | ||
256 | if (flags & O_NONBLOCK) | ||
257 | goto out; | ||
258 | goto wait_connect; | ||
259 | } | ||
260 | break; | ||
261 | case SS_CONNECTED: | ||
262 | switch (sk->sk_state) { | ||
263 | case TCP_SYN_RECV: | ||
264 | err = -EISCONN; | 250 | err = -EISCONN; |
265 | goto out; | 251 | goto out; |
266 | case TCP_CLOSE: | ||
267 | sock->state = SS_UNCONNECTED; | ||
268 | break; | ||
269 | } | 252 | } |
270 | break; | 253 | break; |
271 | case SS_DISCONNECTING: | 254 | case SS_CONNECTING: |
272 | case SS_FREE: | 255 | err = -EALREADY; |
273 | break; | 256 | goto out; |
257 | default: | ||
258 | err = -EISCONN; | ||
259 | goto out; | ||
274 | } | 260 | } |
275 | sk->sk_state = TCP_CLOSE; | ||
276 | sk_stream_kill_queues(sk); | ||
277 | 261 | ||
262 | pn->dobject = pn_sockaddr_get_object(spn); | ||
263 | pn->resource = pn_sockaddr_get_resource(spn); | ||
278 | sock->state = SS_CONNECTING; | 264 | sock->state = SS_CONNECTING; |
265 | |||
279 | err = sk->sk_prot->connect(sk, addr, len); | 266 | err = sk->sk_prot->connect(sk, addr, len); |
280 | if (err < 0) { | 267 | if (err) { |
281 | sock->state = SS_UNCONNECTED; | 268 | sock->state = SS_UNCONNECTED; |
282 | sk->sk_state = TCP_CLOSE; | 269 | pn->dobject = 0; |
283 | goto out; | 270 | goto out; |
284 | } | 271 | } |
285 | 272 | ||
286 | err = -EINPROGRESS; | 273 | while (sk->sk_state == TCP_SYN_SENT) { |
287 | wait_connect: | 274 | DEFINE_WAIT(wait); |
288 | if (sk->sk_state != TCP_SYN_RECV && (flags & O_NONBLOCK)) | ||
289 | goto out; | ||
290 | |||
291 | timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); | ||
292 | release_sock(sk); | ||
293 | 275 | ||
294 | err = -ERESTARTSYS; | 276 | if (!timeo) { |
295 | timeo = wait_event_interruptible_timeout(*sk_sleep(sk), | 277 | err = -EINPROGRESS; |
296 | sk->sk_state != TCP_CLOSE, | 278 | goto out; |
297 | timeo); | 279 | } |
298 | 280 | if (signal_pending(tsk)) { | |
299 | lock_sock(sk); | 281 | err = sock_intr_errno(timeo); |
300 | if (timeo < 0) | 282 | goto out; |
301 | goto out; /* -ERESTARTSYS */ | 283 | } |
302 | |||
303 | err = -ETIMEDOUT; | ||
304 | if (timeo == 0 && sk->sk_state != TCP_SYN_RECV) | ||
305 | goto out; | ||
306 | 284 | ||
307 | if (sk->sk_state != TCP_SYN_RECV) { | 285 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, |
308 | sock->state = SS_UNCONNECTED; | 286 | TASK_INTERRUPTIBLE); |
309 | err = sock_error(sk); | 287 | release_sock(sk); |
310 | if (!err) | 288 | timeo = schedule_timeout(timeo); |
311 | err = -ECONNREFUSED; | 289 | lock_sock(sk); |
312 | goto out; | 290 | finish_wait(sk_sleep(sk), &wait); |
313 | } | 291 | } |
314 | sock->state = SS_CONNECTED; | ||
315 | err = 0; | ||
316 | 292 | ||
293 | if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) | ||
294 | err = 0; | ||
295 | else if (sk->sk_state == TCP_CLOSE_WAIT) | ||
296 | err = -ECONNRESET; | ||
297 | else | ||
298 | err = -ECONNREFUSED; | ||
299 | sock->state = err ? SS_UNCONNECTED : SS_CONNECTED; | ||
317 | out: | 300 | out: |
318 | release_sock(sk); | 301 | release_sock(sk); |
319 | return err; | 302 | return err; |
320 | } | 303 | } |
321 | #endif | ||
322 | 304 | ||
323 | static int pn_socket_accept(struct socket *sock, struct socket *newsock, | 305 | static int pn_socket_accept(struct socket *sock, struct socket *newsock, |
324 | int flags) | 306 | int flags) |
@@ -486,11 +468,7 @@ const struct proto_ops phonet_stream_ops = { | |||
486 | .owner = THIS_MODULE, | 468 | .owner = THIS_MODULE, |
487 | .release = pn_socket_release, | 469 | .release = pn_socket_release, |
488 | .bind = pn_socket_bind, | 470 | .bind = pn_socket_bind, |
489 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
490 | .connect = pn_socket_connect, | 471 | .connect = pn_socket_connect, |
491 | #else | ||
492 | .connect = sock_no_connect, | ||
493 | #endif | ||
494 | .socketpair = sock_no_socketpair, | 472 | .socketpair = sock_no_socketpair, |
495 | .accept = pn_socket_accept, | 473 | .accept = pn_socket_accept, |
496 | .getname = pn_socket_getname, | 474 | .getname = pn_socket_getname, |