summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.ninka.net>2002-06-07 09:30:48 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2002-06-07 09:30:48 -0700
commit75541efda9e25bd86f36b3c7005c88ceaa2f950f (patch)
tree69a94a24b46c05c5cc18b9a100d2b9f848493374
parent410e9a9b57989315c0957f5469e1c9e581d2cb2d (diff)
parent64127bdfc5e42448278f23adf8e0b42289a568c5 (diff)
Merge http://kernel-acme.bkbits.net:8080/net-cleanups-2.5-datagram
into nuts.ninka.net:/home/davem/src/BK/net-2.5
-rw-r--r--net/core/datagram.c246
1 files changed, 142 insertions, 104 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 5d0c4104a6f1..ece74de9d1ca 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -1,19 +1,28 @@
/*
* SUCS NET3:
*
- * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
- * of these would make sense. Not tonight however 8-).
- * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical poll code and mostly
- * identical recvmsg() code. So we share it here. The poll was shared before but buried in udp.c so I moved it.
+ * Generic datagram handling routines. These are generic for all
+ * protocols. Possibly a generic IP version on top of these would
+ * make sense. Not tonight however 8-).
+ * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and
+ * NetROM layer all have identical poll code and mostly
+ * identical recvmsg() code. So we share it here. The poll was
+ * shared before but buried in udp.c so I moved it.
*
- * Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old udp.c code)
+ * Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old
+ * udp.c code)
*
* Fixes:
- * Alan Cox : NULL return from skb_peek_copy() understood
- * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
- * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
- * AX.25 now works right, and SPX is feasible.
- * Alan Cox : Fixed write poll of non IP protocol crash.
+ * Alan Cox : NULL return from skb_peek_copy()
+ * understood
+ * Alan Cox : Rewrote skb_read_datagram to avoid the
+ * skb_peek_copy stuff.
+ * Alan Cox : Added support for SOCK_SEQPACKET.
+ * IPX can no longer use the SO_TYPE hack
+ * but AX.25 now works right, and SPX is
+ * feasible.
+ * Alan Cox : Fixed write poll of non IP protocol
+ * crash.
* Florian La Roche: Changed for my new skbuff handling.
* Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
* Linus Torvalds : BSD semantic fixes.
@@ -48,18 +57,15 @@
/*
* Is a socket 'connection oriented' ?
*/
-
static inline int connection_based(struct sock *sk)
{
- return (sk->type==SOCK_SEQPACKET || sk->type==SOCK_STREAM);
+ return sk->type == SOCK_SEQPACKET || sk->type == SOCK_STREAM;
}
-
/*
* Wait for a packet..
*/
-
-static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
+static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
{
int error;
@@ -74,51 +80,57 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
goto out_err;
if (!skb_queue_empty(&sk->receive_queue))
- goto ready;
+ goto out;
/* Socket shut down? */
if (sk->shutdown & RCV_SHUTDOWN)
goto out_noerr;
- /* Sequenced packets can come disconnected. If so we report the problem */
+ /* Sequenced packets can come disconnected.
+ * If so we report the problem
+ */
error = -ENOTCONN;
- if(connection_based(sk) && !(sk->state==TCP_ESTABLISHED || sk->state==TCP_LISTEN))
+ if (connection_based(sk) && !(sk->state == TCP_ESTABLISHED ||
+ sk->state == TCP_LISTEN))
goto out_err;
/* handle signals */
if (signal_pending(current))
goto interrupted;
+ error = 0;
*timeo_p = schedule_timeout(*timeo_p);
-
-ready:
+out:
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
- return 0;
-
+ return error;
interrupted:
error = sock_intr_errno(*timeo_p);
out_err:
*err = error;
-out:
- current->state = TASK_RUNNING;
- remove_wait_queue(sk->sleep, &wait);
- return error;
+ goto out;
out_noerr:
*err = 0;
error = 1;
goto out;
}
-/*
- * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
- * races. This replaces identical code in packet,raw and udp, as well as the IPX
- * AX.25 and Appletalk. It also finally fixes the long standing peek and read
- * race for datagram sockets. If you alter this routine remember it must be
- * re-entrant.
+/**
+ * skb_recv_datagram - Receive a datagram skbuff
+ * @sk - socket
+ * @flags - MSG_ flags
+ * @noblock - blocking operation?
+ * @err - error code returned
+ *
+ * Get a datagram skbuff, understands the peeking, nonblocking wakeups
+ * and possible races. This replaces identical code in packet, raw and
+ * udp, as well as the IPX AX.25 and Appletalk. It also finally fixes
+ * the long standing peek and read race for datagram sockets. If you
+ * alter this routine remember it must be re-entrant.
*
* This function will lock the socket if a skb is returned, so the caller
- * needs to unlock the socket in that case (usually by calling skb_free_datagram)
+ * needs to unlock the socket in that case (usually by calling
+ * skb_free_datagram)
*
* * It does not lock socket since today. This function is
* * free of race conditions. This measure should/can improve
@@ -132,36 +144,35 @@ out_noerr:
* quite explicitly by POSIX 1003.1g, don't change them without having
* the standard around please.
*/
-
-struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
+struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
+ int noblock, int *err)
{
- int error;
struct sk_buff *skb;
long timeo;
-
/* Caller is allowed not to check sk->err before skb_recv_datagram() */
- error = sock_error(sk);
+ int error = sock_error(sk);
+
if (error)
goto no_packet;
timeo = sock_rcvtimeo(sk, noblock);
do {
- /* Again only user level code calls this function, so nothing interrupt level
- will suddenly eat the receive_queue.
-
- Look at current nfs client by the way...
- However, this function was corrent in any case. 8)
+ /* Again only user level code calls this function, so nothing
+ * interrupt level will suddenly eat the receive_queue.
+ *
+ * Look at current nfs client by the way...
+ * However, this function was corrent in any case. 8)
*/
- if (flags & MSG_PEEK)
- {
+ if (flags & MSG_PEEK) {
unsigned long cpu_flags;
spin_lock_irqsave(&sk->receive_queue.lock, cpu_flags);
skb = skb_peek(&sk->receive_queue);
- if(skb!=NULL)
+ if (skb)
atomic_inc(&skb->users);
- spin_unlock_irqrestore(&sk->receive_queue.lock, cpu_flags);
+ spin_unlock_irqrestore(&sk->receive_queue.lock,
+ cpu_flags);
} else
skb = skb_dequeue(&sk->receive_queue);
@@ -173,7 +184,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
if (!timeo)
goto no_packet;
- } while (wait_for_packet(sk, err, &timeo) == 0);
+ } while (!wait_for_packet(sk, err, &timeo));
return NULL;
@@ -182,7 +193,7 @@ no_packet:
return NULL;
}
-void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
+void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
{
kfree_skb(skb);
}
@@ -190,26 +201,33 @@ void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
/*
* Copy a datagram to a linear buffer.
*/
-
int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size)
{
- struct iovec iov = { to, size };
+ struct iovec iov = {
+ iov_base: to,
+ iov_len: size,
+ };
return skb_copy_datagram_iovec(skb, offset, &iov, size);
}
-/*
- * Copy a datagram to an iovec.
+/**
+ * skb_copy_datagram_iovec - Copy a datagram to an iovec.
+ * @skb - buffer to copy
+ * @offset - offset in the buffer to start copying from
+ * @iovec - io vector to copy to
+ * @len - amount of data to copy from buffer to iovec
+ *
* Note: the iovec is modified during the copy.
*/
-int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec *to,
- int len)
+int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
+ struct iovec *to, int len)
{
- int i, copy;
int start = skb->len - skb->data_len;
+ int i, copy = start - offset;
/* Copy header. */
- if ((copy = start-offset) > 0) {
+ if (copy > 0) {
if (copy > len)
copy = len;
if (memcpy_toiovec(to, skb->data + offset, copy))
@@ -220,13 +238,13 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
}
/* Copy paged appendix. Hmm... why does this look so complicated? */
- for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
- BUG_TRAP(start <= offset+len);
+ BUG_TRAP(start <= offset + len);
end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end-offset) > 0) {
+ if ((copy = end - offset) > 0) {
int err;
u8 *vaddr;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -236,7 +254,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
copy = len;
vaddr = kmap(page);
err = memcpy_toiovec(to, vaddr + frag->page_offset +
- offset-start, copy);
+ offset - start, copy);
kunmap(page);
if (err)
goto fault;
@@ -248,18 +266,20 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
}
if (skb_shinfo(skb)->frag_list) {
- struct sk_buff *list;
+ struct sk_buff *list = skb_shinfo(skb)->frag_list;
- for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+ for (; list; list = list->next) {
int end;
- BUG_TRAP(start <= offset+len);
+ BUG_TRAP(start <= offset + len);
end = start + list->len;
- if ((copy = end-offset) > 0) {
+ if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_copy_datagram_iovec(list, offset-start, to, copy))
+ if (skb_copy_datagram_iovec(list,
+ offset - start,
+ to, copy))
goto fault;
if ((len -= copy) == 0)
return 0;
@@ -268,25 +288,27 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
start = end;
}
}
- if (len == 0)
+ if (!len)
return 0;
fault:
return -EFAULT;
}
-int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump)
+int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
+ u8 *to, int len, unsigned int *csump)
{
- int i, copy;
int start = skb->len - skb->data_len;
int pos = 0;
+ int i, copy = start - offset;
/* Copy header. */
- if ((copy = start-offset) > 0) {
+ if (copy > 0) {
int err = 0;
if (copy > len)
copy = len;
- *csump = csum_and_copy_to_user(skb->data+offset, to, copy, *csump, &err);
+ *csump = csum_and_copy_to_user(skb->data + offset, to, copy,
+ *csump, &err);
if (err)
goto fault;
if ((len -= copy) == 0)
@@ -296,13 +318,13 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
pos = copy;
}
- for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
- BUG_TRAP(start <= offset+len);
+ BUG_TRAP(start <= offset + len);
end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end-offset) > 0) {
+ if ((copy = end - offset) > 0) {
unsigned int csum2;
int err = 0;
u8 *vaddr;
@@ -312,8 +334,10 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
if (copy > len)
copy = len;
vaddr = kmap(page);
- csum2 = csum_and_copy_to_user(vaddr + frag->page_offset +
- offset-start, to, copy, 0, &err);
+ csum2 = csum_and_copy_to_user(vaddr +
+ frag->page_offset +
+ offset - start,
+ to, copy, 0, &err);
kunmap(page);
if (err)
goto fault;
@@ -328,19 +352,22 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
}
if (skb_shinfo(skb)->frag_list) {
- struct sk_buff *list;
+ struct sk_buff *list = skb_shinfo(skb)->frag_list;
- for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+ for (; list; list=list->next) {
int end;
- BUG_TRAP(start <= offset+len);
+ BUG_TRAP(start <= offset + len);
end = start + list->len;
- if ((copy = end-offset) > 0) {
+ if ((copy = end - offset) > 0) {
unsigned int csum2 = 0;
if (copy > len)
copy = len;
- if (skb_copy_and_csum_datagram(list, offset-start, to, copy, &csum2))
+ if (skb_copy_and_csum_datagram(list,
+ offset - start,
+ to, copy,
+ &csum2))
goto fault;
*csump = csum_block_add(*csump, csum2, pos);
if ((len -= copy) == 0)
@@ -352,39 +379,48 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
start = end;
}
}
- if (len == 0)
+ if (!len)
return 0;
fault:
return -EFAULT;
}
-/* Copy and checkum skb to user iovec. Caller _must_ check that
- skb will fit to this iovec.
-
- Returns: 0 - success.
- -EINVAL - checksum failure.
- -EFAULT - fault during copy. Beware, in this case iovec can be
- modified!
+/**
+ * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
+ * @skb - skbuff
+ * @hlen - hardware length
+ * @iovec - io vector
+ *
+ * Caller _must_ check that skb will fit to this iovec.
+ *
+ * Returns: 0 - success.
+ * -EINVAL - checksum failure.
+ * -EFAULT - fault during copy. Beware, in this case iovec
+ * can be modified!
*/
-
-int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov)
+int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb,
+ int hlen, struct iovec *iov)
{
unsigned int csum;
int chunk = skb->len - hlen;
- /* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */
- while (iov->iov_len == 0)
+ /* Skip filled elements.
+ * Pretty silly, look at memcpy_toiovec, though 8)
+ */
+ while (!iov->iov_len)
iov++;
if (iov->iov_len < chunk) {
- if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk+hlen, skb->csum)))
+ if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen,
+ skb->csum)))
goto csum_error;
if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
goto fault;
} else {
csum = csum_partial(skb->data, hlen, skb->csum);
- if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, chunk, &csum))
+ if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base,
+ chunk, &csum))
goto fault;
if ((unsigned short)csum_fold(csum))
goto csum_error;
@@ -392,17 +428,18 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct
iov->iov_base += chunk;
}
return 0;
-
csum_error:
return -EINVAL;
-
fault:
return -EFAULT;
}
-
-
-/*
+/**
+ * datagram_poll - generic datagram poll
+ * @file - file struct
+ * @sock - socket
+ * @wait - poll table
+ *
* Datagram poll: Again totally generic. This also handles
* sequenced packet sockets providing the socket receive queue
* is only ever holding data ready to receive.
@@ -411,8 +448,8 @@ fault:
* and you use a different write policy from sock_writeable()
* then please supply your own write_space callback.
*/
-
-unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
+unsigned int datagram_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
{
struct sock *sk = sock->sk;
unsigned int mask;
@@ -427,12 +464,13 @@ unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *
mask |= POLLHUP;
/* readable? */
- if (!skb_queue_empty(&sk->receive_queue) || (sk->shutdown&RCV_SHUTDOWN))
+ if (!skb_queue_empty(&sk->receive_queue) ||
+ (sk->shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
if (connection_based(sk)) {
- if (sk->state==TCP_CLOSE)
+ if (sk->state == TCP_CLOSE)
mask |= POLLHUP;
/* connection hasn't started yet? */
if (sk->state == TCP_SYN_SENT)