diff options
author | Tom Herbert <tom@quantonium.net> | 2017-07-28 19:22:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-01 18:26:18 -0400 |
commit | 20bf50de3028cb15fa81e1d1e63ab6e0c85257fc (patch) | |
tree | 07618e5eb3db85d12ec764cd235d0de531c4e76e /net/core | |
parent | 306b13eb3cf9515a8214bbf5d69d811371d05792 (diff) |
skbuff: Function to send an skbuf on a socket
Add skb_send_sock to send an skbuff on a socket within the kernel.
Arguments include an offset so that an skbuf might be sent in mulitple
calls (e.g. send buffer limit is hit).
Signed-off-by: Tom Herbert <tom@quantonium.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/skbuff.c | 101 |
1 files changed, 101 insertions, 0 deletions
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 |