Skip to content

Commit 20bf50d

Browse files
Tom Herbertdavem330
Tom Herbert
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 306b13e commit 20bf50d

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

include/linux/skbuff.h

+3
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,9 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
31133113
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
31143114
struct pipe_inode_info *pipe, unsigned int len,
31153115
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);
31163119
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
31173120
unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
31183121
int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,

net/core/skbuff.c

+101
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,107 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
19821982
}
19831983
EXPORT_SYMBOL_GPL(skb_splice_bits);
19841984

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+
19852086
/**
19862087
* skb_store_bits - store bits from kernel buffer to skb
19872088
* @skb: destination buffer

0 commit comments

Comments
 (0)