diff options
| author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-02-03 22:13:24 +0000 |
|---|---|---|
| committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-07-17 15:48:53 +0000 |
| commit | 9de11cc26ab61d7f80e8af84dbc55d8cbd6f832d (patch) | |
| tree | 6c04d6202d8f67e6c3b8c3249be1012764ec7a1b | |
| parent | b36460e5ec4659d0fa14b35c9342c5a154b3db7d (diff) | |
LinuxKPI: skbuff: implement __skb_linearize()
skb_linearize() is used by mt7921, mt7925, and in the general mt76 tx dma
code. __skb_linearize() is used in the general iwlwifi TX code but given
the way we currently create TX skbs in LinuxKPI 802.11 we never hit that
case.
Sponsored by: The FreeBSD Foundation
MFC after: 3 days
| -rw-r--r-- | sys/compat/linuxkpi/common/include/linux/skbuff.h | 6 | ||||
| -rw-r--r-- | sys/compat/linuxkpi/common/src/linux_skbuff.c | 60 |
2 files changed, 63 insertions, 3 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h index a0724803e732..9434655fc9f4 100644 --- a/sys/compat/linuxkpi/common/include/linux/skbuff.h +++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h @@ -209,6 +209,8 @@ void linuxkpi_kfree_skb(struct sk_buff *); struct sk_buff *linuxkpi_skb_copy(const struct sk_buff *, gfp_t); +int lkpi___skb_linearize(struct sk_buff *); + /* -------------------------------------------------------------------------- */ static inline struct sk_buff * @@ -978,9 +980,7 @@ skb_network_header(struct sk_buff *skb) static inline int __skb_linearize(struct sk_buff *skb) { - SKB_TRACE(skb); - SKB_TODO(); - return (-ENXIO); + return (lkpi___skb_linearize(skb)); } static inline int diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c index abfb642ba708..a2aa601d594e 100644 --- a/sys/compat/linuxkpi/common/src/linux_skbuff.c +++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c @@ -222,6 +222,66 @@ linuxkpi_skb_copy(const struct sk_buff *skb, gfp_t gfp) return (new); } +int +lkpi___skb_linearize(struct sk_buff *skb) +{ + struct sk_buff *new; + struct skb_shared_info *shinfo; + uint16_t fragno, count; + + SKB_TRACE(skb); + SKB_IMPROVE("Hack completely re-allocating and freeing; FIXME"); + new = skb_copy(skb, GFP_NOWAIT); + if (new == NULL) + return (-ENOMEM); + + /* Now need to swap head, data, tail, ... and free from old (and then new). */ + shinfo = skb->shinfo; + for (count = fragno = 0; + count < shinfo->nr_frags && fragno < nitems(shinfo->frags); + fragno++) { + + if (shinfo->frags[fragno].page != NULL) { + struct page *p; + + p = shinfo->frags[fragno].page; + shinfo->frags[fragno].size = 0; + shinfo->frags[fragno].offset = 0; + shinfo->frags[fragno].page = NULL; + __free_page(p); + count++; + } + } + + if ((skb->_flags & _SKB_FLAGS_SKBEXTFRAG) != 0) { + void *p; + + p = skb->head; + skb_free_frag(p); + skb->head = NULL; + skb->_flags &= ~_SKB_FLAGS_SKBEXTFRAG; + } + +#ifdef SKB_DMA32_MALLOC + if (__predict_false(linuxkpi_skb_memlimit != 0)) + free(skb->head, M_LKPISKB); + else +#endif + kfree(skb->head); + + skb->head = new->head; + skb->data = new->data; + skb->tail = new->tail; + skb->end = new->end; + skb->len = new->len; + skb->data_len = new->data_len; + skb->truesize = new->truesize; + + uma_zfree(skbzone, new); + + return (0); +} + void linuxkpi_kfree_skb(struct sk_buff *skb) { |
