summaryrefslogtreecommitdiff
path: root/net/rose/af_rose.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rose/af_rose.c')
-rw-r--r--net/rose/af_rose.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 59050caab65c..fd67494f2815 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -170,7 +170,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
if (rose->neighbour == neigh) {
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
- rose->neighbour->use--;
+ rose_neigh_put(rose->neighbour);
rose->neighbour = NULL;
}
}
@@ -212,7 +212,7 @@ start:
if (rose->device == dev) {
rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
if (rose->neighbour)
- rose->neighbour->use--;
+ rose_neigh_put(rose->neighbour);
netdev_put(rose->device, &rose->dev_tracker);
rose->device = NULL;
}
@@ -345,7 +345,7 @@ void rose_destroy_socket(struct sock *);
*/
static void rose_destroy_timer(struct timer_list *t)
{
- struct sock *sk = from_timer(sk, t, sk_timer);
+ struct sock *sk = timer_container_of(sk, t, sk_timer);
rose_destroy_socket(sk);
}
@@ -397,15 +397,15 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
struct rose_sock *rose = rose_sk(sk);
- int opt;
+ unsigned int opt;
if (level != SOL_ROSE)
return -ENOPROTOOPT;
- if (optlen < sizeof(int))
+ if (optlen < sizeof(unsigned int))
return -EINVAL;
- if (copy_from_sockptr(&opt, optval, sizeof(int)))
+ if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
return -EFAULT;
switch (optname) {
@@ -414,31 +414,31 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
return 0;
case ROSE_T1:
- if (opt < 1)
+ if (opt < 1 || opt > UINT_MAX / HZ)
return -EINVAL;
rose->t1 = opt * HZ;
return 0;
case ROSE_T2:
- if (opt < 1)
+ if (opt < 1 || opt > UINT_MAX / HZ)
return -EINVAL;
rose->t2 = opt * HZ;
return 0;
case ROSE_T3:
- if (opt < 1)
+ if (opt < 1 || opt > UINT_MAX / HZ)
return -EINVAL;
rose->t3 = opt * HZ;
return 0;
case ROSE_HOLDBACK:
- if (opt < 1)
+ if (opt < 1 || opt > UINT_MAX / HZ)
return -EINVAL;
rose->hb = opt * HZ;
return 0;
case ROSE_IDLE:
- if (opt < 0)
+ if (opt > UINT_MAX / (60 * HZ))
return -EINVAL;
rose->idle = opt * 60 * HZ;
return 0;
@@ -655,7 +655,7 @@ static int rose_release(struct socket *sock)
break;
case ROSE_STATE_2:
- rose->neighbour->use--;
+ rose_neigh_put(rose->neighbour);
release_sock(sk);
rose_disconnect(sk, 0, -1, -1);
lock_sock(sk);
@@ -693,7 +693,7 @@ static int rose_release(struct socket *sock)
return 0;
}
-static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+static int rose_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
struct rose_sock *rose = rose_sk(sk);
@@ -701,11 +701,9 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net_device *dev;
ax25_address *source;
ax25_uid_assoc *user;
+ int err = -EINVAL;
int n;
- if (!sock_flag(sk, SOCK_ZAPPED))
- return -EINVAL;
-
if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
return -EINVAL;
@@ -718,8 +716,15 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
return -EINVAL;
- if ((dev = rose_dev_get(&addr->srose_addr)) == NULL)
- return -EADDRNOTAVAIL;
+ lock_sock(sk);
+
+ if (!sock_flag(sk, SOCK_ZAPPED))
+ goto out_release;
+
+ err = -EADDRNOTAVAIL;
+ dev = rose_dev_get(&addr->srose_addr);
+ if (!dev)
+ goto out_release;
source = &addr->srose_call;
@@ -730,7 +735,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
} else {
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
dev_put(dev);
- return -EACCES;
+ err = -EACCES;
+ goto out_release;
}
rose->source_call = *source;
}
@@ -753,11 +759,14 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
rose_insert_socket(sk);
sock_reset_flag(sk, SOCK_ZAPPED);
-
- return 0;
+ err = 0;
+out_release:
+ release_sock(sk);
+ return err;
}
-static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len,
+ int flags)
{
struct sock *sk = sock->sk;
struct rose_sock *rose = rose_sk(sk);
@@ -815,6 +824,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
rose->lci = rose_new_lci(rose->neighbour);
if (!rose->lci) {
err = -ENETUNREACH;
+ rose_neigh_put(rose->neighbour);
goto out_release;
}
@@ -826,12 +836,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
dev = rose_dev_first();
if (!dev) {
err = -ENETUNREACH;
+ rose_neigh_put(rose->neighbour);
goto out_release;
}
user = ax25_findbyuid(current_euid());
if (!user) {
err = -EINVAL;
+ rose_neigh_put(rose->neighbour);
dev_put(dev);
goto out_release;
}
@@ -866,8 +878,6 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
rose->state = ROSE_STATE_1;
- rose->neighbour->use++;
-
rose_write_internal(sk, ROSE_CALL_REQUEST);
rose_start_heartbeat(sk);
rose_start_t1timer(sk);
@@ -1069,7 +1079,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
GFP_ATOMIC);
make_rose->facilities = facilities;
- make_rose->neighbour->use++;
+ rose_neigh_hold(make_rose->neighbour);
if (rose_sk(sk)->defer) {
make_rose->state = ROSE_STATE_5;