]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/skbuff.c
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / net / core / skbuff.c
index 944189d96323c9944089eded7b017cb1a3050599..32d5826b7177078eb51dd99bc1887b974516888f 100644 (file)
@@ -362,6 +362,90 @@ void kfree_skb(struct sk_buff *skb)
        __kfree_skb(skb);
 }
 
+static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+{
+       new->tstamp             = old->tstamp;
+       new->dev                = old->dev;
+       new->transport_header   = old->transport_header;
+       new->network_header     = old->network_header;
+       new->mac_header         = old->mac_header;
+       new->dst                = dst_clone(old->dst);
+#ifdef CONFIG_INET
+       new->sp                 = secpath_get(old->sp);
+#endif
+       memcpy(new->cb, old->cb, sizeof(old->cb));
+       new->csum_start         = old->csum_start;
+       new->csum_offset        = old->csum_offset;
+       new->local_df           = old->local_df;
+       new->pkt_type           = old->pkt_type;
+       new->ip_summed          = old->ip_summed;
+       skb_copy_queue_mapping(new, old);
+       new->priority           = old->priority;
+#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
+       new->ipvs_property      = old->ipvs_property;
+#endif
+       new->protocol           = old->protocol;
+       new->mark               = old->mark;
+       __nf_copy(new, old);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+       new->nf_trace           = old->nf_trace;
+#endif
+#ifdef CONFIG_NET_SCHED
+       new->tc_index           = old->tc_index;
+#ifdef CONFIG_NET_CLS_ACT
+       new->tc_verd            = old->tc_verd;
+#endif
+#endif
+       skb_copy_secmark(new, old);
+}
+
+static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
+{
+#define C(x) n->x = skb->x
+
+       n->next = n->prev = NULL;
+       n->sk = NULL;
+       __copy_skb_header(n, skb);
+
+       C(len);
+       C(data_len);
+       C(mac_len);
+       n->cloned = 1;
+       n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
+       n->nohdr = 0;
+       n->destructor = NULL;
+       C(truesize);
+       atomic_set(&n->users, 1);
+       C(head);
+       C(data);
+       C(tail);
+       C(end);
+
+       atomic_inc(&(skb_shinfo(skb)->dataref));
+       skb->cloned = 1;
+
+       return n;
+#undef C
+}
+
+/**
+ *     skb_morph       -       morph one skb into another
+ *     @dst: the skb to receive the contents
+ *     @src: the skb to supply the contents
+ *
+ *     This is identical to skb_clone except that the target skb is
+ *     supplied by the user.
+ *
+ *     The target skb is returned upon exit.
+ */
+struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
+{
+       skb_release_data(dst);
+       return __skb_clone(dst, src);
+}
+EXPORT_SYMBOL_GPL(skb_morph);
+
 /**
  *     skb_clone       -       duplicate an sk_buff
  *     @skb: buffer to clone
@@ -393,66 +477,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
                n->fclone = SKB_FCLONE_UNAVAILABLE;
        }
 
-#define C(x) n->x = skb->x
-
-       n->next = n->prev = NULL;
-       n->sk = NULL;
-       C(tstamp);
-       C(dev);
-       C(transport_header);
-       C(network_header);
-       C(mac_header);
-       C(dst);
-       dst_clone(skb->dst);
-       C(sp);
-#ifdef CONFIG_INET
-       secpath_get(skb->sp);
-#endif
-       memcpy(n->cb, skb->cb, sizeof(skb->cb));
-       C(len);
-       C(data_len);
-       C(mac_len);
-       C(csum);
-       C(local_df);
-       n->cloned = 1;
-       n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
-       n->nohdr = 0;
-       C(pkt_type);
-       C(ip_summed);
-       skb_copy_queue_mapping(n, skb);
-       C(priority);
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
-       C(ipvs_property);
-#endif
-       C(protocol);
-       n->destructor = NULL;
-       C(mark);
-       __nf_copy(n, skb);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
-    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
-       C(nf_trace);
-#endif
-#ifdef CONFIG_NET_SCHED
-       C(tc_index);
-#ifdef CONFIG_NET_CLS_ACT
-       n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
-       n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
-       n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
-       C(iif);
-#endif
-#endif
-       skb_copy_secmark(n, skb);
-       C(truesize);
-       atomic_set(&n->users, 1);
-       C(head);
-       C(data);
-       C(tail);
-       C(end);
-
-       atomic_inc(&(skb_shinfo(skb)->dataref));
-       skb->cloned = 1;
-
-       return n;
+       return __skb_clone(n, skb);
 }
 
 static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
@@ -463,50 +488,15 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
         */
        unsigned long offset = new->data - old->data;
 #endif
-       new->sk         = NULL;
-       new->dev        = old->dev;
-       skb_copy_queue_mapping(new, old);
-       new->priority   = old->priority;
-       new->protocol   = old->protocol;
-       new->dst        = dst_clone(old->dst);
-#ifdef CONFIG_INET
-       new->sp         = secpath_get(old->sp);
-#endif
-       new->csum_start = old->csum_start;
-       new->csum_offset = old->csum_offset;
-       new->ip_summed = old->ip_summed;
-       new->transport_header = old->transport_header;
-       new->network_header   = old->network_header;
-       new->mac_header       = old->mac_header;
+
+       __copy_skb_header(new, old);
+
 #ifndef NET_SKBUFF_DATA_USES_OFFSET
        /* {transport,network,mac}_header are relative to skb->head */
        new->transport_header += offset;
        new->network_header   += offset;
        new->mac_header       += offset;
 #endif
-       memcpy(new->cb, old->cb, sizeof(old->cb));
-       new->local_df   = old->local_df;
-       new->fclone     = SKB_FCLONE_UNAVAILABLE;
-       new->pkt_type   = old->pkt_type;
-       new->tstamp     = old->tstamp;
-       new->destructor = NULL;
-       new->mark       = old->mark;
-       __nf_copy(new, old);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
-    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
-       new->nf_trace   = old->nf_trace;
-#endif
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
-       new->ipvs_property = old->ipvs_property;
-#endif
-#ifdef CONFIG_NET_SCHED
-#ifdef CONFIG_NET_CLS_ACT
-       new->tc_verd = old->tc_verd;
-#endif
-       new->tc_index   = old->tc_index;
-#endif
-       skb_copy_secmark(new, old);
-       atomic_set(&new->users, 1);
        skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
        skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
        skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
@@ -685,7 +675,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
        skb->transport_header += off;
        skb->network_header   += off;
        skb->mac_header       += off;
-       skb->csum_start       += off;
+       skb->csum_start       += nhead;
        skb->cloned   = 0;
        skb->hdr_len  = 0;
        skb->nohdr    = 0;
@@ -2038,8 +2028,8 @@ void __init skb_init(void)
  *     Fill the specified scatter-gather list with mappings/pointers into a
  *     region of the buffer space attached to a socket buffer.
  */
-int
-skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+static int
+__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
@@ -2048,9 +2038,7 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               sg[elt].page = virt_to_page(skb->data + offset);
-               sg[elt].offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
-               sg[elt].length = copy;
+               sg_set_buf(sg, skb->data + offset, copy);
                elt++;
                if ((len -= copy) == 0)
                        return elt;
@@ -2068,9 +2056,8 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 
                        if (copy > len)
                                copy = len;
-                       sg[elt].page = frag->page;
-                       sg[elt].offset = frag->page_offset+offset-start;
-                       sg[elt].length = copy;
+                       sg_set_page(&sg[elt], frag->page, copy,
+                                       frag->page_offset+offset-start);
                        elt++;
                        if (!(len -= copy))
                                return elt;
@@ -2091,7 +2078,8 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
                        if ((copy = end - offset) > 0) {
                                if (copy > len)
                                        copy = len;
-                               elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
+                               elt += __skb_to_sgvec(list, sg+elt, offset - start,
+                                                     copy);
                                if ((len -= copy) == 0)
                                        return elt;
                                offset += copy;
@@ -2103,6 +2091,15 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
        return elt;
 }
 
+int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+       int nsg = __skb_to_sgvec(skb, sg, offset, len);
+
+       sg_mark_end(&sg[nsg - 1]);
+
+       return nsg;
+}
+
 /**
  *     skb_cow_data - Check that a socket buffer's data buffers are writable
  *     @skb: The socket buffer to check.