1 /*-
2  * Copyright (c) 2020-2022 The FreeBSD Foundation
3  * Copyright (c) 2021-2022 Bjoern A. Zeeb
4  *
5  * This software was developed by Björn Zeeb under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * NOTE: this socket buffer compatibility code is highly EXPERIMENTAL.
34  *       Do not rely on the internals of this implementation.  They are highly
35  *       likely to change as we will improve the integration to FreeBSD mbufs.
36  */
37 
38 #ifndef	_LINUXKPI_LINUX_SKBUFF_H
39 #define	_LINUXKPI_LINUX_SKBUFF_H
40 
41 #include <linux/kernel.h>
42 #include <linux/page.h>
43 #include <linux/dma-mapping.h>
44 #include <linux/netdev_features.h>
45 #include <linux/list.h>
46 #include <linux/gfp.h>
47 #include <linux/compiler.h>
48 #include <linux/spinlock.h>
49 
50 /* #define	SKB_DEBUG */
51 #ifdef SKB_DEBUG
52 #define	DSKB_TODO	0x01
53 #define	DSKB_IMPROVE	0x02
54 #define	DSKB_TRACE	0x10
55 #define	DSKB_TRACEX	0x20
56 extern int linuxkpi_debug_skb;
57 
58 #define	SKB_TODO()							\
59     if (linuxkpi_debug_skb & DSKB_TODO)					\
60 	printf("SKB_TODO %s:%d\n", __func__, __LINE__)
61 #define	SKB_IMPROVE(...)						\
62     if (linuxkpi_debug_skb & DSKB_IMPROVE)				\
63 	printf("SKB_IMPROVE %s:%d\n", __func__, __LINE__)
64 #define	SKB_TRACE(_s)							\
65     if (linuxkpi_debug_skb & DSKB_TRACE)				\
66 	printf("SKB_TRACE %s:%d %p\n", __func__, __LINE__, _s)
67 #define	SKB_TRACE2(_s, _p)						\
68     if (linuxkpi_debug_skb & DSKB_TRACE)				\
69 	printf("SKB_TRACE %s:%d %p, %p\n", __func__, __LINE__, _s, _p)
70 #define	SKB_TRACE_FMT(_s, _fmt, ...)					\
71    if (linuxkpi_debug_skb & DSKB_TRACE)					\
72 	printf("SKB_TRACE %s:%d %p " _fmt "\n", __func__, __LINE__, _s,	\
73 	    __VA_ARGS__)
74 #else
75 #define	SKB_TODO()		do { } while(0)
76 #define	SKB_IMPROVE(...)	do { } while(0)
77 #define	SKB_TRACE(_s)		do { } while(0)
78 #define	SKB_TRACE2(_s, _p)	do { } while(0)
79 #define	SKB_TRACE_FMT(_s, ...)	do { } while(0)
80 #endif
81 
82 enum sk_buff_pkt_type {
83 	PACKET_BROADCAST,
84 	PACKET_MULTICAST,
85 	PACKET_OTHERHOST,
86 };
87 
88 #define	NET_SKB_PAD		max(CACHE_LINE_SIZE, 32)
89 
90 struct sk_buff_head {
91 		/* XXX TODO */
92 	struct sk_buff		*next;
93 	struct sk_buff		*prev;
94 	size_t			qlen;
95 	spinlock_t		lock;
96 };
97 
98 enum sk_checksum_flags {
99 	CHECKSUM_NONE			= 0x00,
100 	CHECKSUM_UNNECESSARY		= 0x01,
101 	CHECKSUM_PARTIAL		= 0x02,
102 	CHECKSUM_COMPLETE		= 0x04,
103 };
104 
105 struct skb_frag {
106 		/* XXX TODO */
107 	struct page		*page;		/* XXX-BZ These three are a wild guess so far! */
108 	off_t			offset;
109 	size_t			size;
110 };
111 typedef	struct skb_frag	skb_frag_t;
112 
113 enum skb_shared_info_gso_type {
114 	SKB_GSO_TCPV4,
115 	SKB_GSO_TCPV6,
116 };
117 
118 struct skb_shared_info {
119 	enum skb_shared_info_gso_type	gso_type;
120 	uint16_t			gso_size;
121 	uint16_t			nr_frags;
122 	struct sk_buff			*frag_list;
123 	skb_frag_t			frags[64];	/* XXX TODO, 16xpage? */
124 };
125 
126 struct sk_buff {
127 	/* XXX TODO */
128 	union {
129 		/* struct sk_buff_head */
130 		struct {
131 			struct sk_buff		*next;
132 			struct sk_buff		*prev;
133 		};
134 		struct list_head	list;
135 	};
136 	uint32_t		_alloc_len;	/* Length of alloc data-buf. XXX-BZ give up for truesize? */
137 	uint32_t		len;		/* ? */
138 	uint32_t		data_len;	/* ? If we have frags? */
139 	uint32_t		truesize;	/* The total size of all buffers, incl. frags. */
140 	uint16_t		mac_len;	/* Link-layer header length. */
141 	__sum16			csum;
142 	uint16_t		l3hdroff;	/* network header offset from *head */
143 	uint16_t		l4hdroff;	/* transport header offset from *head */
144 	uint32_t		priority;
145 	uint16_t		qmap;		/* queue mapping */
146 	uint16_t		_flags;		/* Internal flags. */
147 #define	_SKB_FLAGS_SKBEXTFRAG	0x0001
148 	enum sk_buff_pkt_type	pkt_type;
149 
150 	/* "Scratch" area for layers to store metadata. */
151 	/* ??? I see sizeof() operations so probably an array. */
152 	uint8_t			cb[64] __aligned(CACHE_LINE_SIZE);
153 
154 	struct net_device	*dev;
155 	void			*sk;		/* XXX net/sock.h? */
156 
157 	int		csum_offset, csum_start, ip_summed, protocol;
158 
159 	uint8_t			*head;			/* Head of buffer. */
160 	uint8_t			*data;			/* Head of data. */
161 	uint8_t			*tail;			/* End of data. */
162 	uint8_t			*end;			/* End of buffer. */
163 
164 	struct skb_shared_info	*shinfo;
165 
166 	/* FreeBSD specific bandaid (see linuxkpi_kfree_skb). */
167 	void			*m;
168 	void(*m_free_func)(void *);
169 
170 	/* Force padding to CACHE_LINE_SIZE. */
171 	uint8_t			__scratch[0] __aligned(CACHE_LINE_SIZE);
172 };
173 
174 /* -------------------------------------------------------------------------- */
175 
176 struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t);
177 struct sk_buff *linuxkpi_dev_alloc_skb(size_t, gfp_t);
178 struct sk_buff *linuxkpi_build_skb(void *, size_t);
179 void linuxkpi_kfree_skb(struct sk_buff *);
180 
181 struct sk_buff *linuxkpi_skb_copy(struct sk_buff *, gfp_t);
182 
183 /* -------------------------------------------------------------------------- */
184 
185 static inline struct sk_buff *
186 alloc_skb(size_t size, gfp_t gfp)
187 {
188 	struct sk_buff *skb;
189 
190 	skb = linuxkpi_alloc_skb(size, gfp);
191 	SKB_TRACE(skb);
192 	return (skb);
193 }
194 
195 static inline struct sk_buff *
196 __dev_alloc_skb(size_t len, gfp_t gfp)
197 {
198 	struct sk_buff *skb;
199 
200 	skb = linuxkpi_dev_alloc_skb(len, gfp);
201 	SKB_IMPROVE();
202 	SKB_TRACE(skb);
203 	return (skb);
204 }
205 
206 static inline struct sk_buff *
207 dev_alloc_skb(size_t len)
208 {
209 	struct sk_buff *skb;
210 
211 	skb = __dev_alloc_skb(len, GFP_NOWAIT);
212 	SKB_IMPROVE();
213 	SKB_TRACE(skb);
214 	return (skb);
215 }
216 
217 static inline void
218 kfree_skb(struct sk_buff *skb)
219 {
220 	SKB_TRACE(skb);
221 	linuxkpi_kfree_skb(skb);
222 }
223 
224 static inline void
225 dev_kfree_skb(struct sk_buff *skb)
226 {
227 	SKB_TRACE(skb);
228 	kfree_skb(skb);
229 }
230 
231 static inline void
232 dev_kfree_skb_any(struct sk_buff *skb)
233 {
234 	SKB_TRACE(skb);
235 	dev_kfree_skb(skb);
236 }
237 
238 static inline void
239 dev_kfree_skb_irq(struct sk_buff *skb)
240 {
241 	SKB_TRACE(skb);
242 	SKB_IMPROVE("Do we have to defer this?");
243 	dev_kfree_skb(skb);
244 }
245 
246 static inline struct sk_buff *
247 build_skb(void *data, unsigned int fragsz)
248 {
249 	struct sk_buff *skb;
250 
251 	skb = linuxkpi_build_skb(data, fragsz);
252 	SKB_TRACE(skb);
253 	return (skb);
254 }
255 
256 /* -------------------------------------------------------------------------- */
257 
258 /* XXX BZ review this one for terminal condition as Linux "queues" are special. */
259 #define	skb_list_walk_safe(_q, skb, tmp)				\
260 	for ((skb) = (_q)->next; (skb) != NULL && ((tmp) = (skb)->next); (skb) = (tmp))
261 
262 /* Add headroom; cannot do once there is data in there. */
263 static inline void
264 skb_reserve(struct sk_buff *skb, size_t len)
265 {
266 	SKB_TRACE(skb);
267 #if 0
268 	/* Apparently it is allowed to call skb_reserve multiple times in a row. */
269 	KASSERT(skb->data == skb->head, ("%s: skb %p not empty head %p data %p "
270 	    "tail %p\n", __func__, skb, skb->head, skb->data, skb->tail));
271 #else
272 	KASSERT(skb->len == 0 && skb->data == skb->tail, ("%s: skb %p not "
273 	    "empty head %p data %p tail %p len %u\n", __func__, skb,
274 	    skb->head, skb->data, skb->tail, skb->len));
275 #endif
276 	skb->data += len;
277 	skb->tail += len;
278 }
279 
280 /*
281  * Remove headroom; return new data pointer; basically make space at the
282  * front to copy data in (manually).
283  */
284 static inline void *
285 __skb_push(struct sk_buff *skb, size_t len)
286 {
287 	SKB_TRACE(skb);
288 	KASSERT(((skb->data - len) >= skb->head), ("%s: skb %p (data %p - "
289 	    "len %zu) < head %p\n", __func__, skb, skb->data, len, skb->data));
290 	skb->len  += len;
291 	skb->data -= len;
292 	return (skb->data);
293 }
294 
295 static inline void *
296 skb_push(struct sk_buff *skb, size_t len)
297 {
298 
299 	SKB_TRACE(skb);
300 	return (__skb_push(skb, len));
301 }
302 
303 /*
304  * Length of the data on the skb (without any frags)???
305  */
306 static inline size_t
307 skb_headlen(struct sk_buff *skb)
308 {
309 
310 	SKB_TRACE(skb);
311 	return (skb->len - skb->data_len);
312 }
313 
314 
315 /* Return the end of data (tail pointer). */
316 static inline uint8_t *
317 skb_tail_pointer(struct sk_buff *skb)
318 {
319 
320 	SKB_TRACE(skb);
321 	return (skb->tail);
322 }
323 
324 /* Return number of bytes available at end of buffer. */
325 static inline unsigned int
326 skb_tailroom(struct sk_buff *skb)
327 {
328 
329 	SKB_TRACE(skb);
330 	KASSERT((skb->end - skb->tail) >= 0, ("%s: skb %p tailroom < 0, "
331 	    "end %p tail %p\n", __func__, skb, skb->end, skb->tail));
332 	return (skb->end - skb->tail);
333 }
334 
335 /* Return numer of bytes available at the beginning of buffer. */
336 static inline unsigned int
337 skb_headroom(struct sk_buff *skb)
338 {
339 	SKB_TRACE(skb);
340 	KASSERT((skb->data - skb->head) >= 0, ("%s: skb %p headroom < 0, "
341 	    "data %p head %p\n", __func__, skb, skb->data, skb->head));
342 	return (skb->data - skb->head);
343 }
344 
345 
346 /*
347  * Remove tailroom; return the old tail pointer; basically make space at
348  * the end to copy data in (manually).  See also skb_put_data() below.
349  */
350 static inline void *
351 __skb_put(struct sk_buff *skb, size_t len)
352 {
353 	void *s;
354 
355 	SKB_TRACE(skb);
356 	KASSERT(((skb->tail + len) <= skb->end), ("%s: skb %p (tail %p + "
357 	    "len %zu) > end %p, head %p data %p len %u\n", __func__,
358 	    skb, skb->tail, len, skb->end, skb->head, skb->data, skb->len));
359 
360 	s = skb_tail_pointer(skb);
361 	if (len == 0)
362 		return (s);
363 	skb->tail += len;
364 	skb->len += len;
365 #ifdef SKB_DEBUG
366 	if (linuxkpi_debug_skb & DSKB_TRACEX)
367 	printf("%s: skb %p (%u) head %p data %p tail %p end %p, s %p len %zu\n",
368 	    __func__, skb, skb->len, skb->head, skb->data, skb->tail, skb->end,
369 	    s, len);
370 #endif
371 	return (s);
372 }
373 
374 static inline void *
375 skb_put(struct sk_buff *skb, size_t len)
376 {
377 
378 	SKB_TRACE(skb);
379 	return (__skb_put(skb, len));
380 }
381 
382 /* skb_put() + copying data in. */
383 static inline void *
384 skb_put_data(struct sk_buff *skb, const void *buf, size_t len)
385 {
386 	void *s;
387 
388 	SKB_TRACE2(skb, buf);
389 	s = skb_put(skb, len);
390 	if (len == 0)
391 		return (s);
392 	memcpy(s, buf, len);
393 	return (s);
394 }
395 
396 /* skb_put() + filling with zeros. */
397 static inline void *
398 skb_put_zero(struct sk_buff *skb, size_t len)
399 {
400 	void *s;
401 
402 	SKB_TRACE(skb);
403 	s = skb_put(skb, len);
404 	memset(s, '\0', len);
405 	return (s);
406 }
407 
408 /*
409  * Remove len bytes from beginning of data.
410  *
411  * XXX-BZ ath10k checks for !NULL conditions so I assume this doesn't panic;
412  * we return the advanced data pointer so we don't have to keep a temp, correct?
413  */
414 static inline void *
415 skb_pull(struct sk_buff *skb, size_t len)
416 {
417 
418 	SKB_TRACE(skb);
419 #if 0	/* Apparently this doesn't barf... */
420 	KASSERT(skb->len >= len, ("%s: skb %p skb->len %u < len %u, data %p\n",
421 	    __func__, skb, skb->len, len, skb->data));
422 #endif
423 	if (skb->len < len)
424 		return (NULL);
425 	skb->len -= len;
426 	skb->data += len;
427 	return (skb->data);
428 }
429 
430 /* Reduce skb data to given length or do nothing if smaller already. */
431 static inline void
432 __skb_trim(struct sk_buff *skb, unsigned int len)
433 {
434 
435 	SKB_TRACE(skb);
436 	if (skb->len < len)
437 		return;
438 
439 	skb->len = len;
440 	skb->tail = skb->data + skb->len;
441 }
442 
443 static inline void
444 skb_trim(struct sk_buff *skb, unsigned int len)
445 {
446 
447 	return (__skb_trim(skb, len));
448 }
449 
450 static inline struct skb_shared_info *
451 skb_shinfo(struct sk_buff *skb)
452 {
453 
454 	SKB_TRACE(skb);
455 	return (skb->shinfo);
456 }
457 
458 static inline void
459 skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page,
460     off_t offset, size_t size, unsigned int truesize)
461 {
462 	struct skb_shared_info *shinfo;
463 
464 	SKB_TRACE(skb);
465 #ifdef SKB_DEBUG
466 	if (linuxkpi_debug_skb & DSKB_TRACEX)
467 	printf("%s: skb %p head %p data %p tail %p end %p len %u fragno %d "
468 	    "page %#jx offset %ju size %zu truesize %u\n", __func__,
469 	    skb, skb->head, skb->data, skb->tail, skb->end, skb->len, fragno,
470 	    (uintmax_t)(uintptr_t)linux_page_address(page), (uintmax_t)offset,
471 	    size, truesize);
472 #endif
473 
474 	shinfo = skb_shinfo(skb);
475 	KASSERT(fragno >= 0 && fragno < nitems(shinfo->frags), ("%s: skb %p "
476 	    "fragno %d too big\n", __func__, skb, fragno));
477 	shinfo->frags[fragno].page = page;
478 	shinfo->frags[fragno].offset = offset;
479 	shinfo->frags[fragno].size = size;
480 	shinfo->nr_frags = fragno + 1;
481         skb->len += size;
482 	skb->data_len += size;
483         skb->truesize += truesize;
484 
485 	/* XXX TODO EXTEND truesize? */
486 }
487 
488 /* -------------------------------------------------------------------------- */
489 
490 /* XXX BZ review this one for terminal condition as Linux "queues" are special. */
491 #define	skb_queue_walk(_q, skb)						\
492 	for ((skb) = (_q)->next; (skb) != (struct sk_buff *)(_q);	\
493 	    (skb) = (skb)->next)
494 
495 #define	skb_queue_walk_safe(_q, skb, tmp)				\
496 	for ((skb) = (_q)->next, (tmp) = (skb)->next;			\
497 	    (skb) != (struct sk_buff *)(_q); (skb) = (tmp), (tmp) = (skb)->next)
498 
499 static inline bool
500 skb_queue_empty(struct sk_buff_head *q)
501 {
502 
503 	SKB_TRACE(q);
504 	return (q->qlen == 0);
505 }
506 
507 static inline void
508 __skb_queue_head_init(struct sk_buff_head *q)
509 {
510 	SKB_TRACE(q);
511 	q->prev = q->next = (struct sk_buff *)q;
512 	q->qlen = 0;
513 }
514 
515 static inline void
516 skb_queue_head_init(struct sk_buff_head *q)
517 {
518 	SKB_TRACE(q);
519 	return (__skb_queue_head_init(q));
520 }
521 
522 static inline void
523 __skb_insert(struct sk_buff *new, struct sk_buff *prev, struct sk_buff *next,
524     struct sk_buff_head *q)
525 {
526 
527 	SKB_TRACE_FMT(new, "prev %p next %p q %p", prev, next, q);
528 	new->prev = prev;
529 	new->next = next;
530 	next->prev = new;
531 	prev->next = new;
532 	q->qlen++;
533 }
534 
535 static inline void
536 __skb_queue_after(struct sk_buff_head *q, struct sk_buff *skb,
537     struct sk_buff *new)
538 {
539 
540 	SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
541 	__skb_insert(new, skb, skb->next, q);
542 }
543 
544 static inline void
545 __skb_queue_before(struct sk_buff_head *q, struct sk_buff *skb,
546     struct sk_buff *new)
547 {
548 
549 	SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
550 	__skb_insert(new, skb->prev, skb, q);
551 }
552 
553 static inline void
554 __skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
555 {
556 	struct sk_buff *s;
557 
558 	SKB_TRACE2(q, skb);
559 	q->qlen++;
560 	s = (struct sk_buff *)q;
561 	s->prev->next = skb;
562 	skb->prev = s->prev;
563 	skb->next = s;
564 	s->prev = skb;
565 }
566 
567 static inline void
568 skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
569 {
570 	SKB_TRACE2(q, skb);
571 	return (__skb_queue_tail(q, skb));
572 }
573 
574 static inline struct sk_buff *
575 skb_peek(struct sk_buff_head *q)
576 {
577 	struct sk_buff *skb;
578 
579 	skb = q->next;
580 	SKB_TRACE2(q, skb);
581 	if (skb == (struct sk_buff *)q)
582 		return (NULL);
583 	return (skb);
584 }
585 
586 static inline struct sk_buff *
587 skb_peek_tail(struct sk_buff_head *q)
588 {
589 	struct sk_buff *skb;
590 
591 	skb = q->prev;
592 	SKB_TRACE2(q, skb);
593 	if (skb == (struct sk_buff *)q)
594 		return (NULL);
595 	return (skb);
596 }
597 
598 static inline void
599 __skb_unlink(struct sk_buff *skb, struct sk_buff_head *head)
600 {
601 	SKB_TRACE2(skb, head);
602 	struct sk_buff *p, *n;;
603 
604 	head->qlen--;
605 	p = skb->prev;
606 	n = skb->next;
607 	p->next = n;
608 	n->prev = p;
609 	skb->prev = skb->next = NULL;
610 }
611 
612 static inline void
613 skb_unlink(struct sk_buff *skb, struct sk_buff_head *head)
614 {
615 	SKB_TRACE2(skb, head);
616 	return (__skb_unlink(skb, head));
617 }
618 
619 static inline struct sk_buff *
620 __skb_dequeue(struct sk_buff_head *q)
621 {
622 	struct sk_buff *skb;
623 
624 	SKB_TRACE(q);
625 	skb = q->next;
626 	if (skb == (struct sk_buff *)q)
627 		return (NULL);
628 	if (skb != NULL)
629 		__skb_unlink(skb, q);
630 	SKB_TRACE(skb);
631 	return (skb);
632 }
633 
634 static inline struct sk_buff *
635 skb_dequeue(struct sk_buff_head *q)
636 {
637 	SKB_TRACE(q);
638 	return (__skb_dequeue(q));
639 }
640 
641 static inline struct sk_buff *
642 skb_dequeue_tail(struct sk_buff_head *q)
643 {
644 	struct sk_buff *skb;
645 
646 	skb = skb_peek_tail(q);
647 	if (skb != NULL)
648 		__skb_unlink(skb, q);
649 
650 	SKB_TRACE2(q, skb);
651 	return (skb);
652 }
653 
654 static inline void
655 __skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
656 {
657 
658 	SKB_TRACE2(q, skb);
659 	__skb_queue_after(q, (struct sk_buff *)q, skb);
660 }
661 
662 static inline void
663 skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
664 {
665 
666 	SKB_TRACE2(q, skb);
667 	__skb_queue_after(q, (struct sk_buff *)q, skb);
668 }
669 
670 static inline uint32_t
671 skb_queue_len(struct sk_buff_head *head)
672 {
673 
674 	SKB_TRACE(head);
675 	return (head->qlen);
676 }
677 
678 static inline uint32_t
679 skb_queue_len_lockless(const struct sk_buff_head *head)
680 {
681 
682 	SKB_TRACE(head);
683 	return (READ_ONCE(head->qlen));
684 }
685 
686 static inline void
687 __skb_queue_purge(struct sk_buff_head *q)
688 {
689 	struct sk_buff *skb;
690 
691 	SKB_TRACE(q);
692         while ((skb = __skb_dequeue(q)) != NULL)
693 		kfree_skb(skb);
694 }
695 
696 static inline void
697 skb_queue_purge(struct sk_buff_head *q)
698 {
699 	SKB_TRACE(q);
700 	return (__skb_queue_purge(q));
701 }
702 
703 static inline struct sk_buff *
704 skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb)
705 {
706 
707 	SKB_TRACE2(q, skb);
708 	/* XXX what is the q argument good for? */
709 	return (skb->prev);
710 }
711 
712 /* -------------------------------------------------------------------------- */
713 
714 static inline struct sk_buff *
715 skb_copy(struct sk_buff *skb, gfp_t gfp)
716 {
717 	struct sk_buff *new;
718 
719 	new = linuxkpi_skb_copy(skb, gfp);
720 	SKB_TRACE2(skb, new);
721 	return (new);
722 }
723 
724 static inline void
725 consume_skb(struct sk_buff *skb)
726 {
727 	SKB_TRACE(skb);
728 	SKB_TODO();
729 }
730 
731 static inline uint16_t
732 skb_checksum(struct sk_buff *skb, int offs, size_t len, int x)
733 {
734 	SKB_TRACE(skb);
735 	SKB_TODO();
736 	return (0xffff);
737 }
738 
739 static inline int
740 skb_checksum_start_offset(struct sk_buff *skb)
741 {
742 	SKB_TRACE(skb);
743 	SKB_TODO();
744 	return (-1);
745 }
746 
747 static inline dma_addr_t
748 skb_frag_dma_map(struct device *dev, const skb_frag_t *frag, int x,
749     size_t fragsz, enum dma_data_direction dir)
750 {
751 	SKB_TRACE2(frag, dev);
752 	SKB_TODO();
753 	return (-1);
754 }
755 
756 static inline size_t
757 skb_frag_size(const skb_frag_t *frag)
758 {
759 	SKB_TRACE(frag);
760 	SKB_TODO();
761 	return (-1);
762 }
763 
764 #define	skb_walk_frags(_skb, _frag)					\
765 	for ((_frag) = (_skb); false; (_frag)++)
766 
767 static inline void
768 skb_checksum_help(struct sk_buff *skb)
769 {
770 	SKB_TRACE(skb);
771 	SKB_TODO();
772 }
773 
774 static inline bool
775 skb_ensure_writable(struct sk_buff *skb, size_t off)
776 {
777 	SKB_TRACE(skb);
778 	SKB_TODO();
779 	return (false);
780 }
781 
782 static inline void *
783 skb_frag_address(const skb_frag_t *frag)
784 {
785 	SKB_TRACE(frag);
786 	SKB_TODO();
787 	return (NULL);
788 }
789 
790 static inline void
791 skb_free_frag(void *frag)
792 {
793 
794 	page_frag_free(frag);
795 }
796 
797 static inline struct sk_buff *
798 skb_gso_segment(struct sk_buff *skb, netdev_features_t netdev_flags)
799 {
800 	SKB_TRACE(skb);
801 	SKB_TODO();
802 	return (NULL);
803 }
804 
805 static inline bool
806 skb_is_gso(struct sk_buff *skb)
807 {
808 	SKB_TRACE(skb);
809 	SKB_IMPROVE("Really a TODO but get it away from logging");
810 	return (false);
811 }
812 
813 static inline void
814 skb_mark_not_on_list(struct sk_buff *skb)
815 {
816 	SKB_TRACE(skb);
817 	SKB_TODO();
818 }
819 
820 static inline void
821 skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
822 {
823 	struct sk_buff *b, *e, *n;
824 
825 	SKB_TRACE2(from, to);
826 
827 	if (skb_queue_empty(from))
828 		return;
829 
830 	/* XXX do we need a barrier around this? */
831 	b = from->next;
832 	e = from->prev;
833 	n = to->next;
834 
835 	b->prev = (struct sk_buff *)to;
836 	to->next = b;
837 	e->next = n;
838 	n->prev = e;
839 
840 	to->qlen += from->qlen;
841 	__skb_queue_head_init(from);
842 }
843 
844 static inline void
845 skb_reset_transport_header(struct sk_buff *skb)
846 {
847 
848 	SKB_TRACE(skb);
849 	skb->l4hdroff = skb->data - skb->head;
850 }
851 
852 static inline uint8_t *
853 skb_transport_header(struct sk_buff *skb)
854 {
855 
856 	SKB_TRACE(skb);
857         return (skb->head + skb->l4hdroff);
858 }
859 
860 static inline uint8_t *
861 skb_network_header(struct sk_buff *skb)
862 {
863 
864 	SKB_TRACE(skb);
865         return (skb->head + skb->l3hdroff);
866 }
867 
868 static inline bool
869 skb_is_nonlinear(struct sk_buff *skb)
870 {
871 	SKB_TRACE(skb);
872 	return ((skb->data_len > 0) ? true : false);
873 }
874 
875 static inline int
876 __skb_linearize(struct sk_buff *skb)
877 {
878 	SKB_TRACE(skb);
879 	SKB_TODO();
880 	return (ENXIO);
881 }
882 
883 static inline int
884 skb_linearize(struct sk_buff *skb)
885 {
886 
887 	return (skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0);
888 }
889 
890 static inline int
891 pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp)
892 {
893 	SKB_TRACE(skb);
894 	SKB_TODO();
895 	return (-ENXIO);
896 }
897 
898 /* Not really seen this one but need it as symmetric accessor function. */
899 static inline void
900 skb_set_queue_mapping(struct sk_buff *skb, uint16_t qmap)
901 {
902 
903 	SKB_TRACE_FMT(skb, "qmap %u", qmap);
904 	skb->qmap = qmap;
905 }
906 
907 static inline uint16_t
908 skb_get_queue_mapping(struct sk_buff *skb)
909 {
910 
911 	SKB_TRACE_FMT(skb, "qmap %u", skb->qmap);
912 	return (skb->qmap);
913 }
914 
915 static inline bool
916 skb_header_cloned(struct sk_buff *skb)
917 {
918 	SKB_TRACE(skb);
919 	SKB_TODO();
920 	return (false);
921 }
922 
923 static inline uint8_t *
924 skb_mac_header(struct sk_buff *skb)
925 {
926 	SKB_TRACE(skb);
927 	SKB_TODO();
928 	return (NULL);
929 }
930 
931 static inline void
932 skb_orphan(struct sk_buff *skb)
933 {
934 	SKB_TRACE(skb);
935 	SKB_TODO();
936 }
937 
938 static inline void
939 skb_reset_mac_header(struct sk_buff *skb)
940 {
941 	SKB_TRACE(skb);
942 	SKB_TODO();
943 }
944 
945 static inline __sum16
946 csum_unfold(__sum16 sum)
947 {
948 	SKB_TODO();
949 	return (sum);
950 }
951 
952 static __inline void
953 skb_postpush_rcsum(struct sk_buff *skb, const void *data, size_t len)
954 {
955 	SKB_TODO();
956 }
957 
958 static inline void
959 skb_reset_tail_pointer(struct sk_buff *skb)
960 {
961 
962 	SKB_TRACE(skb);
963 #ifdef SKB_DOING_OFFSETS_US_NOT
964 	skb->tail = (uint8_t *)(uintptr_t)(skb->data - skb->head);
965 #endif
966 	skb->tail = skb->data;
967 	SKB_TRACE(skb);
968 }
969 
970 static inline struct sk_buff *
971 skb_get(struct sk_buff *skb)
972 {
973 
974 	SKB_TODO();	/* XXX refcnt? as in get/put_device? */
975 	return (skb);
976 }
977 
978 static inline struct sk_buff *
979 skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
980 {
981 
982 	SKB_TODO();
983 	return (NULL);
984 }
985 
986 static inline void
987 skb_copy_from_linear_data(const struct sk_buff *skb, void *dst, size_t len)
988 {
989 
990 	SKB_TRACE(skb);
991 	/* Let us just hope the destination has len space ... */
992 	memcpy(dst, skb->data, len);
993 }
994 
995 static inline int
996 skb_pad(struct sk_buff *skb, int pad)
997 {
998 
999 	SKB_TRACE(skb);
1000 	SKB_TODO();
1001 	return (-1);
1002 }
1003 
1004 static inline void
1005 skb_list_del_init(struct sk_buff *skb)
1006 {
1007 
1008 	SKB_TRACE(skb);
1009 	SKB_TODO();
1010 }
1011 
1012 static inline void
1013 napi_consume_skb(struct sk_buff *skb, int budget)
1014 {
1015 
1016 	SKB_TRACE(skb);
1017 	SKB_TODO();
1018 }
1019 
1020 #define	SKB_WITH_OVERHEAD(_s)						\
1021 	(_s) - ALIGN(sizeof(struct skb_shared_info), CACHE_LINE_SIZE)
1022 
1023 #endif	/* _LINUXKPI_LINUX_SKBUFF_H */
1024