Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/include/linux/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 148 kB image not shown  

Quelle  skbuff.h   Sprache: C

 
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Definitions for the 'struct sk_buff' memory handlers.
 *
 * Authors:
 * Alan Cox, <gw4pts@gw4pts.ampr.org>
 * Florian La Roche, <rzsfl@rz.uni-sb.de>
 */


#ifndef _LINUX_SKBUFF_H
#define _LINUX_SKBUFF_H

#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/time.h>
#include <linux/bug.h>
#include <linux/bvec.h>
#include <linux/cache.h>
#include <linux/rbtree.h>
#include <linux/socket.h>
#include <linux/refcount.h>

#include <linux/atomic.h>
#include <asm/types.h>
#include <linux/spinlock.h>
#include <net/checksum.h>
#include <linux/rcupdate.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
#include <net/flow_dissector.h>
#include <linux/in6.h>
#include <linux/if_packet.h>
#include <linux/llist.h>
#include <linux/page_frag_cache.h>
#include <net/flow.h>
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <linux/netfilter/nf_conntrack_common.h>
#endif
#include <net/net_debug.h>
#include <net/dropreason-core.h>
#include <net/netmem.h>

/**
 * DOC: skb checksums
 *
 * The interface for checksum offload between the stack and networking drivers
 * is as follows...
 *
 * IP checksum related features
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Drivers advertise checksum offload capabilities in the features of a device.
 * From the stack's point of view these are capabilities offered by the driver.
 * A driver typically only advertises features that it is capable of offloading
 * to its device.
 *
 * .. flat-table:: Checksum related device features
 *   :widths: 1 10
 *
 *   * - %NETIF_F_HW_CSUM
 *     - The driver (or its device) is able to compute one
 *  IP (one's complement) checksum for any combination
 *  of protocols or protocol layering. The checksum is
 *  computed and set in a packet per the CHECKSUM_PARTIAL
 *  interface (see below).
 *
 *   * - %NETIF_F_IP_CSUM
 *     - Driver (device) is only able to checksum plain
 *  TCP or UDP packets over IPv4. These are specifically
 *  unencapsulated packets of the form IPv4|TCP or
 *  IPv4|UDP where the Protocol field in the IPv4 header
 *  is TCP or UDP. The IPv4 header may contain IP options.
 *  This feature cannot be set in features for a device
 *  with NETIF_F_HW_CSUM also set. This feature is being
 *  DEPRECATED (see below).
 *
 *   * - %NETIF_F_IPV6_CSUM
 *     - Driver (device) is only able to checksum plain
 *  TCP or UDP packets over IPv6. These are specifically
 *  unencapsulated packets of the form IPv6|TCP or
 *  IPv6|UDP where the Next Header field in the IPv6
 *  header is either TCP or UDP. IPv6 extension headers
 *  are not supported with this feature. This feature
 *  cannot be set in features for a device with
 *  NETIF_F_HW_CSUM also set. This feature is being
 *  DEPRECATED (see below).
 *
 *   * - %NETIF_F_RXCSUM
 *     - Driver (device) performs receive checksum offload.
 *  This flag is only used to disable the RX checksum
 *  feature for a device. The stack will accept receive
 *  checksum indication in packets received on a device
 *  regardless of whether NETIF_F_RXCSUM is set.
 *
 * Checksumming of received packets by device
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Indication of checksum verification is set in &sk_buff.ip_summed.
 * Possible values are:
 *
 * - %CHECKSUM_NONE
 *
 *   Device did not checksum this packet e.g. due to lack of capabilities.
 *   The packet contains full (though not verified) checksum in packet but
 *   not in skb->csum. Thus, skb->csum is undefined in this case.
 *
 * - %CHECKSUM_UNNECESSARY
 *
 *   The hardware you're dealing with doesn't calculate the full checksum
 *   (as in %CHECKSUM_COMPLETE), but it does parse headers and verify checksums
 *   for specific protocols. For such packets it will set %CHECKSUM_UNNECESSARY
 *   if their checksums are okay. &sk_buff.csum is still undefined in this case
 *   though. A driver or device must never modify the checksum field in the
 *   packet even if checksum is verified.
 *
 *   %CHECKSUM_UNNECESSARY is applicable to following protocols:
 *
 *     - TCP: IPv6 and IPv4.
 *     - UDP: IPv4 and IPv6. A device may apply CHECKSUM_UNNECESSARY to a
 *       zero UDP checksum for either IPv4 or IPv6, the networking stack
 *       may perform further validation in this case.
 *     - GRE: only if the checksum is present in the header.
 *     - SCTP: indicates the CRC in SCTP header has been validated.
 *     - FCOE: indicates the CRC in FC frame has been validated.
 *
 *   &sk_buff.csum_level indicates the number of consecutive checksums found in
 *   the packet minus one that have been verified as %CHECKSUM_UNNECESSARY.
 *   For instance if a device receives an IPv6->UDP->GRE->IPv4->TCP packet
 *   and a device is able to verify the checksums for UDP (possibly zero),
 *   GRE (checksum flag is set) and TCP, &sk_buff.csum_level would be set to
 *   two. If the device were only able to verify the UDP checksum and not
 *   GRE, either because it doesn't support GRE checksum or because GRE
 *   checksum is bad, skb->csum_level would be set to zero (TCP checksum is
 *   not considered in this case).
 *
 * - %CHECKSUM_COMPLETE
 *
 *   This is the most generic way. The device supplied checksum of the _whole_
 *   packet as seen by netif_rx() and fills in &sk_buff.csum. This means the
 *   hardware doesn't need to parse L3/L4 headers to implement this.
 *
 *   Notes:
 *
 *   - Even if device supports only some protocols, but is able to produce
 *     skb->csum, it MUST use CHECKSUM_COMPLETE, not CHECKSUM_UNNECESSARY.
 *   - CHECKSUM_COMPLETE is not applicable to SCTP and FCoE protocols.
 *
 * - %CHECKSUM_PARTIAL
 *
 *   A checksum is set up to be offloaded to a device as described in the
 *   output description for CHECKSUM_PARTIAL. This may occur on a packet
 *   received directly from another Linux OS, e.g., a virtualized Linux kernel
 *   on the same host, or it may be set in the input path in GRO or remote
 *   checksum offload. For the purposes of checksum verification, the checksum
 *   referred to by skb->csum_start + skb->csum_offset and any preceding
 *   checksums in the packet are considered verified. Any checksums in the
 *   packet that are after the checksum being offloaded are not considered to
 *   be verified.
 *
 * Checksumming on transmit for non-GSO
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * The stack requests checksum offload in the &sk_buff.ip_summed for a packet.
 * Values are:
 *
 * - %CHECKSUM_PARTIAL
 *
 *   The driver is required to checksum the packet as seen by hard_start_xmit()
 *   from &sk_buff.csum_start up to the end, and to record/write the checksum at
 *   offset &sk_buff.csum_start + &sk_buff.csum_offset.
 *   A driver may verify that the
 *   csum_start and csum_offset values are valid values given the length and
 *   offset of the packet, but it should not attempt to validate that the
 *   checksum refers to a legitimate transport layer checksum -- it is the
 *   purview of the stack to validate that csum_start and csum_offset are set
 *   correctly.
 *
 *   When the stack requests checksum offload for a packet, the driver MUST
 *   ensure that the checksum is set correctly. A driver can either offload the
 *   checksum calculation to the device, or call skb_checksum_help (in the case
 *   that the device does not support offload for a particular checksum).
 *
 *   %NETIF_F_IP_CSUM and %NETIF_F_IPV6_CSUM are being deprecated in favor of
 *   %NETIF_F_HW_CSUM. New devices should use %NETIF_F_HW_CSUM to indicate
 *   checksum offload capability.
 *   skb_csum_hwoffload_help() can be called to resolve %CHECKSUM_PARTIAL based
 *   on network device checksumming capabilities: if a packet does not match
 *   them, skb_checksum_help() or skb_crc32c_help() (depending on the value of
 *   &sk_buff.csum_not_inet, see :ref:`crc`)
 *   is called to resolve the checksum.
 *
 * - %CHECKSUM_NONE
 *
 *   The skb was already checksummed by the protocol, or a checksum is not
 *   required.
 *
 * - %CHECKSUM_UNNECESSARY
 *
 *   This has the same meaning as CHECKSUM_NONE for checksum offload on
 *   output.
 *
 * - %CHECKSUM_COMPLETE
 *
 *   Not used in checksum output. If a driver observes a packet with this value
 *   set in skbuff, it should treat the packet as if %CHECKSUM_NONE were set.
 *
 * .. _crc:
 *
 * Non-IP checksum (CRC) offloads
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * .. flat-table::
 *   :widths: 1 10
 *
 *   * - %NETIF_F_SCTP_CRC
 *     - This feature indicates that a device is capable of
 *  offloading the SCTP CRC in a packet. To perform this offload the stack
 *  will set csum_start and csum_offset accordingly, set ip_summed to
 *  %CHECKSUM_PARTIAL and set csum_not_inet to 1, to provide an indication
 *  in the skbuff that the %CHECKSUM_PARTIAL refers to CRC32c.
 *  A driver that supports both IP checksum offload and SCTP CRC32c offload
 *  must verify which offload is configured for a packet by testing the
 *  value of &sk_buff.csum_not_inet; skb_crc32c_csum_help() is provided to
 *  resolve %CHECKSUM_PARTIAL on skbs where csum_not_inet is set to 1.
 *
 *   * - %NETIF_F_FCOE_CRC
 *     - This feature indicates that a device is capable of offloading the FCOE
 *  CRC in a packet. To perform this offload the stack will set ip_summed
 *  to %CHECKSUM_PARTIAL and set csum_start and csum_offset
 *  accordingly. Note that there is no indication in the skbuff that the
 *  %CHECKSUM_PARTIAL refers to an FCOE checksum, so a driver that supports
 *  both IP checksum offload and FCOE CRC offload must verify which offload
 *  is configured for a packet, presumably by inspecting packet headers.
 *
 * Checksumming on output with GSO
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * In the case of a GSO packet (skb_is_gso() is true), checksum offload
 * is implied by the SKB_GSO_* flags in gso_type. Most obviously, if the
 * gso_type is %SKB_GSO_TCPV4 or %SKB_GSO_TCPV6, TCP checksum offload as
 * part of the GSO operation is implied. If a checksum is being offloaded
 * with GSO then ip_summed is %CHECKSUM_PARTIAL, and both csum_start and
 * csum_offset are set to refer to the outermost checksum being offloaded
 * (two offloaded checksums are possible with UDP encapsulation).
 */


/* Don't change this without changing skb_csum_unnecessary! */
#define CHECKSUM_NONE  0
#define CHECKSUM_UNNECESSARY 1
#define CHECKSUM_COMPLETE 2
#define CHECKSUM_PARTIAL 3

/* Maximum value in skb->csum_level */
#define SKB_MAX_CSUM_LEVEL 3

#define SKB_DATA_ALIGN(X) ALIGN(X, SMP_CACHE_BYTES)
#define SKB_WITH_OVERHEAD(X) \
 ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

/* For X bytes available in skb->head, what is the minimal
 * allocation needed, knowing struct skb_shared_info needs
 * to be aligned.
 */

#define SKB_HEAD_ALIGN(X) (SKB_DATA_ALIGN(X) + \
 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

#define SKB_MAX_ORDER(X, ORDER) \
 SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
#define SKB_MAX_HEAD(X)  (SKB_MAX_ORDER((X), 0))
#define SKB_MAX_ALLOC  (SKB_MAX_ORDER(0, 2))

/* return minimum truesize of one skb containing X bytes of data */
#define SKB_TRUESIZE(X) ((X) +      \
    SKB_DATA_ALIGN(sizeof(struct sk_buff)) + \
    SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

struct net_device;
struct scatterlist;
struct pipe_inode_info;
struct iov_iter;
struct napi_struct;
struct bpf_prog;
union bpf_attr;
struct skb_ext;
struct ts_config;

#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct nf_bridge_info {
 enum {
  BRNF_PROTO_UNCHANGED,
  BRNF_PROTO_8021Q,
  BRNF_PROTO_PPPOE
 } orig_proto:8;
 u8   pkt_otherhost:1;
 u8   in_prerouting:1;
 u8   bridged_dnat:1;
 u8   sabotage_in_done:1;
 __u16   frag_max_size;
 int   physinif;

 /* always valid & non-NULL from FORWARD on, for physdev match */
 struct net_device *physoutdev;
 union {
  /* prerouting: detect dnat in orig/reply direction */
  __be32          ipv4_daddr;
  struct in6_addr ipv6_daddr;

  /* after prerouting + nat detected: store original source
 * mac since neigh resolution overwrites it, only used while
 * skb is out in neigh layer.
 */

  char neigh_header[8];
 };
};
#endif

#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
/* Chain in tc_skb_ext will be used to share the tc chain with
 * ovs recirc_id. It will be set to the current chain by tc
 * and read by ovs to recirc_id.
 */

struct tc_skb_ext {
 union {
  u64 act_miss_cookie;
  __u32 chain;
 };
 __u16 mru;
 __u16 zone;
 u8 post_ct:1;
 u8 post_ct_snat:1;
 u8 post_ct_dnat:1;
 u8 act_miss:1; /* Set if act_miss_cookie is used */
 u8 l2_miss:1; /* Set by bridge upon FDB or MDB miss */
};
#endif

struct sk_buff_head {
 /* These two members must be first to match sk_buff. */
 struct_group_tagged(sk_buff_list, list,
  struct sk_buff *next;
  struct sk_buff *prev;
 );

 __u32  qlen;
 spinlock_t lock;
};

struct sk_buff;

#ifndef CONFIG_MAX_SKB_FRAGS
define CONFIG_MAX_SKB_FRAGS 17
#endif

#define MAX_SKB_FRAGS CONFIG_MAX_SKB_FRAGS

/* Set skb_shinfo(skb)->gso_size to this in case you want skb_segment to
 * segment using its current segmentation instead.
 */

#define GSO_BY_FRAGS 0xFFFF

typedef struct skb_frag {
 netmem_ref netmem;
 unsigned int len;
 unsigned int offset;
} skb_frag_t;

/**
 * skb_frag_size() - Returns the size of a skb fragment
 * @frag: skb fragment
 */

static inline unsigned int skb_frag_size(const skb_frag_t *frag)
{
 return frag->len;
}

/**
 * skb_frag_size_set() - Sets the size of a skb fragment
 * @frag: skb fragment
 * @size: size of fragment
 */

static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size)
{
 frag->len = size;
}

/**
 * skb_frag_size_add() - Increments the size of a skb fragment by @delta
 * @frag: skb fragment
 * @delta: value to add
 */

static inline void skb_frag_size_add(skb_frag_t *frag, int delta)
{
 frag->len += delta;
}

/**
 * skb_frag_size_sub() - Decrements the size of a skb fragment by @delta
 * @frag: skb fragment
 * @delta: value to subtract
 */

static inline void skb_frag_size_sub(skb_frag_t *frag, int delta)
{
 frag->len -= delta;
}

/**
 * skb_frag_must_loop - Test if %p is a high memory page
 * @p: fragment's page
 */

static inline bool skb_frag_must_loop(struct page *p)
{
#if defined(CONFIG_HIGHMEM)
 if (IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) || PageHighMem(p))
  return true;
#endif
 return false;
}

/**
 * skb_frag_foreach_page - loop over pages in a fragment
 *
 * @f: skb frag to operate on
 * @f_off: offset from start of f->netmem
 * @f_len: length from f_off to loop over
 * @p: (temp var) current page
 * @p_off: (temp var) offset from start of current page,
 *                            non-zero only on first page.
 * @p_len: (temp var) length in current page,
 *    < PAGE_SIZE only on first and last page.
 * @copied: (temp var) length so far, excluding current p_len.
 *
 * A fragment can hold a compound page, in which case per-page
 * operations, notably kmap_atomic, must be called for each
 * regular page.
 */

#define skb_frag_foreach_page(f, f_off, f_len, p, p_off, p_len, copied) \
 for (p = skb_frag_page(f) + ((f_off) >> PAGE_SHIFT),  \
      p_off = (f_off) & (PAGE_SIZE - 1),    \
      p_len = skb_frag_must_loop(p) ?    \
      min_t(u32, f_len, PAGE_SIZE - p_off) : f_len,  \
      copied = 0;      \
      copied < f_len;      \
      copied += p_len, p++, p_off = 0,    \
      p_len = min_t(u32, f_len - copied, PAGE_SIZE))  \

/**
 * struct skb_shared_hwtstamps - hardware time stamps
 * @hwtstamp: hardware time stamp transformed into duration
 * since arbitrary point in time
 * @netdev_data: address/cookie of network device driver used as
 * reference to actual hardware time stamp
 *
 * Software time stamps generated by ktime_get_real() are stored in
 * skb->tstamp.
 *
 * hwtstamps can only be compared against other hwtstamps from
 * the same device.
 *
 * This structure is attached to packets as part of the
 * &skb_shared_info. Use skb_hwtstamps() to get a pointer.
 */

struct skb_shared_hwtstamps {
 union {
  ktime_t hwtstamp;
  void *netdev_data;
 };
};

/* Definitions for tx_flags in struct skb_shared_info */
enum {
 /* generate hardware time stamp */
 SKBTX_HW_TSTAMP_NOBPF = 1 << 0,

 /* generate software time stamp when queueing packet to NIC */
 SKBTX_SW_TSTAMP = 1 << 1,

 /* device driver is going to provide hardware time stamp */
 SKBTX_IN_PROGRESS = 1 << 2,

 /* generate software time stamp on packet tx completion */
 SKBTX_COMPLETION_TSTAMP = 1 << 3,

 /* determine hardware time stamp based on time or cycles */
 SKBTX_HW_TSTAMP_NETDEV = 1 << 5,

 /* generate software time stamp when entering packet scheduling */
 SKBTX_SCHED_TSTAMP = 1 << 6,

 /* used for bpf extension when a bpf program is loaded */
 SKBTX_BPF = 1 << 7,
};

#define SKBTX_HW_TSTAMP  (SKBTX_HW_TSTAMP_NOBPF | SKBTX_BPF)

#define SKBTX_ANY_SW_TSTAMP (SKBTX_SW_TSTAMP    | \
     SKBTX_SCHED_TSTAMP | \
     SKBTX_BPF          | \
     SKBTX_COMPLETION_TSTAMP)
#define SKBTX_ANY_TSTAMP (SKBTX_HW_TSTAMP | \
     SKBTX_ANY_SW_TSTAMP)

/* Definitions for flags in struct skb_shared_info */
enum {
 /* use zcopy routines */
 SKBFL_ZEROCOPY_ENABLE = BIT(0),

 /* This indicates at least one fragment might be overwritten
 * (as in vmsplice(), sendfile() ...)
 * If we need to compute a TX checksum, we'll need to copy
 * all frags to avoid possible bad checksum
 */

 SKBFL_SHARED_FRAG = BIT(1),

 /* segment contains only zerocopy data and should not be
 * charged to the kernel memory.
 */

 SKBFL_PURE_ZEROCOPY = BIT(2),

 SKBFL_DONT_ORPHAN = BIT(3),

 /* page references are managed by the ubuf_info, so it's safe to
 * use frags only up until ubuf_info is released
 */

 SKBFL_MANAGED_FRAG_REFS = BIT(4),
};

#define SKBFL_ZEROCOPY_FRAG (SKBFL_ZEROCOPY_ENABLE | SKBFL_SHARED_FRAG)
#define SKBFL_ALL_ZEROCOPY (SKBFL_ZEROCOPY_FRAG | SKBFL_PURE_ZEROCOPY | \
     SKBFL_DONT_ORPHAN | SKBFL_MANAGED_FRAG_REFS)

struct ubuf_info_ops {
 void (*complete)(struct sk_buff *, struct ubuf_info *,
    bool zerocopy_success);
 /* has to be compatible with skb_zcopy_set() */
 int (*link_skb)(struct sk_buff *skb, struct ubuf_info *uarg);
};

/*
 * The callback notifies userspace to release buffers when skb DMA is done in
 * lower device, the skb last reference should be 0 when calling this.
 * The zerocopy_success argument is true if zero copy transmit occurred,
 * false on data copy or out of memory error caused by data copy attempt.
 * The ctx field is used to track device context.
 * The desc field is used to track userspace buffer index.
 */

struct ubuf_info {
 const struct ubuf_info_ops *ops;
 refcount_t refcnt;
 u8 flags;
};

struct ubuf_info_msgzc {
 struct ubuf_info ubuf;

 union {
  struct {
   unsigned long desc;
   void *ctx;
  };
  struct {
   u32 id;
   u16 len;
   u16 zerocopy:1;
   u32 bytelen;
  };
 };

 struct mmpin {
  struct user_struct *user;
  unsigned int num_pg;
 } mmp;
};

#define skb_uarg(SKB) ((struct ubuf_info *)(skb_shinfo(SKB)->destructor_arg))
#define uarg_to_msgzc(ubuf_ptr) container_of((ubuf_ptr), struct ubuf_info_msgzc, \
          ubuf)

int mm_account_pinned_pages(struct mmpin *mmp, size_t size);
void mm_unaccount_pinned_pages(struct mmpin *mmp);

/* Preserve some data across TX submission and completion.
 *
 * Note, this state is stored in the driver. Extending the layout
 * might need some special care.
 */

struct xsk_tx_metadata_compl {
 __u64 *tx_timestamp;
};

/* This data is invariant across clones and lives at
 * the end of the header data, ie. at skb->end.
 */

struct skb_shared_info {
 __u8  flags;
 __u8  meta_len;
 __u8  nr_frags;
 __u8  tx_flags;
 unsigned short gso_size;
 /* Warning: this field is not always filled in (UFO)! */
 unsigned short gso_segs;
 struct sk_buff *frag_list;
 union {
  struct skb_shared_hwtstamps hwtstamps;
  struct xsk_tx_metadata_compl xsk_meta;
 };
 unsigned int gso_type;
 u32  tskey;

 /*
 * Warning : all fields before dataref are cleared in __alloc_skb()
 */

 atomic_t dataref;

 union {
  struct {
   u32  xdp_frags_size;
   u32  xdp_frags_truesize;
  };

  /*
 * Intermediate layers must ensure that destructor_arg
 * remains valid until skb destructor.
 */

  void  *destructor_arg;
 };

 /* must be last field, see pskb_expand_head() */
 skb_frag_t frags[MAX_SKB_FRAGS];
};

/**
 * DOC: dataref and headerless skbs
 *
 * Transport layers send out clones of payload skbs they hold for
 * retransmissions. To allow lower layers of the stack to prepend their headers
 * we split &skb_shared_info.dataref into two halves.
 * The lower 16 bits count the overall number of references.
 * The higher 16 bits indicate how many of the references are payload-only.
 * skb_header_cloned() checks if skb is allowed to add / write the headers.
 *
 * The creator of the skb (e.g. TCP) marks its skb as &sk_buff.nohdr
 * (via __skb_header_release()). Any clone created from marked skb will get
 * &sk_buff.hdr_len populated with the available headroom.
 * If there's the only clone in existence it's able to modify the headroom
 * at will. The sequence of calls inside the transport layer is::
 *
 *  <alloc skb>
 *  skb_reserve()
 *  __skb_header_release()
 *  skb_clone()
 *  // send the clone down the stack
 *
 * This is not a very generic construct and it depends on the transport layers
 * doing the right thing. In practice there's usually only one payload-only skb.
 * Having multiple payload-only skbs with different lengths of hdr_len is not
 * possible. The payload-only skbs should never leave their owner.
 */

#define SKB_DATAREF_SHIFT 16
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)


enum {
 SKB_FCLONE_UNAVAILABLE, /* skb has no fclone (from head_cache) */
 SKB_FCLONE_ORIG, /* orig skb (from fclone_cache) */
 SKB_FCLONE_CLONE, /* companion fclone skb (from fclone_cache) */
};

enum {
 SKB_GSO_TCPV4 = 1 << 0,

 /* This indicates the skb is from an untrusted source. */
 SKB_GSO_DODGY = 1 << 1,

 /* This indicates the tcp segment has CWR set. */
 SKB_GSO_TCP_ECN = 1 << 2,

 SKB_GSO_TCP_FIXEDID = 1 << 3,

 SKB_GSO_TCPV6 = 1 << 4,

 SKB_GSO_FCOE = 1 << 5,

 SKB_GSO_GRE = 1 << 6,

 SKB_GSO_GRE_CSUM = 1 << 7,

 SKB_GSO_IPXIP4 = 1 << 8,

 SKB_GSO_IPXIP6 = 1 << 9,

 SKB_GSO_UDP_TUNNEL = 1 << 10,

 SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11,

 SKB_GSO_PARTIAL = 1 << 12,

 SKB_GSO_TUNNEL_REMCSUM = 1 << 13,

 SKB_GSO_SCTP = 1 << 14,

 SKB_GSO_ESP = 1 << 15,

 SKB_GSO_UDP = 1 << 16,

 SKB_GSO_UDP_L4 = 1 << 17,

 SKB_GSO_FRAGLIST = 1 << 18,

 SKB_GSO_TCP_ACCECN = 1 << 19,
};

#if BITS_PER_LONG > 32
#define NET_SKBUFF_DATA_USES_OFFSET 1
#endif

#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif

enum skb_tstamp_type {
 SKB_CLOCK_REALTIME,
 SKB_CLOCK_MONOTONIC,
 SKB_CLOCK_TAI,
 __SKB_CLOCK_MAX = SKB_CLOCK_TAI,
};

/**
 * DOC: Basic sk_buff geometry
 *
 * struct sk_buff itself is a metadata structure and does not hold any packet
 * data. All the data is held in associated buffers.
 *
 * &sk_buff.head points to the main "head" buffer. The head buffer is divided
 * into two parts:
 *
 *  - data buffer, containing headers and sometimes payload;
 *    this is the part of the skb operated on by the common helpers
 *    such as skb_put() or skb_pull();
 *  - shared info (struct skb_shared_info) which holds an array of pointers
 *    to read-only data in the (page, offset, length) format.
 *
 * Optionally &skb_shared_info.frag_list may point to another skb.
 *
 * Basic diagram may look like this::
 *
 *                                  ---------------
 *                                 | sk_buff       |
 *                                  ---------------
 *     ,---------------------------  + head
 *    /          ,-----------------  + data
 *   /          /      ,-----------  + tail
 *  |          |      |            , + end
 *  |          |      |           |
 *  v          v      v           v
 *   -----------------------------------------------
 *  | headroom | data |  tailroom | skb_shared_info |
 *   -----------------------------------------------
 *                                 + [page frag]
 *                                 + [page frag]
 *                                 + [page frag]
 *                                 + [page frag]       ---------
 *                                 + frag_list    --> | sk_buff |
 *                                                     ---------
 *
 */


/**
 * struct sk_buff - socket buffer
 * @next: Next buffer in list
 * @prev: Previous buffer in list
 * @tstamp: Time we arrived/left
 * @skb_mstamp_ns: (aka @tstamp) earliest departure time; start point
 * for retransmit timer
 * @rbnode: RB tree node, alternative to next/prev for netem/tcp
 * @list: queue head
 * @ll_node: anchor in an llist (eg socket defer_list)
 * @sk: Socket we are owned by
 * @dev: Device we arrived on/are leaving by
 * @dev_scratch: (aka @dev) alternate use of @dev when @dev would be %NULL
 * @cb: Control buffer. Free for use by every layer. Put private vars here
 * @_skb_refdst: destination entry (with norefcount bit)
 * @len: Length of actual data
 * @data_len: Data length
 * @mac_len: Length of link layer header
 * @hdr_len: writable header length of cloned skb
 * @csum: Checksum (must include start/offset pair)
 * @csum_start: Offset from skb->head where checksumming should start
 * @csum_offset: Offset from csum_start where checksum should be stored
 * @priority: Packet queueing priority
 * @ignore_df: allow local fragmentation
 * @cloned: Head may be cloned (check refcnt to be sure)
 * @ip_summed: Driver fed us an IP checksum
 * @nohdr: Payload reference only, must not modify header
 * @pkt_type: Packet class
 * @fclone: skbuff clone status
 * @ipvs_property: skbuff is owned by ipvs
 * @inner_protocol_type: whether the inner protocol is
 * ENCAP_TYPE_ETHER or ENCAP_TYPE_IPPROTO
 * @remcsum_offload: remote checksum offload is enabled
 * @offload_fwd_mark: Packet was L2-forwarded in hardware
 * @offload_l3_fwd_mark: Packet was L3-forwarded in hardware
 * @tc_skip_classify: do not classify packet. set by IFB device
 * @tc_at_ingress: used within tc_classify to distinguish in/egress
 * @redirected: packet was redirected by packet classifier
 * @from_ingress: packet was redirected from the ingress path
 * @nf_skip_egress: packet shall skip nf egress - see netfilter_netdev.h
 * @peeked: this packet has been seen already, so stats have been
 * done for it, don't do them again
 * @nf_trace: netfilter packet trace flag
 * @protocol: Packet protocol from driver
 * @destructor: Destruct function
 * @tcp_tsorted_anchor: list structure for TCP (tp->tsorted_sent_queue)
 * @_sk_redir: socket redirection information for skmsg
 * @_nfct: Associated connection, if any (with nfctinfo bits)
 * @skb_iif: ifindex of device we arrived on
 * @tc_index: Traffic control index
 * @hash: the packet hash
 * @queue_mapping: Queue mapping for multiqueue devices
 * @head_frag: skb was allocated from page fragments,
 * not allocated by kmalloc() or vmalloc().
 * @pfmemalloc: skbuff was allocated from PFMEMALLOC reserves
 * @pp_recycle: mark the packet for recycling instead of freeing (implies
 * page_pool support on driver)
 * @active_extensions: active extensions (skb_ext_id types)
 * @ndisc_nodetype: router type (from link layer)
 * @ooo_okay: allow the mapping of a socket to a queue to be changed
 * @l4_hash: indicate hash is a canonical 4-tuple hash over transport
 * ports.
 * @sw_hash: indicates hash was computed in software stack
 * @wifi_acked_valid: wifi_acked was set
 * @wifi_acked: whether frame was acked on wifi or not
 * @no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS
 * @encapsulation: indicates the inner headers in the skbuff are valid
 * @encap_hdr_csum: software checksum is needed
 * @csum_valid: checksum is already valid
 * @csum_not_inet: use CRC32c to resolve CHECKSUM_PARTIAL
 * @csum_complete_sw: checksum was completed by software
 * @csum_level: indicates the number of consecutive checksums found in
 * the packet minus one that have been verified as
 * CHECKSUM_UNNECESSARY (max 3)
 * @unreadable: indicates that at least 1 of the fragments in this skb is
 * unreadable.
 * @dst_pending_confirm: need to confirm neighbour
 * @decrypted: Decrypted SKB
 * @slow_gro: state present at GRO time, slower prepare step required
 * @tstamp_type: When set, skb->tstamp has the
 * delivery_time clock base of skb->tstamp.
 * @napi_id: id of the NAPI struct this skb came from
 * @sender_cpu: (aka @napi_id) source CPU in XPS
 * @alloc_cpu: CPU which did the skb allocation.
 * @secmark: security marking
 * @mark: Generic packet mark
 * @reserved_tailroom: (aka @mark) number of bytes of free space available
 * at the tail of an sk_buff
 * @vlan_all: vlan fields (proto & tci)
 * @vlan_proto: vlan encapsulation protocol
 * @vlan_tci: vlan tag control information
 * @inner_protocol: Protocol (encapsulation)
 * @inner_ipproto: (aka @inner_protocol) stores ipproto when
 * skb->inner_protocol_type == ENCAP_TYPE_IPPROTO;
 * @inner_transport_header: Inner transport layer header (encapsulation)
 * @inner_network_header: Network layer header (encapsulation)
 * @inner_mac_header: Link layer header (encapsulation)
 * @transport_header: Transport layer header
 * @network_header: Network layer header
 * @mac_header: Link layer header
 * @kcov_handle: KCOV remote handle for remote coverage collection
 * @tail: Tail pointer
 * @end: End pointer
 * @head: Head of buffer
 * @data: Data head pointer
 * @truesize: Buffer size
 * @users: User count - see {datagram,tcp}.c
 * @extensions: allocated extensions, valid if active_extensions is nonzero
 */


struct sk_buff {
 union {
  struct {
   /* These two members must be first to match sk_buff_head. */
   struct sk_buff  *next;
   struct sk_buff  *prev;

   union {
    struct net_device *dev;
    /* Some protocols might use this space to store information,
 * while device pointer would be NULL.
 * UDP receive path is one user.
 */

    unsigned long  dev_scratch;
   };
  };
  struct rb_node  rbnode; /* used in netem, ip4 defrag, and tcp stack */
  struct list_head list;
  struct llist_node ll_node;
 };

 struct sock  *sk;

 union {
  ktime_t  tstamp;
  u64  skb_mstamp_ns; /* earliest departure time */
 };
 /*
 * This is the control buffer. It is free to use for every
 * layer. Please put your private variables there. If you
 * want to keep them across layers you have to do a skb_clone()
 * first. This is owned by whoever has the skb queued ATM.
 */

 char   cb[48] __aligned(8);

 union {
  struct {
   unsigned long _skb_refdst;
   void  (*destructor)(struct sk_buff *skb);
  };
  struct list_head tcp_tsorted_anchor;
#ifdef CONFIG_NET_SOCK_MSG
  unsigned long  _sk_redir;
#endif
 };

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 unsigned long   _nfct;
#endif
 unsigned int  len,
    data_len;
 __u16   mac_len,
    hdr_len;

 /* Following fields are _not_ copied in __copy_skb_header()
 * Note that queue_mapping is here mostly to fill a hole.
 */

 __u16   queue_mapping;

/* if you move cloned around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define CLONED_MASK (1 << 7)
#else
#define CLONED_MASK 1
#endif
#define CLONED_OFFSET  offsetof(struct sk_buff, __cloned_offset)

 /* private: */
 __u8   __cloned_offset[0];
 /* public: */
 __u8   cloned:1,
    nohdr:1,
    fclone:2,
    peeked:1,
    head_frag:1,
    pfmemalloc:1,
    pp_recycle:1; /* page_pool recycle indicator */
#ifdef CONFIG_SKB_EXTENSIONS
 __u8   active_extensions;
#endif

 /* Fields enclosed in headers group are copied
 * using a single memcpy() in __copy_skb_header()
 */

 struct_group(headers,

 /* private: */
 __u8   __pkt_type_offset[0];
 /* public: */
 __u8   pkt_type:3; /* see PKT_TYPE_MAX */
 __u8   ignore_df:1;
 __u8   dst_pending_confirm:1;
 __u8   ip_summed:2;
 __u8   ooo_okay:1;

 /* private: */
 __u8   __mono_tc_offset[0];
 /* public: */
 __u8   tstamp_type:2; /* See skb_tstamp_type */
#ifdef CONFIG_NET_XGRESS
 __u8   tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */
 __u8   tc_skip_classify:1;
#endif
 __u8   remcsum_offload:1;
 __u8   csum_complete_sw:1;
 __u8   csum_level:2;
 __u8   inner_protocol_type:1;

 __u8   l4_hash:1;
 __u8   sw_hash:1;
#ifdef CONFIG_WIRELESS
 __u8   wifi_acked_valid:1;
 __u8   wifi_acked:1;
#endif
 __u8   no_fcs:1;
 /* Indicates the inner headers are valid in the skbuff. */
 __u8   encapsulation:1;
 __u8   encap_hdr_csum:1;
 __u8   csum_valid:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
 __u8   ndisc_nodetype:2;
#endif

#if IS_ENABLED(CONFIG_IP_VS)
 __u8   ipvs_property:1;
#endif
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)
 __u8   nf_trace:1;
#endif
#ifdef CONFIG_NET_SWITCHDEV
 __u8   offload_fwd_mark:1;
 __u8   offload_l3_fwd_mark:1;
#endif
 __u8   redirected:1;
#ifdef CONFIG_NET_REDIRECT
 __u8   from_ingress:1;
#endif
#ifdef CONFIG_NETFILTER_SKIP_EGRESS
 __u8   nf_skip_egress:1;
#endif
#ifdef CONFIG_SKB_DECRYPTED
 __u8   decrypted:1;
#endif
 __u8   slow_gro:1;
#if IS_ENABLED(CONFIG_IP_SCTP)
 __u8   csum_not_inet:1;
#endif
 __u8   unreadable:1;
#if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS)
 __u16   tc_index; /* traffic control index */
#endif

 u16   alloc_cpu;

 union {
  __wsum  csum;
  struct {
   __u16 csum_start;
   __u16 csum_offset;
  };
 };
 __u32   priority;
 int   skb_iif;
 __u32   hash;
 union {
  u32  vlan_all;
  struct {
   __be16 vlan_proto;
   __u16 vlan_tci;
  };
 };
#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)
 union {
  unsigned int napi_id;
  unsigned int sender_cpu;
 };
#endif
#ifdef CONFIG_NETWORK_SECMARK
 __u32  secmark;
#endif

 union {
  __u32  mark;
  __u32  reserved_tailroom;
 };

 union {
  __be16  inner_protocol;
  __u8  inner_ipproto;
 };

 __u16   inner_transport_header;
 __u16   inner_network_header;
 __u16   inner_mac_header;

 __be16   protocol;
 __u16   transport_header;
 __u16   network_header;
 __u16   mac_header;

#ifdef CONFIG_KCOV
 u64   kcov_handle;
#endif

 ); /* end headers group */

 /* These elements must be at the end, see alloc_skb() for details.  */
 sk_buff_data_t  tail;
 sk_buff_data_t  end;
 unsigned char  *head,
    *data;
 unsigned int  truesize;
 refcount_t  users;

#ifdef CONFIG_SKB_EXTENSIONS
 /* only usable after checking ->active_extensions != 0 */
 struct skb_ext  *extensions;
#endif
};

/* if you move pkt_type around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define PKT_TYPE_MAX (7 << 5)
#else
#define PKT_TYPE_MAX 7
#endif
#define PKT_TYPE_OFFSET  offsetof(struct sk_buff, __pkt_type_offset)

/* if you move tc_at_ingress or tstamp_type
 * around, you also must adapt these constants.
 */

#ifdef __BIG_ENDIAN_BITFIELD
#define SKB_TSTAMP_TYPE_MASK  (3 << 6)
#define SKB_TSTAMP_TYPE_RSHIFT  (6)
#define TC_AT_INGRESS_MASK  (1 << 5)
#else
#define SKB_TSTAMP_TYPE_MASK  (3)
#define TC_AT_INGRESS_MASK  (1 << 2)
#endif
#define SKB_BF_MONO_TC_OFFSET  offsetof(struct sk_buff, __mono_tc_offset)

#ifdef __KERNEL__
/*
 * Handling routines are only of interest to the kernel
 */


#define SKB_ALLOC_FCLONE 0x01
#define SKB_ALLOC_RX  0x02
#define SKB_ALLOC_NAPI  0x04

/**
 * skb_pfmemalloc - Test if the skb was allocated from PFMEMALLOC reserves
 * @skb: buffer
 */

static inline bool skb_pfmemalloc(const struct sk_buff *skb)
{
 return unlikely(skb->pfmemalloc);
}

/*
 * skb might have a dst pointer attached, refcounted or not.
 * _skb_refdst low order bit is set if refcount was _not_ taken
 */

#define SKB_DST_NOREF 1UL
#define SKB_DST_PTRMASK ~(SKB_DST_NOREF)

/**
 * skb_dst - returns skb dst_entry
 * @skb: buffer
 *
 * Returns: skb dst_entry, regardless of reference taken or not.
 */

static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
 /* If refdst was not refcounted, check we still are in a
 * rcu_read_lock section
 */

 WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) &&
  !rcu_read_lock_held() &&
  !rcu_read_lock_bh_held());
 return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK);
}

/**
 * skb_dst_set - sets skb dst
 * @skb: buffer
 * @dst: dst entry
 *
 * Sets skb dst, assuming a reference was taken on dst and should
 * be released by skb_dst_drop()
 */

static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
 skb->slow_gro |= !!dst;
 skb->_skb_refdst = (unsigned long)dst;
}

/**
 * skb_dst_set_noref - sets skb dst, hopefully, without taking reference
 * @skb: buffer
 * @dst: dst entry
 *
 * Sets skb dst, assuming a reference was not taken on dst.
 * If dst entry is cached, we do not take reference and dst_release
 * will be avoided by refdst_drop. If dst entry is not cached, we take
 * reference, so that last dst_release can destroy the dst immediately.
 */

static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
 WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
 skb->slow_gro |= !!dst;
 skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
}

/**
 * skb_dst_is_noref - Test if skb dst isn't refcounted
 * @skb: buffer
 */

static inline bool skb_dst_is_noref(const struct sk_buff *skb)
{
 return (skb->_skb_refdst & SKB_DST_NOREF) && skb_dst(skb);
}

/* For mangling skb->pkt_type from user space side from applications
 * such as nft, tc, etc, we only allow a conservative subset of
 * possible pkt_types to be set.
*/

static inline bool skb_pkt_type_ok(u32 ptype)
{
 return ptype <= PACKET_OTHERHOST;
}

/**
 * skb_napi_id - Returns the skb's NAPI id
 * @skb: buffer
 */

static inline unsigned int skb_napi_id(const struct sk_buff *skb)
{
#ifdef CONFIG_NET_RX_BUSY_POLL
 return skb->napi_id;
#else
 return 0;
#endif
}

static inline bool skb_wifi_acked_valid(const struct sk_buff *skb)
{
#ifdef CONFIG_WIRELESS
 return skb->wifi_acked_valid;
#else
 return 0;
#endif
}

/**
 * skb_unref - decrement the skb's reference count
 * @skb: buffer
 *
 * Returns: true if we can free the skb.
 */

static inline bool skb_unref(struct sk_buff *skb)
{
 if (unlikely(!skb))
  return false;
 if (!IS_ENABLED(CONFIG_DEBUG_NET) && likely(refcount_read(&skb->users) == 1))
  smp_rmb();
 else if (likely(!refcount_dec_and_test(&skb->users)))
  return false;

 return true;
}

static inline bool skb_data_unref(const struct sk_buff *skb,
      struct skb_shared_info *shinfo)
{
 int bias;

 if (!skb->cloned)
  return true;

 bias = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;

 if (atomic_read(&shinfo->dataref) == bias)
  smp_rmb();
 else if (atomic_sub_return(bias, &shinfo->dataref))
  return false;

 return true;
}

void __fix_address sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb,
          enum skb_drop_reason reason);

static inline void
kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason)
{
 sk_skb_reason_drop(NULL, skb, reason);
}

/**
 * kfree_skb - free an sk_buff with 'NOT_SPECIFIED' reason
 * @skb: buffer to free
 */

static inline void kfree_skb(struct sk_buff *skb)
{
 kfree_skb_reason(skb, SKB_DROP_REASON_NOT_SPECIFIED);
}

void skb_release_head_state(struct sk_buff *skb);
void kfree_skb_list_reason(struct sk_buff *segs,
      enum skb_drop_reason reason);
void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt);
void skb_tx_error(struct sk_buff *skb);

static inline void kfree_skb_list(struct sk_buff *segs)
{
 kfree_skb_list_reason(segs, SKB_DROP_REASON_NOT_SPECIFIED);
}

#ifdef CONFIG_TRACEPOINTS
void consume_skb(struct sk_buff *skb);
#else
static inline void consume_skb(struct sk_buff *skb)
{
 return kfree_skb(skb);
}
#endif

void __consume_stateless_skb(struct sk_buff *skb);
void  __kfree_skb(struct sk_buff *skb);

void kfree_skb_partial(struct sk_buff *skb, bool head_stolen);
bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
        bool *fragstolen, int *delta_truesize);

struct sk_buff *__alloc_skb(unsigned int size, gfp_t priority, int flags,
       int node);
struct sk_buff *__build_skb(void *data, unsigned int frag_size);
struct sk_buff *build_skb(void *data, unsigned int frag_size);
struct sk_buff *build_skb_around(struct sk_buff *skb,
     void *data, unsigned int frag_size);
void skb_attempt_defer_free(struct sk_buff *skb);

u32 napi_skb_cache_get_bulk(void **skbs, u32 n);
struct sk_buff *napi_build_skb(void *data, unsigned int frag_size);
struct sk_buff *slab_build_skb(void *data);

/**
 * alloc_skb - allocate a network buffer
 * @size: size to allocate
 * @priority: allocation mask
 *
 * This function is a convenient wrapper around __alloc_skb().
 */

static inline struct sk_buff *alloc_skb(unsigned int size,
     gfp_t priority)
{
 return __alloc_skb(size, priority, 0, NUMA_NO_NODE);
}

struct sk_buff *alloc_skb_with_frags(unsigned long header_len,
         unsigned long data_len,
         int max_page_order,
         int *errcode,
         gfp_t gfp_mask);
struct sk_buff *alloc_skb_for_msg(struct sk_buff *first);

/* Layout of fast clones : [skb1][skb2][fclone_ref] */
struct sk_buff_fclones {
 struct sk_buff skb1;

 struct sk_buff skb2;

 refcount_t fclone_ref;
};

/**
 * skb_fclone_busy - check if fclone is busy
 * @sk: socket
 * @skb: buffer
 *
 * Returns: true if skb is a fast clone, and its clone is not freed.
 * Some drivers call skb_orphan() in their ndo_start_xmit(),
 * so we also check that didn't happen.
 */

static inline bool skb_fclone_busy(const struct sock *sk,
       const struct sk_buff *skb)
{
 const struct sk_buff_fclones *fclones;

 fclones = container_of(skb, struct sk_buff_fclones, skb1);

 return skb->fclone == SKB_FCLONE_ORIG &&
        refcount_read(&fclones->fclone_ref) > 1 &&
        READ_ONCE(fclones->skb2.sk) == sk;
}

/**
 * alloc_skb_fclone - allocate a network buffer from fclone cache
 * @size: size to allocate
 * @priority: allocation mask
 *
 * This function is a convenient wrapper around __alloc_skb().
 */

static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
            gfp_t priority)
{
 return __alloc_skb(size, priority, SKB_ALLOC_FCLONE, NUMA_NO_NODE);
}

struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
void skb_headers_offset_update(struct sk_buff *skb, int off);
int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t priority);
void skb_copy_header(struct sk_buff *newconst struct sk_buff *old);
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t priority);
struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
       gfp_t gfp_mask, bool fclone);
static inline struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom,
       gfp_t gfp_mask)
{
 return __pskb_copy_fclone(skb, headroom, gfp_mask, false);
}

int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, gfp_t gfp_mask);
struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
         unsigned int headroom);
struct sk_buff *skb_expand_head(struct sk_buff *skb, unsigned int headroom);
struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
    int newtailroom, gfp_t priority);
int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
         int offset, int len);
int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
         int offset, int len);
int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
int __skb_pad(struct sk_buff *skb, int pad, bool free_on_error);

/**
 * skb_pad - zero pad the tail of an skb
 * @skb: buffer to pad
 * @pad: space to pad
 *
 * Ensure that a buffer is followed by a padding area that is zero
 * filled. Used by network drivers which may DMA or transfer data
 * beyond the buffer end onto the wire.
 *
 * May return error in out of memory cases. The skb is freed on error.
 */

static inline int skb_pad(struct sk_buff *skb, int pad)
{
 return __skb_pad(skb, pad, true);
}
#define dev_kfree_skb(a) consume_skb(a)

int skb_append_pagefrags(struct sk_buff *skb, struct page *page,
    int offset, size_t size, size_t max_frags);

struct skb_seq_state {
 __u32  lower_offset;
 __u32  upper_offset;
 __u32  frag_idx;
 __u32  stepped_offset;
 struct sk_buff *root_skb;
 struct sk_buff *cur_skb;
 __u8  *frag_data;
 __u32  frag_off;
};

void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
     unsigned int to, struct skb_seq_state *st);
unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
     struct skb_seq_state *st);
void skb_abort_seq_read(struct skb_seq_state *st);
int skb_copy_seq_read(struct skb_seq_state *st, int offset, void *to, int len);

unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
      unsigned int to, struct ts_config *config);

/*
 * Packet hash types specify the type of hash in skb_set_hash.
 *
 * Hash types refer to the protocol layer addresses which are used to
 * construct a packet's hash. The hashes are used to differentiate or identify
 * flows of the protocol layer for the hash type. Hash types are either
 * layer-2 (L2), layer-3 (L3), or layer-4 (L4).
 *
 * Properties of hashes:
 *
 * 1) Two packets in different flows have different hash values
 * 2) Two packets in the same flow should have the same hash value
 *
 * A hash at a higher layer is considered to be more specific. A driver should
 * set the most specific hash possible.
 *
 * A driver cannot indicate a more specific hash than the layer at which a hash
 * was computed. For instance an L3 hash cannot be set as an L4 hash.
 *
 * A driver may indicate a hash level which is less specific than the
 * actual layer the hash was computed on. For instance, a hash computed
 * at L4 may be considered an L3 hash. This should only be done if the
 * driver can't unambiguously determine that the HW computed the hash at
 * the higher layer. Note that the "should" in the second property above
 * permits this.
 */

enum pkt_hash_types {
 PKT_HASH_TYPE_NONE, /* Undefined type */
 PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */
 PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */
 PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */
};

static inline void skb_clear_hash(struct sk_buff *skb)
{
 skb->hash = 0;
 skb->sw_hash = 0;
 skb->l4_hash = 0;
}

static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
{
 if (!skb->l4_hash)
  skb_clear_hash(skb);
}

static inline void
__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4)
{
 skb->l4_hash = is_l4;
 skb->sw_hash = is_sw;
 skb->hash = hash;
}

static inline void
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
 /* Used by drivers to set hash from HW */
 __skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4);
}

static inline void
__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)
{
 __skb_set_hash(skb, hash, true, is_l4);
}

u32 __skb_get_hash_symmetric_net(const struct net *net, const struct sk_buff *skb);

static inline u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
{
 return __skb_get_hash_symmetric_net(NULL, skb);
}

void __skb_get_hash_net(const struct net *net, struct sk_buff *skb);
u32 skb_get_poff(const struct sk_buff *skb);
u32 __skb_get_poff(const struct sk_buff *skb, const void *data,
     const struct flow_keys_basic *keys, int hlen);
__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
     const void *data, int hlen_proto);

void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
        const struct flow_dissector_key *key,
        unsigned int key_count);

struct bpf_flow_dissector;
u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
       __be16 proto, int nhoff, int hlen, unsigned int flags);

bool __skb_flow_dissect(const struct net *net,
   const struct sk_buff *skb,
   struct flow_dissector *flow_dissector,
   void *target_container, const void *data,
   __be16 proto, int nhoff, int hlen, unsigned int flags);

static inline bool skb_flow_dissect(const struct sk_buff *skb,
        struct flow_dissector *flow_dissector,
        void *target_container, unsigned int flags)
{
 return __skb_flow_dissect(NULL, skb, flow_dissector,
      target_container, NULL, 0, 0, 0, flags);
}

static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb,
           struct flow_keys *flow,
           unsigned int flags)
{
 memset(flow, 0, sizeof(*flow));
 return __skb_flow_dissect(NULL, skb, &flow_keys_dissector,
      flow, NULL, 0, 0, 0, flags);
}

static inline bool
skb_flow_dissect_flow_keys_basic(const struct net *net,
     const struct sk_buff *skb,
     struct flow_keys_basic *flow,
     const void *data, __be16 proto,
     int nhoff, int hlen, unsigned int flags)
{
 memset(flow, 0, sizeof(*flow));
 return __skb_flow_dissect(net, skb, &flow_keys_basic_dissector, flow,
      data, proto, nhoff, hlen, flags);
}

void skb_flow_dissect_meta(const struct sk_buff *skb,
      struct flow_dissector *flow_dissector,
      void *target_container);

/* Gets a skb connection tracking info, ctinfo map should be a
 * map of mapsize to translate enum ip_conntrack_info states
 * to user states.
 */

void
skb_flow_dissect_ct(const struct sk_buff *skb,
      struct flow_dissector *flow_dissector,
      void *target_container,
      u16 *ctinfo_map, size_t mapsize,
      bool post_ct, u16 zone);
void
skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
        struct flow_dissector *flow_dissector,
        void *target_container);

void skb_flow_dissect_hash(const struct sk_buff *skb,
      struct flow_dissector *flow_dissector,
      void *target_container);

static inline __u32 skb_get_hash_net(const struct net *net, struct sk_buff *skb)
{
 if (!skb->l4_hash && !skb->sw_hash)
  __skb_get_hash_net(net, skb);

 return skb->hash;
}

static inline __u32 skb_get_hash(struct sk_buff *skb)
{
 if (!skb->l4_hash && !skb->sw_hash)
  __skb_get_hash_net(NULL, skb);

 return skb->hash;
}

static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6)
{
 if (!skb->l4_hash && !skb->sw_hash) {
  struct flow_keys keys;
  __u32 hash = __get_hash_from_flowi6(fl6, &keys);

  __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
 }

 return skb->hash;
}

__u32 skb_get_hash_perturb(const struct sk_buff *skb,
      const siphash_key_t *perturb);

static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
{
 return skb->hash;
}

static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
{
 to->hash = from->hash;
 to->sw_hash = from->sw_hash;
 to->l4_hash = from->l4_hash;
};

static inline int skb_cmp_decrypted(const struct sk_buff *skb1,
        const struct sk_buff *skb2)
{
#ifdef CONFIG_SKB_DECRYPTED
 return skb2->decrypted - skb1->decrypted;
#else
 return 0;
#endif
}

static inline bool skb_is_decrypted(const struct sk_buff *skb)
{
#ifdef CONFIG_SKB_DECRYPTED
 return skb->decrypted;
#else
 return false;
#endif
}

static inline void skb_copy_decrypted(struct sk_buff *to,
          const struct sk_buff *from)
{
#ifdef CONFIG_SKB_DECRYPTED
 to->decrypted = from->decrypted;
#endif
}

#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
 return skb->head + skb->end;
}

static inline unsigned int skb_end_offset(const struct sk_buff *skb)
{
 return skb->end;
}

static inline void skb_set_end_offset(struct sk_buff *skb, unsigned int offset)
{
 skb->end = offset;
}
#else
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
 return skb->end;
}

static inline unsigned int skb_end_offset(const struct sk_buff *skb)
{
 return skb->end - skb->head;
}

static inline void skb_set_end_offset(struct sk_buff *skb, unsigned int offset)
{
 skb->end = skb->head + offset;
}
#endif

extern const struct ubuf_info_ops msg_zerocopy_ubuf_ops;

struct ubuf_info *msg_zerocopy_realloc(struct sock *sk, size_t size,
           struct ubuf_info *uarg, bool devmem);

void msg_zerocopy_put_abort(struct ubuf_info *uarg, bool have_uref);

struct net_devmem_dmabuf_binding;

int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
       struct sk_buff *skb, struct iov_iter *from,
       size_t length,
       struct net_devmem_dmabuf_binding *binding);

int zerocopy_fill_skb_from_iter(struct sk_buff *skb,
    struct iov_iter *from, size_t length);

static inline int skb_zerocopy_iter_dgram(struct sk_buff *skb,
       struct msghdr *msg, int len)
{
 return __zerocopy_sg_from_iter(msg, skb->sk, skb, &msg->msg_iter, len,
           NULL);
}

int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
        struct msghdr *msg, int len,
        struct ubuf_info *uarg,
        struct net_devmem_dmabuf_binding *binding);

/* Internal */
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))

static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
{
 return &skb_shinfo(skb)->hwtstamps;
}

static inline struct ubuf_info *skb_zcopy(struct sk_buff *skb)
{
 bool is_zcopy = skb && skb_shinfo(skb)->flags & SKBFL_ZEROCOPY_ENABLE;

 return is_zcopy ? skb_uarg(skb) : NULL;
}

static inline bool skb_zcopy_pure(const struct sk_buff *skb)
{
 return skb_shinfo(skb)->flags & SKBFL_PURE_ZEROCOPY;
}

static inline bool skb_zcopy_managed(const struct sk_buff *skb)
{
 return skb_shinfo(skb)->flags & SKBFL_MANAGED_FRAG_REFS;
}

static inline bool skb_pure_zcopy_same(const struct sk_buff *skb1,
           const struct sk_buff *skb2)
{
 return skb_zcopy_pure(skb1) == skb_zcopy_pure(skb2);
}

static inline void net_zcopy_get(struct ubuf_info *uarg)
{
 refcount_inc(&uarg->refcnt);
}

static inline void skb_zcopy_init(struct sk_buff *skb, struct ubuf_info *uarg)
{
 skb_shinfo(skb)->destructor_arg = uarg;
 skb_shinfo(skb)->flags |= uarg->flags;
}

static inline void skb_zcopy_set(struct sk_buff *skb, struct ubuf_info *uarg,
     bool *have_ref)
{
 if (skb && uarg && !skb_zcopy(skb)) {
  if (unlikely(have_ref && *have_ref))
   *have_ref = false;
  else
   net_zcopy_get(uarg);
  skb_zcopy_init(skb, uarg);
 }
}

static inline void skb_zcopy_set_nouarg(struct sk_buff *skb, void *val)
{
 skb_shinfo(skb)->destructor_arg = (void *)((uintptr_t) val | 0x1UL);
 skb_shinfo(skb)->flags |= SKBFL_ZEROCOPY_FRAG;
}

static inline bool skb_zcopy_is_nouarg(struct sk_buff *skb)
{
 return (uintptr_t) skb_shinfo(skb)->destructor_arg & 0x1UL;
}

static inline void *skb_zcopy_get_nouarg(struct sk_buff *skb)
{
 return (void *)((uintptr_t) skb_shinfo(skb)->destructor_arg & ~0x1UL);
}

static inline void net_zcopy_put(struct ubuf_info *uarg)
{
 if (uarg)
  uarg->ops->complete(NULL, uarg, true);
}

static inline void net_zcopy_put_abort(struct ubuf_info *uarg, bool have_uref)
{
 if (uarg) {
  if (uarg->ops == &msg_zerocopy_ubuf_ops)
   msg_zerocopy_put_abort(uarg, have_uref);
  else if (have_uref)
   net_zcopy_put(uarg);
 }
}

/* Release a reference on a zerocopy structure */
static inline void skb_zcopy_clear(struct sk_buff *skb, bool zerocopy_success)
{
 struct ubuf_info *uarg = skb_zcopy(skb);

 if (uarg) {
  if (!skb_zcopy_is_nouarg(skb))
   uarg->ops->complete(skb, uarg, zerocopy_success);

  skb_shinfo(skb)->flags &= ~SKBFL_ALL_ZEROCOPY;
 }
}

void __skb_zcopy_downgrade_managed(struct sk_buff *skb);

static inline void skb_zcopy_downgrade_managed(struct sk_buff *skb)
{
 if (unlikely(skb_zcopy_managed(skb)))
  __skb_zcopy_downgrade_managed(skb);
}

/* Return true if frags in this skb are readable by the host. */
static inline bool skb_frags_readable(const struct sk_buff *skb)
{
 return !skb->unreadable;
}

static inline void skb_mark_not_on_list(struct sk_buff *skb)
{
 skb->next = NULL;
}

static inline void skb_poison_list(struct sk_buff *skb)
{
#ifdef CONFIG_DEBUG_NET
 skb->next = SKB_LIST_POISON_NEXT;
#endif
}

/* Iterate through singly-linked GSO fragments of an skb. */
#define skb_list_walk_safe(first, skb, next_skb)                               \
 for ((skb) = (first), (next_skb) = (skb) ? (skb)->next : NULL; (skb);  \
      (skb) = (next_skb), (next_skb) = (skb) ? (skb)->next : NULL)

static inline void skb_list_del_init(struct sk_buff *skb)
{
 __list_del_entry(&skb->list);
 skb_mark_not_on_list(skb);
}

/**
 * skb_queue_empty - check if a queue is empty
 * @list: queue head
 *
 * Returns true if the queue is empty, false otherwise.
 */

static inline int skb_queue_empty(const struct sk_buff_head *list)
{
 return list->next == (const struct sk_buff *) list;
}

/**
 * skb_queue_empty_lockless - check if a queue is empty
 * @list: queue head
 *
 * Returns true if the queue is empty, false otherwise.
 * This variant can be used in lockless contexts.
 */

static inline bool skb_queue_empty_lockless(const struct sk_buff_head *list)
{
 return READ_ONCE(list->next) == (const struct sk_buff *) list;
}


/**
 * skb_queue_is_last - check if skb is the last entry in the queue
 * @list: queue head
 * @skb: buffer
 *
 * Returns true if @skb is the last buffer on the list.
 */

static inline bool skb_queue_is_last(const struct sk_buff_head *list,
         const struct sk_buff *skb)
{
 return skb->next == (const struct sk_buff *) list;
}

/**
 * skb_queue_is_first - check if skb is the first entry in the queue
 * @list: queue head
 * @skb: buffer
 *
 * Returns true if @skb is the first buffer on the list.
 */

static inline bool skb_queue_is_first(const struct sk_buff_head *list,
          const struct sk_buff *skb)
{
 return skb->prev == (const struct sk_buff *) list;
}

/**
 * skb_queue_next - return the next packet in the queue
 * @list: queue head
 * @skb: current buffer
 *
 * Return the next packet in @list after @skb.  It is only valid to
 * call this if skb_queue_is_last() evaluates to false.
 */

static inline struct sk_buff *skb_queue_next(const struct sk_buff_head *list,
          const struct sk_buff *skb)
{
 /* This BUG_ON may seem severe, but if we just return then we
 * are going to dereference garbage.
 */

 BUG_ON(skb_queue_is_last(list, skb));
 return skb->next;
}

/**
 * skb_queue_prev - return the prev packet in the queue
 * @list: queue head
 * @skb: current buffer
 *
 * Return the prev packet in @list before @skb.  It is only valid to
 * call this if skb_queue_is_first() evaluates to false.
 */

static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list,
          const struct sk_buff *skb)
{
 /* This BUG_ON may seem severe, but if we just return then we
 * are going to dereference garbage.
 */

 BUG_ON(skb_queue_is_first(list, skb));
 return skb->prev;
}

/**
 * skb_get - reference buffer
 * @skb: buffer to reference
 *
 * Makes another reference to a socket buffer and returns a pointer
 * to the buffer.
 */

static inline struct sk_buff *skb_get(struct sk_buff *skb)
{
 refcount_inc(&skb->users);
 return skb;
}

/*
 * If users == 1, we are the only owner and can avoid redundant atomic changes.
 */


/**
 * skb_cloned - is the buffer a clone
 * @skb: buffer to check
 *
 * Returns true if the buffer was generated with skb_clone() and is
 * one of multiple shared copies of the buffer. Cloned buffers are
 * shared data so must not be written to under normal circumstances.
 */

static inline int skb_cloned(const struct sk_buff *skb)
{
 return skb->cloned &&
        (atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1;
}

static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
{
 might_sleep_if(gfpflags_allow_blocking(pri));

 if (skb_cloned(skb))
  return pskb_expand_head(skb, 0, 0, pri);

 return 0;
}

/* This variant of skb_unclone() makes sure skb->truesize
 * and skb_end_offset() are not changed, whenever a new skb->head is needed.
 *
 * Indeed there is no guarantee that ksize(kmalloc(X)) == ksize(kmalloc(X))
 * when various debugging features are in place.
 */

int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri);
static inline int skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri)
{
 might_sleep_if(gfpflags_allow_blocking(pri));

 if (skb_cloned(skb))
  return __skb_unclone_keeptruesize(skb, pri);
 return 0;
}

/**
 * skb_header_cloned - is the header a clone
 * @skb: buffer to check
 *
 * Returns true if modifying the header part of the buffer requires
 * the data to be copied.
 */

static inline int skb_header_cloned(const struct sk_buff *skb)
{
 int dataref;

 if (!skb->cloned)
  return 0;

 dataref = atomic_read(&skb_shinfo(skb)->dataref);
 dataref = (dataref & SKB_DATAREF_MASK) - (dataref >> SKB_DATAREF_SHIFT);
 return dataref != 1;
}

static inline int skb_header_unclone(struct sk_buff *skb, gfp_t pri)
{
 might_sleep_if(gfpflags_allow_blocking(pri));

 if (skb_header_cloned(skb))
  return pskb_expand_head(skb, 0, 0, pri);

 return 0;
}

/**
 * __skb_header_release() - allow clones to use the headroom
 * @skb: buffer to operate on
 *
 * See "DOC: dataref and headerless skbs".
 */

static inline void __skb_header_release(struct sk_buff *skb)
{
 skb->nohdr = 1;
 atomic_set(&skb_shinfo(skb)->dataref, 1 + (1 << SKB_DATAREF_SHIFT));
}


/**
 * skb_shared - is the buffer shared
 * @skb: buffer to check
 *
 * Returns true if more than one person has a reference to this
 * buffer.
 */

static inline int skb_shared(const struct sk_buff *skb)
{
 return refcount_read(&skb->users) != 1;
}

/**
 * skb_share_check - check if buffer is shared and if so clone it
 * @skb: buffer to check
 * @pri: priority for memory allocation
 *
 * If the buffer is shared the buffer is cloned and the old copy
 * drops a reference. A new clone with a single reference is returned.
 * If the buffer is not shared the original buffer is returned. When
 * being called from interrupt status or with spinlocks held pri must
 * be GFP_ATOMIC.
 *
 * NULL is returned on a memory allocation failure.
 */

static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri)
{
 might_sleep_if(gfpflags_allow_blocking(pri));
 if (skb_shared(skb)) {
  struct sk_buff *nskb = skb_clone(skb, pri);

  if (likely(nskb))
   consume_skb(skb);
  else
   kfree_skb(skb);
  skb = nskb;
 }
 return skb;
}

/*
 * Copy shared buffers into a new sk_buff. We effectively do COW on
 * packets to handle cases where we have a local reader and forward
 * and a couple of other messy ones. The normal one is tcpdumping
 * a packet that's being forwarded.
 */


/**
 * skb_unshare - make a copy of a shared buffer
 * @skb: buffer to check
 * @pri: priority for memory allocation
 *
 * If the socket buffer is a clone then this function creates a new
 * copy of the data, drops a reference count on the old copy and returns
 * the new copy with the reference count at 1. If the buffer is not a clone
 * the original buffer is returned. When called with a spinlock held or
 * from interrupt state @pri must be %GFP_ATOMIC
 *
 * %NULL is returned on a memory allocation failure.
 */

static inline struct sk_buff *skb_unshare(struct sk_buff *skb,
       gfp_t pri)
{
 might_sleep_if(gfpflags_allow_blocking(pri));
 if (skb_cloned(skb)) {
  struct sk_buff *nskb = skb_copy(skb, pri);

  /* Free our shared copy */
  if (likely(nskb))
   consume_skb(skb);
  else
   kfree_skb(skb);
  skb = nskb;
 }
 return skb;
}

/**
 * skb_peek - peek at the head of an &sk_buff_head
 * @list_: list to peek at
 *
 * Peek an &sk_buff. Unlike most other operations you _MUST_
 * be careful with this one. A peek leaves the buffer on the
 * list and someone else may run off with it. You must hold
 * the appropriate locks or have a private queue to do this.
 *
 * Returns %NULL for an empty list or a pointer to the head element.
 * The reference count is not incremented and the reference is therefore
 * volatile. Use with caution.
 */

static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_)
{
 struct sk_buff *skb = list_->next;

 if (skb == (struct sk_buff *)list_)
  skb = NULL;
 return skb;
}

/**
 * __skb_peek - peek at the head of a non-empty &sk_buff_head
 * @list_: list to peek at
 *
 * Like skb_peek(), but the caller knows that the list is not empty.
 */

static inline struct sk_buff *__skb_peek(const struct sk_buff_head *list_)
{
 return list_->next;
}

/**
 * skb_peek_next - peek skb following the given one from a queue
 * @skb: skb to start from
 * @list_: list to peek at
 *
 * Returns %NULL when the end of the list is met or a pointer to the
 * next element. The reference count is not incremented and the
 * reference is therefore volatile. Use with caution.
 */

static inline struct sk_buff *skb_peek_next(struct sk_buff *skb,
  const struct sk_buff_head *list_)
{
 struct sk_buff *next = skb->next;

 if (next == (struct sk_buff *)list_)
  next = NULL;
 return next;
}

/**
 * skb_peek_tail - peek at the tail of an &sk_buff_head
 * @list_: list to peek at
 *
 * Peek an &sk_buff. Unlike most other operations you _MUST_
 * be careful with this one. A peek leaves the buffer on the
 * list and someone else may run off with it. You must hold
 * the appropriate locks or have a private queue to do this.
 *
 * Returns %NULL for an empty list or a pointer to the tail element.
 * The reference count is not incremented and the reference is therefore
 * volatile. Use with caution.
 */

static inline struct sk_buff *skb_peek_tail(const struct sk_buff_head *list_)
{
 struct sk_buff *skb = READ_ONCE(list_->prev);

 if (skb == (struct sk_buff *)list_)
  skb = NULL;
 return skb;

}

/**
 * skb_queue_len - get queue length
 * @list_: list to measure
 *
 * Return the length of an &sk_buff queue.
 */

static inline __u32 skb_queue_len(const struct sk_buff_head *list_)
{
 return list_->qlen;
}

/**
 * skb_queue_len_lockless - get queue length
 * @list_: list to measure
 *
 * Return the length of an &sk_buff queue.
 * This variant can be used in lockless contexts.
 */

--> --------------------

--> maximum size reached

--> --------------------

100%


¤ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.