Commit e7d2dc10 authored by David S. Miller's avatar David S. Miller

Merge master.kernel.org:/home/acme/BK/x25-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 606456cc 53cdc7d9
...@@ -330,7 +330,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -330,7 +330,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
kfree_skb(skb); kfree_skb(skb);
} }
if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) {
/* Defer: outstanding buffers */ /* Defer: outstanding buffers */
init_timer(&sk->timer); init_timer(&sk->timer);
sk->timer.expires = jiffies + 10 * HZ; sk->timer.expires = jiffies + 10 * HZ;
...@@ -351,75 +351,71 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -351,75 +351,71 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
*/ */
static int x25_setsockopt(struct socket *sock, int level, int optname, static int x25_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock *sk = sock->sk;
int opt; int opt;
struct sock *sk = sock->sk;
int rc = -ENOPROTOOPT;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EINVAL;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return-EINVAL; goto out;
rc = -EFAULT;
if (get_user(opt, (int *)optval)) if (get_user(opt, (int *)optval))
return -EFAULT; goto out;
switch (optname) { x25_sk(sk)->qbitincl = !!opt;
case X25_QBITINCL: rc = 0;
x25_sk(sk)->qbitincl = opt ? 1 : 0; out:
return 0; return rc;
default:
return -ENOPROTOOPT;
}
} }
static int x25_getsockopt(struct socket *sock, int level, int optname, static int x25_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int val = 0; int val, len, rc = -ENOPROTOOPT;
int len;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EFAULT;
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; goto out;
switch (optname) {
case X25_QBITINCL:
val = x25_sk(sk)->qbitincl;
break;
default:
return -ENOPROTOOPT;
}
len = min_t(unsigned int, len, sizeof(int)); len = min_t(unsigned int, len, sizeof(int));
rc = -EINVAL;
if (len < 0) if (len < 0)
return -EINVAL; goto out;
rc = -EFAULT;
if (put_user(len, optlen)) if (put_user(len, optlen))
return -EFAULT; goto out;
return copy_to_user(optval, &val, len) ? -EFAULT : 0; val = x25_sk(sk)->qbitincl;
rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
out:
return rc;
} }
static int x25_listen(struct socket *sock, int backlog) static int x25_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int rc = -EOPNOTSUPP;
if (sk->state != TCP_LISTEN) { if (sk->state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
return 0; rc = 0;
} }
return -EOPNOTSUPP; return rc;
} }
static struct sock *x25_alloc_socket(void) static struct sock *x25_alloc_socket(void)
...@@ -436,7 +432,7 @@ static struct sock *x25_alloc_socket(void) ...@@ -436,7 +432,7 @@ static struct sock *x25_alloc_socket(void)
if (!x25) if (!x25)
goto frees; goto frees;
memset(x25, 0x00, sizeof(*x25)); memset(x25, 0, sizeof(*x25));
x25->sk = sk; x25->sk = sk;
...@@ -460,12 +456,14 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -460,12 +456,14 @@ static int x25_create(struct socket *sock, int protocol)
{ {
struct sock *sk; struct sock *sk;
x25_cb *x25; x25_cb *x25;
int rc = -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || protocol != 0) if (sock->type != SOCK_SEQPACKET || protocol)
return -ESOCKTNOSUPPORT; goto out;
rc = -ENOMEM;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return -ENOMEM; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -489,20 +487,21 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -489,20 +487,21 @@ static int x25_create(struct socket *sock, int protocol)
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE; x25->facilities.reverse = X25_DEFAULT_REVERSE;
rc = 0;
return 0; out:
return rc;
} }
static struct sock *x25_make_new(struct sock *osk) static struct sock *x25_make_new(struct sock *osk)
{ {
struct sock *sk; struct sock *sk = NULL;
x25_cb *x25, *ox25; x25_cb *x25, *ox25;
if (osk->type != SOCK_SEQPACKET) if (osk->type != SOCK_SEQPACKET)
return NULL; goto out;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return NULL; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -527,7 +526,7 @@ static struct sock *x25_make_new(struct sock *osk) ...@@ -527,7 +526,7 @@ static struct sock *x25_make_new(struct sock *osk)
x25->qbitincl = ox25->qbitincl; x25->qbitincl = ox25->qbitincl;
init_timer(&x25->timer); init_timer(&x25->timer);
out:
return sk; return sk;
} }
...@@ -577,21 +576,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -577,21 +576,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
if (sk->zapped == 0) if (!sk->zapped ||
return -EINVAL; addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr_len != sizeof(struct sockaddr_x25))
return -EINVAL;
if (addr->sx25_family != AF_X25)
return -EINVAL; return -EINVAL;
x25_sk(sk)->source_addr = addr->sx25_addr; x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk); x25_insert_socket(sk);
sk->zapped = 0; sk->zapped = 0;
SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
return 0; return 0;
...@@ -603,42 +595,49 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -603,42 +595,49 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
struct net_device *dev; struct net_device *dev;
int rc = 0;
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
return 0; /* Connect completed during a ERESTARTSYS event */ goto out; /* Connect completed during a ERESTARTSYS event */
} }
rc = -ECONNREFUSED;
if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return -ECONNREFUSED; goto out;
} }
rc = -EISCONN; /* No reconnect on a seqpacket socket */
if (sk->state == TCP_ESTABLISHED) if (sk->state == TCP_ESTABLISHED)
return -EISCONN; /* No reconnect on a seqpacket socket */ goto out;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if (addr_len != sizeof(struct sockaddr_x25)) rc = -EINVAL;
return -EINVAL; if (addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr->sx25_family != AF_X25) goto out;
return -EINVAL;
if ((dev = x25_get_route(&addr->sx25_addr)) == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; dev = x25_get_route(&addr->sx25_addr);
if (!dev)
goto out;
if ((x25->neighbour = x25_get_neigh(dev)) == NULL) x25->neighbour = x25_get_neigh(dev);
return -ENETUNREACH; if (!x25->neighbour)
goto out;
x25_limit_facilities(&x25->facilities, x25->neighbour); x25_limit_facilities(&x25->facilities, x25->neighbour);
if ((x25->lci = x25_new_lci(x25->neighbour)) == 0) x25->lci = x25_new_lci(x25->neighbour);
return -ENETUNREACH; if (!x25->lci)
goto out;
rc = -EINVAL;
if (sk->zapped) /* Must bind first - autobinding does not work */ if (sk->zapped) /* Must bind first - autobinding does not work */
return -EINVAL; goto out;
if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr)) if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
memset(&x25->source_addr, '\0', X25_ADDR_LEN); memset(&x25->source_addr, '\0', X25_ADDR_LEN);
...@@ -657,49 +656,50 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -657,49 +656,50 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_start_t21timer(sk); x25_start_t21timer(sk);
/* Now the loop */ /* Now the loop */
rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS; goto out;
cli(); /* To avoid races on the sleep */ cli(); /* To avoid races on the sleep */
/* /*
* A Clear Request or timeout or failed routing will go to closed. * A Clear Request or timeout or failed routing will go to closed.
*/ */
rc = -ERESTARTSYS;
while (sk->state == TCP_SYN_SENT) { while (sk->state == TCP_SYN_SENT) {
/* FIXME: going to sleep with interrupts disabled */
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) { if (signal_pending(current))
sti(); goto out_unlock;
return -ERESTARTSYS;
}
} }
if (sk->state != TCP_ESTABLISHED) { if (sk->state != TCP_ESTABLISHED) {
sti();
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */ rc = sock_error(sk); /* Always set at this point */
goto out_unlock;
} }
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
rc = 0;
out_unlock:
sti(); sti();
out:
return 0; return rc;
} }
static int x25_accept(struct socket *sock, struct socket *newsock, int flags) static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct sock *sk; struct sock *sk = sock->sk;
struct sock *newsk; struct sock *newsk;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -EINVAL;
if ((sk = sock->sk) == NULL) if (!sk || sk->state != TCP_LISTEN)
return -EINVAL; goto out;
rc = -EOPNOTSUPP;
if (sk->type != SOCK_SEQPACKET) if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP; goto out;
if (sk->state != TCP_LISTEN)
return -EINVAL;
/* /*
* The write queue this time is holding sockets ready to use * The write queue this time is holding sockets ready to use
...@@ -708,32 +708,35 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -708,32 +708,35 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
do { do {
cli(); cli();
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) { rc = -EWOULDBLOCK;
sti(); if (flags & O_NONBLOCK)
return -EWOULDBLOCK; goto out_unlock;
} /* FIXME: going to sleep with interrupts disabled */
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) { rc = -ERESTARTSYS;
sti(); if (signal_pending(current))
return -ERESTARTSYS; goto out_unlock;
}
} }
} while (skb == NULL); } while (!skb);
newsk = skb->sk; newsk = skb->sk;
newsk->pair = NULL; newsk->pair = NULL;
newsk->socket = newsock; newsk->socket = newsock;
newsk->sleep = &newsock->wait; newsk->sleep = &newsock->wait;
sti(); sti();
/* Now attach up the new socket */ /* Now attach up the new socket */
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb); kfree_skb(skb);
sk->ack_backlog--; sk->ack_backlog--;
newsock->sk = newsk; newsock->sk = newsk;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
rc = 0;
return 0; out:
return rc;
out_unlock:
sti();
goto out;
} }
static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
...@@ -742,16 +745,15 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l ...@@ -742,16 +745,15 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
if (peer != 0) { if (peer) {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; return -ENOTCONN;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} else { } else
sx25->sx25_addr = x25->source_addr; sx25->sx25_addr = x25->source_addr;
}
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
*uaddr_len = sizeof(struct sockaddr_x25); *uaddr_len = sizeof(*sx25);
return 0; return 0;
} }
...@@ -784,7 +786,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -784,7 +786,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
/* /*
* We can't accept the Call Request. * We can't accept the Call Request.
*/ */
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog) { if (!sk || sk->ack_backlog == sk->max_ack_backlog) {
x25_transmit_clear_request(neigh, lci, 0x01); x25_transmit_clear_request(neigh, lci, 0x01);
return 0; return 0;
} }
...@@ -807,7 +809,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -807,7 +809,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
/* /*
* Try to create a new socket. * Try to create a new socket.
*/ */
if ((make = x25_make_new(sk)) == NULL) { make = x25_make_new(sk);
if (!make) {
x25_transmit_clear_request(neigh, lci, 0x01); x25_transmit_clear_request(neigh, lci, 0x01);
return 0; return 0;
} }
...@@ -860,46 +863,53 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -860,46 +863,53 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name; struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
int err;
struct sockaddr_x25 sx25; struct sockaddr_x25 sx25;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int size, qbit = 0; int noblock = msg->msg_flags & MSG_DONTWAIT;
int size, qbit = 0, rc = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR)) if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR))
return -EINVAL; goto out;
/* we currently don't support segmented records at the user interface */ /* we currently don't support segmented records at the user interface */
if (!(msg->msg_flags & (MSG_EOR|MSG_OOB))) if (!(msg->msg_flags & (MSG_EOR|MSG_OOB)))
return -EINVAL; goto out;
rc = -EADDRNOTAVAIL;
if (sk->zapped) if (sk->zapped)
return -EADDRNOTAVAIL; goto out;
rc = -EPIPE;
if (sk->shutdown & SEND_SHUTDOWN) { if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0); send_sig(SIGPIPE, current, 0);
return -EPIPE; goto out;
} }
if (x25->neighbour == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; if (!x25->neighbour)
goto out;
if (usx25 != NULL) { if (usx25) {
rc = -EINVAL;
if (msg->msg_namelen < sizeof(sx25)) if (msg->msg_namelen < sizeof(sx25))
return -EINVAL; goto out;
sx25 = *usx25; memcpy(&sx25, usx25, sizeof(sx25));
rc = -EISCONN;
if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr)) if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr))
return -EISCONN; goto out;
rc = -EINVAL;
if (sx25.sx25_family != AF_X25) if (sx25.sx25_family != AF_X25)
return -EINVAL; goto out;
} else { } else {
/* /*
* FIXME 1003.1g - if the socket is like this because * FIXME 1003.1g - if the socket is like this because
* it has become closed (not started closed) we ought * it has become closed (not started closed) we ought
* to SIGPIPE, EPIPE; * to SIGPIPE, EPIPE;
*/ */
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
sx25.sx25_family = AF_X25; sx25.sx25_family = AF_X25;
sx25.sx25_addr = x25->dest_addr; sx25.sx25_addr = x25->dest_addr;
...@@ -915,8 +925,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -915,8 +925,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) skb = sock_alloc_send_skb(sk, size, noblock, &rc);
return err; if (!skb)
goto out;
X25_SKB_CB(skb)->flags = msg->msg_flags; X25_SKB_CB(skb)->flags = msg->msg_flags;
skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN); skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
...@@ -928,7 +939,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -928,7 +939,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (rc)
goto out_kfree_skb;
/* /*
* If the Q BIT Include socket option is in force, the first * If the Q BIT Include socket option is in force, the first
...@@ -979,21 +992,18 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -979,21 +992,18 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n"); SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n");
SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n");
if (sk->state != TCP_ESTABLISHED) { rc = -ENOTCONN;
kfree_skb(skb); if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out_kfree_skb;
}
if (msg->msg_flags & MSG_OOB) { if (msg->msg_flags & MSG_OOB)
skb_queue_tail(&x25->interrupt_out_queue, skb); skb_queue_tail(&x25->interrupt_out_queue, skb);
} else { else {
len = x25_output(sk, skb); len = x25_output(sk, skb);
if(len<0){ if (len < 0)
kfree_skb(skb); kfree_skb(skb);
} else { else if (x25->qbitincl)
if (x25->qbitincl) len++;
len++;
}
} }
/* /*
...@@ -1013,12 +1023,17 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1013,12 +1023,17 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
lock_sock(sk); lock_sock(sk);
x25_kick(sk); x25_kick(sk);
release_sock(sk); release_sock(sk);
rc = len;
return len; out:
return rc;
out_kfree_skb:
kfree_skb(skb);
goto out;
} }
static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
...@@ -1026,18 +1041,19 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1026,18 +1041,19 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
int copied, qbit; int copied, qbit;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int er; int rc = -ENOTCONN;
/* /*
* This works for seqpacket too. The receiver has ordered the queue for * This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though * us! We do one quick check first though
*/ */
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
if (flags & MSG_OOB) { if (flags & MSG_OOB) {
rc = -EINVAL;
if (sk->urginline || !skb_peek(&x25->interrupt_in_queue)) if (sk->urginline || !skb_peek(&x25->interrupt_in_queue))
return -EINVAL; goto out;
skb = skb_dequeue(&x25->interrupt_in_queue); skb = skb_dequeue(&x25->interrupt_in_queue);
...@@ -1054,8 +1070,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1054,8 +1070,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
msg->msg_flags |= MSG_OOB; msg->msg_flags |= MSG_OOB;
} else { } else {
/* 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) skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc);
return er; if (!skb)
goto out;
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
...@@ -1080,21 +1097,25 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1080,21 +1097,25 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
/* Currently, each datagram always contains a complete record */ /* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR; msg->msg_flags |= MSG_EOR;
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (rc)
goto out_free_dgram;
if (sx25 != NULL) { if (sx25) {
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} }
msg->msg_namelen = sizeof(struct sockaddr_x25); msg->msg_namelen = sizeof(struct sockaddr_x25);
skb_free_datagram(sk, skb);
lock_sock(sk); lock_sock(sk);
x25_check_rbuf(sk); x25_check_rbuf(sk);
release_sock(sk); release_sock(sk);
rc = copied;
return copied; out_free_dgram:
skb_free_datagram(sk, skb);
out:
return rc;
} }
......
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