opnsense-src/sys/compat/linuxkpi/common/include/linux/skbuff.h
Bjoern A. Zeeb 6a8973c332 LinuxKPI: skbuff: fix skb_queue_splice_init()
In skb_queue_splice_init() we set a next value and then used that new
value to further update the remaining linking rather than the original
value.  Introduce another temporary variable 'n' to hold the original
value and use that.
While here rename q and h to from and to as otherwise it was too
confusing to read.

Also initialize skb->prev and skb->next to point to skb itself if
for nothing else at least to aid debugging.

Reported by:	phk (panic in iwl_txq_reclaim)
Sponsored by:	The FreeBSD Foundation
MFC after:	3 days
2022-03-23 17:18:00 +00:00

930 lines
20 KiB
C

/*-
* Copyright (c) 2020-2022 The FreeBSD Foundation
* Copyright (c) 2021-2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* NOTE: this socket buffer compatibility code is highly EXPERIMENTAL.
* Do not rely on the internals of this implementation. They are highly
* likely to change as we will improve the integration to FreeBSD mbufs.
*/
#ifndef _LINUXKPI_LINUX_SKBUFF_H
#define _LINUXKPI_LINUX_SKBUFF_H
#include <linux/page.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
#include <linux/list.h>
#include <linux/gfp.h>
#include <linux/compiler.h>
#include <linux/spinlock.h>
/* #define SKB_DEBUG */
#ifdef SKB_DEBUG
#define DSKB_TODO 0x01
#define DSKB_IMPROVE 0x02
#define DSKB_TRACE 0x10
#define DSKB_TRACEX 0x20
extern int linuxkpi_debug_skb;
#define SKB_TODO() \
if (linuxkpi_debug_skb & DSKB_TODO) \
printf("SKB_TODO %s:%d\n", __func__, __LINE__)
#define SKB_IMPROVE(...) \
if (linuxkpi_debug_skb & DSKB_IMPROVE) \
printf("SKB_IMPROVE %s:%d\n", __func__, __LINE__)
#define SKB_TRACE(_s) \
if (linuxkpi_debug_skb & DSKB_TRACE) \
printf("SKB_TRACE %s:%d %p\n", __func__, __LINE__, _s)
#define SKB_TRACE2(_s, _p) \
if (linuxkpi_debug_skb & DSKB_TRACE) \
printf("SKB_TRACE %s:%d %p, %p\n", __func__, __LINE__, _s, _p)
#define SKB_TRACE_FMT(_s, _fmt, ...) \
if (linuxkpi_debug_skb & DSKB_TRACE) \
printf("SKB_TRACE %s:%d %p " _fmt "\n", __func__, __LINE__, _s, \
__VA_ARGS__)
#else
#define SKB_TODO() do { } while(0)
#define SKB_IMPROVE(...) do { } while(0)
#define SKB_TRACE(_s) do { } while(0)
#define SKB_TRACE2(_s, _p) do { } while(0)
#define SKB_TRACE_FMT(_s, ...) do { } while(0)
#endif
enum sk_buff_pkt_type {
PACKET_BROADCAST,
PACKET_MULTICAST,
PACKET_OTHERHOST,
};
#define NET_SKB_PAD CACHE_LINE_SIZE /* ? */
struct sk_buff_head {
/* XXX TODO */
struct sk_buff *next;
struct sk_buff *prev;
size_t qlen;
spinlock_t lock;
};
enum sk_checksum_flags {
CHECKSUM_NONE = 0x00,
CHECKSUM_UNNECESSARY = 0x01,
CHECKSUM_PARTIAL = 0x02,
CHECKSUM_COMPLETE = 0x04,
};
struct skb_frag {
/* XXX TODO */
struct page *page; /* XXX-BZ These three are a wild guess so far! */
off_t offset;
size_t size;
};
typedef struct skb_frag skb_frag_t;
enum skb_shared_info_gso_type {
SKB_GSO_TCPV4,
SKB_GSO_TCPV6,
};
struct skb_shared_info {
enum skb_shared_info_gso_type gso_type;
uint16_t gso_size;
uint16_t nr_frags;
struct sk_buff *frag_list;
skb_frag_t frags[64]; /* XXX TODO, 16xpage? */
};
struct sk_buff {
/* XXX TODO */
/* struct sk_buff_head */
struct sk_buff *next;
struct sk_buff *prev;
int list; /* XXX TYPE */
uint32_t _alloc_len; /* Length of alloc data-buf. XXX-BZ give up for truesize? */
uint32_t len; /* ? */
uint32_t data_len; /* ? If we have frags? */
uint32_t truesize; /* The total size of all buffers, incl. frags. */
uint16_t mac_len; /* Link-layer header length. */
__sum16 csum;
uint16_t l3hdroff; /* network header offset from *head */
uint16_t l4hdroff; /* transport header offset from *head */
uint32_t priority;
uint16_t qmap; /* queue mapping */
uint16_t _spareu16_0;
enum sk_buff_pkt_type pkt_type;
/* "Scratch" area for layers to store metadata. */
/* ??? I see sizeof() operations so probably an array. */
uint8_t cb[64] __aligned(CACHE_LINE_SIZE);
struct net_device *dev;
void *sk; /* XXX net/sock.h? */
int csum_offset, csum_start, ip_summed, protocol;
uint8_t *head; /* Head of buffer. */
uint8_t *data; /* Head of data. */
uint8_t *tail; /* End of data. */
uint8_t *end; /* End of buffer. */
struct skb_shared_info *shinfo;
/* FreeBSD specific bandaid (see linuxkpi_kfree_skb). */
void *m;
void(*m_free_func)(void *);
/* Force padding to CACHE_LINE_SIZE. */
uint8_t __scratch[0] __aligned(CACHE_LINE_SIZE);
};
/* -------------------------------------------------------------------------- */
struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t);
void linuxkpi_kfree_skb(struct sk_buff *);
/* -------------------------------------------------------------------------- */
static inline struct sk_buff *
alloc_skb(size_t size, gfp_t gfp)
{
struct sk_buff *skb;
skb = linuxkpi_alloc_skb(size, gfp);
SKB_TRACE(skb);
return (skb);
}
static inline struct sk_buff *
__dev_alloc_skb(size_t len, gfp_t gfp)
{
struct sk_buff *skb;
skb = alloc_skb(len, gfp);
SKB_IMPROVE();
SKB_TRACE(skb);
return (skb);
}
static inline struct sk_buff *
dev_alloc_skb(size_t len)
{
struct sk_buff *skb;
skb = alloc_skb(len, GFP_NOWAIT);
SKB_IMPROVE();
SKB_TRACE(skb);
return (skb);
}
static inline void
kfree_skb(struct sk_buff *skb)
{
SKB_TRACE(skb);
linuxkpi_kfree_skb(skb);
}
static inline void
dev_kfree_skb(struct sk_buff *skb)
{
SKB_TRACE(skb);
kfree_skb(skb);
}
static inline void
dev_kfree_skb_any(struct sk_buff *skb)
{
SKB_TRACE(skb);
dev_kfree_skb(skb);
}
static inline void
dev_kfree_skb_irq(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
/* -------------------------------------------------------------------------- */
/* XXX BZ review this one for terminal condition as Linux "queues" are special. */
#define skb_list_walk_safe(_q, skb, tmp) \
for ((skb) = (_q)->next; (skb) != NULL && ((tmp) = (skb)->next); (skb) = (tmp))
/* Add headroom; cannot do once there is data in there. */
static inline void
skb_reserve(struct sk_buff *skb, size_t len)
{
SKB_TRACE(skb);
#if 0
/* Apparently it is allowed to call skb_reserve multiple times in a row. */
KASSERT(skb->data == skb->head, ("%s: skb %p not empty head %p data %p "
"tail %p\n", __func__, skb, skb->head, skb->data, skb->tail));
#else
KASSERT(skb->len == 0 && skb->data == skb->tail, ("%s: skb %p not "
"empty head %p data %p tail %p len %u\n", __func__, skb,
skb->head, skb->data, skb->tail, skb->len));
#endif
skb->data += len;
skb->tail += len;
}
/*
* Remove headroom; return new data pointer; basically make space at the
* front to copy data in (manually).
*/
static inline void *
skb_push(struct sk_buff *skb, size_t len)
{
SKB_TRACE(skb);
KASSERT(((skb->data - len) >= skb->head), ("%s: skb %p (data %p - "
"len %zu) < head %p\n", __func__, skb, skb->data, len, skb->data));
skb->len += len;
skb->data -= len;
return (skb->data);
}
/*
* Length of the data on the skb (without any frags)???
*/
static inline size_t
skb_headlen(struct sk_buff *skb)
{
SKB_TRACE(skb);
return (skb->len - skb->data_len);
}
/* Return the end of data (tail pointer). */
static inline uint8_t *
skb_tail_pointer(struct sk_buff *skb)
{
SKB_TRACE(skb);
return (skb->tail);
}
/* Return number of bytes available at end of buffer. */
static inline unsigned int
skb_tailroom(struct sk_buff *skb)
{
SKB_TRACE(skb);
KASSERT((skb->end - skb->tail) >= 0, ("%s: skb %p tailroom < 0, "
"end %p tail %p\n", __func__, skb, skb->end, skb->tail));
return (skb->end - skb->tail);
}
/* Return numer of bytes available at the beginning of buffer. */
static inline unsigned int
skb_headroom(struct sk_buff *skb)
{
SKB_TRACE(skb);
KASSERT((skb->data - skb->head) >= 0, ("%s: skb %p headroom < 0, "
"data %p head %p\n", __func__, skb, skb->data, skb->head));
return (skb->data - skb->head);
}
/*
* Remove tailroom; return the old tail pointer; basically make space at
* the end to copy data in (manually). See also skb_put_data() below.
*/
static inline void *
skb_put(struct sk_buff *skb, size_t len)
{
void *s;
SKB_TRACE(skb);
KASSERT(((skb->tail + len) <= skb->end), ("%s: skb %p (tail %p + "
"len %zu) > end %p, head %p data %p len %u\n", __func__,
skb, skb->tail, len, skb->end, skb->head, skb->data, skb->len));
s = skb_tail_pointer(skb);
skb->tail += len;
skb->len += len;
#ifdef SKB_DEBUG
if (linuxkpi_debug_skb & DSKB_TRACEX)
printf("%s: skb %p (%u) head %p data %p tail %p end %p, s %p len %zu\n",
__func__, skb, skb->len, skb->head, skb->data, skb->tail, skb->end,
s, len);
#endif
return (s);
}
/* skb_put() + copying data in. */
static inline void *
skb_put_data(struct sk_buff *skb, const void *buf, size_t len)
{
void *s;
SKB_TRACE2(skb, buf);
s = skb_put(skb, len);
memcpy(s, buf, len);
return (s);
}
/* skb_put() + filling with zeros. */
static inline void *
skb_put_zero(struct sk_buff *skb, size_t len)
{
void *s;
SKB_TRACE(skb);
s = skb_put(skb, len);
memset(s, '\0', len);
return (s);
}
/*
* Remove len bytes from beginning of data.
*
* XXX-BZ ath10k checks for !NULL conditions so I assume this doesn't panic;
* we return the advanced data pointer so we don't have to keep a temp, correct?
*/
static inline void *
skb_pull(struct sk_buff *skb, size_t len)
{
SKB_TRACE(skb);
#if 0 /* Apparently this doesn't barf... */
KASSERT(skb->len >= len, ("%s: skb %p skb->len %u < len %u, data %p\n",
__func__, skb, skb->len, len, skb->data));
#endif
if (skb->len < len)
return (NULL);
skb->len -= len;
skb->data += len;
return (skb->data);
}
/* Reduce skb data to given length or do nothing if smaller already. */
static inline void
__skb_trim(struct sk_buff *skb, unsigned int len)
{
SKB_TRACE(skb);
if (skb->len < len)
return;
skb->len = len;
skb->tail = skb->data + skb->len;
}
static inline void
skb_trim(struct sk_buff *skb, unsigned int len)
{
return (__skb_trim(skb, len));
}
static inline struct skb_shared_info *
skb_shinfo(struct sk_buff *skb)
{
SKB_TRACE(skb);
return (skb->shinfo);
}
static inline void
skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page,
off_t offset, size_t size, unsigned int truesize)
{
struct skb_shared_info *shinfo;
SKB_TRACE(skb);
#ifdef SKB_DEBUG
if (linuxkpi_debug_skb & DSKB_TRACEX)
printf("%s: skb %p head %p data %p tail %p end %p len %u fragno %d "
"page %#jx offset %ju size %zu truesize %u\n", __func__,
skb, skb->head, skb->data, skb->tail, skb->end, skb->len, fragno,
(uintmax_t)(uintptr_t)linux_page_address(page), (uintmax_t)offset,
size, truesize);
#endif
shinfo = skb_shinfo(skb);
KASSERT(fragno >= 0 && fragno < nitems(shinfo->frags), ("%s: skb %p "
"fragno %d too big\n", __func__, skb, fragno));
shinfo->frags[fragno].page = page;
shinfo->frags[fragno].offset = offset;
shinfo->frags[fragno].size = size;
shinfo->nr_frags = fragno + 1;
skb->len += size;
skb->truesize += truesize;
/* XXX TODO EXTEND truesize? */
}
/* -------------------------------------------------------------------------- */
/* XXX BZ review this one for terminal condition as Linux "queues" are special. */
#define skb_queue_walk(_q, skb) \
for ((skb) = (_q)->next; (skb) != (struct sk_buff *)(_q); \
(skb) = (skb)->next)
#define skb_queue_walk_safe(_q, skb, tmp) \
for ((skb) = (_q)->next, (tmp) = (skb)->next; \
(skb) != (struct sk_buff *)(_q); (skb) = (tmp), (tmp) = (skb)->next)
static inline bool
skb_queue_empty(struct sk_buff_head *q)
{
SKB_TRACE(q);
return (q->qlen == 0);
}
static inline void
__skb_queue_head_init(struct sk_buff_head *q)
{
SKB_TRACE(q);
q->prev = q->next = (struct sk_buff *)q;
q->qlen = 0;
}
static inline void
skb_queue_head_init(struct sk_buff_head *q)
{
SKB_TRACE(q);
return (__skb_queue_head_init(q));
}
static inline void
__skb_insert(struct sk_buff *new, struct sk_buff *prev, struct sk_buff *next,
struct sk_buff_head *q)
{
SKB_TRACE_FMT(new, "prev %p next %p q %p", prev, next, q);
new->prev = prev;
new->next = next;
next->prev = new;
prev->next = new;
q->qlen++;
}
static inline void
__skb_queue_after(struct sk_buff_head *q, struct sk_buff *skb,
struct sk_buff *new)
{
SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
__skb_insert(new, skb, skb->next, q);
}
static inline void
__skb_queue_before(struct sk_buff_head *q, struct sk_buff *skb,
struct sk_buff *new)
{
SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
__skb_insert(new, skb->prev, skb, q);
}
static inline void
__skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
{
struct sk_buff *s;
SKB_TRACE2(q, skb);
q->qlen++;
s = (struct sk_buff *)q;
s->prev->next = skb;
skb->prev = s->prev;
skb->next = s;
s->prev = skb;
}
static inline void
skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
{
SKB_TRACE2(q, skb);
return (__skb_queue_tail(q, skb));
}
static inline struct sk_buff *
skb_peek_tail(struct sk_buff_head *q)
{
struct sk_buff *skb;
skb = q->prev;
SKB_TRACE2(q, skb);
if (skb == (struct sk_buff *)q)
return (NULL);
return (skb);
}
static inline void
__skb_unlink(struct sk_buff *skb, struct sk_buff_head *head)
{
SKB_TRACE2(skb, head);
struct sk_buff *p, *n;;
head->qlen--;
p = skb->prev;
n = skb->next;
p->next = n;
n->prev = p;
skb->prev = skb->next = NULL;
}
static inline void
skb_unlink(struct sk_buff *skb, struct sk_buff_head *head)
{
SKB_TRACE2(skb, head);
return (__skb_unlink(skb, head));
}
static inline struct sk_buff *
__skb_dequeue(struct sk_buff_head *q)
{
struct sk_buff *skb;
SKB_TRACE(q);
skb = q->next;
if (skb == (struct sk_buff *)q)
return (NULL);
if (skb != NULL)
__skb_unlink(skb, q);
SKB_TRACE(skb);
return (skb);
}
static inline struct sk_buff *
skb_dequeue(struct sk_buff_head *q)
{
SKB_TRACE(q);
return (__skb_dequeue(q));
}
static inline struct sk_buff *
skb_dequeue_tail(struct sk_buff_head *q)
{
struct sk_buff *skb;
skb = skb_peek_tail(q);
if (skb != NULL)
__skb_unlink(skb, q);
SKB_TRACE2(q, skb);
return (skb);
}
static inline void
__skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
{
SKB_TRACE2(q, skb);
__skb_queue_after(q, (struct sk_buff *)q, skb);
}
static inline void
skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
{
SKB_TRACE2(q, skb);
__skb_queue_after(q, (struct sk_buff *)q, skb);
}
static inline uint32_t
skb_queue_len(struct sk_buff_head *head)
{
SKB_TRACE(head);
return (head->qlen);
}
static inline uint32_t
skb_queue_len_lockless(const struct sk_buff_head *head)
{
SKB_TRACE(head);
return (READ_ONCE(head->qlen));
}
static inline void
__skb_queue_purge(struct sk_buff_head *q)
{
struct sk_buff *skb;
SKB_TRACE(q);
while ((skb = __skb_dequeue(q)) != NULL)
kfree_skb(skb);
}
static inline void
skb_queue_purge(struct sk_buff_head *q)
{
SKB_TRACE(q);
return (__skb_queue_purge(q));
}
static inline struct sk_buff *
skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb)
{
SKB_TRACE2(q, skb);
/* XXX what is the q argument good for? */
return (skb->prev);
}
/* -------------------------------------------------------------------------- */
static inline struct sk_buff *
skb_copy(struct sk_buff *skb, gfp_t gfp)
{
SKB_TRACE(skb);
SKB_TODO();
return (NULL);
}
static inline void
consume_skb(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
static inline uint16_t
skb_checksum(struct sk_buff *skb, int offs, size_t len, int x)
{
SKB_TRACE(skb);
SKB_TODO();
return (0xffff);
}
static inline int
skb_checksum_start_offset(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
return (-1);
}
static inline dma_addr_t
skb_frag_dma_map(struct device *dev, const skb_frag_t *frag, int x,
size_t fragsz, enum dma_data_direction dir)
{
SKB_TRACE2(frag, dev);
SKB_TODO();
return (-1);
}
static inline size_t
skb_frag_size(const skb_frag_t *frag)
{
SKB_TRACE(frag);
SKB_TODO();
return (-1);
}
static inline bool
skb_is_nonlinear(struct sk_buff *skb)
{
SKB_TRACE(skb);
return ((skb->data_len > 0) ? true : false);
}
#define skb_walk_frags(_skb, _frag) \
for ((_frag) = (_skb); false; (_frag)++)
static inline void
skb_checksum_help(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
static inline bool
skb_ensure_writable(struct sk_buff *skb, size_t off)
{
SKB_TRACE(skb);
SKB_TODO();
return (false);
}
static inline void *
skb_frag_address(const skb_frag_t *frag)
{
SKB_TRACE(frag);
SKB_TODO();
return (NULL);
}
static inline struct sk_buff *
skb_gso_segment(struct sk_buff *skb, netdev_features_t netdev_flags)
{
SKB_TRACE(skb);
SKB_TODO();
return (NULL);
}
static inline bool
skb_is_gso(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
return (false);
}
static inline void
skb_mark_not_on_list(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
static inline void
skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
{
struct sk_buff *b, *e, *n;
SKB_TRACE2(from, to);
if (skb_queue_empty(from))
return;
/* XXX do we need a barrier around this? */
b = from->next;
e = from->prev;
n = to->next;
b->prev = (struct sk_buff *)to;
to->next = b;
e->next = n;
n->prev = e;
to->qlen += from->qlen;
__skb_queue_head_init(from);
}
static inline void
skb_reset_transport_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
skb->l4hdroff = skb->data - skb->head;
}
static inline uint8_t *
skb_transport_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
return (skb->head + skb->l4hdroff);
}
static inline uint8_t *
skb_network_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
return (skb->head + skb->l3hdroff);
}
static inline int
__skb_linearize(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
return (ENXIO);
}
static inline int
pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp)
{
SKB_TRACE(skb);
SKB_TODO();
return (-ENXIO);
}
/* Not really seen this one but need it as symmetric accessor function. */
static inline void
skb_set_queue_mapping(struct sk_buff *skb, uint16_t qmap)
{
SKB_TRACE_FMT(skb, "qmap %u", qmap);
skb->qmap = qmap;
}
static inline uint16_t
skb_get_queue_mapping(struct sk_buff *skb)
{
SKB_TRACE_FMT(skb, "qmap %u", skb->qmap);
return (skb->qmap);
}
static inline bool
skb_header_cloned(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
return (false);
}
static inline uint8_t *
skb_mac_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
return (NULL);
}
static inline void
skb_orphan(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
static inline void
skb_reset_mac_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
SKB_TODO();
}
static inline struct sk_buff *
skb_peek(struct sk_buff_head *q)
{
SKB_TRACE(q);
SKB_TODO();
return (NULL);
}
static inline __sum16
csum_unfold(__sum16 sum)
{
SKB_TODO();
return (sum);
}
static __inline void
skb_postpush_rcsum(struct sk_buff *skb, const void *data, size_t len)
{
SKB_TODO();
}
static inline void
skb_reset_tail_pointer(struct sk_buff *skb)
{
SKB_TRACE(skb);
skb->tail = (uint8_t *)(uintptr_t)(skb->data - skb->head);
SKB_TRACE(skb);
}
static inline struct sk_buff *
skb_get(struct sk_buff *skb)
{
SKB_TODO(); /* XXX refcnt? as in get/put_device? */
return (skb);
}
static inline struct sk_buff *
skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
{
SKB_TODO();
return (NULL);
}
static inline void
skb_copy_from_linear_data(const struct sk_buff *skb, void *dst, size_t len)
{
SKB_TRACE(skb);
/* Let us just hope the destination has len space ... */
memcpy(dst, skb->data, len);
}
#endif /* _LINUXKPI_LINUX_SKBUFF_H */