This is xnu-11215.1.10. See this file in:
/*
 * Copyright (c) 2015-2023 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

/*
 * Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri.
 * All rights reserved.
 * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
 *
 * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 _SKYWALK_NEXUS_NEXUSVAR_H_
#define _SKYWALK_NEXUS_NEXUSVAR_H_

#ifdef BSD_KERNEL_PRIVATE
#include <skywalk/core/skywalk_var.h>
#include <skywalk/os_nexus_private.h>

struct chreq;
struct nxdom;
struct kern_channel;
struct kern_nexus_domain_provider;

/*
 * Nexus controller instance.
 */
struct nxctl {
	decl_lck_mtx_data(, nxctl_lock);
	uint32_t                nxctl_refcnt;
	uint32_t                nxctl_flags;
	uuid_t                  nxctl_uuid;
	uuid_t                  nxctl_proc_uuid;
	uint64_t                nxctl_proc_uniqueid;
	STAILQ_ENTRY(nxctl)     nxctl_link;
	struct fileproc         *nxctl_fp;
	kauth_cred_t            nxctl_cred;
	/*
	 * -fbounds-safety: nxctl_traffic_rule_storage only gets used as of type
	 * struct nxctl_traffic_rule_storage *
	 */
	struct nxctl_traffic_rule_storage *nxctl_traffic_rule_storage;
};

#define NEXUSCTLF_ATTACHED      0x1
#define NEXUSCTLF_NOFDREF       0x2
#define NEXUSCTLF_KERNEL        0x4

#define NEXUSCTLF_BITS  \
	"\020\01ATTACHED\02NOFDREF\03KERNEL"

/*
 * Nexus port binding structure.
 */
struct nxbind {
	uint32_t                nxb_flags;
	pid_t                   nxb_pid;
	uint64_t                nxb_uniqueid;
	uuid_t                  nxb_exec_uuid;
	uint32_t                nxb_key_len;
	void                    *__sized_by(nxb_key_len) nxb_key;
};

#define NXBF_MATCH_UNIQUEID     0x1     /* match against process's unique ID */
#define NXBF_MATCH_EXEC_UUID    0x2     /* match against executable's UUID */
#define NXBF_MATCH_KEY          0x4     /* match against key blob */

#define NXBF_BITS       \
	"\020\01UNIQUEID\02EXEC_UUID\03KEY"

/*
 * Nexus port info structure.
 */
struct nx_port_info {
	/*
	 * We need to store some states on the nexus port info,
	 * e.g. defunct.  The states are encoded in the tagged
	 * pointer handle npi_nah.
	 */
	uintptr_t               npi_nah;
	struct nxbind           *npi_nxb;
	void                    *npi_info;
};

/*
 * Used for indicating what type is attached to npi_info
 * The type enum is defined here. One namespace for all nexus types.
 * The actual structure is defined in nexus specific headers.
 */
typedef enum {
	NX_PORT_INFO_TYPE_NETIF = 0x10000001
} nx_port_info_type_t;

/*
 * Header of nexus specific structure npi_info
 */
struct nx_port_info_header {
	nx_port_info_type_t     ih_type;
	size_t                  ih_size;
};

#define NX_PORT_CHUNK      64
#define NX_PORT_CHUNK_FREE 0xffffffffffffffff /* entire chunk is free */

/*
 * Nexus port state type.
 *
 * Be mindful that due to the use of tagger pointer for nexus adapter in the
 * nexus port info structure, this type gets encoded with the requirement
 * that the object addresses are aligned on 4-bytes boundary at the minimum.
 * That leaves 2 bits for the states, therefore limiting the maximum enum
 * value to 3.
 */
typedef enum {
	NEXUS_PORT_STATE_WORKING = 0,           /* fully operational */
	NEXUS_PORT_STATE_DEFUNCT,               /* no longer in service */
	NEXUS_PORT_STATE_RESERVED_1,            /* for future use */
	NEXUS_PORT_STATE_RESERVED_2,            /* for future use */
	NEXUS_PORT_STATE_MAX = NEXUS_PORT_STATE_RESERVED_2
} nexus_port_state_t;

#define NPI_NA_STATE_MASK       ((uintptr_t)0x3)        /* 11 */
#define NPI_NA_TAG_MASK         ((uintptr_t)0x3)        /* 11 */

#define NPI_NA_TAG(_p)          ((uintptr_t)(_p) & NPI_NA_TAG_MASK)
#define NPI_NA_ADDR_MASK        (~NPI_NA_TAG_MASK)

#define NPI_NA_STATE(_p)        ((uintptr_t)(_p) & NPI_NA_STATE_MASK)
#define NPI_NA_STATE_ENC(_s)    ((uintptr_t)(_s) & NPI_NA_STATE_MASK)

#define NPI_NA_ADDR(_p)         ((uintptr_t)(_p) & NPI_NA_ADDR_MASK)
#define NPI_NA_ADDR_ENC(_p)     ((uintptr_t)(_p) & NPI_NA_ADDR_MASK)

#define NPI_NA_ENCODE(_p, _s)   (NPI_NA_ADDR_ENC(_p) | NPI_NA_STATE_ENC(_s))

#define NPI_NA(_npi)            \
	(__unsafe_forge_single(struct nexus_adapter *, NPI_NA_ADDR((_npi)->npi_nah)))
#define NPI_IS_DEFUNCT(_npi)    \
	(NPI_NA_STATE((_npi)->npi_nah) == NEXUS_PORT_STATE_DEFUNCT)

/*
 * Nexus-wide advisory region and object.
 */
struct kern_nexus_advisory {
	struct skmem_region     *nxv_reg;
	void                    *__sized_by(nxv_adv_size) nxv_adv;
	nexus_advisory_type_t   nxv_adv_type;
	union {
		struct sk_nexusadv             *flowswitch_nxv_adv;
		struct netif_nexus_advisory    *netif_nxv_adv;
	};
	uint32_t                nxv_adv_size;
};

/*
 * Nexus instance.
 *
 * At present most fields are protected by sk_lock.  The exception is
 * the nx_ch_if_adv_head list which uses nx_ch_if_adv_lock instead.
 *
 * In cases where sk_lock, nx_ch_if_adv_lock and ch_lock must be held,
 * the following ordering needs to be followed:
 *
 *   sk_lock -> nx_ch_if_adv_lock -> ch_lock
 */
struct kern_nexus {
	uint32_t                nx_refcnt;
	volatile uint32_t       nx_flags;
	void                    *nx_ctx;
	nexus_ctx_release_fn_t  nx_ctx_release;
	struct kern_nexus_provider *nx_prov;
	uint64_t                nx_id;
	uuid_t                  nx_uuid;
	STAILQ_ENTRY(kern_nexus) nx_prov_link;
	RB_ENTRY(kern_nexus)    nx_link;
	STAILQ_HEAD(, kern_channel) nx_ch_head;
	uint32_t                nx_ch_count;
	STAILQ_HEAD(, kern_channel) nx_ch_nonxref_head;
	decl_lck_rw_data(, nx_ch_if_adv_lock);
	STAILQ_HEAD(, kern_channel) nx_ch_if_adv_head;
	void                    *nx_arg;
	struct kern_pbufpool    *nx_rx_pp;
	struct kern_pbufpool    *nx_tx_pp;
	struct kern_nexus_advisory nx_adv;

	/* nexus port */
	struct nx_port_info     *__counted_by(nx_num_ports) nx_ports;
	bitmap_t                *__sized_by(nx_ports_bmap_size) nx_ports_bmap;
	nexus_port_size_t       nx_active_ports;
	nexus_port_size_t       nx_num_ports;
	size_t                  nx_ports_bmap_size;
};

#define NXF_ATTACHED    0x1
#define NXF_CLOSED      0x2             /* attached but closed */
#define NXF_REJECT      (1U << 31)      /* not accepting channel activities */

#define NXF_BITS        \
	"\020\01ATTACHED\02CLOSED\040REJECT"

#define NX_PROV(_nx)            ((_nx)->nx_prov)
#define NX_PROV_PARAMS(_nx)     (NX_PROV(_nx)->nxprov_params)
#define NX_DOM_PROV(_nx)        (NX_PROV(_nx)->nxprov_dom_prov)
#define NX_DOM(_nx)             (NX_DOM_PROV(_nx)->nxdom_prov_dom)

#define NX_REJECT_ACT(_nx)      (((_nx)->nx_flags & NXF_REJECT) != 0)

/*
 * Nexus provider.
 */
struct kern_nexus_provider {
	uint32_t                        nxprov_refcnt;
	uint32_t                        nxprov_flags;
	STAILQ_ENTRY(kern_nexus_provider) nxprov_link;
	STAILQ_HEAD(, kern_nexus)       nxprov_nx_head;
	uint32_t                        nxprov_nx_count;
	struct nxctl                    *nxprov_ctl;
	uuid_t                          nxprov_uuid;
	struct kern_nexus_domain_provider *nxprov_dom_prov;
	union {
		struct kern_nexus_provider_init nxprov_ext;
		struct kern_nexus_netif_provider_init nxprov_netif_ext;
	};
	struct nxprov_params            *nxprov_params;
	struct skmem_region_params      nxprov_region_params[SKMEM_REGIONS];
};

/* valid flags for nxprov_flags */
#define NXPROVF_ATTACHED        0x1     /* attached to global list */
#define NXPROVF_CLOSED          0x2     /* attached but closed */
#define NXPROVF_EXTERNAL        0x4     /* external nexus provider */
#define NXPROVF_VIRTUAL_DEVICE  0x8     /* device is virtual (no DMA) */

#define NXPROV_LLINK(_nxp) \
	((_nxp)->nxprov_params->nxp_flags & NXPF_NETIF_LLINK)

#define NXPROVF_BITS    \
	"\020\01ATTACHED\02CLOSED\03EXTERNAL\04VIRTUALDEV"

#define NX_ANONYMOUS_PROV(_nx)  \
	(NX_PROV(_nx)->nxprov_params->nxp_flags & NXPF_ANONYMOUS)
#define NX_USER_CHANNEL_PROV(_nx) \
	(NX_PROV(_nx)->nxprov_params->nxp_flags & NXPF_USER_CHANNEL)
#define NX_LLINK_PROV(_nx)    NXPROV_LLINK(NX_PROV(_nx))

/*
 * Nexus domain provider.
 */
struct kern_nexus_domain_provider {
	STAILQ_ENTRY(kern_nexus_domain_provider) nxdom_prov_link;
	STAILQ_ENTRY(kern_nexus_domain_provider) nxdom_prov_detaching_link;
	char                    nxdom_prov_name[64];
	uuid_t                  nxdom_prov_uuid;
	uint64_t                nxdom_prov_gencnt;
	uint32_t                nxdom_prov_refcnt;
	uint32_t                nxdom_prov_flags;
	struct nxdom            *nxdom_prov_dom;
	struct kern_nexus_domain_provider_init nxdom_prov_ext;
	/*
	 * The callbacks are grouped together to simplify the
	 * initialization of external domain providers; see
	 * kern_nexus_register_domain_provider() for details.
	 */
	struct nxdom_prov_cb {
		int (*dp_cb_init)(struct kern_nexus_domain_provider *);
		void (*dp_cb_fini)(struct kern_nexus_domain_provider *);
		int (*dp_cb_params)(struct kern_nexus_domain_provider *,
		    const uint32_t, const struct nxprov_params *,
		    struct nxprov_params *,
		    struct skmem_region_params[SKMEM_REGIONS], uint32_t);
		int (*dp_cb_mem_new)(struct kern_nexus_domain_provider *,
		    struct kern_nexus *, struct nexus_adapter *);
		int (*dp_cb_config)(struct kern_nexus_domain_provider *,
		    struct kern_nexus *, struct nx_cfg_req *, int,
		    struct proc *, kauth_cred_t);
		int (*dp_cb_nx_ctor)(struct kern_nexus *);
		void (*dp_cb_nx_dtor)(struct kern_nexus *);
		int (*dp_cb_nx_mem_info)(struct kern_nexus *,
		    struct kern_pbufpool **, struct kern_pbufpool **);
		size_t (*dp_cb_nx_mib_get)(struct kern_nexus *,
		    struct nexus_mib_filter *, void *, size_t, struct proc *);
		int (*dp_cb_nx_stop)(struct kern_nexus *);
	} nxdom_prov_cb;
#define nxdom_prov_init         nxdom_prov_cb.dp_cb_init
#define nxdom_prov_fini         nxdom_prov_cb.dp_cb_fini
#define nxdom_prov_params       nxdom_prov_cb.dp_cb_params
#define nxdom_prov_mem_new      nxdom_prov_cb.dp_cb_mem_new
#define nxdom_prov_config       nxdom_prov_cb.dp_cb_config
#define nxdom_prov_nx_ctor      nxdom_prov_cb.dp_cb_nx_ctor
#define nxdom_prov_nx_dtor      nxdom_prov_cb.dp_cb_nx_dtor
#define nxdom_prov_nx_mem_info  nxdom_prov_cb.dp_cb_nx_mem_info
#define nxdom_prov_nx_mib_get   nxdom_prov_cb.dp_cb_nx_mib_get
#define nxdom_prov_nx_stop      nxdom_prov_cb.dp_cb_nx_stop
};

#define NXDOMPROVF_INITIALIZED  0x1     /* provider has been initialized */
#define NXDOMPROVF_ATTACHED     0x2     /* provider is attached to a domain */
#define NXDOMPROVF_DETACHING    0x4     /* provider is being detached */
#define NXDOMPROVF_EXT          0x8     /* external provider */
#define NXDOMPROVF_EXT_INITED   0x10    /* nxpi_init() succeeded */
#define NXDOMPROVF_DEFAULT      0x20    /* default provider for domain */

struct nxp_bounds {
	uint32_t        nb_def;
	uint32_t        nb_min;
	uint32_t        nb_max;
};

/*
 * Nexus domain.
 *
 * Each Nexus type is represented by a Nexus domain; there can
 * be more than one providers for a given domain.
 */
struct nxdom {
	STAILQ_ENTRY(nxdom) nxdom_link;
	STAILQ_HEAD(, kern_nexus_domain_provider) nxdom_prov_head;
	nexus_type_t    nxdom_type;
	nexus_meta_type_t nxdom_md_type;
	nexus_meta_subtype_t nxdom_md_subtype;
	uint32_t        nxdom_flags;
	struct nxp_bounds nxdom_ports;
	struct nxp_bounds nxdom_tx_rings;
	struct nxp_bounds nxdom_rx_rings;
	struct nxp_bounds nxdom_tx_slots;
	struct nxp_bounds nxdom_rx_slots;
	struct nxp_bounds nxdom_buf_size;
	struct nxp_bounds nxdom_large_buf_size;
	struct nxp_bounds nxdom_meta_size;
	struct nxp_bounds nxdom_stats_size;
	struct nxp_bounds nxdom_pipes;
	struct nxp_bounds nxdom_extensions;
	struct nxp_bounds nxdom_mhints;
	struct nxp_bounds nxdom_flowadv_max;
	struct nxp_bounds nxdom_nexusadv_size;
	struct nxp_bounds nxdom_capabilities;
	struct nxp_bounds nxdom_qmap;
	struct nxp_bounds nxdom_max_frags;
	struct skmem_region_params nxdom_region_params[SKMEM_REGIONS];
	const char      *nxdom_name;

	/*
	 * Nexus domain callbacks.
	 */
	void (*nxdom_init)(struct nxdom *);             /* optional */
	void (*nxdom_terminate)(struct nxdom *);        /* optional */
	void (*nxdom_fini)(struct nxdom *);             /* optional */
	int (*nxdom_find_port)                          /* optional */
	(struct kern_nexus *, boolean_t, nexus_port_t *);
	boolean_t (*nxdom_port_is_reserved)             /* optional */
	(struct kern_nexus *, nexus_port_t);
	int (*nxdom_bind_port)                          /* required */
	(struct kern_nexus *, nexus_port_t *, struct nxbind *, void *);
	int (*nxdom_unbind_port)                        /* required */
	(struct kern_nexus *, nexus_port_t);
	int (*nxdom_connect)                            /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, struct chreq *, struct kern_channel *,
	struct nxbind *, struct proc *);
	void (*nxdom_disconnect)                        /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *);
	void (*nxdom_defunct)                           /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, struct proc *);
	void (*nxdom_defunct_finalize)                  /* required */
	(struct kern_nexus_domain_provider *, struct kern_nexus *,
	struct kern_channel *, boolean_t);
};

#define NEXUSDOMF_INITIALIZED   0x1     /* domain has been initialized */
#define NEXUSDOMF_ATTACHED      0x2     /* domain is globally attached */
#define NEXUSDOMF_TERMINATED    0x4     /* domain has been terminated */

#define NXDOM_DEF(_dom, var)    ((_dom)->nxdom_##var.nb_def)
#define NXDOM_MIN(_dom, var)    ((_dom)->nxdom_##var.nb_min)
#define NXDOM_MAX(_dom, var)    ((_dom)->nxdom_##var.nb_max)

extern struct nexus_controller kernnxctl;
extern struct nexus_controller usernxctl;
extern lck_grp_t nexus_lock_group;
extern lck_grp_t nexus_mbq_lock_group;
extern lck_grp_t nexus_pktq_lock_group;
extern lck_attr_t nexus_lock_attr;
extern kern_allocation_name_t skmem_tag_nx_key;
extern kern_allocation_name_t skmem_tag_nx_port_info;

extern struct kern_nexus_domain_provider *nxdom_prov_default[NEXUS_TYPE_MAX];

#define NX_SHARED_NXCTL_INSTANCE(_nxctl)        \
    ((_nxctl) == kernnxctl.ncd_nxctl)

#define NXCTL_LOCK(_nxctl)      do {                    \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        lck_mtx_lock(&((_nxctl)->nxctl_lock));  \
	} else {                                        \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_NOTOWNED);           \
	}                                               \
} while (0)

#define NXCTL_UNLOCK(_nxctl)    do {                    \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        lck_mtx_unlock(&((_nxctl)->nxctl_lock));\
	}                                               \
	LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock),         \
	    LCK_MTX_ASSERT_NOTOWNED);                   \
} while (0)

#define NXCTL_LOCK_ASSERT_HELD(_nxctl)  do {            \
	if (!NX_SHARED_NXCTL_INSTANCE((_nxctl))) {      \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_OWNED);              \
	} else {                                        \
	        LCK_MTX_ASSERT(&((_nxctl)->nxctl_lock), \
	            LCK_MTX_ASSERT_NOTOWNED);           \
	}                                               \
} while (0)

__BEGIN_DECLS
extern int nexus_init(void);
extern void nexus_fini(void);

extern struct kern_nexus *nx_create(struct nxctl *, const uuid_t,
    const nexus_type_t, const void *, nexus_ctx_release_fn_t,
    struct kern_pbufpool *, struct kern_pbufpool *, int *);
extern void nx_retain(struct kern_nexus *);
extern void nx_retain_locked(struct kern_nexus *);
extern int nx_release(struct kern_nexus *);
extern int nx_release_locked(struct kern_nexus *);
extern void nx_detach(struct kern_nexus *);
extern void nx_stop(struct kern_nexus *nx);
extern int nx_close(struct kern_nexus *, boolean_t);
extern int nx_destroy(struct nxctl *, const uuid_t);
extern struct kern_nexus *nx_find(const uuid_t, boolean_t);
extern int nx_advisory_alloc(struct kern_nexus *, const char *,
    struct skmem_region_params *, nexus_advisory_type_t);
extern void nx_advisory_free(struct kern_nexus *);
extern int nx_port_find(struct kern_nexus *, nexus_port_t,
    nexus_port_t, nexus_port_t *);
extern int nx_port_alloc(struct kern_nexus *, nexus_port_t,
    struct nxbind *, struct nexus_adapter **, struct proc *);
extern int nx_port_bind(struct kern_nexus *, nexus_port_t,
    struct nxbind *);
extern int nx_port_bind_info(struct kern_nexus *, nexus_port_t,
    struct nxbind *, void *);
extern int nx_port_unbind(struct kern_nexus *, nexus_port_t);
extern struct nexus_adapter *nx_port_get_na(struct kern_nexus *,
    nexus_port_t);
extern int nx_port_get_info(struct kern_nexus *, nexus_port_t,
    nx_port_info_type_t, void *__sized_by(len), uint32_t len);
extern void nx_port_defunct(struct kern_nexus *, nexus_port_t);
extern void nx_port_free(struct kern_nexus *, nexus_port_t);
extern void nx_port_free_all(struct kern_nexus *);
extern bool nx_port_is_valid(struct kern_nexus *, nexus_port_t);
extern bool nx_port_is_defunct(struct kern_nexus *, nexus_port_t);
extern void nx_port_foreach(struct kern_nexus *, void (^)(nexus_port_t));
extern void nx_interface_advisory_notify(struct kern_nexus *);

extern struct nxctl *nxctl_create(struct proc *, struct fileproc *,
    const uuid_t, int *);
extern void nxctl_close(struct nxctl *);
extern void nxctl_traffic_rule_clean(struct nxctl *);
extern void nxctl_traffic_rule_init(void);
extern void nxctl_traffic_rule_fini(void);
extern int nxctl_inet_traffic_rule_find_qset_id_with_pkt(const char *,
    struct __kern_packet *, uint64_t *);
extern int nxctl_inet_traffic_rule_find_qset_id(const char *,
    struct ifnet_traffic_descriptor_inet *, uint64_t *);
extern int nxctl_inet_traffic_rule_get_count(const char *, uint32_t *);
extern int nxctl_get_opt(struct nxctl *, struct sockopt *);
extern int nxctl_set_opt(struct nxctl *, struct sockopt *);
extern void nxctl_retain(struct nxctl *);
extern int nxctl_release(struct nxctl *);
extern void nxctl_dtor(struct nxctl *);

extern int nxprov_advise_connect(struct kern_nexus *, struct kern_channel *,
    struct proc *p);
extern void nxprov_advise_disconnect(struct kern_nexus *,
    struct kern_channel *);
extern struct kern_nexus_provider *nxprov_create(struct proc *,
    struct nxctl *, struct nxprov_reg *, int *);
extern struct kern_nexus_provider *nxprov_create_kern(struct nxctl *,
    struct kern_nexus_domain_provider *, struct nxprov_reg *,
    const struct kern_nexus_provider_init *init, int *err);
extern int nxprov_close(struct kern_nexus_provider *, boolean_t);
extern int nxprov_destroy(struct nxctl *, const uuid_t);
extern void nxprov_retain(struct kern_nexus_provider *);
extern int nxprov_release(struct kern_nexus_provider *);
extern struct nxprov_params *nxprov_params_alloc(zalloc_flags_t);
extern void nxprov_params_free(struct nxprov_params *);

struct nxprov_adjusted_params {
	nexus_meta_subtype_t *adj_md_subtype;
	uint32_t *adj_stats_size;
	uint32_t *adj_flowadv_max;
	uint32_t *adj_nexusadv_size;
	uint32_t *adj_caps;
	uint32_t *adj_tx_rings;
	uint32_t *adj_rx_rings;
	uint32_t *adj_tx_slots;
	uint32_t *adj_rx_slots;
	uint32_t *adj_alloc_rings;
	uint32_t *adj_free_rings;
	uint32_t *adj_alloc_slots;
	uint32_t *adj_free_slots;
	uint32_t *adj_buf_size;
	uint32_t *adj_buf_region_segment_size;
	uint32_t *adj_pp_region_config_flags;
	uint32_t *adj_max_frags;
	uint32_t *adj_event_rings;
	uint32_t *adj_event_slots;
	uint32_t *adj_max_buffers;
	uint32_t *adj_large_buf_size;
};

extern int nxprov_params_adjust(struct kern_nexus_domain_provider *,
    const uint32_t, const struct nxprov_params *, struct nxprov_params *,
    struct skmem_region_params[SKMEM_REGIONS], const struct nxdom *,
    const struct nxdom *, const struct nxdom *, uint32_t,
    int (*adjust_fn)(const struct kern_nexus_domain_provider *,
    const struct nxprov_params *, struct nxprov_adjusted_params *));

extern void nxdom_attach_all(void);
extern void nxdom_detach_all(void);
extern struct nxdom *nxdom_find(nexus_type_t);

extern struct kern_nexus_domain_provider *nxdom_prov_find(
	const struct nxdom *, const char *);
extern struct kern_nexus_domain_provider *nxdom_prov_find_uuid(const uuid_t);
extern int nxdom_prov_add(struct nxdom *, struct kern_nexus_domain_provider *);
extern void nxdom_prov_del(struct kern_nexus_domain_provider *);
extern void nxdom_prov_retain_locked(struct kern_nexus_domain_provider *);
extern void nxdom_prov_retain(struct kern_nexus_domain_provider *);
extern boolean_t nxdom_prov_release_locked(struct kern_nexus_domain_provider *);
extern boolean_t nxdom_prov_release(struct kern_nexus_domain_provider *);
extern int nxdom_prov_validate_params(struct kern_nexus_domain_provider *,
    const struct nxprov_reg *, struct nxprov_params *,
    struct skmem_region_params[SKMEM_REGIONS], const uint32_t, uint32_t);

extern struct nxbind *nxb_alloc(zalloc_flags_t);
extern void nxb_free(struct nxbind *);
extern boolean_t nxb_is_equal(struct nxbind *, struct nxbind *);
extern void nxb_move(struct nxbind *, struct nxbind *);

typedef void kern_nexus_walktree_f_t(struct kern_nexus *, void *);
extern void kern_nexus_walktree(kern_nexus_walktree_f_t *, void *, boolean_t);

extern int kern_nexus_get_pbufpool_info(const uuid_t nx_uuid,
    struct kern_pbufpool_memory_info *rx_pool,
    struct kern_pbufpool_memory_info *tx_pool);
__END_DECLS

#include <skywalk/nexus/nexus_adapter.h>

__attribute__((always_inline))
static inline int
nx_sync_tx(struct __kern_channel_ring *kring, boolean_t commit)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_TX);
	if (nxprov->nxprov_ext.nxpi_sync_tx != NULL) {
		return nxprov->nxprov_ext.nxpi_sync_tx(nxprov,
		           KRNA(kring)->na_nx, kring,
		           (commit ? KERN_NEXUS_SYNCF_COMMIT : 0));
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static inline int
nx_sync_rx(struct __kern_channel_ring *kring, boolean_t commit)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	if (nxprov->nxprov_ext.nxpi_sync_rx != NULL) {
		return nxprov->nxprov_ext.nxpi_sync_rx(nxprov,
		           KRNA(kring)->na_nx, kring,
		           (commit ? KERN_NEXUS_SYNCF_COMMIT : 0));
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static __inline__ void
nx_tx_doorbell(struct __kern_channel_ring *kring, boolean_t async)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_TX);
	ASSERT(nxprov->nxprov_ext.nxpi_tx_doorbell != NULL);
	nxprov->nxprov_ext.nxpi_tx_doorbell(nxprov, KRNA(kring)->na_nx,
	    kring, (async ? KERN_NEXUS_TXDOORBELLF_ASYNC_REFILL: 0));
}

__attribute__((always_inline))
static inline int
nx_rx_sync_packets(struct __kern_channel_ring *kring,
    uint64_t *__counted_by(*count)packets, uint32_t *count)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	if (nxprov->nxprov_ext.nxpi_rx_sync_packets != NULL) {
		return nxprov->nxprov_ext.nxpi_rx_sync_packets(nxprov,
		           KRNA(kring)->na_nx, kring, packets, count, 0);
	} else {
		return 0;
	}
}

__attribute__((always_inline))
static inline boolean_t
nx_has_rx_sync_packets(struct __kern_channel_ring *kring)
{
	struct kern_nexus_provider *nxprov = NX_PROV(KRNA(kring)->na_nx);

	ASSERT(kring->ckr_tx == NR_RX);
	return nxprov->nxprov_ext.nxpi_rx_sync_packets != NULL;
}

__attribute__((always_inline))
static __inline__ errno_t
nx_tx_qset_notify(struct kern_nexus *nx, void *qset_ctx)
{
	struct kern_nexus_provider *nxprov = NX_PROV(nx);
	sk_protect_t protect;
	errno_t err;

	ASSERT(nxprov->nxprov_netif_ext.nxnpi_tx_qset_notify != NULL);
	protect = sk_tx_notify_protect();
	err = nxprov->nxprov_netif_ext.nxnpi_tx_qset_notify(nxprov, nx,
	    qset_ctx, 0);
	sk_tx_notify_unprotect(protect);
	return err;
}
#endif /* BSD_KERNEL_PRIVATE */
#endif /* _SKYWALK_NEXUS_NEXUSVAR_H_ */