patch-2.4.4 linux/include/linux/skbuff.h
Next file: linux/include/linux/socket.h
Previous file: linux/include/linux/shmem_fs.h
Back to the patch index
Back to the overall index
- Lines: 381
- Date:
Fri Apr 27 15:48:50 2001
- Orig file:
v2.4.3/linux/include/linux/skbuff.h
- Orig date:
Mon Mar 26 15:48:19 2001
diff -u --recursive --new-file v2.4.3/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
@@ -18,10 +18,13 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/cache.h>
#include <asm/atomic.h>
#include <asm/types.h>
#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
#define HAVE_ALLOC_SKB /* For the drivers to know */
#define HAVE_ALIGNABLE_SKB /* Ditto 8) */
@@ -31,6 +34,47 @@
#define CHECKSUM_HW 1
#define CHECKSUM_UNNECESSARY 2
+#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES-1)) & ~(SMP_CACHE_BYTES-1))
+#define SKB_MAX_HEAD(X) ((PAGE_SIZE - (X) - sizeof(struct skb_shared_info))&~(SMP_CACHE_BYTES-1))
+
+/* A. Checksumming of received packets by device.
+ *
+ * NONE: device failed to checksum this packet.
+ * skb->csum is undefined.
+ *
+ * UNNECESSARY: device parsed packet and wouldbe verified checksum.
+ * skb->csum is undefined.
+ * It is bad option, but, unfortunately, many of vendors do this.
+ * Apparently with secret goal to sell you new device, when you
+ * will add new protocol to your host. F.e. IPv6. 8)
+ *
+ * HW: the most generic way. Device supplied checksum of _all_
+ * the packet as seen by netif_rx in skb->csum.
+ * NOTE: Even if device supports only some protocols, but
+ * is able to produce some skb->csum, it MUST use HW,
+ * not UNNECESSARY.
+ *
+ * B. Checksumming on output.
+ *
+ * NONE: skb is checksummed by protocol or csum is not required.
+ *
+ * HW: device is required to csum packet as seen by hard_start_xmit
+ * from skb->h.raw to the end and to record the checksum
+ * at skb->h.raw+skb->csum.
+ *
+ * Device must show its capabilities in dev->features, set
+ * at device setup time.
+ * NETIF_F_HW_CSUM - it is clever device, it is able to checksum
+ * everything.
+ * NETIF_F_NO_CSUM - loopback or reliable single hop media.
+ * NETIF_F_IP_CSUM - device is dumb. It is able to csum only
+ * TCP/UDP over IPv4. Sigh. Vendors like this
+ * way by an unknown reason. Though, see comment above
+ * about CHECKSUM_UNNECESSARY. 8)
+ *
+ * Any questions? No questions, good. --ANK
+ */
+
#ifdef __i386__
#define NET_CALLER(arg) (*(((void**)&arg)-1))
#else
@@ -57,6 +101,29 @@
spinlock_t lock;
};
+struct sk_buff;
+
+#define MAX_SKB_FRAGS 6
+
+typedef struct skb_frag_struct skb_frag_t;
+
+struct skb_frag_struct
+{
+ struct page *page;
+ __u16 page_offset;
+ __u16 size;
+};
+
+/* This data is invariant across clones and lives at
+ * the end of the header data, ie. at skb->end.
+ */
+struct skb_shared_info {
+ atomic_t dataref;
+ unsigned int nr_frags;
+ struct sk_buff *frag_list;
+ skb_frag_t frags[MAX_SKB_FRAGS];
+};
+
struct sk_buff {
/* These two members must be first. */
struct sk_buff * next; /* Next buffer in list */
@@ -107,9 +174,10 @@
char cb[48];
unsigned int len; /* Length of actual data */
+ unsigned int data_len;
unsigned int csum; /* Checksum */
- volatile char used; /* Data moved to user and not MSG_PEEK */
- unsigned char cloned, /* head may be cloned (check refcnt to be sure). */
+ unsigned char __unused, /* Dead field, may be reused */
+ cloned, /* head may be cloned (check refcnt to be sure). */
pkt_type, /* Packet class */
ip_summed; /* Driver fed us an IP checksum */
__u32 priority; /* Packet queueing priority */
@@ -122,6 +190,7 @@
unsigned char *data; /* Data head pointer */
unsigned char *tail; /* Tail pointer */
unsigned char *end; /* End pointer */
+
void (*destructor)(struct sk_buff *); /* Destruct function */
#ifdef CONFIG_NETFILTER
/* Can be used for communication between hooks. */
@@ -158,11 +227,13 @@
#include <asm/system.h>
extern void __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list);
extern struct sk_buff * alloc_skb(unsigned int size, int priority);
extern void kfree_skbmem(struct sk_buff *skb);
extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority);
extern struct sk_buff * skb_copy(const struct sk_buff *skb, int priority);
+extern struct sk_buff * pskb_copy(struct sk_buff *skb, int gfp_mask);
+extern int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask);
+extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom);
extern struct sk_buff * skb_copy_expand(const struct sk_buff *skb,
int newheadroom,
int newtailroom,
@@ -171,14 +242,8 @@
extern void skb_over_panic(struct sk_buff *skb, int len, void *here);
extern void skb_under_panic(struct sk_buff *skb, int len, void *here);
-/* Backwards compatibility */
-#define skb_realloc_headroom(skb, nhr) skb_copy_expand(skb, nhr, skb_tailroom(skb), GFP_ATOMIC)
-
/* Internal */
-static inline atomic_t *skb_datarefp(struct sk_buff *skb)
-{
- return (atomic_t *)(skb->end);
-}
+#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
/**
* skb_queue_empty - check if a queue is empty
@@ -243,7 +308,7 @@
static inline int skb_cloned(struct sk_buff *skb)
{
- return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
+ return skb->cloned && atomic_read(&skb_shinfo(skb)->dataref) != 1;
}
/**
@@ -679,6 +744,20 @@
return result;
}
+static inline int skb_is_nonlinear(const struct sk_buff *skb)
+{
+ return skb->data_len;
+}
+
+static inline int skb_headlen(const struct sk_buff *skb)
+{
+ return skb->len - skb->data_len;
+}
+
+#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) BUG(); } while (0)
+#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) BUG(); } while (0)
+#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) BUG(); } while (0)
+
/*
* Add data to an sk_buff
*/
@@ -686,6 +765,7 @@
static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
+ SKB_LINEAR_ASSERT(skb);
skb->tail+=len;
skb->len+=len;
return tmp;
@@ -704,6 +784,7 @@
static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
+ SKB_LINEAR_ASSERT(skb);
skb->tail+=len;
skb->len+=len;
if(skb->tail>skb->end) {
@@ -742,6 +823,8 @@
static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
{
skb->len-=len;
+ if (skb->len < skb->data_len)
+ BUG();
return skb->data+=len;
}
@@ -763,6 +846,33 @@
return __skb_pull(skb,len);
}
+extern unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta);
+
+static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len)
+{
+ if (len > skb_headlen(skb) &&
+ __pskb_pull_tail(skb, len-skb_headlen(skb)) == NULL)
+ return NULL;
+ skb->len -= len;
+ return skb->data += len;
+}
+
+static inline unsigned char * pskb_pull(struct sk_buff *skb, unsigned int len)
+{
+ if (len > skb->len)
+ return NULL;
+ return __pskb_pull(skb,len);
+}
+
+static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
+{
+ if (len <= skb_headlen(skb))
+ return 1;
+ if (len > skb->len)
+ return 0;
+ return (__pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL);
+}
+
/**
* skb_headroom - bytes at buffer head
* @skb: buffer to check
@@ -784,7 +894,7 @@
static inline int skb_tailroom(const struct sk_buff *skb)
{
- return skb->end-skb->tail;
+ return skb_is_nonlinear(skb) ? 0 : skb->end-skb->tail;
}
/**
@@ -802,11 +912,16 @@
skb->tail+=len;
}
+extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc);
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
{
- skb->len = len;
- skb->tail = skb->data+len;
+ if (!skb->data_len) {
+ skb->len = len;
+ skb->tail = skb->data+len;
+ } else {
+ ___pskb_trim(skb, len, 0);
+ }
}
/**
@@ -825,6 +940,25 @@
}
}
+
+static inline int __pskb_trim(struct sk_buff *skb, unsigned int len)
+{
+ if (!skb->data_len) {
+ skb->len = len;
+ skb->tail = skb->data+len;
+ return 0;
+ } else {
+ return ___pskb_trim(skb, len, 1);
+ }
+}
+
+static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
+{
+ if (len < skb->len)
+ return __pskb_trim(skb, len);
+ return 0;
+}
+
/**
* skb_orphan - orphan a buffer
* @skb: buffer to orphan
@@ -920,32 +1054,57 @@
}
/**
- * skb_cow - copy a buffer if need be
- * @skb: buffer to copy
+ * skb_cow - copy header of skb when it is required
+ * @skb: buffer to cow
* @headroom: needed headroom
*
- * If the buffer passed lacks sufficient headroom or is a clone then
- * it is copied and the additional headroom made available. If there
- * is no free memory %NULL is returned. The new buffer is returned if
- * a copy was made (and the old one dropped a reference). The existing
- * buffer is returned otherwise.
+ * If the skb passed lacks sufficient headroom or its data part
+ * is shared, data is reallocated. If reallocation fails, an error
+ * is returned and original skb is not changed.
*
- * This function primarily exists to avoid making two copies when making
- * a writable copy of a buffer and then growing the headroom.
+ * The result is skb with writable area skb->head...skb->tail
+ * and at least @headroom of space at head.
*/
-
-static inline struct sk_buff *
+static inline int
skb_cow(struct sk_buff *skb, unsigned int headroom)
{
- headroom = (headroom+15)&~15;
+ int delta = headroom - skb_headroom(skb);
- if ((unsigned)skb_headroom(skb) < headroom || skb_cloned(skb)) {
- struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
- kfree_skb(skb);
- skb = skb2;
- }
- return skb;
+ if (delta < 0)
+ delta = 0;
+
+ if (delta || skb_cloned(skb))
+ return pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC);
+ return 0;
+}
+
+/**
+ * skb_linearize - convert paged skb to linear one
+ * @skb: buffer to linarize
+ * @gfp_mask: allocation mode
+ *
+ * If there is no free memory -ENOMEM is returned, otherwise zero
+ * is returned and the old skb data released. */
+int skb_linearize(struct sk_buff *skb, int gfp);
+
+static inline void *kmap_skb_frag(const skb_frag_t *frag)
+{
+#ifdef CONFIG_HIGHMEM
+ if (in_irq())
+ BUG();
+
+ local_bh_disable();
+#endif
+ return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ);
+}
+
+static inline void kunmap_skb_frag(void *vaddr)
+{
+ kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
+#ifdef CONFIG_HIGHMEM
+ local_bh_enable();
+#endif
}
#define skb_queue_walk(queue, skb) \
@@ -956,9 +1115,15 @@
extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait);
-extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern int skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
+extern int skb_copy_datagram(const struct sk_buff *from, int offset, char *to,int size);
+extern int skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to,int size);
+extern int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump);
+extern int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov);
extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb);
+
+extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum);
+extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
+extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum);
extern void skb_init(void);
extern void skb_add_mtu(int mtu);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)