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