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>
This commit is contained in:
committed by
David S. Miller
parent
acaf7df610
commit
297edb6003
@@ -225,15 +225,18 @@ static int pn_socket_autobind(struct socket *sock)
|
||||
return 0; /* socket was already bound */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PHONET_PIPECTRLR
|
||||
static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
|
||||
int len, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct pn_sock *pn = pn_sk(sk);
|
||||
struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
|
||||
long timeo;
|
||||
struct task_struct *tsk = current;
|
||||
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
|
||||
int err;
|
||||
|
||||
if (pn_socket_autobind(sock))
|
||||
return -ENOBUFS;
|
||||
if (len < sizeof(struct sockaddr_pn))
|
||||
return -EINVAL;
|
||||
if (spn->spn_family != AF_PHONET)
|
||||
@@ -243,82 +246,61 @@ static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
|
||||
|
||||
switch (sock->state) {
|
||||
case SS_UNCONNECTED:
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
if (sk->sk_state != TCP_CLOSE) {
|
||||
err = -EISCONN;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case SS_CONNECTING:
|
||||
switch (sk->sk_state) {
|
||||
case TCP_SYN_RECV:
|
||||
sock->state = SS_CONNECTED;
|
||||
err = -EISCONN;
|
||||
goto out;
|
||||
case TCP_CLOSE:
|
||||
err = -EALREADY;
|
||||
if (flags & O_NONBLOCK)
|
||||
goto out;
|
||||
goto wait_connect;
|
||||
}
|
||||
break;
|
||||
case SS_CONNECTED:
|
||||
switch (sk->sk_state) {
|
||||
case TCP_SYN_RECV:
|
||||
err = -EISCONN;
|
||||
goto out;
|
||||
case TCP_CLOSE:
|
||||
sock->state = SS_UNCONNECTED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SS_DISCONNECTING:
|
||||
case SS_FREE:
|
||||
break;
|
||||
err = -EALREADY;
|
||||
goto out;
|
||||
default:
|
||||
err = -EISCONN;
|
||||
goto out;
|
||||
}
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sk_stream_kill_queues(sk);
|
||||
|
||||
pn->dobject = pn_sockaddr_get_object(spn);
|
||||
pn->resource = pn_sockaddr_get_resource(spn);
|
||||
sock->state = SS_CONNECTING;
|
||||
|
||||
err = sk->sk_prot->connect(sk, addr, len);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
sock->state = SS_UNCONNECTED;
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
pn->dobject = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -EINPROGRESS;
|
||||
wait_connect:
|
||||
if (sk->sk_state != TCP_SYN_RECV && (flags & O_NONBLOCK))
|
||||
goto out;
|
||||
while (sk->sk_state == TCP_SYN_SENT) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
|
||||
release_sock(sk);
|
||||
if (!timeo) {
|
||||
err = -EINPROGRESS;
|
||||
goto out;
|
||||
}
|
||||
if (signal_pending(tsk)) {
|
||||
err = sock_intr_errno(timeo);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -ERESTARTSYS;
|
||||
timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
|
||||
sk->sk_state != TCP_CLOSE,
|
||||
timeo);
|
||||
|
||||
lock_sock(sk);
|
||||
if (timeo < 0)
|
||||
goto out; /* -ERESTARTSYS */
|
||||
|
||||
err = -ETIMEDOUT;
|
||||
if (timeo == 0 && sk->sk_state != TCP_SYN_RECV)
|
||||
goto out;
|
||||
|
||||
if (sk->sk_state != TCP_SYN_RECV) {
|
||||
sock->state = SS_UNCONNECTED;
|
||||
err = sock_error(sk);
|
||||
if (!err)
|
||||
err = -ECONNREFUSED;
|
||||
goto out;
|
||||
prepare_to_wait_exclusive(sk_sleep(sk), &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
release_sock(sk);
|
||||
timeo = schedule_timeout(timeo);
|
||||
lock_sock(sk);
|
||||
finish_wait(sk_sleep(sk), &wait);
|
||||
}
|
||||
sock->state = SS_CONNECTED;
|
||||
err = 0;
|
||||
|
||||
if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
|
||||
err = 0;
|
||||
else if (sk->sk_state == TCP_CLOSE_WAIT)
|
||||
err = -ECONNRESET;
|
||||
else
|
||||
err = -ECONNREFUSED;
|
||||
sock->state = err ? SS_UNCONNECTED : SS_CONNECTED;
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pn_socket_accept(struct socket *sock, struct socket *newsock,
|
||||
int flags)
|
||||
@@ -486,11 +468,7 @@ const struct proto_ops phonet_stream_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.release = pn_socket_release,
|
||||
.bind = pn_socket_bind,
|
||||
#ifdef CONFIG_PHONET_PIPECTRLR
|
||||
.connect = pn_socket_connect,
|
||||
#else
|
||||
.connect = sock_no_connect,
|
||||
#endif
|
||||
.socketpair = sock_no_socketpair,
|
||||
.accept = pn_socket_accept,
|
||||
.getname = pn_socket_getname,
|
||||
|
Reference in New Issue
Block a user