aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/socket.c
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 /net/phonet/socket.c
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>
Diffstat (limited to 'net/phonet/socket.c')
-rw-r--r--net/phonet/socket.c102
1 files changed, 40 insertions, 62 deletions
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,