diff options
-rw-r--r-- | include/linux/skbuff.h | 3 | ||||
-rw-r--r-- | net/core/skbuff.c | 101 |
2 files changed, 104 insertions, 0 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4093552be1de..18e76bf9574e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -3113,6 +3113,9 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, | |||
3113 | int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, | 3113 | int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, |
3114 | struct pipe_inode_info *pipe, unsigned int len, | 3114 | struct pipe_inode_info *pipe, unsigned int len, |
3115 | unsigned int flags); | 3115 | unsigned int flags); |
3116 | int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset, | ||
3117 | int len); | ||
3118 | int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len); | ||
3116 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); | 3119 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); |
3117 | unsigned int skb_zerocopy_headlen(const struct sk_buff *from); | 3120 | unsigned int skb_zerocopy_headlen(const struct sk_buff *from); |
3118 | int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, | 3121 | int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c27da51d14e4..9c0e015ff3fe 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1982,6 +1982,107 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, | |||
1982 | } | 1982 | } |
1983 | EXPORT_SYMBOL_GPL(skb_splice_bits); | 1983 | EXPORT_SYMBOL_GPL(skb_splice_bits); |
1984 | 1984 | ||
1985 | /* Send skb data on a socket. Socket must be locked. */ | ||
1986 | int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset, | ||
1987 | int len) | ||
1988 | { | ||
1989 | unsigned int orig_len = len; | ||
1990 | struct sk_buff *head = skb; | ||
1991 | unsigned short fragidx; | ||
1992 | int slen, ret; | ||
1993 | |||
1994 | do_frag_list: | ||
1995 | |||
1996 | /* Deal with head data */ | ||
1997 | while (offset < skb_headlen(skb) && len) { | ||
1998 | struct kvec kv; | ||
1999 | struct msghdr msg; | ||
2000 | |||
2001 | slen = min_t(int, len, skb_headlen(skb) - offset); | ||
2002 | kv.iov_base = skb->data + offset; | ||
2003 | kv.iov_len = len; | ||
2004 | memset(&msg, 0, sizeof(msg)); | ||
2005 | |||
2006 | ret = kernel_sendmsg_locked(sk, &msg, &kv, 1, slen); | ||
2007 | if (ret <= 0) | ||
2008 | goto error; | ||
2009 | |||
2010 | offset += ret; | ||
2011 | len -= ret; | ||
2012 | } | ||
2013 | |||
2014 | /* All the data was skb head? */ | ||
2015 | if (!len) | ||
2016 | goto out; | ||
2017 | |||
2018 | /* Make offset relative to start of frags */ | ||
2019 | offset -= skb_headlen(skb); | ||
2020 | |||
2021 | /* Find where we are in frag list */ | ||
2022 | for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags; fragidx++) { | ||
2023 | skb_frag_t *frag = &skb_shinfo(skb)->frags[fragidx]; | ||
2024 | |||
2025 | if (offset < frag->size) | ||
2026 | break; | ||
2027 | |||
2028 | offset -= frag->size; | ||
2029 | } | ||
2030 | |||
2031 | for (; len && fragidx < skb_shinfo(skb)->nr_frags; fragidx++) { | ||
2032 | skb_frag_t *frag = &skb_shinfo(skb)->frags[fragidx]; | ||
2033 | |||
2034 | slen = min_t(size_t, len, frag->size - offset); | ||
2035 | |||
2036 | while (slen) { | ||
2037 | ret = kernel_sendpage_locked(sk, frag->page.p, | ||
2038 | frag->page_offset + offset, | ||
2039 | slen, MSG_DONTWAIT); | ||
2040 | if (ret <= 0) | ||
2041 | goto error; | ||
2042 | |||
2043 | len -= ret; | ||
2044 | offset += ret; | ||
2045 | slen -= ret; | ||
2046 | } | ||
2047 | |||
2048 | offset = 0; | ||
2049 | } | ||
2050 | |||
2051 | if (len) { | ||
2052 | /* Process any frag lists */ | ||
2053 | |||
2054 | if (skb == head) { | ||
2055 | if (skb_has_frag_list(skb)) { | ||
2056 | skb = skb_shinfo(skb)->frag_list; | ||
2057 | goto do_frag_list; | ||
2058 | } | ||
2059 | } else if (skb->next) { | ||
2060 | skb = skb->next; | ||
2061 | goto do_frag_list; | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | out: | ||
2066 | return orig_len - len; | ||
2067 | |||
2068 | error: | ||
2069 | return orig_len == len ? ret : orig_len - len; | ||
2070 | } | ||
2071 | EXPORT_SYMBOL_GPL(skb_send_sock_locked); | ||
2072 | |||
2073 | /* Send skb data on a socket. */ | ||
2074 | int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len) | ||
2075 | { | ||
2076 | int ret = 0; | ||
2077 | |||
2078 | lock_sock(sk); | ||
2079 | ret = skb_send_sock_locked(sk, skb, offset, len); | ||
2080 | release_sock(sk); | ||
2081 | |||
2082 | return ret; | ||
2083 | } | ||
2084 | EXPORT_SYMBOL_GPL(skb_send_sock); | ||
2085 | |||
1985 | /** | 2086 | /** |
1986 | * skb_store_bits - store bits from kernel buffer to skb | 2087 | * skb_store_bits - store bits from kernel buffer to skb |
1987 | * @skb: destination buffer | 2088 | * @skb: destination buffer |