root/sys/compat/linuxkpi/common/include/linux/netdevice.h
/*-
 * Copyright (c) 2010 Isilon Systems, Inc.
 * Copyright (c) 2010 iX Systems, Inc.
 * Copyright (c) 2010 Panasas, Inc.
 * Copyright (c) 2013-2019 Mellanox Technologies, Ltd.
 * All rights reserved.
 * Copyright (c) 2020-2025 The FreeBSD Foundation
 * Copyright (c) 2020-2022 Bjoern A. Zeeb
 *
 * Portions of this software were developed by Björn Zeeb
 * under sponsorship from the FreeBSD Foundation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef _LINUXKPI_LINUX_NETDEVICE_H
#define _LINUXKPI_LINUX_NETDEVICE_H

#include <linux/types.h>
#include <linux/netdev_features.h>

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/taskqueue.h>

#include <net/if_types.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>

#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/net.h>
#include <linux/if_ether.h>
#include <linux/notifier.h>
#include <linux/random.h>
#include <linux/rcupdate.h>

#ifdef VIMAGE
#define init_net *vnet0
#else
#define init_net *((struct vnet *)0)
#endif

struct sk_buff;
struct net_device;
struct wireless_dev;            /* net/cfg80211.h */

#define MAX_ADDR_LEN            20

#define NET_NAME_UNKNOWN        0

enum net_addr_assign_type {
        NET_ADDR_RANDOM,
};

enum netdev_tx {
        NETDEV_TX_OK            = 0,
};
typedef enum netdev_tx          netdev_tx_t;

struct netdev_hw_addr {
        struct list_head        addr_list;
        uint8_t                 addr[MAX_ADDR_LEN];
};

struct netdev_hw_addr_list {
        struct list_head        addr_list;
        int                     count;
};

enum net_device_reg_state {
        NETREG_DUMMY            = 1,
        NETREG_REGISTERED,
};

enum tc_setup_type {
        TC_SETUP_MAX_DUMMY,
};

struct net_device_ops {
        int (*ndo_open)(struct net_device *);
        int (*ndo_stop)(struct net_device *);
        int (*ndo_set_mac_address)(struct net_device *,  void *);
        netdev_tx_t (*ndo_start_xmit)(struct sk_buff *, struct net_device *);
        void (*ndo_set_rx_mode)(struct net_device *);
};

struct net_device {
        /* net_device fields seen publicly. */
        /* XXX can we later make some aliases to ifnet? */
        char                            name[IFNAMSIZ];
        struct wireless_dev             *ieee80211_ptr;
        uint8_t                         dev_addr[ETH_ALEN];
        struct netdev_hw_addr_list      mc;
        netdev_features_t               features;
        struct {
                unsigned long           multicast;

                unsigned long           rx_bytes;
                unsigned long           rx_errors;
                unsigned long           rx_packets;
                unsigned long           tx_bytes;
                unsigned long           tx_dropped;
                unsigned long           tx_errors;
                unsigned long           tx_packets;
        } stats;
        enum net_addr_assign_type       addr_assign_type;
        enum net_device_reg_state       reg_state;
        const struct ethtool_ops        *ethtool_ops;
        const struct net_device_ops     *netdev_ops;

        bool                            needs_free_netdev;
        /* Not properly typed as-of now. */
        int     flags, type;
        int     name_assign_type, needed_headroom;
        int     threaded;

        void (*priv_destructor)(struct net_device *);

        /* net_device internal. */
        struct device                   dev;

        /*
         * In case we delete the net_device we need to be able to clear all
         * NAPI consumers.
         */
        struct mtx                      napi_mtx;
        TAILQ_HEAD(, napi_struct)       napi_head;
        struct taskqueue                *napi_tq;

        /* Must stay last. */
        uint8_t                         drv_priv[0] __aligned(CACHE_LINE_SIZE);
};

#define SET_NETDEV_DEV(_ndev, _dev)     (_ndev)->dev.parent = _dev;

enum net_device_path_type {
        DEV_PATH_MTK_WDMA,
};

struct net_device_path {
        enum net_device_path_type               type;
        const struct net_device                 *dev;
        /* We assume there's a struct per type. */
        union {
                struct {
                        uint16_t                wcid;
                        uint8_t                 wdma_idx;
                        uint8_t                 queue;
                        uint8_t                 bss;
                        uint8_t                 amsdu;
                } mtk_wdma;
        };
};

struct net_device_path_ctx {
        const struct net_device                 *dev;
};


/* -------------------------------------------------------------------------- */
/* According to linux::ipoib_main.c. */
struct netdev_notifier_info {
        struct net_device       *dev;
        struct ifnet            *ifp;
};

static inline struct net_device *
netdev_notifier_info_to_dev(struct netdev_notifier_info *ni)
{
        return (ni->dev);
}

static inline struct ifnet *
netdev_notifier_info_to_ifp(struct netdev_notifier_info *ni)
{
        return (ni->ifp);
}

int     register_netdevice_notifier(struct notifier_block *);
int     register_inetaddr_notifier(struct notifier_block *);
int     unregister_netdevice_notifier(struct notifier_block *);
int     unregister_inetaddr_notifier(struct notifier_block *);

/* -------------------------------------------------------------------------- */

#define NAPI_POLL_WEIGHT                        64      /* budget */

/*
 * There are drivers directly testing napi state bits, so we need to publicly
 * expose them.  If you ask me, those accesses should be hid behind an
 * inline function and the bit flags not be directly exposed.
 */
enum napi_state_bits {
        /*
         * Official Linux flags encountered.
         */
        NAPI_STATE_SCHED = 1,

        /*
         * Our internal versions (for now).
         */
        /* Do not schedule new things while we are waiting to clear things. */
        LKPI_NAPI_FLAG_DISABLE_PENDING = 0,
        /* To synchronise that only one poll is ever running. */
        LKPI_NAPI_FLAG_IS_SCHEDULED = 1,
        /* If trying to schedule while poll is running. Need to re-schedule. */
        LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN = 2,
        /* When shutting down forcefully prevent anything from running task/poll. */
        LKPI_NAPI_FLAG_SHUTDOWN = 3,
};

struct napi_struct {
        TAILQ_ENTRY(napi_struct)        entry;

        struct list_head        rx_list;
        struct net_device       *dev;
        int                     (*poll)(struct napi_struct *, int);
        int                     budget;
        int                     rx_count;


        /*
         * These flags mostly need to be checked/changed atomically
         * (multiple together in some cases).
         */
        volatile unsigned long  state;

        /* FreeBSD internal. */
        /* Use task for now, so we can easily switch between direct and task. */
        struct task             napi_task;
};

void linuxkpi_init_dummy_netdev(struct net_device *);
void linuxkpi_netif_napi_add(struct net_device *, struct napi_struct *,
    int(*napi_poll)(struct napi_struct *, int));
void linuxkpi_netif_napi_del(struct napi_struct *);
bool linuxkpi_napi_schedule_prep(struct napi_struct *);
void linuxkpi___napi_schedule(struct napi_struct *);
bool linuxkpi_napi_schedule(struct napi_struct *);
void linuxkpi_napi_reschedule(struct napi_struct *);
bool linuxkpi_napi_complete_done(struct napi_struct *, int);
bool linuxkpi_napi_complete(struct napi_struct *);
void linuxkpi_napi_disable(struct napi_struct *);
void linuxkpi_napi_enable(struct napi_struct *);
void linuxkpi_napi_synchronize(struct napi_struct *);

#define init_dummy_netdev(_n)                                           \
        linuxkpi_init_dummy_netdev(_n)
#define netif_napi_add(_nd, _ns, _p)                                    \
        linuxkpi_netif_napi_add(_nd, _ns, _p)
#define netif_napi_del(_n)                                              \
        linuxkpi_netif_napi_del(_n)
#define napi_schedule_prep(_n)                                          \
        linuxkpi_napi_schedule_prep(_n)
#define __napi_schedule(_n)                                             \
        linuxkpi___napi_schedule(_n)
#define napi_schedule(_n)                                               \
        linuxkpi_napi_schedule(_n)
#define napi_reschedule(_n)                                             \
        linuxkpi_napi_reschedule(_n)
#define napi_complete_done(_n, _r)                                      \
        linuxkpi_napi_complete_done(_n, _r)
#define napi_complete(_n)                                               \
        linuxkpi_napi_complete(_n)
#define napi_disable(_n)                                                \
        linuxkpi_napi_disable(_n)
#define napi_enable(_n)                                                 \
        linuxkpi_napi_enable(_n)
#define napi_synchronize(_n)                                            \
        linuxkpi_napi_synchronize(_n)


static inline void
netif_napi_add_tx(struct net_device *dev, struct napi_struct *napi,
    int(*napi_poll)(struct napi_struct *, int))
{

        netif_napi_add(dev, napi, napi_poll);
}

static inline bool
napi_is_scheduled(struct napi_struct *napi)
{

        return (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state));
}

/* -------------------------------------------------------------------------- */

static inline void
netdev_rss_key_fill(uint32_t *buf, size_t len)
{

        /*
         * Remembering from a previous life there was discussions on what is
         * a good RSS hash key.  See end of rss_init() in net/rss_config.c.
         * iwlwifi is looking for a 10byte "secret" so stay with random for now.
         */
        get_random_bytes(buf, len);
}

static inline void
__hw_addr_init(struct netdev_hw_addr_list *list)
{
        list->count = 0;
        INIT_LIST_HEAD(&list->addr_list);
}

static inline int
netdev_hw_addr_list_count(struct netdev_hw_addr_list *list)
{

        return (list->count);
}

static inline int
netdev_mc_count(struct net_device *ndev)
{

        return (netdev_hw_addr_list_count(&ndev->mc));
}

#define netdev_hw_addr_list_for_each(_addr, _list)                      \
        list_for_each_entry((_addr), &(_list)->addr_list, addr_list)

#define netdev_for_each_mc_addr(na, ndev)                               \
        netdev_hw_addr_list_for_each(na, &(ndev)->mc)

static __inline void
synchronize_net(void)
{

        /* We probably cannot do that unconditionally at some point anymore. */
        synchronize_rcu();
}

static __inline void
netif_receive_skb_list(struct list_head *head)
{

        pr_debug("%s: TODO\n", __func__);
}

static __inline int
napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{

        pr_debug("%s: TODO\n", __func__);
        return (-1);
}

static __inline void
ether_setup(struct net_device *ndev)
{

        pr_debug("%s: TODO\n", __func__);
}

static __inline void
dev_net_set(struct net_device *ndev, void *p)
{

        pr_debug("%s: TODO\n", __func__);
}

static __inline int
dev_set_threaded(struct net_device *ndev, bool threaded)
{

        pr_debug("%s: TODO\n", __func__);
        return (-ENODEV);
}

/* -------------------------------------------------------------------------- */

static __inline bool
netif_carrier_ok(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
        return (false);
}

static __inline void
netif_carrier_off(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

static __inline void
netif_carrier_on(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

/* -------------------------------------------------------------------------- */

static __inline bool
netif_queue_stopped(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
        return (false);
}

static __inline void
netif_stop_queue(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

static __inline void
netif_wake_queue(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

/* -------------------------------------------------------------------------- */

static __inline int
register_netdevice(struct net_device *ndev)
{

        /* assert rtnl_locked? */
        pr_debug("%s: TODO\n", __func__);
        return (0);
}

static __inline int
register_netdev(struct net_device *ndev)
{
        int error;

        /* lock */
        error = register_netdevice(ndev);
        /* unlock */
        pr_debug("%s: TODO\n", __func__);
        return (error);
}

static __inline void
unregister_netdev(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

static __inline void
unregister_netdevice(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

/* -------------------------------------------------------------------------- */

static __inline void
netif_rx(struct sk_buff *skb)
{
        pr_debug("%s: TODO\n", __func__);
}

static __inline void
netif_rx_ni(struct sk_buff *skb)
{
        pr_debug("%s: TODO\n", __func__);
}

/* -------------------------------------------------------------------------- */

struct net_device *linuxkpi_alloc_netdev(size_t, const char *, uint32_t,
    void(*)(struct net_device *));
void linuxkpi_free_netdev(struct net_device *);

#define alloc_netdev(_l, _n, _f, _func)                                         \
        linuxkpi_alloc_netdev(_l, _n, _f, _func)
#define alloc_netdev_dummy(_l)                                                  \
        linuxkpi_alloc_netdev(_l, "dummy", NET_NAME_UNKNOWN, NULL)
#define free_netdev(_n)                                                         \
        linuxkpi_free_netdev(_n)

static inline void *
netdev_priv(const struct net_device *ndev)
{

        return (__DECONST(void *, ndev->drv_priv));
}

/* -------------------------------------------------------------------------- */

static __inline void
netif_device_attach(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}

static __inline void
netif_device_detach(struct net_device *ndev)
{
        pr_debug("%s: TODO\n", __func__);
}


/* -------------------------------------------------------------------------- */
/* This is really rtnetlink and probably belongs elsewhere. */

#define rtnl_lock()             do { } while(0)
#define rtnl_unlock()           do { } while(0)
#define rcu_dereference_rtnl(x) READ_ONCE(x)

#endif  /* _LINUXKPI_LINUX_NETDEVICE_H */