diff options
Diffstat (limited to 'net/phonet/socket.c')
-rw-r--r-- | net/phonet/socket.c | 102 |
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 | ||
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, |