aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h24
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/netfilter/core.c4
3 files changed, 25 insertions, 5 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 6f0b2f7d001..881fe80f01d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -147,8 +147,8 @@ struct skb_shared_info {
147 147
148/* We divide dataref into two halves. The higher 16 bits hold references 148/* We divide dataref into two halves. The higher 16 bits hold references
149 * to the payload part of skb->data. The lower 16 bits hold references to 149 * to the payload part of skb->data. The lower 16 bits hold references to
150 * the entire skb->data. It is up to the users of the skb to agree on 150 * the entire skb->data. A clone of a headerless skb holds the length of
151 * where the payload starts. 151 * the header in skb->hdr_len.
152 * 152 *
153 * All users must obey the rule that the skb->data reference count must be 153 * All users must obey the rule that the skb->data reference count must be
154 * greater than or equal to the payload reference count. 154 * greater than or equal to the payload reference count.
@@ -206,6 +206,7 @@ typedef unsigned char *sk_buff_data_t;
206 * @len: Length of actual data 206 * @len: Length of actual data
207 * @data_len: Data length 207 * @data_len: Data length
208 * @mac_len: Length of link layer header 208 * @mac_len: Length of link layer header
209 * @hdr_len: writable header length of cloned skb
209 * @csum: Checksum (must include start/offset pair) 210 * @csum: Checksum (must include start/offset pair)
210 * @csum_start: Offset from skb->head where checksumming should start 211 * @csum_start: Offset from skb->head where checksumming should start
211 * @csum_offset: Offset from csum_start where checksum should be stored 212 * @csum_offset: Offset from csum_start where checksum should be stored
@@ -260,8 +261,9 @@ struct sk_buff {
260 char cb[48]; 261 char cb[48];
261 262
262 unsigned int len, 263 unsigned int len,
263 data_len, 264 data_len;
264 mac_len; 265 __u16 mac_len,
266 hdr_len;
265 union { 267 union {
266 __wsum csum; 268 __wsum csum;
267 struct { 269 struct {
@@ -1322,6 +1324,20 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
1322} 1324}
1323 1325
1324/** 1326/**
1327 * skb_clone_writable - is the header of a clone writable
1328 * @skb: buffer to check
1329 * @len: length up to which to write
1330 *
1331 * Returns true if modifying the header part of the cloned buffer
1332 * does not requires the data to be copied.
1333 */
1334static inline int skb_clone_writable(struct sk_buff *skb, int len)
1335{
1336 return !skb_header_cloned(skb) &&
1337 skb_headroom(skb) + len <= skb->hdr_len;
1338}
1339
1340/**
1325 * skb_cow - copy header of skb when it is required 1341 * skb_cow - copy header of skb when it is required
1326 * @skb: buffer to cow 1342 * @skb: buffer to cow
1327 * @headroom: needed headroom 1343 * @headroom: needed headroom
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3943c3ad914..c989c3a0f90 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -415,6 +415,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
415 C(csum); 415 C(csum);
416 C(local_df); 416 C(local_df);
417 n->cloned = 1; 417 n->cloned = 1;
418 n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
418 n->nohdr = 0; 419 n->nohdr = 0;
419 C(pkt_type); 420 C(pkt_type);
420 C(ip_summed); 421 C(ip_summed);
@@ -676,6 +677,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
676 skb->network_header += off; 677 skb->network_header += off;
677 skb->mac_header += off; 678 skb->mac_header += off;
678 skb->cloned = 0; 679 skb->cloned = 0;
680 skb->hdr_len = 0;
679 skb->nohdr = 0; 681 skb->nohdr = 0;
680 atomic_set(&skb_shinfo(skb)->dataref, 1); 682 atomic_set(&skb_shinfo(skb)->dataref, 1);
681 return 0; 683 return 0;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a84478ee2de..3aaabec70d1 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -203,7 +203,9 @@ int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
203 return 0; 203 return 0;
204 204
205 /* Not exclusive use of packet? Must copy. */ 205 /* Not exclusive use of packet? Must copy. */
206 if (skb_shared(*pskb) || skb_cloned(*pskb)) 206 if (skb_cloned(*pskb) && !skb_clone_writable(*pskb, writable_len))
207 goto copy_skb;
208 if (skb_shared(*pskb))
207 goto copy_skb; 209 goto copy_skb;
208 210
209 return pskb_may_pull(*pskb, writable_len); 211 return pskb_may_pull(*pskb, writable_len);