net: Add framework to allow sending packets with customized CRC.
[linux-2.6-block.git] / net / core / skbuff.c
index 3c30ee4a57105a2746b3e1b2bfab68af8ef0c917..6eb656acdfe53a27680c894b5cd8a6a7222f2db1 100644 (file)
@@ -244,6 +244,55 @@ nodata:
 }
 EXPORT_SYMBOL(__alloc_skb);
 
+/**
+ * build_skb - build a network buffer
+ * @data: data buffer provided by caller
+ *
+ * Allocate a new &sk_buff. Caller provides space holding head and
+ * skb_shared_info. @data must have been allocated by kmalloc()
+ * The return is the new skb buffer.
+ * On a failure the return is %NULL, and @data is not freed.
+ * Notes :
+ *  Before IO, driver allocates only data buffer where NIC put incoming frame
+ *  Driver should add room at head (NET_SKB_PAD) and
+ *  MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
+ *  After IO, driver calls build_skb(), to allocate sk_buff and populate it
+ *  before giving packet to stack.
+ *  RX rings only contains data buffers, not full skbs.
+ */
+struct sk_buff *build_skb(void *data)
+{
+       struct skb_shared_info *shinfo;
+       struct sk_buff *skb;
+       unsigned int size;
+
+       skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       memset(skb, 0, offsetof(struct sk_buff, tail));
+       skb->truesize = SKB_TRUESIZE(size);
+       atomic_set(&skb->users, 1);
+       skb->head = data;
+       skb->data = data;
+       skb_reset_tail_pointer(skb);
+       skb->end = skb->tail + size;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+       skb->mac_header = ~0U;
+#endif
+
+       /* make sure we initialize shinfo sequentially */
+       shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+       atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
+
+       return skb;
+}
+EXPORT_SYMBOL(build_skb);
+
 /**
  *     __netdev_alloc_skb - allocate an skbuff for rx on a specific device
  *     @dev: network device to receive on
@@ -403,7 +452,7 @@ static void skb_release_head_state(struct sk_buff *skb)
                WARN_ON(in_irq());
                skb->destructor(skb);
        }
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
        nf_conntrack_put(skb->nfct);
 #endif
 #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
@@ -543,6 +592,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->rxhash             = old->rxhash;
        new->ooo_okay           = old->ooo_okay;
        new->l4_rxhash          = old->l4_rxhash;
+       new->no_fcs             = old->no_fcs;
 #ifdef CONFIG_XFRM
        new->sp                 = secpath_get(old->sp);
 #endif
@@ -553,15 +603,14 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        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)
+#if IS_ENABLED(CONFIG_IP_VS)
        new->ipvs_property      = old->ipvs_property;
 #endif
        new->protocol           = old->protocol;
        new->mark               = old->mark;
        new->skb_iif            = old->skb_iif;
        __nf_copy(new, old);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
-    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
        new->nf_trace           = old->nf_trace;
 #endif
 #ifdef CONFIG_NET_SCHED
@@ -791,8 +840,9 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
 EXPORT_SYMBOL(skb_copy);
 
 /**
- *     pskb_copy       -       create copy of an sk_buff with private head.
+ *     __pskb_copy     -       create copy of an sk_buff with private head.
  *     @skb: buffer to copy
+ *     @headroom: headroom of new skb
  *     @gfp_mask: allocation priority
  *
  *     Make a copy of both an &sk_buff and part of its data, located
@@ -803,16 +853,16 @@ EXPORT_SYMBOL(skb_copy);
  *     The returned buffer has a reference count of 1.
  */
 
-struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
+struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
 {
-       unsigned int size = skb_end_pointer(skb) - skb->head;
+       unsigned int size = skb_headlen(skb) + headroom;
        struct sk_buff *n = alloc_skb(size, gfp_mask);
 
        if (!n)
                goto out;
 
        /* Set the data pointer */
-       skb_reserve(n, skb_headroom(skb));
+       skb_reserve(n, headroom);
        /* Set the tail pointer and length */
        skb_put(n, skb_headlen(skb));
        /* Copy the bytes */
@@ -848,7 +898,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
 out:
        return n;
 }
-EXPORT_SYMBOL(pskb_copy);
+EXPORT_SYMBOL(__pskb_copy);
 
 /**
  *     pskb_expand_head - reallocate header of &sk_buff
@@ -2621,7 +2671,7 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
@@ -2857,7 +2907,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        nskb->prev = p;
 
        nskb->data_len += p->len;
-       nskb->truesize += p->len;
+       nskb->truesize += p->truesize;
        nskb->len += p->len;
 
        *head = nskb;
@@ -2867,6 +2917,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        p = nskb;
 
 merge:
+       p->truesize += skb->truesize - len;
        if (offset > headlen) {
                unsigned int eat = offset - headlen;
 
@@ -3169,6 +3220,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
 }
 EXPORT_SYMBOL_GPL(skb_tstamp_tx);
 
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+       struct sock *sk = skb->sk;
+       struct sock_exterr_skb *serr;
+       int err;
+
+       skb->wifi_acked_valid = 1;
+       skb->wifi_acked = acked;
+
+       serr = SKB_EXT_ERR(skb);
+       memset(serr, 0, sizeof(*serr));
+       serr->ee.ee_errno = ENOMSG;
+       serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+       err = sock_queue_err_skb(sk, skb);
+       if (err)
+               kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+
 
 /**
  * skb_partial_csum_set - set up and verify partial csum values for packet