/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1985, 1986, 19934* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031#ifndef _NETINET_IN_VAR_H_32#define _NETINET_IN_VAR_H_3334/*35* Argument structure for SIOCAIFADDR.36*/37struct in_aliasreq {38char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */39struct sockaddr_in ifra_addr;40struct sockaddr_in ifra_broadaddr;41#define ifra_dstaddr ifra_broadaddr42struct sockaddr_in ifra_mask;43int ifra_vhid;44};4546#ifdef _KERNEL47#include <sys/queue.h>48#include <sys/fnv_hash.h>49#include <sys/tree.h>5051struct igmp_ifsoftc;52struct in_multi;53struct lltable;54SLIST_HEAD(in_multi_head, in_multi);5556/*57* IPv4 per-interface state.58*/59struct in_ifinfo {60struct lltable *ii_llt; /* ARP state */61struct igmp_ifsoftc *ii_igmp; /* IGMP state */62struct in_multi *ii_allhosts; /* 224.0.0.1 membership */63};6465/*66* Interface address, Internet version. One of these structures67* is allocated for each Internet address on an interface.68* The ifaddr structure contains the protocol-independent part69* of the structure and is assumed to be first.70*/71struct in_ifaddr {72struct ifaddr ia_ifa; /* protocol-independent info */73#define ia_ifp ia_ifa.ifa_ifp74#define ia_flags ia_ifa.ifa_flags75/* ia_subnet{,mask} in host order */76u_long ia_subnet; /* subnet address */77u_long ia_subnetmask; /* mask of subnet */78CK_LIST_ENTRY(in_ifaddr) ia_hash; /* hash of internet addresses */79CK_STAILQ_ENTRY(in_ifaddr) ia_link; /* list of internet addresses */80struct sockaddr_in ia_addr; /* reserve space for interface name */81struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */82#define ia_broadaddr ia_dstaddr83struct sockaddr_in ia_sockmask; /* reserve space for general netmask */84struct callout ia_garp_timer; /* timer for retransmitting GARPs */85int ia_garp_count; /* count of retransmitted GARPs */86};8788/*89* Given a pointer to an in_ifaddr (ifaddr),90* return a pointer to the addr as a sockaddr_in.91*/92#define IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr))93#define IA_DSTSIN(ia) (&(((struct in_ifaddr *)(ia))->ia_dstaddr))94#define IA_MASKSIN(ia) (&(((struct in_ifaddr *)(ia))->ia_sockmask))9596#define IN_LNAOF(in, ifa) \97((ntohl((in).s_addr) & ~((struct in_ifaddr *)(ifa)->ia_subnetmask))9899#ifdef _KERNEL100#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \101((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 )102#endif103104#define LLTABLE(ifp) ((struct in_ifinfo *)(ifp)->if_inet)->ii_llt105/*106* Hash table for IP addresses.107*/108CK_STAILQ_HEAD(in_ifaddrhead, in_ifaddr);109CK_LIST_HEAD(in_ifaddrhashhead, in_ifaddr);110111VNET_DECLARE(struct in_ifaddrhashhead *, in_ifaddrhashtbl);112VNET_DECLARE(struct in_ifaddrhead, in_ifaddrhead);113VNET_DECLARE(u_long, in_ifaddrhmask); /* mask for hash table */114115#define V_in_ifaddrhashtbl VNET(in_ifaddrhashtbl)116#define V_in_ifaddrhead VNET(in_ifaddrhead)117#define V_in_ifaddrhmask VNET(in_ifaddrhmask)118119#define INADDR_NHASH_LOG2 9120#define INADDR_NHASH (1 << INADDR_NHASH_LOG2)121#define INADDR_HASHVAL(x) fnv_32_buf((&(x)), sizeof(x), FNV1_32_INIT)122#define INADDR_HASH(x) \123(&V_in_ifaddrhashtbl[INADDR_HASHVAL(x) & V_in_ifaddrhmask])124125/*126* Macro for finding the internet address structure (in_ifaddr)127* corresponding to one of our IP addresses (in_addr).128*/129#define INADDR_TO_IFADDR(addr, ia) \130/* struct in_addr addr; */ \131/* struct in_ifaddr *ia; */ \132do { \133NET_EPOCH_ASSERT(); \134CK_LIST_FOREACH(ia, INADDR_HASH((addr).s_addr), ia_hash) \135if (IA_SIN(ia)->sin_addr.s_addr == (addr).s_addr) \136break; \137} while (0)138139/*140* Macro for finding the interface (ifnet structure) corresponding to one141* of our IP addresses.142*/143#define INADDR_TO_IFP(addr, ifp) \144/* struct in_addr addr; */ \145/* struct ifnet *ifp; */ \146{ \147struct in_ifaddr *ia; \148\149INADDR_TO_IFADDR(addr, ia); \150(ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \151}152153/*154* Macro for finding the internet address structure (in_ifaddr) corresponding155* to a given interface (ifnet structure).156*/157#define IFP_TO_IA(ifp, ia) \158/* struct ifnet *ifp; */ \159/* struct in_ifaddr *ia; */ \160do { \161NET_EPOCH_ASSERT(); \162for ((ia) = CK_STAILQ_FIRST(&V_in_ifaddrhead); \163(ia) != NULL && (ia)->ia_ifp != (ifp); \164(ia) = CK_STAILQ_NEXT((ia), ia_link)) \165continue; \166} while (0)167168/*169* Legacy IPv4 IGMP per-link structure.170*/171struct router_info {172struct ifnet *rti_ifp;173int rti_type; /* type of router which is querier on this interface */174int rti_time; /* # of slow timeouts since last old query */175SLIST_ENTRY(router_info) rti_list;176};177178/*179* IPv4 multicast IGMP-layer source entry.180*/181struct ip_msource {182RB_ENTRY(ip_msource) ims_link; /* RB tree links */183in_addr_t ims_haddr; /* host byte order */184struct ims_st {185uint16_t ex; /* # of exclusive members */186uint16_t in; /* # of inclusive members */187} ims_st[2]; /* state at t0, t1 */188uint8_t ims_stp; /* pending query */189};190191/*192* IPv4 multicast PCB-layer source entry.193*/194struct in_msource {195RB_ENTRY(ip_msource) ims_link; /* RB tree links */196in_addr_t ims_haddr; /* host byte order */197uint8_t imsl_st[2]; /* state before/at commit */198};199200RB_HEAD(ip_msource_tree, ip_msource); /* define struct ip_msource_tree */201202static __inline int203ip_msource_cmp(const struct ip_msource *a, const struct ip_msource *b)204{205206if (a->ims_haddr < b->ims_haddr)207return (-1);208if (a->ims_haddr == b->ims_haddr)209return (0);210return (1);211}212RB_PROTOTYPE(ip_msource_tree, ip_msource, ims_link, ip_msource_cmp);213214/*215* IPv4 multicast PCB-layer group filter descriptor.216*/217struct in_mfilter {218struct ip_msource_tree imf_sources; /* source list for (S,G) */219u_long imf_nsrc; /* # of source entries */220uint8_t imf_st[2]; /* state before/at commit */221struct in_multi *imf_inm; /* associated multicast address */222STAILQ_ENTRY(in_mfilter) imf_entry; /* list entry */223};224225/*226* Helper types and functions for IPv4 multicast filters.227*/228STAILQ_HEAD(ip_mfilter_head, in_mfilter);229230struct in_mfilter *ip_mfilter_alloc(int mflags, int st0, int st1);231void ip_mfilter_free(struct in_mfilter *);232233static inline void234ip_mfilter_init(struct ip_mfilter_head *head)235{236237STAILQ_INIT(head);238}239240static inline struct in_mfilter *241ip_mfilter_first(const struct ip_mfilter_head *head)242{243244return (STAILQ_FIRST(head));245}246247static inline void248ip_mfilter_insert(struct ip_mfilter_head *head, struct in_mfilter *imf)249{250251STAILQ_INSERT_TAIL(head, imf, imf_entry);252}253254static inline void255ip_mfilter_remove(struct ip_mfilter_head *head, struct in_mfilter *imf)256{257258STAILQ_REMOVE(head, imf, in_mfilter, imf_entry);259}260261#define IP_MFILTER_FOREACH(imf, head) \262STAILQ_FOREACH(imf, head, imf_entry)263264static inline size_t265ip_mfilter_count(struct ip_mfilter_head *head)266{267struct in_mfilter *imf;268size_t num = 0;269270STAILQ_FOREACH(imf, head, imf_entry)271num++;272return (num);273}274275/*276* IPv4 group descriptor.277*278* For every entry on an ifnet's if_multiaddrs list which represents279* an IP multicast group, there is one of these structures.280*281* If any source filters are present, then a node will exist in the RB-tree282* to permit fast lookup by source whenever an operation takes place.283* This permits pre-order traversal when we issue reports.284* Source filter trees are kept separately from the socket layer to285* greatly simplify locking.286*287* When IGMPv3 is active, inm_timer is the response to group query timer.288* The state-change timer inm_sctimer is separate; whenever state changes289* for the group the state change record is generated and transmitted,290* and kept if retransmissions are necessary.291*292* FUTURE: inm_link is now only used when groups are being purged293* on a detaching ifnet. It could be demoted to a SLIST_ENTRY, but294* because it is at the very start of the struct, we can't do this295* w/o breaking the ABI for ifmcstat.296*/297struct in_multi {298LIST_ENTRY(in_multi) inm_link; /* to-be-released by in_ifdetach */299struct in_addr inm_addr; /* IP multicast address, convenience */300struct ifnet *inm_ifp; /* back pointer to ifnet */301struct ifmultiaddr *inm_ifma; /* back pointer to ifmultiaddr */302u_int inm_timer; /* IGMPv1/v2 group / v3 query timer */303u_int inm_state; /* state of the membership */304void *inm_rti; /* unused, legacy field */305u_int inm_refcount; /* reference count */306307/* New fields for IGMPv3 follow. */308struct igmp_ifsoftc *inm_igi; /* IGMP info */309SLIST_ENTRY(in_multi) inm_nrele; /* to-be-released by IGMP */310struct ip_msource_tree inm_srcs; /* tree of sources */311u_long inm_nsrc; /* # of tree entries */312313struct mbufq inm_scq; /* queue of pending314* state-change packets */315struct timeval inm_lastgsrtv; /* Time of last G-S-R query */316uint16_t inm_sctimer; /* state-change timer */317uint16_t inm_scrv; /* state-change rexmit count */318319/*320* SSM state counters which track state at T0 (the time the last321* state-change report's RV timer went to zero) and T1322* (time of pending report, i.e. now).323* Used for computing IGMPv3 state-change reports. Several refcounts324* are maintained here to optimize for common use-cases.325*/326struct inm_st {327uint16_t iss_fmode; /* IGMP filter mode */328uint16_t iss_asm; /* # of ASM listeners */329uint16_t iss_ex; /* # of exclusive members */330uint16_t iss_in; /* # of inclusive members */331uint16_t iss_rec; /* # of recorded sources */332} inm_st[2]; /* state at t0, t1 */333};334335/*336* Helper function to derive the filter mode on a source entry337* from its internal counters. Predicates are:338* A source is only excluded if all listeners exclude it.339* A source is only included if no listeners exclude it,340* and at least one listener includes it.341* May be used by ifmcstat(8).342*/343static __inline uint8_t344ims_get_mode(const struct in_multi *inm, const struct ip_msource *ims,345uint8_t t)346{347348t = !!t;349if (inm->inm_st[t].iss_ex > 0 &&350inm->inm_st[t].iss_ex == ims->ims_st[t].ex)351return (MCAST_EXCLUDE);352else if (ims->ims_st[t].in > 0 && ims->ims_st[t].ex == 0)353return (MCAST_INCLUDE);354return (MCAST_UNDEFINED);355}356357#ifdef SYSCTL_DECL358SYSCTL_DECL(_net_inet);359SYSCTL_DECL(_net_inet_ip);360SYSCTL_DECL(_net_inet_raw);361#endif362363/*364* Lock macros for IPv4 layer multicast address lists. IPv4 lock goes365* before link layer multicast locks in the lock order. In most cases,366* consumers of IN_*_MULTI() macros should acquire the locks before367* calling them; users of the in_{add,del}multi() functions should not.368*/369extern struct mtx in_multi_list_mtx;370extern struct sx in_multi_sx;371372#define IN_MULTI_LIST_LOCK() mtx_lock(&in_multi_list_mtx)373#define IN_MULTI_LIST_UNLOCK() mtx_unlock(&in_multi_list_mtx)374#define IN_MULTI_LIST_LOCK_ASSERT() mtx_assert(&in_multi_list_mtx, MA_OWNED)375#define IN_MULTI_LIST_UNLOCK_ASSERT() mtx_assert(&in_multi_list_mtx, MA_NOTOWNED)376377#define IN_MULTI_LOCK() sx_xlock(&in_multi_sx)378#define IN_MULTI_UNLOCK() sx_xunlock(&in_multi_sx)379#define IN_MULTI_LOCK_ASSERT() sx_assert(&in_multi_sx, SA_XLOCKED)380#define IN_MULTI_UNLOCK_ASSERT() sx_assert(&in_multi_sx, SA_XUNLOCKED)381382void inm_disconnect(struct in_multi *inm);383384/*385* Get the in_multi pointer from a ifmultiaddr.386* Returns NULL if ifmultiaddr is no longer valid.387*/388static __inline struct in_multi *389inm_ifmultiaddr_get_inm(struct ifmultiaddr *ifma)390{391392NET_EPOCH_ASSERT();393394return ((ifma->ifma_addr->sa_family != AF_INET ||395(ifma->ifma_flags & IFMA_F_ENQUEUED) == 0) ? NULL :396ifma->ifma_protospec);397}398399/* Acquire an in_multi record. */400static __inline void401inm_acquire_locked(struct in_multi *inm)402{403404IN_MULTI_LIST_LOCK_ASSERT();405++inm->inm_refcount;406}407408static __inline void409inm_acquire(struct in_multi *inm)410{411IN_MULTI_LIST_LOCK();412inm_acquire_locked(inm);413IN_MULTI_LIST_UNLOCK();414}415416static __inline void417inm_rele_locked(struct in_multi_head *inmh, struct in_multi *inm)418{419MPASS(inm->inm_refcount > 0);420IN_MULTI_LIST_LOCK_ASSERT();421422if (--inm->inm_refcount == 0) {423MPASS(inmh != NULL);424inm_disconnect(inm);425inm->inm_ifma->ifma_protospec = NULL;426SLIST_INSERT_HEAD(inmh, inm, inm_nrele);427}428}429430/*431* Return values for imo_multi_filter().432*/433#define MCAST_PASS 0 /* Pass */434#define MCAST_NOTGMEMBER 1 /* This host not a member of group */435#define MCAST_NOTSMEMBER 2 /* This host excluded source */436#define MCAST_MUTED 3 /* [deprecated] */437438struct rib_head;439struct ip_moptions;440struct ucred;441442struct in_multi *inm_lookup_locked(struct ifnet *, const struct in_addr);443struct in_multi *inm_lookup(struct ifnet *, const struct in_addr);444int imo_multi_filter(const struct ip_moptions *, const struct ifnet *,445const struct sockaddr *, const struct sockaddr *);446void inm_commit(struct in_multi *);447void inm_clear_recorded(struct in_multi *);448void inm_print(const struct in_multi *);449int inm_record_source(struct in_multi *inm, const in_addr_t);450void inm_release_deferred(struct in_multi *);451void inm_release_list_deferred(struct in_multi_head *);452void inm_release_wait(void *);453int in_joingroup(struct ifnet *, const struct in_addr *,454/*const*/ struct in_mfilter *, struct in_multi **);455int in_joingroup_locked(struct ifnet *, const struct in_addr *,456/*const*/ struct in_mfilter *, struct in_multi **);457int in_leavegroup(struct in_multi *, /*const*/ struct in_mfilter *);458int in_leavegroup_locked(struct in_multi *,459/*const*/ struct in_mfilter *);460int in_mask2len(struct in_addr *);461int in_control(struct socket *, u_long, void *, struct ifnet *,462struct thread *);463int in_control_ioctl(u_long, void *, struct ifnet *,464struct ucred *);465int in_addprefix(struct in_ifaddr *);466int in_scrubprefix(struct in_ifaddr *, u_int);467void in_ifscrub_all(void);468void ip_input(struct mbuf *);469void ip_direct_input(struct mbuf *);470void in_ifadown(struct ifaddr *ifa, int);471struct mbuf *ip_tryforward(struct mbuf *);472struct rib_head *in_inithead(uint32_t fibnum);473void in_ifattach(void *, struct ifnet *);474475#ifdef VIMAGE476void in_detachhead(struct rib_head *rh);477#endif478479#endif /* _KERNEL */480481/* INET6 stuff */482#include <netinet6/in6_var.h>483484#endif /* _NETINET_IN_VAR_H_ */485486487