Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2536b94a authored by Ralf Baechle's avatar Ralf Baechle Committed by David S. Miller
Browse files

[ROSE]: Socket locking is a great invention.



Especially if you actually try to do it ;-)

Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6cee77db
Loading
Loading
Loading
Loading
+50 −28
Original line number Diff line number Diff line
@@ -700,23 +700,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
	unsigned char cause, diagnostic;
	struct net_device *dev;
	ax25_uid_assoc *user;
	int n;

	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
		sock->state = SS_CONNECTED;
		return 0;	/* Connect completed during a ERESTARTSYS event */
	}

	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
		sock->state = SS_UNCONNECTED;
		return -ECONNREFUSED;
	}

	if (sk->sk_state == TCP_ESTABLISHED)
		return -EISCONN;	/* No reconnect on a seqpacket socket */

	sk->sk_state   = TCP_CLOSE;
	sock->state = SS_UNCONNECTED;
	int n, err = 0;

	if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
		return -EINVAL;
@@ -734,24 +718,53 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
	if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS)
		return -EINVAL;

	lock_sock(sk);

	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
		/* Connect completed during a ERESTARTSYS event */
		sock->state = SS_CONNECTED;
		goto out_release;
	}

	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
		sock->state = SS_UNCONNECTED;
		err = -ECONNREFUSED;
		goto out_release;
	}

	if (sk->sk_state == TCP_ESTABLISHED) {
		/* No reconnect on a seqpacket socket */
		err = -EISCONN;
		goto out_release;
	}

	sk->sk_state   = TCP_CLOSE;
	sock->state = SS_UNCONNECTED;

	rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause,
					 &diagnostic);
	if (!rose->neighbour)
		return -ENETUNREACH;

	rose->lci = rose_new_lci(rose->neighbour);
	if (!rose->lci)
		return -ENETUNREACH;
	if (!rose->lci) {
		err = -ENETUNREACH;
		goto out_release;
	}

	if (sock_flag(sk, SOCK_ZAPPED)) {	/* Must bind first - autobinding in this may or may not work */
		sock_reset_flag(sk, SOCK_ZAPPED);

		if ((dev = rose_dev_first()) == NULL)
			return -ENETUNREACH;
		if ((dev = rose_dev_first()) == NULL) {
			err = -ENETUNREACH;
			goto out_release;
		}

		user = ax25_findbyuid(current->euid);
		if (!user)
			return -EINVAL;
		if (!user) {
			err = -EINVAL;
			goto out_release;
		}

		memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN);
		rose->source_call = user->call;
@@ -789,8 +802,10 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
	rose_start_t1timer(sk);

	/* Now the loop */
	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
		return -EINPROGRESS;
	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
		err = -EINPROGRESS;
		goto out_release;
	}

	/*
	 * A Connect Ack with Choke or timeout or failed routing will go to
@@ -805,8 +820,10 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
			set_current_state(TASK_INTERRUPTIBLE);
			if (sk->sk_state != TCP_SYN_SENT)
				break;
			release_sock(sk);
			if (!signal_pending(tsk)) {
				schedule();
				lock_sock(sk);
				continue;
			}
			current->state = TASK_RUNNING;
@@ -822,14 +839,19 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
		rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic);
		if (rose->neighbour)
			goto rose_try_next_neigh;
	/* No more neighbour */

		/* No more neighbours */
		sock->state = SS_UNCONNECTED;
		return sock_error(sk);	/* Always set at this point */
		err = sock_error(sk);	/* Always set at this point */
		goto out_release;
	}

	sock->state = SS_CONNECTED;

	return 0;
out_release:
	release_sock(sk);

	return err;
}

static int rose_accept(struct socket *sock, struct socket *newsock, int flags)