/*
 * Copyright (c) 1999-2024 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@
 */
/*
 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
 * support for mandatory and extensible security protections.  This notice
 * is included in support of clause 2.2 (b) of the Apple Public License,
 * Version 2.0.
 */
#ifndef DLIL_VAR_PRIVATE_H
#define DLIL_VAR_PRIVATE_H

#include "kern/kern_types.h"
#include <sys/kernel_types.h>


#include <stddef.h>
#include <ptrauth.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/domain.h>
#include <sys/user.h>
#include <sys/random.h>
#include <sys/socketvar.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_var.h>
#include <net/dlil.h>
#include <net/if_arp.h>
#include <net/iptap.h>
#include <net/pktap.h>
#include <net/droptap.h>
#include <net/nwk_wq.h>
#include <sys/kern_event.h>
#include <sys/kdebug.h>
#include <sys/mcache.h>
#include <sys/syslog.h>
#include <sys/protosw.h>
#include <sys/priv.h>

#include <kern/assert.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <kern/sched_prim.h>
#include <kern/locks.h>
#include <kern/kalloc.h>
#include <kern/zalloc.h>

#include <net/kpi_protocol.h>
#include <net/kpi_interface.h>
#include <net/if_types.h>
#include <net/if_ipsec.h>
#include <net/if_llreach.h>
#include <net/if_utun.h>
#include <net/kpi_interfacefilter.h>
#include <net/classq/classq.h>
#include <net/classq/classq_sfb.h>
#include <net/flowhash.h>
#include <net/ntstat.h>

#include <net/net_api_stats.h>
#include <net/if_ports_used.h>
#include <net/if_vlan_var.h>
#include <netinet/in.h>
#if INET
#include <netinet/in_var.h>
#include <netinet/igmp_var.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet/if_ether.h>
#include <netinet/in_pcb.h>
#include <netinet/in_tclass.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#endif /* INET */

#include <net/nat464_utils.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/mld6_var.h>
#include <netinet6/scope6_var.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <net/pf_pbuf.h>
#include <libkern/OSAtomic.h>
#include <libkern/tree.h>

#include <dev/random/randomdev.h>
#include <machine/machine_routines.h>

#include <mach/thread_act.h>
#include <mach/sdt.h>

#if CONFIG_MACF
#include <sys/kauth.h>
#include <security/mac_framework.h>
#include <net/ethernet.h>
#include <net/firewire.h>
#endif

#if PF
#include <net/pfvar.h>
#endif /* PF */
#include <net/pktsched/pktsched.h>
#include <net/pktsched/pktsched_netem.h>

#if NECP
#include <net/necp.h>
#endif /* NECP */

#if SKYWALK
#include <skywalk/packet/packet_queue.h>
#include <skywalk/nexus/netif/nx_netif.h>
#include <skywalk/nexus/flowswitch/nx_flowswitch.h>
#endif /* SKYWALK */

#include <net/sockaddr_utils.h>

#include <os/log.h>

#ifndef BSD_KERNEL_PRIVATE
#error __FILE__ ## " can only be privately included"
#endif /* BSD_KERNEL_PRIVATE */


#define DBG_LAYER_BEG           DLILDBG_CODE(DBG_DLIL_STATIC, 0)
#define DBG_LAYER_END           DLILDBG_CODE(DBG_DLIL_STATIC, 2)
#define DBG_FNC_DLIL_INPUT      DLILDBG_CODE(DBG_DLIL_STATIC, (1 << 8))
#define DBG_FNC_DLIL_OUTPUT     DLILDBG_CODE(DBG_DLIL_STATIC, (2 << 8))
#define DBG_FNC_DLIL_IFOUT      DLILDBG_CODE(DBG_DLIL_STATIC, (3 << 8))

#define IF_DATA_REQUIRE_ALIGNED_64(f)   \
	static_assert(!(offsetof(struct if_data_internal, f) % sizeof(u_int64_t)))

#define IFNET_IF_DATA_REQUIRE_ALIGNED_64(f)     \
	static_assert(!(offsetof(struct ifnet, if_data.f) % sizeof(u_int64_t)))

enum {
	kProtoKPI_v1    = 1,
	kProtoKPI_v2    = 2
};

#if 1
#define DLIL_PRINTF     printf
#else
#define DLIL_PRINTF     kprintf
#endif


extern unsigned int net_rxpoll;
extern unsigned int net_affinity;
extern unsigned int net_async;     /* 0: synchronous, 1: asynchronous */

#if SKYWALK
/*
 * Skywalk ifnet attachment modes.
 */
extern uint32_t if_attach_nx;
extern uint32_t if_enable_fsw_ip_netagent;
extern uint32_t if_enable_fsw_transport_netagent;
extern uint32_t if_netif_all;
#endif /* SKYWALK */

#define DLIL_SDLDATALEN \
	(DLIL_SDLMAXLEN - offsetof(struct sockaddr_dl, sdl_data[0]))


/*
 * In the common case, the LL address is stored in the
 * `dl_if_lladdr' member of the `dlil_ifnet'. This is sufficient
 * for LL addresses that do not exceed the `DLIL_SDLMAXLEN' constant.
 */
struct dl_if_lladdr_std {
	struct ifaddr   ifa;
	u_int8_t        addr_sdl_bytes[DLIL_SDLMAXLEN];
	u_int8_t        mask_sdl_bytes[DLIL_SDLMAXLEN];
};

/*
 * However, in some rare cases we encounter LL addresses which
 * would not fit in the `DLIL_SDLMAXLEN' limitation. In such cases
 * we allocate the storage in the permanent arena, using this memory layout.
 */
struct dl_if_lladdr_xtra_space {
	struct ifaddr   ifa;
	u_int8_t        addr_sdl_bytes[SOCK_MAXADDRLEN];
	u_int8_t        mask_sdl_bytes[SOCK_MAXADDRLEN];
};

struct dlil_ifnet {
	struct ifnet    dl_if;                  /* public ifnet */
	/*
	 * DLIL private fields, protected by dl_if_lock
	 */
	decl_lck_mtx_data(, dl_if_lock);
	TAILQ_ENTRY(dlil_ifnet) dl_if_link;     /* dlil_ifnet link */
	u_int32_t dl_if_flags;                  /* flags (below) */
	u_int32_t dl_if_refcnt;                 /* refcnt */
	void    *dl_if_uniqueid __sized_by_or_null(dl_if_uniqueid_len);                /* unique interface id */
	size_t  dl_if_uniqueid_len;             /* length of the unique id */
	char    dl_if_namestorage[IFNAMSIZ];    /* interface name storage */
	char    dl_if_xnamestorage[IFXNAMSIZ];  /* external name storage */
	struct dl_if_lladdr_std dl_if_lladdr;   /* link-level address storage*/
	u_int8_t dl_if_descstorage[IF_DESCSIZE]; /* desc storage */
	u_int8_t dl_if_permanent_ether[ETHER_ADDR_LEN]; /* permanent address */
	u_int8_t dl_if_permanent_ether_is_set;
	u_int8_t dl_if_unused;
	struct dlil_threading_info dl_if_inpstorage; /* input thread storage */
	ctrace_t        dl_if_attach;           /* attach PC stacktrace */
	ctrace_t        dl_if_detach;           /* detach PC stacktrace */
};


/* Values for dl_if_flags (private to DLIL) */
#define DLIF_INUSE      0x1     /* DLIL ifnet recycler, ifnet in use */
#define DLIF_REUSE      0x2     /* DLIL ifnet recycles, ifnet is not new */


#define DLIL_TO_IFP(s)  (&s->dl_if)
#define IFP_TO_DLIL(s)  ((struct dlil_ifnet *)s)

struct ifnet_filter {
	TAILQ_ENTRY(ifnet_filter)       filt_next;
	u_int32_t                       filt_skip;
	u_int32_t                       filt_flags;
	ifnet_t                         filt_ifp;
	const char                      *filt_name;
	void                            *filt_cookie;
	protocol_family_t               filt_protocol;
	iff_input_func                  filt_input;
	iff_output_func                 filt_output;
	iff_event_func                  filt_event;
	iff_ioctl_func                  filt_ioctl;
	iff_detached_func               filt_detached;
};


/* Mbuf queue used for freeing the excessive mbufs */
typedef MBUFQ_HEAD(dlil_freeq) dlil_freeq_t;

typedef TAILQ_HEAD(, dlil_ifnet) dlil_ifnet_queue_t;

extern dlil_ifnet_queue_t dlil_ifnet_head;

struct proto_input_entry;

/*
 * Utility routines
 */
extern kern_return_t dlil_affinity_set(struct thread *, u_int32_t);
extern boolean_t packet_has_vlan_tag(struct mbuf * m);

/*
 * Monitor routines.
 */
extern void if_flt_monitor_busy(struct ifnet *);
extern void if_flt_monitor_unbusy(struct ifnet *);
extern void if_flt_monitor_enter(struct ifnet *);
extern void if_flt_monitor_leave(struct ifnet *);

/*
 * Allocation routines
 */
extern void dlil_allocation_zones_init(void);

extern struct dlil_ifnet * dlif_ifnet_alloc(void);
extern void dlif_ifnet_free(struct dlil_ifnet *);

extern struct ifnet_filter * dlif_filt_alloc(void);
extern void dlif_filt_free(struct ifnet_filter *);

extern struct if_proto * dlif_proto_alloc(void);
extern void dlif_proto_free(struct if_proto * );

extern struct tcpstat_local * dlif_tcpstat_alloc(void);
extern void dlif_tcpstat_free(struct tcpstat_local *);

extern struct udpstat_local * dlif_udpstat_alloc(void);
extern void dlif_udpstat_free(struct udpstat_local *);

extern void if_proto_ref(struct if_proto *);
extern void if_proto_free(struct if_proto *);

/*
 * Prepare the storage for the first/permanent link address, which must
 * must have the same lifetime as the ifnet itself.  Although the link
 * address gets removed from if_addrhead and ifnet_addrs[] at detach time,
 * its location in memory must never change as it may still be referred
 * to by some parts of the system afterwards (unfortunate implementation
 * artifacts inherited from BSD.)
 *
 * Caller must hold ifnet lock as writer.
 */
extern struct ifaddr * dlil_alloc_lladdr(struct ifnet *ifp, const struct sockaddr_dl *ll_addr);


/*
 * dlil_ifp_protolist
 * - get the list of protocols attached to the interface, or just the number
 *   of attached protocols
 * - if the number returned is greater than 'list_count', truncation occurred
 *
 * Note:
 * - caller must already be holding ifnet lock.
 */
extern u_int32_t dlil_ifp_protolist(struct ifnet *ifp, protocol_family_t *list __counted_by(list_count),
    u_int32_t list_count);

extern uint64_t if_creation_generation_count;


/*
 * Interface management functions
 */
extern void dlil_if_trace(struct dlil_ifnet *, int);

extern void _dlil_if_release(ifnet_t ifp, bool clear_in_use);

/*
 * Stats management
 */
void dlil_input_stats_add(const struct ifnet_stat_increment_param *,
    struct dlil_threading_info *, struct ifnet *, boolean_t);

boolean_t dlil_input_stats_sync(struct ifnet *,
    struct dlil_threading_info *);

/*
 * Thread management
 */
extern uint32_t dlil_pending_thread_cnt;


/* DLIL data threshold thread call */
extern void dlil_dt_tcall_fn(thread_call_param_t, thread_call_param_t);

extern void dlil_clean_threading_info(struct dlil_threading_info *inp);

int dlil_create_input_thread(ifnet_t, struct dlil_threading_info *,
    thread_continue_t *);

void dlil_terminate_input_thread(struct dlil_threading_info *);

extern boolean_t dlil_is_rxpoll_input(thread_continue_t func);
boolean_t dlil_is_native_netif_nexus(ifnet_t ifp);

void dlil_incr_pending_thread_count(void);
void dlil_decr_pending_thread_count(void);

struct if_proto * find_attached_proto(struct ifnet *ifp, u_int32_t protocol_family);

int dlil_is_clat_needed(protocol_family_t proto_family, mbuf_t m);
errno_t dlil_clat46(ifnet_t ifp, protocol_family_t *proto_family, mbuf_t *m);
errno_t dlil_clat64(ifnet_t ifp, protocol_family_t *proto_family, mbuf_t *m);

/*
 * Lock management functions
 */
extern lck_attr_t dlil_lck_attributes;
extern lck_rw_t ifnet_head_lock;
extern lck_mtx_t dlil_ifnet_lock;
extern lck_grp_t dlil_lock_group;
extern lck_grp_t ifnet_head_lock_group;
extern lck_grp_t ifnet_snd_lock_group;
extern lck_grp_t ifnet_rcv_lock_group;
extern lck_mtx_t dlil_thread_sync_lock;

extern void dlil_if_lock(void);

extern void dlil_if_unlock(void);

extern void dlil_if_lock_assert(void);

extern void ifnet_head_lock_assert(ifnet_lock_assert_t what);

extern void ifnet_lock_assert(struct ifnet *ifp, ifnet_lock_assert_t what);

extern void ifnet_lock_shared(struct ifnet *ifp);

extern void ifnet_lock_exclusive(struct ifnet *ifp);

extern void ifnet_lock_done(struct ifnet *ifp);

#if INET
extern void if_inetdata_lock_shared(struct ifnet *ifp);

extern void if_inetdata_lock_exclusive(struct ifnet *ifp);

extern void if_inetdata_lock_done(struct ifnet *ifp);

#endif /* INET */

extern void if_inet6data_lock_shared(struct ifnet *ifp);

extern void if_inet6data_lock_exclusive(struct ifnet *ifp);

extern void if_inet6data_lock_done(struct ifnet *ifp);

extern void ifnet_head_lock_shared(void);

extern void ifnet_head_lock_exclusive(void);

extern void ifnet_head_done(void);

extern void ifnet_head_assert_exclusive(void);

/*
 * mcasts
 */
errno_t if_mcasts_update_async(struct ifnet *);


#endif /* DLIL_VAR_PRIVATE_H */
