root/usr.sbin/rtadvd/rtadvd.h
/*      $KAME: rtadvd.h,v 1.26 2003/08/05 12:34:23 itojun Exp $ */

/*-
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright (C) 1998 WIDE Project.
 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
 * 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.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
 */

#include <stdbool.h>

#define ELM_MALLOC(p,error_action)                                      \
        do {                                                            \
                p = malloc(sizeof(*p));                                 \
                if (p == NULL) {                                        \
                        syslog(LOG_ERR, "<%s> malloc failed: %s",       \
                            __func__, strerror(errno));                 \
                        error_action;                                   \
                }                                                       \
                memset(p, 0, sizeof(*p));                               \
        } while(0)

#define IN6ADDR_LINKLOCAL_ALLNODES_INIT                         \
        {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     \
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}

#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT                       \
        {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     \
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}

#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT                       \
        {{{ 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     \
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}

extern struct sockaddr_in6 sin6_linklocal_allnodes;
extern struct sockaddr_in6 sin6_linklocal_allrouters;
extern struct sockaddr_in6 sin6_sitelocal_allrouters;

/*
 * RFC 3542 API deprecates IPV6_PKTINFO in favor of
 * IPV6_RECVPKTINFO
 */
#ifndef IPV6_RECVPKTINFO
#ifdef IPV6_PKTINFO
#define IPV6_RECVPKTINFO        IPV6_PKTINFO
#endif
#endif

/*
 * RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
 * IPV6_RECVHOPLIMIT
 */
#ifndef IPV6_RECVHOPLIMIT
#ifdef IPV6_HOPLIMIT
#define IPV6_RECVHOPLIMIT       IPV6_HOPLIMIT
#endif
#endif

/* protocol constants and default values */
#define DEF_MAXRTRADVINTERVAL 600
#define DEF_ADVLINKMTU 0
#define DEF_ADVREACHABLETIME 0
#define DEF_ADVRETRANSTIMER 0
#define DEF_ADVCURHOPLIMIT 64
#define DEF_ADVVALIDLIFETIME 2592000
#define DEF_ADVPREFERREDLIFETIME 604800

#define MAXROUTERLIFETIME 9000
#define MIN_MAXINTERVAL 4
#define MAX_MAXINTERVAL 1800
#define MIN_MININTERVAL 3
#define MAXREACHABLETIME 3600000

#define MAX_INITIAL_RTR_ADVERT_INTERVAL  16
#define MAX_INITIAL_RTR_ADVERTISEMENTS    3
#define MAX_FINAL_RTR_ADVERTISEMENTS      3
#define MIN_DELAY_BETWEEN_RAS             3
#define MAX_RA_DELAY_TIME                 500000 /* usec */

#define PREFIX_FROM_KERNEL 1
#define PREFIX_FROM_CONFIG 2
#define PREFIX_FROM_DYNAMIC 3

struct prefix {
        TAILQ_ENTRY(prefix)     pfx_next;

        struct rainfo *pfx_rainfo;      /* back pointer to the interface */
        /*
         * Expiration timer.  This is used when a prefix derived from
         * the kernel is deleted.
         */
        struct rtadvd_timer *pfx_timer;

        uint32_t        pfx_validlifetime;      /* AdvValidLifetime */
        uint32_t        pfx_vltimeexpire;       /* Expiration of vltime */
        uint32_t        pfx_preflifetime;       /* AdvPreferredLifetime */
        uint32_t        pfx_pltimeexpire;       /* Expiration of pltime */
        int             pfx_onlinkflg;          /* bool: AdvOnLinkFlag */
        int             pfx_autoconfflg;        /* bool: AdvAutonomousFlag */
        int             pfx_prefixlen;
        int             pfx_origin;             /* From kernel or config */

        struct in6_addr pfx_prefix;
};

struct rtinfo {
        TAILQ_ENTRY(rtinfo)     rti_next;

        uint32_t        rti_ltime;      /* route lifetime */
        int             rti_rtpref;     /* route preference */
        int             rti_prefixlen;
        struct in6_addr rti_prefix;
};

struct rdnss_addr {
        TAILQ_ENTRY(rdnss_addr) ra_next;

        struct in6_addr ra_dns; /* DNS server entry */
};

struct rdnss {
        TAILQ_ENTRY(rdnss) rd_next;

        TAILQ_HEAD(, rdnss_addr) rd_list;       /* list of DNS servers */
        uint32_t rd_ltime;      /* number of seconds valid */
};

struct pref64 {
        TAILQ_ENTRY(pref64) p64_next;
        uint16_t        p64_plc;        /* prefix length code */
        uint16_t        p64_sl;         /* scaled lifetime */
        struct in6_addr p64_prefix;
};

/*
 * The maximum length of a domain name in a DNS search list is calculated
 * by a domain name + length fields per 63 octets + a zero octet at
 * the tail and adding 8 octet boundary padding.
 */
#define _DNAME_LABELENC_MAXLEN \
        (NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)

#define DNAME_LABELENC_MAXLEN \
        (_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)

struct dnssl_addr {
        TAILQ_ENTRY(dnssl_addr) da_next;

        int da_len;                             /* length of entry */
        char da_dom[DNAME_LABELENC_MAXLEN];     /* search domain name entry */
};

struct dnssl {
        TAILQ_ENTRY(dnssl)      dn_next;

        TAILQ_HEAD(, dnssl_addr) dn_list;       /* list of search domains */
        uint32_t dn_ltime;                      /* number of seconds valid */
};

struct soliciter {
        TAILQ_ENTRY(soliciter)  sol_next;

        struct sockaddr_in6     sol_addr;
};

struct  rainfo {
        /* pointer for list */
        TAILQ_ENTRY(rainfo)     rai_next;

        /* interface information */
        struct ifinfo *rai_ifinfo;

        int     rai_advlinkopt;         /* bool: whether include link-layer addr opt */
        int     rai_advifprefix;        /* bool: gather IF prefixes? */

        /* Router configuration variables */
        uint16_t        rai_lifetime;           /* AdvDefaultLifetime */
        uint16_t        rai_maxinterval;        /* MaxRtrAdvInterval */
        uint16_t        rai_mininterval;        /* MinRtrAdvInterval */
        int     rai_managedflg;         /* AdvManagedFlag */
        int     rai_otherflg;           /* AdvOtherConfigFlag */
#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
        int     rai_ipv6onlyflg;        /* AdvIPv6OnlyFlag */
#endif

        int     rai_rtpref;             /* router preference */
        uint32_t        rai_linkmtu;            /* AdvLinkMTU */
        uint32_t        rai_reachabletime;      /* AdvReachableTime */
        uint32_t        rai_retranstimer;       /* AdvRetransTimer */
        uint8_t rai_hoplimit;           /* AdvCurHopLimit */

        TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
        int     rai_pfxs;               /* number of prefixes */

        uint16_t        rai_clockskew;  /* used for consisitency check of lifetimes */

        TAILQ_HEAD(, rdnss) rai_rdnss;  /* DNS server list */
        TAILQ_HEAD(, dnssl) rai_dnssl;  /* search domain list */
        TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
        int     rai_routes;             /* number of route information options */
        /* actual RA packet data and its length */
        size_t  rai_ra_datalen;
        char    *rai_ra_data;
        TAILQ_HEAD(, pref64) rai_pref64; /* PREF64 option */

        /* info about soliciter */
        TAILQ_HEAD(, soliciter) rai_soliciter;  /* recent solication source */
};

/* RA information list */
extern TAILQ_HEAD(railist_head_t, rainfo) railist;

/*
 * ifi_state:
 *
 *           (INIT)
 *              |
 *              | update_ifinfo()
 *              | update_persist_ifinfo()
 *              v
 *         UNCONFIGURED
 *               |  ^
 *   loadconfig()|  |rm_ifinfo(), ra_output()
 *      (MC join)|  |(MC leave)
 *               |  |
 *               |  |
 *               v  |
 *         TRANSITIVE
 *               |  ^
 *    ra_output()|  |getconfig()
 *               |  |
 *               |  |
 *               |  |
 *               v  |
 *         CONFIGURED
 *
 *
 */
#define IFI_STATE_UNCONFIGURED  0
#define IFI_STATE_CONFIGURED    1
#define IFI_STATE_TRANSITIVE    2

struct  ifinfo {
        TAILQ_ENTRY(ifinfo)     ifi_next;

        uint16_t        ifi_state;
        uint16_t        ifi_persist;
        uint16_t        ifi_ifindex;
        char    ifi_ifname[IFNAMSIZ];
        uint8_t ifi_type;
        uint16_t        ifi_flags;
        uint32_t        ifi_nd_flags;
        uint32_t        ifi_phymtu;
        struct sockaddr_dl      ifi_sdl;

        struct rainfo   *ifi_rainfo;
        struct rainfo   *ifi_rainfo_trans;
        uint16_t        ifi_burstcount;
        uint32_t        ifi_burstinterval;
        struct rtadvd_timer     *ifi_ra_timer;
        /* timestamp when the latest RA was sent */
        struct timespec         ifi_ra_lastsent;
        uint16_t        ifi_rs_waitcount;

        /* statistics */
        uint64_t ifi_raoutput;          /* # of RAs sent */
        uint64_t ifi_rainput;           /* # of RAs received */
        uint64_t ifi_rainconsistent;    /* # of inconsistent recv'd RAs  */
        uint64_t ifi_rsinput;           /* # of RSs received */
};

/* Interface list */
extern TAILQ_HEAD(ifilist_head_t, ifinfo) ifilist;

extern char *mcastif;

struct rtadvd_timer     *ra_timeout(void *);
void                    ra_timer_update(void *, struct timespec *);
void                    ra_output(struct ifinfo *);

int                     prefix_match(struct in6_addr *, int,
                            struct in6_addr *, int);
struct ifinfo           *if_indextoifinfo(int);
struct prefix           *find_prefix(struct rainfo *,
                            struct in6_addr *, int);
void                    rtadvd_set_reload(int);
void                    rtadvd_set_shutdown(int);