Commit 94ca866c authored by Jeroen Vreeken's avatar Jeroen Vreeken Committed by David S. Miller

[NETROM]: Lock sockets while doing protocol processing.

parent af8a45cb
......@@ -147,8 +147,10 @@ static struct sock *nr_find_listener(ax25_address *addr)
spin_lock_bh(&nr_list_lock);
sk_for_each(s, node, &nr_list)
if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
s->sk_state == TCP_LISTEN)
s->sk_state == TCP_LISTEN) {
bh_lock_sock(s);
goto found;
}
s = NULL;
found:
spin_unlock_bh(&nr_list_lock);
......@@ -167,9 +169,11 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
sk_for_each(s, node, &nr_list) {
nr_cb *nr = nr_sk(s);
if (nr->my_index == index && nr->my_id == id)
if (nr->my_index == index && nr->my_id == id) {
bh_lock_sock(s);
goto found;
}
}
s = NULL;
found:
spin_unlock_bh(&nr_list_lock);
......@@ -190,9 +194,11 @@ static struct sock *nr_find_peer(unsigned char index, unsigned char id,
nr_cb *nr = nr_sk(s);
if (nr->your_index == index && nr->your_id == id &&
!ax25cmp(&nr->dest_addr, dest))
!ax25cmp(&nr->dest_addr, dest)) {
bh_lock_sock(s);
goto found;
}
}
s = NULL;
found:
spin_unlock_bh(&nr_list_lock);
......@@ -206,14 +212,17 @@ static unsigned short nr_find_next_circuit(void)
{
unsigned short id = circuit;
unsigned char i, j;
struct sock *sk;
for (;;) {
i = id / 256;
j = id % 256;
if (i != 0 && j != 0)
if (nr_find_socket(i, j) == NULL)
if (i != 0 && j != 0) {
if ((sk=nr_find_socket(i, j)) == NULL)
break;
bh_unlock_sock(sk);
}
id++;
}
......@@ -231,7 +240,12 @@ void nr_destroy_socket(struct sock *);
*/
static void nr_destroy_timer(unsigned long data)
{
nr_destroy_socket((struct sock *)data);
struct sock *sk=(struct sock *)data;
bh_lock_sock(sk);
sock_hold(sk);
nr_destroy_socket(sk);
bh_unlock_sock(sk);
sock_put(sk);
}
/*
......@@ -277,7 +291,7 @@ void nr_destroy_socket(struct sock *sk)
sk->sk_timer.data = (unsigned long)sk;
add_timer(&sk->sk_timer);
} else
sk_free(sk);
sock_put(sk);
}
/*
......@@ -391,12 +405,15 @@ static int nr_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
lock_sock(sk);
if (sk->sk_state != TCP_LISTEN) {
memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
sk->sk_max_ack_backlog = backlog;
sk->sk_state = TCP_LISTEN;
release_sock(sk);
return 0;
}
release_sock(sk);
return -EOPNOTSUPP;
}
......@@ -498,6 +515,7 @@ static int nr_release(struct socket *sock)
if (sk == NULL) return 0;
lock_sock(sk);
nr = nr_sk(sk);
switch (nr->state) {
......@@ -531,6 +549,7 @@ static int nr_release(struct socket *sock)
}
sock->sk = NULL;
release_sock(sk);
return 0;
}
......@@ -543,21 +562,26 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net_device *dev;
ax25_address *user, *source;
if (!sk->sk_zapped)
lock_sock(sk);
if (!sk->sk_zapped) {
release_sock(sk);
return -EINVAL;
if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct
full_sockaddr_ax25))
}
if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) {
release_sock(sk);
return -EINVAL;
if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25)))
}
if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) {
release_sock(sk);
return -EINVAL;
if (addr->fsa_ax25.sax25_family != AF_NETROM)
}
if (addr->fsa_ax25.sax25_family != AF_NETROM) {
release_sock(sk);
return -EINVAL;
}
if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n");
release_sock(sk);
return -EADDRNOTAVAIL;
}
......@@ -565,16 +589,22 @@ full_sockaddr_ax25))
* Only the super user can set an arbitrary user callsign.
*/
if (addr->fsa_ax25.sax25_ndigis == 1) {
if (!capable(CAP_NET_BIND_SERVICE))
if (!capable(CAP_NET_BIND_SERVICE)) {
dev_put(dev);
release_sock(sk);
return -EACCES;
}
nr->user_addr = addr->fsa_digipeater[0];
nr->source_addr = addr->fsa_ax25.sax25_call;
} else {
source = &addr->fsa_ax25.sax25_call;
if ((user = ax25_findbyuid(current->euid)) == NULL) {
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
release_sock(sk);
dev_put(dev);
return -EPERM;
}
user = source;
}
......@@ -586,6 +616,8 @@ full_sockaddr_ax25))
nr_insert_socket(sk);
sk->sk_zapped = 0;
dev_put(dev);
release_sock(sk);
SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
return 0;
}
......@@ -599,39 +631,50 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
ax25_address *user, *source = NULL;
struct net_device *dev;
lock_sock(sk);
if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
release_sock(sk);
return 0; /* Connect completed during a ERESTARTSYS event */
}
if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED;
release_sock(sk);
return -ECONNREFUSED;
}
if (sk->sk_state == TCP_ESTABLISHED)
if (sk->sk_state == TCP_ESTABLISHED) {
release_sock(sk);
return -EISCONN; /* No reconnect on a seqpacket socket */
}
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
release_sock(sk);
return -EINVAL;
if (addr->sax25_family != AF_NETROM)
}
if (addr->sax25_family != AF_NETROM) {
release_sock(sk);
return -EINVAL;
}
if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */
sk->sk_zapped = 0;
if ((dev = nr_dev_first()) == NULL)
if ((dev = nr_dev_first()) == NULL) {
release_sock(sk);
return -ENETUNREACH;
}
source = (ax25_address *)dev->dev_addr;
if ((user = ax25_findbyuid(current->euid)) == NULL) {
if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
dev_put(dev);
release_sock(sk);
return -EPERM;
}
user = source;
}
......@@ -639,12 +682,15 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
nr->source_addr = *source;
nr->device = dev;
dev_put(dev);
nr_insert_socket(sk); /* Finish the bind */
}
nr->dest_addr = addr->sax25_call;
release_sock(sk);
circuit = nr_find_next_circuit();
lock_sock(sk);
nr->my_index = circuit / 256;
nr->my_id = circuit % 256;
......@@ -662,8 +708,10 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
nr_start_heartbeat(sk);
/* Now the loop */
if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
release_sock(sk);
return -EINPROGRESS;
}
/*
* A Connect Ack with Choke or timeout or failed routing will go to
......@@ -678,8 +726,10 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
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;
}
return -ERESTARTSYS;
......@@ -690,10 +740,12 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->sk_state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED;
release_sock(sk);
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED;
release_sock(sk);
return 0;
}
......@@ -756,6 +808,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
newsock->sk = newsk;
out:
release_sock(sk);
return err;
}
......@@ -766,9 +819,12 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
struct sock *sk = sock->sk;
nr_cb *nr = nr_sk(sk);
lock_sock(sk);
if (peer != 0) {
if (sk->sk_state != TCP_ESTABLISHED)
if (sk->sk_state != TCP_ESTABLISHED) {
release_sock(sk);
return -ENOTCONN;
}
sax->fsa_ax25.sax25_family = AF_NETROM;
sax->fsa_ax25.sax25_ndigis = 1;
sax->fsa_ax25.sax25_call = nr->user_addr;
......@@ -780,6 +836,7 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
sax->fsa_ax25.sax25_call = nr->source_addr;
*uaddr_len = sizeof(struct sockaddr_ax25);
}
release_sock(sk);
return 0;
}
......@@ -793,6 +850,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
unsigned short circuit_index, circuit_id;
unsigned short peer_circuit_index, peer_circuit_id;
unsigned short frametype, flags, window, timeout;
int ret;
skb->sk = NULL; /* Initially we don't know who it's for */
......@@ -850,7 +908,9 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
else
nr_sk(sk)->bpqext = 0;
return nr_process_rx_frame(sk, skb);
ret = nr_process_rx_frame(sk, skb);
bh_unlock_sock(sk);
return ret;
}
/*
......@@ -880,6 +940,8 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
(make = nr_make_new(sk)) == NULL) {
nr_transmit_refusal(skb, 0);
if (sk)
bh_unlock_sock(sk);
return 0;
}
......@@ -897,7 +959,9 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
nr_make->your_index = circuit_index;
nr_make->your_id = circuit_id;
bh_unlock_sock(sk);
circuit = nr_find_next_circuit();
bh_lock_sock(sk);
nr_make->my_index = circuit / 256;
nr_make->my_id = circuit % 256;
......@@ -939,6 +1003,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk, skb->len);
bh_unlock_sock(sk);
return 1;
}
......@@ -957,28 +1022,42 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
return -EINVAL;
if (sk->sk_zapped)
return -EADDRNOTAVAIL;
lock_sock(sk);
if (sk->sk_zapped) {
err = -EADDRNOTAVAIL;
goto out;
}
if (sk->sk_shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0);
return -EPIPE;
err = -EPIPE;
goto out;
}
if (nr->device == NULL)
return -ENETUNREACH;
if (nr->device == NULL) {
err = -ENETUNREACH;
goto out;
}
if (usax) {
if (msg->msg_namelen < sizeof(sax))
return -EINVAL;
if (msg->msg_namelen < sizeof(sax)) {
err = -EINVAL;
goto out;
}
sax = *usax;
if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0)
return -EISCONN;
if (sax.sax25_family != AF_NETROM)
return -EINVAL;
if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) {
err = -EISCONN;
goto out;
}
if (sax.sax25_family != AF_NETROM) {
err = -EINVAL;
goto out;
}
} else {
if (sk->sk_state != TCP_ESTABLISHED)
return -ENOTCONN;
if (sk->sk_state != TCP_ESTABLISHED) {
err = -ENOTCONN;
goto out;
}
sax.sax25_family = AF_NETROM;
sax.sax25_call = nr->dest_addr;
}
......@@ -987,10 +1066,10 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
/* Build a packet */
SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
return err;
goto out;
skb_reserve(skb, size - len);
......@@ -1025,12 +1104,16 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_state != TCP_ESTABLISHED) {
kfree_skb(skb);
return -ENOTCONN;
err = -ENOTCONN;
goto out;
}
nr_output(sk, skb); /* Shove it onto the queue */
return len;
err = len;
out:
release_sock(sk);
return err;
}
static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
......@@ -1047,12 +1130,17 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
* us! We do one quick check first though
*/
if (sk->sk_state != TCP_ESTABLISHED)
lock_sock(sk);
if (sk->sk_state != TCP_ESTABLISHED) {
release_sock(sk);
return -ENOTCONN;
}
/* Now we can treat all alike */
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) {
release_sock(sk);
return er;
}
skb->h.raw = skb->data;
copied = skb->len;
......@@ -1073,6 +1161,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_free_datagram(sk, skb);
release_sock(sk);
return copied;
}
......@@ -1080,13 +1169,16 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
int ret;
lock_sock(sk);
switch (cmd) {
case TIOCOUTQ: {
long amount;
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
release_sock(sk);
return put_user(amount, (int *)arg);
}
......@@ -1096,15 +1188,21 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
amount = skb->len;
release_sock(sk);
return put_user(amount, (int *)arg);
}
case SIOCGSTAMP:
if (sk != NULL) {
if (!sk->sk_stamp.tv_sec)
if (!sk->sk_stamp.tv_sec) {
release_sock(sk);
return -ENOENT;
return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
}
ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
release_sock(sk);
return ret;
}
release_sock(sk);
return -EINVAL;
case SIOCGIFADDR:
......@@ -1117,17 +1215,21 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
release_sock(sk);
return -EINVAL;
case SIOCADDRT:
case SIOCDELRT:
case SIOCNRDECOBS:
release_sock(sk);
if (!capable(CAP_NET_ADMIN)) return -EPERM;
return nr_rt_ioctl(cmd, (void *)arg);
default:
release_sock(sk);
return dev_ioctl(cmd, (void *)arg);
}
release_sock(sk);
return 0;
}
......@@ -1147,7 +1249,9 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n");
sk_for_each(s, node, &nr_list) {
nr_cb *nr = nr_sk(s);
nr_cb *nr;
bh_lock_sock(s);
nr = nr_sk(s);
if ((dev = nr->device) == NULL)
devname = "???";
......@@ -1190,7 +1294,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
len = 0;
begin = pos;
}
bh_unlock_sock(s);
if (pos > offset + length)
break;
}
......
......@@ -74,6 +74,7 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK: {
nr_cb *nr = nr_sk(sk);
......@@ -102,6 +103,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
default:
break;
}
bh_unlock_sock(sk);
return 0;
}
......@@ -114,6 +116,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK | NR_CHOKE_FLAG:
nr_disconnect(sk, ECONNRESET);
......@@ -129,6 +132,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
default:
break;
}
bh_unlock_sock(sk);
return 0;
}
......@@ -150,6 +154,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr = skb->data[18];
ns = skb->data[17];
bh_lock_sock(sk);
switch (frametype) {
case NR_CONNREQ:
nr_write_internal(sk, NR_CONNACK);
......@@ -260,6 +265,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
default:
break;
}
bh_unlock_sock(sk);
return queued;
}
......
......@@ -143,7 +143,10 @@ static void nr_heartbeat_expiry(unsigned long param)
is accepted() it isn't 'dead' so doesn't get removed. */
if (sock_flag(sk, SOCK_DESTROY) ||
(sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
sock_hold(sk);
nr_destroy_socket(sk);
bh_unlock_sock(sk);
sock_put(sk);
return;
}
break;
......@@ -227,6 +230,7 @@ static void nr_t1timer_expiry(unsigned long param)
case NR_STATE_1:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
......@@ -237,6 +241,7 @@ static void nr_t1timer_expiry(unsigned long param)
case NR_STATE_2:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
......@@ -247,6 +252,7 @@ static void nr_t1timer_expiry(unsigned long param)
case NR_STATE_3:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment