aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 267185a848f6..844b8abeb18c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2018,6 +2018,146 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
2018 skb_split_no_header(skb, skb1, len, pos); 2018 skb_split_no_header(skb, skb1, len, pos);
2019} 2019}
2020 2020
2021/* Shifting from/to a cloned skb is a no-go.
2022 *
2023 * TODO: handle cloned skbs by using pskb_expand_head()
2024 */
2025static int skb_prepare_for_shift(struct sk_buff *skb)
2026{
2027 return skb_cloned(skb);
2028}
2029
2030/**
2031 * skb_shift - Shifts paged data partially from skb to another
2032 * @tgt: buffer into which tail data gets added
2033 * @skb: buffer from which the paged data comes from
2034 * @shiftlen: shift up to this many bytes
2035 *
2036 * Attempts to shift up to shiftlen worth of bytes, which may be less than
2037 * the length of the skb, from tgt to skb. Returns number bytes shifted.
2038 * It's up to caller to free skb if everything was shifted.
2039 *
2040 * If @tgt runs out of frags, the whole operation is aborted.
2041 *
2042 * Skb cannot include anything else but paged data while tgt is allowed
2043 * to have non-paged data as well.
2044 *
2045 * TODO: full sized shift could be optimized but that would need
2046 * specialized skb free'er to handle frags without up-to-date nr_frags.
2047 */
2048int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
2049{
2050 int from, to, merge, todo;
2051 struct skb_frag_struct *fragfrom, *fragto;
2052
2053 BUG_ON(shiftlen > skb->len);
2054 BUG_ON(skb_headlen(skb)); /* Would corrupt stream */
2055
2056 todo = shiftlen;
2057 from = 0;
2058 to = skb_shinfo(tgt)->nr_frags;
2059 fragfrom = &skb_shinfo(skb)->frags[from];
2060
2061 /* Actual merge is delayed until the point when we know we can
2062 * commit all, so that we don't have to undo partial changes
2063 */
2064 if (!to ||
2065 !skb_can_coalesce(tgt, to, fragfrom->page, fragfrom->page_offset)) {
2066 merge = -1;
2067 } else {
2068 merge = to - 1;
2069
2070 todo -= fragfrom->size;
2071 if (todo < 0) {
2072 if (skb_prepare_for_shift(skb) ||
2073 skb_prepare_for_shift(tgt))
2074 return 0;
2075
2076 fragto = &skb_shinfo(tgt)->frags[merge];
2077
2078 fragto->size += shiftlen;
2079 fragfrom->size -= shiftlen;
2080 fragfrom->page_offset += shiftlen;
2081
2082 goto onlymerged;
2083 }
2084
2085 from++;
2086 }
2087
2088 /* Skip full, not-fitting skb to avoid expensive operations */
2089 if ((shiftlen == skb->len) &&
2090 (skb_shinfo(skb)->nr_frags - from) > (MAX_SKB_FRAGS - to))
2091 return 0;
2092
2093 if (skb_prepare_for_shift(skb) || skb_prepare_for_shift(tgt))
2094 return 0;
2095
2096 while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) {
2097 if (to == MAX_SKB_FRAGS)
2098 return 0;
2099
2100 fragfrom = &skb_shinfo(skb)->frags[from];
2101 fragto = &skb_shinfo(tgt)->frags[to];
2102
2103 if (todo >= fragfrom->size) {
2104 *fragto = *fragfrom;
2105 todo -= fragfrom->size;
2106 from++;
2107 to++;
2108
2109 } else {
2110 get_page(fragfrom->page);
2111 fragto->page = fragfrom->page;
2112 fragto->page_offset = fragfrom->page_offset;
2113 fragto->size = todo;
2114
2115 fragfrom->page_offset += todo;
2116 fragfrom->size -= todo;
2117 todo = 0;
2118
2119 to++;
2120 break;
2121 }
2122 }
2123
2124 /* Ready to "commit" this state change to tgt */
2125 skb_shinfo(tgt)->nr_frags = to;
2126
2127 if (merge >= 0) {
2128 fragfrom = &skb_shinfo(skb)->frags[0];
2129 fragto = &skb_shinfo(tgt)->frags[merge];
2130
2131 fragto->size += fragfrom->size;
2132 put_page(fragfrom->page);
2133 }
2134
2135 /* Reposition in the original skb */
2136 to = 0;
2137 while (from < skb_shinfo(skb)->nr_frags)
2138 skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++];
2139 skb_shinfo(skb)->nr_frags = to;
2140
2141 BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags);
2142
2143onlymerged:
2144 /* Most likely the tgt won't ever need its checksum anymore, skb on
2145 * the other hand might need it if it needs to be resent
2146 */
2147 tgt->ip_summed = CHECKSUM_PARTIAL;
2148 skb->ip_summed = CHECKSUM_PARTIAL;
2149
2150 /* Yak, is it really working this way? Some helper please? */
2151 skb->len -= shiftlen;
2152 skb->data_len -= shiftlen;
2153 skb->truesize -= shiftlen;
2154 tgt->len += shiftlen;
2155 tgt->data_len += shiftlen;
2156 tgt->truesize += shiftlen;
2157
2158 return shiftlen;
2159}
2160
2021/** 2161/**
2022 * skb_prepare_seq_read - Prepare a sequential read of skb data 2162 * skb_prepare_seq_read - Prepare a sequential read of skb data
2023 * @skb: the buffer to read 2163 * @skb: the buffer to read