diff options
| author | David S. Miller <davem@nuts.ninka.net> | 2002-06-07 09:30:48 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2002-06-07 09:30:48 -0700 |
| commit | 75541efda9e25bd86f36b3c7005c88ceaa2f950f (patch) | |
| tree | 69a94a24b46c05c5cc18b9a100d2b9f848493374 | |
| parent | 410e9a9b57989315c0957f5469e1c9e581d2cb2d (diff) | |
| parent | 64127bdfc5e42448278f23adf8e0b42289a568c5 (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.c | 246 |
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) |
