aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2011-03-08 17:44:12 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-09 14:59:33 -0500
commit297edb6003268c1d60da8c21eb76bf39b6428213 (patch)
treeb17c7544eed3430ed89a56e54a3de14fe9755c3c
parentacaf7df610ff3faf1778ce40d601fc3dd4a41b40 (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.txt53
-rw-r--r--net/phonet/pep.c172
-rw-r--r--net/phonet/socket.c102
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
157Connections are established between two endpoints by a "third party" 157Connections are traditionally established between two endpoints by a
158application. This means that both endpoints are passive; so connect() 158"third party" application. This means that both endpoints are passive.
159is not possible. 159
160
161As of Linux kernel version 2.6.39, it is also possible to connect
162two endpoints directly, using connect() on the active side. This is
163intended to support the newer Nokia Wireless Modem API, as found in
164e.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
161WARNING: 180WARNING:
162When polling a connected pipe socket for writability, there is an 181When 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:
189Phonet Pipe-controller Implementation 208Phonet Pipe-controller Implementation
190------------------------------------- 209-------------------------------------
191 210
192Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig 211Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR
193option. It is useful when communicating with those Nokia Modems which do not 212Kconfig option.
194implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
195U8500 platform.
196
197The implementation is based on the Data Connection Establishment Sequence
198depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
199document.
200
201It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
202between itself and a remote pipe-end point (e.g. modem).
203 213
204The implementation adds socket options at SOL_PNPIPE level: 214The 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
210The implementation also adds socket 'connect'. On calling the 'connect', pipe
211will be created between the source socket and the destination, and the pipe
212state will be set to PIPE_DISABLED.
213
214After a pipe has been created and enabled successfully, the Pipe data can be
215exchanged between the host-pep and remote-pep (modem).
216
217User-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
226Authors 221Authors
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
140static int pipe_handler_request(struct sock *sk, u8 id, u8 code, 139static 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
171static 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
176static int pipe_handler_enable_pipe(struct sock *sk, int enable) 171static 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
525static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) 489static 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. */
547static 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 */
586static struct sock *pep_find_pipe(const struct hlist_head *hlist, 612static 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 }
673drop: 698drop:
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
679static int pipe_do_remove(struct sock *sk) 703static 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 */
699static void pep_sock_close(struct sock *sk, long timeout) 722static 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
848static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) 869static 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
862static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 886static 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)
1243static struct proto pep_proto = { 1275static 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
229static int pn_socket_connect(struct socket *sock, struct sockaddr *addr, 228static 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) {
287wait_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;
317out: 300out:
318 release_sock(sk); 301 release_sock(sk);
319 return err; 302 return err;
320} 303}
321#endif
322 304
323static int pn_socket_accept(struct socket *sock, struct socket *newsock, 305static 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,