xref: /openbsd-src/libexec/snmpd/snmpd_metrics/kroute.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: kroute.c,v 1.3 2023/03/08 04:43:06 guenther Exp $	*/
25e39b809Smartijn 
35e39b809Smartijn /*
45e39b809Smartijn  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
55e39b809Smartijn  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
65e39b809Smartijn  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
75e39b809Smartijn  *
85e39b809Smartijn  * Permission to use, copy, modify, and distribute this software for any
95e39b809Smartijn  * purpose with or without fee is hereby granted, provided that the above
105e39b809Smartijn  * copyright notice and this permission notice appear in all copies.
115e39b809Smartijn  *
125e39b809Smartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
135e39b809Smartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
145e39b809Smartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
155e39b809Smartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
165e39b809Smartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
175e39b809Smartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
185e39b809Smartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
195e39b809Smartijn  */
205e39b809Smartijn 
215e39b809Smartijn #include <sys/types.h>
225e39b809Smartijn #include <sys/socket.h>
235e39b809Smartijn #include <sys/sysctl.h>
245e39b809Smartijn #include <sys/tree.h>
255e39b809Smartijn #include <sys/uio.h>
265e39b809Smartijn #include <sys/ioctl.h>
275e39b809Smartijn 
285e39b809Smartijn #include <net/if.h>
295e39b809Smartijn #include <net/if_dl.h>
305e39b809Smartijn #include <net/if_types.h>
315e39b809Smartijn #include <net/route.h>
325e39b809Smartijn #include <netinet/in.h>
335e39b809Smartijn #include <netinet/if_ether.h>
345e39b809Smartijn #include <arpa/inet.h>
355e39b809Smartijn 
365e39b809Smartijn #include <err.h>
375e39b809Smartijn #include <errno.h>
385e39b809Smartijn #include <fcntl.h>
395e39b809Smartijn #include <stdio.h>
405e39b809Smartijn #include <stdlib.h>
415e39b809Smartijn #include <string.h>
425e39b809Smartijn #include <unistd.h>
435e39b809Smartijn #include <event.h>
445e39b809Smartijn 
455e39b809Smartijn #include "snmpd.h"
465e39b809Smartijn 
475e39b809Smartijn struct ktable		**krt;
485e39b809Smartijn u_int			  krt_size;
495e39b809Smartijn 
505e39b809Smartijn struct {
515e39b809Smartijn 	struct event		 ks_ev;
525e39b809Smartijn 	u_long			 ks_iflastchange;
535e39b809Smartijn 	u_long			 ks_nroutes;	/* 4 billions enough? */
545e39b809Smartijn 	int			 ks_fd;
555e39b809Smartijn 	int			 ks_ifd;
565e39b809Smartijn 	u_short			 ks_nkif;
575e39b809Smartijn } kr_state;
585e39b809Smartijn 
595e39b809Smartijn struct kroute_node {
605e39b809Smartijn 	RB_ENTRY(kroute_node)	 entry;
615e39b809Smartijn 	struct kroute		 r;
625e39b809Smartijn 	struct kroute_node	*next;
635e39b809Smartijn };
645e39b809Smartijn 
655e39b809Smartijn struct kroute6_node {
665e39b809Smartijn 	RB_ENTRY(kroute6_node)	 entry;
675e39b809Smartijn 	struct kroute6		 r;
685e39b809Smartijn 	struct kroute6_node	*next;
695e39b809Smartijn };
705e39b809Smartijn 
715e39b809Smartijn struct kif_node {
725e39b809Smartijn 	RB_ENTRY(kif_node)	 entry;
735e39b809Smartijn 	TAILQ_HEAD(, kif_addr)	 addrs;
745e39b809Smartijn 	TAILQ_HEAD(, kif_arp)	 arps;
755e39b809Smartijn 	struct kif		 k;
765e39b809Smartijn };
775e39b809Smartijn 
785e39b809Smartijn int	kroute_compare(struct kroute_node *, struct kroute_node *);
795e39b809Smartijn int	kroute6_compare(struct kroute6_node *, struct kroute6_node *);
805e39b809Smartijn int	kif_compare(struct kif_node *, struct kif_node *);
815e39b809Smartijn 
825e39b809Smartijn void			 ktable_init(void);
835e39b809Smartijn int			 ktable_new(u_int, u_int);
845e39b809Smartijn void			 ktable_free(u_int);
855e39b809Smartijn int			 ktable_exists(u_int, u_int *);
865e39b809Smartijn struct ktable		*ktable_get(u_int);
875e39b809Smartijn int			 ktable_update(u_int);
885e39b809Smartijn 
895e39b809Smartijn struct kroute_node	*kroute_find(struct ktable *, in_addr_t, u_int8_t,
905e39b809Smartijn 			    u_int8_t);
915e39b809Smartijn struct kroute_node	*kroute_matchgw(struct kroute_node *,
925e39b809Smartijn 			    struct sockaddr_in *);
935e39b809Smartijn int			 kroute_insert(struct ktable *, struct kroute_node *);
945e39b809Smartijn int			 kroute_remove(struct ktable *, struct kroute_node *);
955e39b809Smartijn void			 kroute_clear(struct ktable *);
965e39b809Smartijn 
975e39b809Smartijn struct kroute6_node	*kroute6_find(struct ktable *, const struct in6_addr *,
985e39b809Smartijn 			    u_int8_t, u_int8_t);
995e39b809Smartijn struct kroute6_node	*kroute6_matchgw(struct kroute6_node *,
1005e39b809Smartijn 			    struct sockaddr_in6 *);
1015e39b809Smartijn int			 kroute6_insert(struct ktable *, struct kroute6_node *);
1025e39b809Smartijn int			 kroute6_remove(struct ktable *, struct kroute6_node *);
1035e39b809Smartijn void			 kroute6_clear(struct ktable *);
1045e39b809Smartijn 
1055e39b809Smartijn struct kif_arp		*karp_find(struct sockaddr *, u_short);
1065e39b809Smartijn int			 karp_insert(struct kif_node *, struct kif_arp *);
1075e39b809Smartijn int			 karp_remove(struct kif_node *, struct kif_arp *);
1085e39b809Smartijn 
1095e39b809Smartijn struct kif_node		*kif_find(u_short);
1105e39b809Smartijn struct kif_node		*kif_insert(u_short);
1115e39b809Smartijn int			 kif_remove(struct kif_node *);
1125e39b809Smartijn void			 kif_clear(void);
1135e39b809Smartijn struct kif		*kif_update(u_short, int, struct if_data *,
1145e39b809Smartijn 			    struct sockaddr_dl *);
1155e39b809Smartijn 
1165e39b809Smartijn int			 ka_compare(struct kif_addr *, struct kif_addr *);
1175e39b809Smartijn void			 ka_insert(u_short, struct kif_addr *);
1185e39b809Smartijn struct kif_addr		*ka_find(struct sockaddr *);
1195e39b809Smartijn int			 ka_remove(struct kif_addr *);
1205e39b809Smartijn 
1215e39b809Smartijn u_int8_t	prefixlen_classful(in_addr_t);
1225e39b809Smartijn u_int8_t	mask2prefixlen(in_addr_t);
1235e39b809Smartijn in_addr_t	prefixlen2mask(u_int8_t);
1245e39b809Smartijn u_int8_t	mask2prefixlen6(struct sockaddr_in6 *);
1255e39b809Smartijn struct in6_addr *prefixlen2mask6(u_int8_t);
1265e39b809Smartijn void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
1275e39b809Smartijn void		if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
1285e39b809Smartijn void		if_newaddr(u_short, struct sockaddr *, struct sockaddr *,
1295e39b809Smartijn 		    struct sockaddr *);
1305e39b809Smartijn void		if_deladdr(u_short, struct sockaddr *, struct sockaddr *,
1315e39b809Smartijn 		    struct sockaddr *);
1325e39b809Smartijn void		if_announce(void *);
1335e39b809Smartijn 
1345e39b809Smartijn int		fetchtable(struct ktable *);
1355e39b809Smartijn int		fetchifs(u_short);
1365e39b809Smartijn int		fetcharp(struct ktable *);
1375e39b809Smartijn void		dispatch_rtmsg(int, short, void *);
1385e39b809Smartijn int		rtmsg_process(char *, int);
1395e39b809Smartijn int		dispatch_rtmsg_addr(struct ktable *, struct rt_msghdr *,
1405e39b809Smartijn 		    struct sockaddr *[RTAX_MAX]);
1415e39b809Smartijn 
1425e39b809Smartijn RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
1435e39b809Smartijn RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
1445e39b809Smartijn 
1455e39b809Smartijn RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare)
1465e39b809Smartijn RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare)
1475e39b809Smartijn 
1485e39b809Smartijn RB_HEAD(kif_tree, kif_node)		kit;
1495e39b809Smartijn RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
1505e39b809Smartijn RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
1515e39b809Smartijn 
1525e39b809Smartijn RB_HEAD(ka_tree, kif_addr)		kat;
RB_PROTOTYPE(ka_tree,kif_addr,node,ka_compare)1535e39b809Smartijn RB_PROTOTYPE(ka_tree, kif_addr, node, ka_compare)
1545e39b809Smartijn RB_GENERATE(ka_tree, kif_addr, node, ka_compare)
1555e39b809Smartijn 
1565e39b809Smartijn void
1575e39b809Smartijn kr_init(void)
1585e39b809Smartijn {
1595e39b809Smartijn 	int		opt = 0, rcvbuf, default_rcvbuf;
1605e39b809Smartijn 	unsigned int	tid = RTABLE_ANY;
1615e39b809Smartijn 	socklen_t	optlen;
1625e39b809Smartijn 
1635e39b809Smartijn 	if ((kr_state.ks_ifd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1645e39b809Smartijn 		fatal("kr_init: ioctl socket");
1655e39b809Smartijn 
1665e39b809Smartijn 	if ((kr_state.ks_fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
1675e39b809Smartijn 		fatal("kr_init: route socket");
1685e39b809Smartijn 
1695e39b809Smartijn 	/* not interested in my own messages */
1705e39b809Smartijn 	if (setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_USELOOPBACK,
1715e39b809Smartijn 	    &opt, sizeof(opt)) == -1)
1725e39b809Smartijn 		log_warn("%s: SO_USELOOPBACK", __func__);	/* not fatal */
1735e39b809Smartijn 
1745e39b809Smartijn 	if (snmpd_env->sc_rtfilter && setsockopt(kr_state.ks_fd, AF_ROUTE,
1755e39b809Smartijn 	    ROUTE_MSGFILTER, &snmpd_env->sc_rtfilter,
1765e39b809Smartijn 	    sizeof(snmpd_env->sc_rtfilter)) == -1)
1775e39b809Smartijn 		log_warn("%s: ROUTE_MSGFILTER", __func__);
1785e39b809Smartijn 
1795e39b809Smartijn 	/* grow receive buffer, don't wanna miss messages */
1805e39b809Smartijn 	optlen = sizeof(default_rcvbuf);
1815e39b809Smartijn 	if (getsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
1825e39b809Smartijn 	    &default_rcvbuf, &optlen) == -1)
1835e39b809Smartijn 		log_warn("%s: SO_RCVBUF", __func__);
1845e39b809Smartijn 	else
1855e39b809Smartijn 		for (rcvbuf = MAX_RTSOCK_BUF;
1865e39b809Smartijn 		    rcvbuf > default_rcvbuf &&
1875e39b809Smartijn 		    setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
1885e39b809Smartijn 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
1895e39b809Smartijn 		    rcvbuf /= 2)
1905e39b809Smartijn 			;	/* nothing */
1915e39b809Smartijn 
1925e39b809Smartijn 	if (setsockopt(kr_state.ks_fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
1935e39b809Smartijn 	    sizeof(tid)) == -1)
1945e39b809Smartijn 		log_warn("%s: ROUTE_TABLEFILTER", __func__);
1955e39b809Smartijn 
1965e39b809Smartijn 	RB_INIT(&kit);
1975e39b809Smartijn 	RB_INIT(&kat);
1985e39b809Smartijn 
1995e39b809Smartijn 	if (fetchifs(0) == -1)
2005e39b809Smartijn 		fatalx("kr_init: fetchifs");
2015e39b809Smartijn 
2025e39b809Smartijn 	ktable_init();
2035e39b809Smartijn 
2045e39b809Smartijn 	event_set(&kr_state.ks_ev, kr_state.ks_fd, EV_READ | EV_PERSIST,
2055e39b809Smartijn 	    dispatch_rtmsg, NULL);
2065e39b809Smartijn 	event_add(&kr_state.ks_ev, NULL);
2075e39b809Smartijn }
2085e39b809Smartijn 
2095e39b809Smartijn void
ktable_init(void)2105e39b809Smartijn ktable_init(void)
2115e39b809Smartijn {
2125e39b809Smartijn 	u_int		 i;
2135e39b809Smartijn 
2145e39b809Smartijn 	for (i = 0; i <= RT_TABLEID_MAX; i++)
2155e39b809Smartijn 		if (ktable_exists(i, NULL))
2165e39b809Smartijn 			ktable_update(i);
2175e39b809Smartijn }
2185e39b809Smartijn 
2195e39b809Smartijn int
ktable_new(u_int rtableid,u_int rdomid)2205e39b809Smartijn ktable_new(u_int rtableid, u_int rdomid)
2215e39b809Smartijn {
2225e39b809Smartijn 	struct ktable	**xkrt;
2235e39b809Smartijn 	struct ktable	 *kt;
2245e39b809Smartijn 	size_t		  newsize, oldsize;
2255e39b809Smartijn 
2265e39b809Smartijn 	/* resize index table if needed */
2275e39b809Smartijn 	if (rtableid >= krt_size) {
2285e39b809Smartijn 		if ((xkrt = reallocarray(krt, rtableid + 1,
2295e39b809Smartijn 		    sizeof(struct ktable *))) == NULL) {
2305e39b809Smartijn 			log_warn("%s: realloc", __func__);
2315e39b809Smartijn 			return (-1);
2325e39b809Smartijn 		}
2335e39b809Smartijn 		krt = xkrt;
2345e39b809Smartijn 		oldsize = krt_size * sizeof(struct ktable *);
2355e39b809Smartijn 		krt_size = rtableid + 1;
2365e39b809Smartijn 		newsize = krt_size * sizeof(struct ktable *);
2375e39b809Smartijn 		bzero((char *)krt + oldsize, newsize - oldsize);
2385e39b809Smartijn 	}
2395e39b809Smartijn 
2405e39b809Smartijn 	if (krt[rtableid])
2415e39b809Smartijn 		fatalx("ktable_new: table already exists");
2425e39b809Smartijn 
2435e39b809Smartijn 	/* allocate new element */
2445e39b809Smartijn 	kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
2455e39b809Smartijn 	if (kt == NULL) {
2465e39b809Smartijn 		log_warn("%s: calloc", __func__);
2475e39b809Smartijn 		return (-1);
2485e39b809Smartijn 	}
2495e39b809Smartijn 
2505e39b809Smartijn 	/* initialize structure ... */
2515e39b809Smartijn 	RB_INIT(&kt->krt);
2525e39b809Smartijn 	RB_INIT(&kt->krt6);
2535e39b809Smartijn 	kt->rtableid = rtableid;
2545e39b809Smartijn 	kt->rdomain = rdomid;
2555e39b809Smartijn 
2565e39b809Smartijn 	/* ... and load it */
2575e39b809Smartijn 	if (fetchtable(kt) == -1)
2585e39b809Smartijn 		return (-1);
2595e39b809Smartijn 	/* load arp information */
2605e39b809Smartijn 	if (fetcharp(kt) == -1)
2615e39b809Smartijn 		return (-1);
2625e39b809Smartijn 
2635e39b809Smartijn 	log_debug("%s: new ktable for rtableid %d", __func__, rtableid);
2645e39b809Smartijn 	return (0);
2655e39b809Smartijn }
2665e39b809Smartijn 
2675e39b809Smartijn void
ktable_free(u_int rtableid)2685e39b809Smartijn ktable_free(u_int rtableid)
2695e39b809Smartijn {
2705e39b809Smartijn 	struct ktable	*kt;
2715e39b809Smartijn 
2725e39b809Smartijn 	if ((kt = ktable_get(rtableid)) == NULL)
2735e39b809Smartijn 		return;
2745e39b809Smartijn 
2755e39b809Smartijn 	log_debug("%s: freeing ktable rtableid %u", __func__, kt->rtableid);
2765e39b809Smartijn 	kroute_clear(kt);
2775e39b809Smartijn 	kroute6_clear(kt);
2785e39b809Smartijn 
2795e39b809Smartijn 	krt[kt->rtableid] = NULL;
2805e39b809Smartijn 	free(kt);
2815e39b809Smartijn }
2825e39b809Smartijn 
2835e39b809Smartijn struct ktable *
ktable_get(u_int rtableid)2845e39b809Smartijn ktable_get(u_int rtableid)
2855e39b809Smartijn {
2865e39b809Smartijn 	if (rtableid >= krt_size)
2875e39b809Smartijn 		return (NULL);
2885e39b809Smartijn 	return (krt[rtableid]);
2895e39b809Smartijn }
2905e39b809Smartijn 
2915e39b809Smartijn int
ktable_update(u_int rtableid)2925e39b809Smartijn ktable_update(u_int rtableid)
2935e39b809Smartijn {
2945e39b809Smartijn 	struct ktable	*kt;
2955e39b809Smartijn 	u_int		 rdomid;
2965e39b809Smartijn 
2975e39b809Smartijn 	if (!ktable_exists(rtableid, &rdomid))
2985e39b809Smartijn 		fatalx("ktable_update: table doesn't exist");
2995e39b809Smartijn 
3005e39b809Smartijn 	if (rdomid != rtableid) {
3015e39b809Smartijn 		if (ktable_get(rdomid) == NULL &&
3025e39b809Smartijn 		    ktable_new(rdomid, rdomid) != 0)
3035e39b809Smartijn 			return (-1);
3045e39b809Smartijn 	}
3055e39b809Smartijn 
3065e39b809Smartijn 	kt = ktable_get(rtableid);
3075e39b809Smartijn 	if (kt == NULL) {
3085e39b809Smartijn 		if (ktable_new(rtableid, rdomid))
3095e39b809Smartijn 			return (-1);
3105e39b809Smartijn 	}
3115e39b809Smartijn 	return (0);
3125e39b809Smartijn }
3135e39b809Smartijn 
3145e39b809Smartijn int
ktable_exists(u_int rtableid,u_int * rdomid)3155e39b809Smartijn ktable_exists(u_int rtableid, u_int *rdomid)
3165e39b809Smartijn {
3175e39b809Smartijn 	size_t			 len;
3185e39b809Smartijn 	struct rt_tableinfo	 info;
3195e39b809Smartijn 	int			 mib[6];
3205e39b809Smartijn 
3215e39b809Smartijn 	mib[0] = CTL_NET;
3225e39b809Smartijn 	mib[1] = PF_ROUTE;
3235e39b809Smartijn 	mib[2] = 0;
3245e39b809Smartijn 	mib[3] = 0;
3255e39b809Smartijn 	mib[4] = NET_RT_TABLE;
3265e39b809Smartijn 	mib[5] = rtableid;
3275e39b809Smartijn 
3285e39b809Smartijn 	len = sizeof(info);
3295e39b809Smartijn 	if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
3305e39b809Smartijn 		if (errno == ENOENT)
3315e39b809Smartijn 			/* table nonexistent */
3325e39b809Smartijn 			return (0);
3335e39b809Smartijn 		log_warn("%s: sysctl", __func__);
3345e39b809Smartijn 		/* must return 0 so that the table is considered non-existent */
3355e39b809Smartijn 		return (0);
3365e39b809Smartijn 	}
3375e39b809Smartijn 	if (rdomid)
3385e39b809Smartijn 		*rdomid = info.rti_domainid;
3395e39b809Smartijn 	return (1);
3405e39b809Smartijn }
3415e39b809Smartijn 
3425e39b809Smartijn void
kr_shutdown(void)3435e39b809Smartijn kr_shutdown(void)
3445e39b809Smartijn {
3455e39b809Smartijn 	u_int	i;
3465e39b809Smartijn 
3475e39b809Smartijn 	for (i = krt_size; i > 0; i--)
3485e39b809Smartijn 		ktable_free(i - 1);
3495e39b809Smartijn 	kif_clear();
3505e39b809Smartijn }
3515e39b809Smartijn 
3525e39b809Smartijn u_int
kr_ifnumber(void)3535e39b809Smartijn kr_ifnumber(void)
3545e39b809Smartijn {
3555e39b809Smartijn 	return (kr_state.ks_nkif);
3565e39b809Smartijn }
3575e39b809Smartijn 
3585e39b809Smartijn u_long
kr_iflastchange(void)3595e39b809Smartijn kr_iflastchange(void)
3605e39b809Smartijn {
3615e39b809Smartijn 	return (kr_state.ks_iflastchange);
3625e39b809Smartijn }
3635e39b809Smartijn 
3645e39b809Smartijn int
kr_updateif(u_int if_index)3655e39b809Smartijn kr_updateif(u_int if_index)
3665e39b809Smartijn {
3675e39b809Smartijn 	return (fetchifs(if_index));
3685e39b809Smartijn }
3695e39b809Smartijn 
3705e39b809Smartijn u_long
kr_routenumber(void)3715e39b809Smartijn kr_routenumber(void)
3725e39b809Smartijn {
3735e39b809Smartijn 	return (kr_state.ks_nroutes);
3745e39b809Smartijn }
3755e39b809Smartijn 
3765e39b809Smartijn /* rb-tree compare */
3775e39b809Smartijn int
kroute_compare(struct kroute_node * a,struct kroute_node * b)3785e39b809Smartijn kroute_compare(struct kroute_node *a, struct kroute_node *b)
3795e39b809Smartijn {
3805e39b809Smartijn 	if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
3815e39b809Smartijn 		return (-1);
3825e39b809Smartijn 	if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
3835e39b809Smartijn 		return (1);
3845e39b809Smartijn 	if (a->r.prefixlen < b->r.prefixlen)
3855e39b809Smartijn 		return (-1);
3865e39b809Smartijn 	if (a->r.prefixlen > b->r.prefixlen)
3875e39b809Smartijn 		return (1);
3885e39b809Smartijn 
3895e39b809Smartijn 	/* if the priority is RTP_ANY finish on the first address hit */
3905e39b809Smartijn 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
3915e39b809Smartijn 		return (0);
3925e39b809Smartijn 	if (a->r.priority < b->r.priority)
3935e39b809Smartijn 		return (-1);
3945e39b809Smartijn 	if (a->r.priority > b->r.priority)
3955e39b809Smartijn 		return (1);
3965e39b809Smartijn 	return (0);
3975e39b809Smartijn }
3985e39b809Smartijn 
3995e39b809Smartijn int
kroute6_compare(struct kroute6_node * a,struct kroute6_node * b)4005e39b809Smartijn kroute6_compare(struct kroute6_node *a, struct kroute6_node *b)
4015e39b809Smartijn {
4025e39b809Smartijn 	int i;
4035e39b809Smartijn 
4045e39b809Smartijn 	for (i = 0; i < 16; i++) {
4055e39b809Smartijn 		if (a->r.prefix.s6_addr[i] < b->r.prefix.s6_addr[i])
4065e39b809Smartijn 			return (-1);
4075e39b809Smartijn 		if (a->r.prefix.s6_addr[i] > b->r.prefix.s6_addr[i])
4085e39b809Smartijn 			return (1);
4095e39b809Smartijn 	}
4105e39b809Smartijn 
4115e39b809Smartijn 	if (a->r.prefixlen < b->r.prefixlen)
4125e39b809Smartijn 		return (-1);
4135e39b809Smartijn 	if (a->r.prefixlen > b->r.prefixlen)
4145e39b809Smartijn 		return (1);
4155e39b809Smartijn 
4165e39b809Smartijn 	/* if the priority is RTP_ANY finish on the first address hit */
4175e39b809Smartijn 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
4185e39b809Smartijn 		return (0);
4195e39b809Smartijn 	if (a->r.priority < b->r.priority)
4205e39b809Smartijn 		return (-1);
4215e39b809Smartijn 	if (a->r.priority > b->r.priority)
4225e39b809Smartijn 		return (1);
4235e39b809Smartijn 	return (0);
4245e39b809Smartijn }
4255e39b809Smartijn 
4265e39b809Smartijn int
kif_compare(struct kif_node * a,struct kif_node * b)4275e39b809Smartijn kif_compare(struct kif_node *a, struct kif_node *b)
4285e39b809Smartijn {
4295e39b809Smartijn 	return (a->k.if_index - b->k.if_index);
4305e39b809Smartijn }
4315e39b809Smartijn 
4325e39b809Smartijn int
ka_compare(struct kif_addr * a,struct kif_addr * b)4335e39b809Smartijn ka_compare(struct kif_addr *a, struct kif_addr *b)
4345e39b809Smartijn {
4355e39b809Smartijn 	if (a->addr.sa.sa_family < b->addr.sa.sa_family)
4365e39b809Smartijn 		return (-1);
4375e39b809Smartijn 	if (a->addr.sa.sa_family > b->addr.sa.sa_family)
4385e39b809Smartijn 		return (1);
4395e39b809Smartijn 	return (memcmp(&a->addr.sa, &b->addr.sa, a->addr.sa.sa_len));
4405e39b809Smartijn }
4415e39b809Smartijn 
4425e39b809Smartijn /* tree management */
4435e39b809Smartijn struct kroute_node *
kroute_find(struct ktable * kt,in_addr_t prefix,u_int8_t prefixlen,u_int8_t prio)4445e39b809Smartijn kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen,
4455e39b809Smartijn     u_int8_t prio)
4465e39b809Smartijn {
4475e39b809Smartijn 	struct kroute_node	s;
4485e39b809Smartijn 	struct kroute_node	*kn, *tmp;
4495e39b809Smartijn 
4505e39b809Smartijn 	s.r.prefix.s_addr = prefix;
4515e39b809Smartijn 	s.r.prefixlen = prefixlen;
4525e39b809Smartijn 	s.r.priority = prio;
4535e39b809Smartijn 
4545e39b809Smartijn 	kn = RB_FIND(kroute_tree, &kt->krt, &s);
4555e39b809Smartijn 	if (kn && prio == RTP_ANY) {
4565e39b809Smartijn 		tmp = RB_PREV(kroute_tree, &kt->krt, kn);
4575e39b809Smartijn 		while (tmp) {
4585e39b809Smartijn 			if (kroute_compare(&s, tmp) == 0)
4595e39b809Smartijn 				kn = tmp;
4605e39b809Smartijn 			else
4615e39b809Smartijn 				break;
4625e39b809Smartijn 			tmp = RB_PREV(kroute_tree, &kt->krt, kn);
4635e39b809Smartijn 		}
4645e39b809Smartijn 	}
4655e39b809Smartijn 	return (kn);
4665e39b809Smartijn }
4675e39b809Smartijn 
4685e39b809Smartijn struct kroute_node *
kroute_matchgw(struct kroute_node * kr,struct sockaddr_in * sa_in)4695e39b809Smartijn kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
4705e39b809Smartijn {
4715e39b809Smartijn 	in_addr_t	nexthop;
4725e39b809Smartijn 
4735e39b809Smartijn 	if (sa_in == NULL) {
4745e39b809Smartijn 		log_warnx("%s: no nexthop defined", __func__);
4755e39b809Smartijn 		return (NULL);
4765e39b809Smartijn 	}
4775e39b809Smartijn 	nexthop = sa_in->sin_addr.s_addr;
4785e39b809Smartijn 
4795e39b809Smartijn 	while (kr) {
4805e39b809Smartijn 		if (kr->r.nexthop.s_addr == nexthop)
4815e39b809Smartijn 			return (kr);
4825e39b809Smartijn 		kr = kr->next;
4835e39b809Smartijn 	}
4845e39b809Smartijn 
4855e39b809Smartijn 	return (NULL);
4865e39b809Smartijn }
4875e39b809Smartijn 
4885e39b809Smartijn int
kroute_insert(struct ktable * kt,struct kroute_node * kr)4895e39b809Smartijn kroute_insert(struct ktable *kt, struct kroute_node *kr)
4905e39b809Smartijn {
4915e39b809Smartijn 	struct kroute_node	*krm;
4925e39b809Smartijn 
4935e39b809Smartijn 	if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) {
4945e39b809Smartijn 		/* multipath route, add at end of list */
4955e39b809Smartijn 		while (krm->next != NULL)
4965e39b809Smartijn 			krm = krm->next;
4975e39b809Smartijn 		krm->next = kr;
4985e39b809Smartijn 		kr->next = NULL; /* to be sure */
4995e39b809Smartijn 	}
5005e39b809Smartijn 
5015e39b809Smartijn 	kr_state.ks_nroutes++;
5025e39b809Smartijn 	return (0);
5035e39b809Smartijn }
5045e39b809Smartijn 
5055e39b809Smartijn int
kroute_remove(struct ktable * kt,struct kroute_node * kr)5065e39b809Smartijn kroute_remove(struct ktable *kt, struct kroute_node *kr)
5075e39b809Smartijn {
5085e39b809Smartijn 	struct kroute_node	*krm;
5095e39b809Smartijn 
5105e39b809Smartijn 	if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) {
5115e39b809Smartijn 		log_warnx("%s: failed to find %s/%u", __func__,
5125e39b809Smartijn 		    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
5135e39b809Smartijn 		return (-1);
5145e39b809Smartijn 	}
5155e39b809Smartijn 
5165e39b809Smartijn 	if (krm == kr) {
5175e39b809Smartijn 		/* head element */
5185e39b809Smartijn 		if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) {
5195e39b809Smartijn 			log_warnx("%s: failed for %s/%u", __func__,
5205e39b809Smartijn 			    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
5215e39b809Smartijn 			return (-1);
5225e39b809Smartijn 		}
5235e39b809Smartijn 		if (kr->next != NULL) {
5245e39b809Smartijn 			if (RB_INSERT(kroute_tree, &kt->krt, kr->next)
5255e39b809Smartijn 			    != NULL) {
5265e39b809Smartijn 				log_warnx("%s: failed to add %s/%u", __func__,
5275e39b809Smartijn 				    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
5285e39b809Smartijn 				return (-1);
5295e39b809Smartijn 			}
5305e39b809Smartijn 		}
5315e39b809Smartijn 	} else {
5325e39b809Smartijn 		/* somewhere in the list */
5335e39b809Smartijn 		while (krm->next != kr && krm->next != NULL)
5345e39b809Smartijn 			krm = krm->next;
5355e39b809Smartijn 		if (krm->next == NULL) {
5365e39b809Smartijn 			log_warnx("%s: multipath list corrupted for %s/%u",
5375e39b809Smartijn 			    __func__, inet_ntoa(kr->r.prefix), kr->r.prefixlen);
5385e39b809Smartijn 			return (-1);
5395e39b809Smartijn 		}
5405e39b809Smartijn 		krm->next = kr->next;
5415e39b809Smartijn 	}
5425e39b809Smartijn 
5435e39b809Smartijn 	kr_state.ks_nroutes--;
5445e39b809Smartijn 	free(kr);
5455e39b809Smartijn 	return (0);
5465e39b809Smartijn }
5475e39b809Smartijn 
5485e39b809Smartijn void
kroute_clear(struct ktable * kt)5495e39b809Smartijn kroute_clear(struct ktable *kt)
5505e39b809Smartijn {
5515e39b809Smartijn 	struct kroute_node	*kr;
5525e39b809Smartijn 
5535e39b809Smartijn 	while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL)
5545e39b809Smartijn 		kroute_remove(kt, kr);
5555e39b809Smartijn }
5565e39b809Smartijn 
5575e39b809Smartijn struct kroute6_node *
kroute6_find(struct ktable * kt,const struct in6_addr * prefix,u_int8_t prefixlen,u_int8_t prio)5585e39b809Smartijn kroute6_find(struct ktable *kt, const struct in6_addr *prefix,
5595e39b809Smartijn     u_int8_t prefixlen, u_int8_t prio)
5605e39b809Smartijn {
5615e39b809Smartijn 	struct kroute6_node	s;
5625e39b809Smartijn 	struct kroute6_node	*kn6, *tmp;
5635e39b809Smartijn 
5645e39b809Smartijn 	memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr));
5655e39b809Smartijn 	s.r.prefixlen = prefixlen;
5665e39b809Smartijn 	s.r.priority = prio;
5675e39b809Smartijn 
5685e39b809Smartijn 	kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s);
5695e39b809Smartijn 	if (kn6 && prio == RTP_ANY) {
5705e39b809Smartijn 		tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
5715e39b809Smartijn 		while (tmp) {
5725e39b809Smartijn 			if (kroute6_compare(&s, tmp) == 0)
5735e39b809Smartijn 				kn6 = tmp;
5745e39b809Smartijn 			else
5755e39b809Smartijn 				break;
5765e39b809Smartijn 			tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
5775e39b809Smartijn 		}
5785e39b809Smartijn 	}
5795e39b809Smartijn 	return (kn6);
5805e39b809Smartijn }
5815e39b809Smartijn 
5825e39b809Smartijn struct kroute6_node *
kroute6_matchgw(struct kroute6_node * kr,struct sockaddr_in6 * sa_in6)5835e39b809Smartijn kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
5845e39b809Smartijn {
5855e39b809Smartijn 	struct in6_addr	nexthop;
5865e39b809Smartijn 
5875e39b809Smartijn 	if (sa_in6 == NULL) {
5885e39b809Smartijn 		log_warnx("%s: no nexthop defined", __func__);
5895e39b809Smartijn 		return (NULL);
5905e39b809Smartijn 	}
5915e39b809Smartijn 	memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
5925e39b809Smartijn 
5935e39b809Smartijn 	while (kr) {
5945e39b809Smartijn 		if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
5955e39b809Smartijn 			return (kr);
5965e39b809Smartijn 		kr = kr->next;
5975e39b809Smartijn 	}
5985e39b809Smartijn 
5995e39b809Smartijn 	return (NULL);
6005e39b809Smartijn }
6015e39b809Smartijn 
6025e39b809Smartijn int
kroute6_insert(struct ktable * kt,struct kroute6_node * kr)6035e39b809Smartijn kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
6045e39b809Smartijn {
6055e39b809Smartijn 	struct kroute6_node	*krm;
6065e39b809Smartijn 
6075e39b809Smartijn 	if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) {
6085e39b809Smartijn 		/* multipath route, add at end of list */
6095e39b809Smartijn 		while (krm->next != NULL)
6105e39b809Smartijn 			krm = krm->next;
6115e39b809Smartijn 		krm->next = kr;
6125e39b809Smartijn 		kr->next = NULL; /* to be sure */
6135e39b809Smartijn 	}
6145e39b809Smartijn 
6155e39b809Smartijn 	kr_state.ks_nroutes++;
6165e39b809Smartijn 	return (0);
6175e39b809Smartijn }
6185e39b809Smartijn 
6195e39b809Smartijn int
kroute6_remove(struct ktable * kt,struct kroute6_node * kr)6205e39b809Smartijn kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
6215e39b809Smartijn {
6225e39b809Smartijn 	struct kroute6_node	*krm;
6235e39b809Smartijn 
6245e39b809Smartijn 	if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) {
6255e39b809Smartijn 		log_warnx("%s: failed for %s/%u", __func__,
6265e39b809Smartijn 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
6275e39b809Smartijn 		return (-1);
6285e39b809Smartijn 	}
6295e39b809Smartijn 
6305e39b809Smartijn 	if (krm == kr) {
6315e39b809Smartijn 		/* head element */
6325e39b809Smartijn 		if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) {
6335e39b809Smartijn 			log_warnx("%s: failed for %s/%u", __func__,
6345e39b809Smartijn 			    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
6355e39b809Smartijn 			return (-1);
6365e39b809Smartijn 		}
6375e39b809Smartijn 		if (kr->next != NULL) {
6385e39b809Smartijn 			if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) !=
6395e39b809Smartijn 			    NULL) {
6405e39b809Smartijn 				log_warnx("%s: failed to add %s/%u", __func__,
6415e39b809Smartijn 				    log_in6addr(&kr->r.prefix),
6425e39b809Smartijn 				    kr->r.prefixlen);
6435e39b809Smartijn 				return (-1);
6445e39b809Smartijn 			}
6455e39b809Smartijn 		}
6465e39b809Smartijn 	} else {
6475e39b809Smartijn 		/* somewhere in the list */
6485e39b809Smartijn 		while (krm->next != kr && krm->next != NULL)
6495e39b809Smartijn 			krm = krm->next;
6505e39b809Smartijn 		if (krm->next == NULL) {
6515e39b809Smartijn 			log_warnx("%s: multipath list corrupted for %s/%u",
6525e39b809Smartijn 			    __func__, log_in6addr(&kr->r.prefix),
6535e39b809Smartijn 			    kr->r.prefixlen);
6545e39b809Smartijn 			return (-1);
6555e39b809Smartijn 		}
6565e39b809Smartijn 		krm->next = kr->next;
6575e39b809Smartijn 	}
6585e39b809Smartijn 
6595e39b809Smartijn 	kr_state.ks_nroutes--;
6605e39b809Smartijn 	free(kr);
6615e39b809Smartijn 	return (0);
6625e39b809Smartijn }
6635e39b809Smartijn 
6645e39b809Smartijn void
kroute6_clear(struct ktable * kt)6655e39b809Smartijn kroute6_clear(struct ktable *kt)
6665e39b809Smartijn {
6675e39b809Smartijn 	struct kroute6_node	*kr;
6685e39b809Smartijn 
6695e39b809Smartijn 	while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL)
6705e39b809Smartijn 		kroute6_remove(kt, kr);
6715e39b809Smartijn }
6725e39b809Smartijn 
6735e39b809Smartijn static inline int
karp_compare(struct kif_arp * a,struct kif_arp * b)6745e39b809Smartijn karp_compare(struct kif_arp *a, struct kif_arp *b)
6755e39b809Smartijn {
6765e39b809Smartijn 	/* Interface indices are assumed equal */
6775e39b809Smartijn 	if (ntohl(a->addr.sin.sin_addr.s_addr) >
6785e39b809Smartijn 	    ntohl(b->addr.sin.sin_addr.s_addr))
6795e39b809Smartijn 		return (1);
6805e39b809Smartijn 	if (ntohl(a->addr.sin.sin_addr.s_addr) <
6815e39b809Smartijn 	    ntohl(b->addr.sin.sin_addr.s_addr))
6825e39b809Smartijn 		return (-1);
6835e39b809Smartijn 	return (0);
6845e39b809Smartijn }
6855e39b809Smartijn 
6865e39b809Smartijn static inline struct kif_arp *
karp_search(struct kif_node * kn,struct kif_arp * ka)6875e39b809Smartijn karp_search(struct kif_node *kn, struct kif_arp *ka)
6885e39b809Smartijn {
6895e39b809Smartijn 	struct kif_arp		*pivot;
6905e39b809Smartijn 
6915e39b809Smartijn 	TAILQ_FOREACH(pivot, &kn->arps, entry) {
6925e39b809Smartijn 		switch (karp_compare(ka, pivot)) {
6935e39b809Smartijn 		case 0: /* found */
6945e39b809Smartijn 			return (pivot);
6955e39b809Smartijn 		case -1: /* ka < pivot, end the search */
6965e39b809Smartijn 			return (NULL);
6975e39b809Smartijn 		}
6985e39b809Smartijn 	}
6995e39b809Smartijn 	/* looped through the whole list and didn't find */
7005e39b809Smartijn 	return (NULL);
7015e39b809Smartijn }
7025e39b809Smartijn 
7035e39b809Smartijn struct kif_arp *
karp_find(struct sockaddr * sa,u_short ifindex)7045e39b809Smartijn karp_find(struct sockaddr *sa, u_short ifindex)
7055e39b809Smartijn {
7065e39b809Smartijn 	struct kif_node		*kn;
7075e39b809Smartijn 	struct kif_arp		*ka = NULL, s;
7085e39b809Smartijn 
7095e39b809Smartijn 	memcpy(&s.addr.sa, sa, sa->sa_len);
7105e39b809Smartijn 
7115e39b809Smartijn 	if (ifindex == 0) {
7125e39b809Smartijn 		/*
7135e39b809Smartijn 		 * We iterate manually to handle zero ifindex special
7145e39b809Smartijn 		 * case differently from kif_find, in particular we
7155e39b809Smartijn 		 * want to look for the address on all available
7165e39b809Smartijn 		 * interfaces.
7175e39b809Smartijn 		 */
7185e39b809Smartijn 		RB_FOREACH(kn, kif_tree, &kit) {
7195e39b809Smartijn 			if ((ka = karp_search(kn, &s)) != NULL)
7205e39b809Smartijn 				break;
7215e39b809Smartijn 		}
7225e39b809Smartijn 	} else {
7235e39b809Smartijn 		if ((kn = kif_find(ifindex)) == NULL)
7245e39b809Smartijn 			return (NULL);
7255e39b809Smartijn 		ka = karp_search(kn, &s);
7265e39b809Smartijn 	}
7275e39b809Smartijn 	return (ka);
7285e39b809Smartijn }
7295e39b809Smartijn 
7305e39b809Smartijn int
karp_insert(struct kif_node * kn,struct kif_arp * ka)7315e39b809Smartijn karp_insert(struct kif_node *kn, struct kif_arp *ka)
7325e39b809Smartijn {
7335e39b809Smartijn 	struct kif_arp		*pivot;
7345e39b809Smartijn 
7355e39b809Smartijn 	if (ka->if_index == 0)
7365e39b809Smartijn 		return (-1);
7375e39b809Smartijn 	if (!kn && (kn = kif_find(ka->if_index)) == NULL)
7385e39b809Smartijn 		return (-1);
7395e39b809Smartijn 	/* Put entry on the list in the ascending lexical order */
7405e39b809Smartijn 	TAILQ_FOREACH(pivot, &kn->arps, entry) {
7415e39b809Smartijn 		switch (karp_compare(ka, pivot)) {
7425e39b809Smartijn 		case 0: /* collision */
7435e39b809Smartijn 			return (-1);
7445e39b809Smartijn 		case -1: /* ka < pivot */
7455e39b809Smartijn 			TAILQ_INSERT_BEFORE(pivot, ka, entry);
7465e39b809Smartijn 			return (0);
7475e39b809Smartijn 		}
7485e39b809Smartijn 	}
7495e39b809Smartijn 	/* ka is larger than any other element on the list */
7505e39b809Smartijn 	TAILQ_INSERT_TAIL(&kn->arps, ka, entry);
7515e39b809Smartijn 	return (0);
7525e39b809Smartijn }
7535e39b809Smartijn 
7545e39b809Smartijn int
karp_remove(struct kif_node * kn,struct kif_arp * ka)7555e39b809Smartijn karp_remove(struct kif_node *kn, struct kif_arp *ka)
7565e39b809Smartijn {
7575e39b809Smartijn 	if (ka->if_index == 0)
7585e39b809Smartijn 		return (-1);
7595e39b809Smartijn 	if (!kn && (kn = kif_find(ka->if_index)) == NULL)
7605e39b809Smartijn 		return (-1);
7615e39b809Smartijn 	TAILQ_REMOVE(&kn->arps, ka, entry);
7625e39b809Smartijn 	free(ka);
7635e39b809Smartijn 	return (0);
7645e39b809Smartijn }
7655e39b809Smartijn 
7665e39b809Smartijn struct kif_arp *
karp_first(u_short ifindex)7675e39b809Smartijn karp_first(u_short ifindex)
7685e39b809Smartijn {
7695e39b809Smartijn 	struct kif_node		*kn;
7705e39b809Smartijn 
7715e39b809Smartijn 	if ((kn = kif_find(ifindex)) == NULL)
7725e39b809Smartijn 		return (NULL);
7735e39b809Smartijn 	return (TAILQ_FIRST(&kn->arps));
7745e39b809Smartijn }
7755e39b809Smartijn 
7765e39b809Smartijn struct kif_arp *
karp_getaddr(struct sockaddr * sa,u_short ifindex,int next)7775e39b809Smartijn karp_getaddr(struct sockaddr *sa, u_short ifindex, int next)
7785e39b809Smartijn {
7795e39b809Smartijn 	struct kif_arp		*ka;
7805e39b809Smartijn 
7815e39b809Smartijn 	if ((ka = karp_find(sa, ifindex)) == NULL)
7825e39b809Smartijn 		return (NULL);
7835e39b809Smartijn 	return (next ? TAILQ_NEXT(ka, entry) : ka);
7845e39b809Smartijn }
7855e39b809Smartijn 
7865e39b809Smartijn struct kif_node *
kif_find(u_short if_index)7875e39b809Smartijn kif_find(u_short if_index)
7885e39b809Smartijn {
7895e39b809Smartijn 	struct kif_node	s;
7905e39b809Smartijn 
7915e39b809Smartijn 	if (if_index == 0)
7925e39b809Smartijn 		return (RB_MIN(kif_tree, &kit));
7935e39b809Smartijn 
7945e39b809Smartijn 	bzero(&s, sizeof(s));
7955e39b809Smartijn 	s.k.if_index = if_index;
7965e39b809Smartijn 
7975e39b809Smartijn 	return (RB_FIND(kif_tree, &kit, &s));
7985e39b809Smartijn }
7995e39b809Smartijn 
8005e39b809Smartijn struct kif *
kr_getif(u_short if_index)8015e39b809Smartijn kr_getif(u_short if_index)
8025e39b809Smartijn {
8035e39b809Smartijn 	struct kif_node	*kn;
8045e39b809Smartijn 
8055e39b809Smartijn 	kn = kif_find(if_index);
8065e39b809Smartijn 	if (kn == NULL)
8075e39b809Smartijn 		return (NULL);
8085e39b809Smartijn 
8095e39b809Smartijn 	return (&kn->k);
8105e39b809Smartijn }
8115e39b809Smartijn 
8125e39b809Smartijn struct kif *
kr_getnextif(u_short if_index)8135e39b809Smartijn kr_getnextif(u_short if_index)
8145e39b809Smartijn {
8155e39b809Smartijn 	struct kif_node	*kn;
8165e39b809Smartijn 
8175e39b809Smartijn 	if ((kn = kif_find(if_index)) == NULL)
8185e39b809Smartijn 		return (NULL);
8195e39b809Smartijn 	if (if_index)
8205e39b809Smartijn 		kn = RB_NEXT(kif_tree, &kit, kn);
8215e39b809Smartijn 	if (kn == NULL)
8225e39b809Smartijn 		return (NULL);
8235e39b809Smartijn 
8245e39b809Smartijn 	return (&kn->k);
8255e39b809Smartijn }
8265e39b809Smartijn 
8275e39b809Smartijn struct kif_node *
kif_insert(u_short if_index)8285e39b809Smartijn kif_insert(u_short if_index)
8295e39b809Smartijn {
8305e39b809Smartijn 	struct kif_node	*kif;
8315e39b809Smartijn 
8325e39b809Smartijn 	if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
8335e39b809Smartijn 		return (NULL);
8345e39b809Smartijn 
8355e39b809Smartijn 	kif->k.if_index = if_index;
8365e39b809Smartijn 	TAILQ_INIT(&kif->addrs);
8375e39b809Smartijn 	TAILQ_INIT(&kif->arps);
8385e39b809Smartijn 
8395e39b809Smartijn 	if (RB_INSERT(kif_tree, &kit, kif) != NULL)
8405e39b809Smartijn 		fatalx("kif_insert: RB_INSERT");
8415e39b809Smartijn 
8425e39b809Smartijn 	kr_state.ks_nkif++;
8435e39b809Smartijn 	kr_state.ks_iflastchange = smi_getticks();
8445e39b809Smartijn 
8455e39b809Smartijn 	return (kif);
8465e39b809Smartijn }
8475e39b809Smartijn 
8485e39b809Smartijn int
kif_remove(struct kif_node * kif)8495e39b809Smartijn kif_remove(struct kif_node *kif)
8505e39b809Smartijn {
8515e39b809Smartijn 	struct kif_addr	*ka;
8525e39b809Smartijn 	struct kif_arp	*kr;
8535e39b809Smartijn 
8545e39b809Smartijn 	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
8555e39b809Smartijn 		log_warnx("%s: RB_REMOVE failed", __func__);
8565e39b809Smartijn 		return (-1);
8575e39b809Smartijn 	}
8585e39b809Smartijn 
8595e39b809Smartijn 	while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
8605e39b809Smartijn 		TAILQ_REMOVE(&kif->addrs, ka, entry);
8615e39b809Smartijn 		ka_remove(ka);
8625e39b809Smartijn 	}
8635e39b809Smartijn 	while ((kr = TAILQ_FIRST(&kif->arps)) != NULL) {
8645e39b809Smartijn 		karp_remove(kif, kr);
8655e39b809Smartijn 	}
8665e39b809Smartijn 	free(kif);
8675e39b809Smartijn 
8685e39b809Smartijn 	kr_state.ks_nkif--;
8695e39b809Smartijn 	kr_state.ks_iflastchange = smi_getticks();
8705e39b809Smartijn 
8715e39b809Smartijn 	return (0);
8725e39b809Smartijn }
8735e39b809Smartijn 
8745e39b809Smartijn void
kif_clear(void)8755e39b809Smartijn kif_clear(void)
8765e39b809Smartijn {
8775e39b809Smartijn 	struct kif_node	*kif;
8785e39b809Smartijn 
8795e39b809Smartijn 	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
8805e39b809Smartijn 		kif_remove(kif);
8815e39b809Smartijn 	kr_state.ks_nkif = 0;
8825e39b809Smartijn 	kr_state.ks_iflastchange = smi_getticks();
8835e39b809Smartijn }
8845e39b809Smartijn 
8855e39b809Smartijn struct kif *
kif_update(u_short if_index,int flags,struct if_data * ifd,struct sockaddr_dl * sdl)8865e39b809Smartijn kif_update(u_short if_index, int flags, struct if_data *ifd,
8875e39b809Smartijn     struct sockaddr_dl *sdl)
8885e39b809Smartijn {
8895e39b809Smartijn 	struct kif_node		*kif;
8905e39b809Smartijn 	struct ether_addr	*ea;
8915e39b809Smartijn 	struct ifreq		 ifr;
8925e39b809Smartijn 
8935e39b809Smartijn 	if ((kif = kif_find(if_index)) == NULL)
8945e39b809Smartijn 		if ((kif = kif_insert(if_index)) == NULL)
8955e39b809Smartijn 			return (NULL);
8965e39b809Smartijn 
8975e39b809Smartijn 	kif->k.if_flags = flags;
8985e39b809Smartijn 	bcopy(ifd, &kif->k.if_data, sizeof(struct if_data));
8995e39b809Smartijn 	kif->k.if_ticks = smi_getticks();
9005e39b809Smartijn 
9015e39b809Smartijn 	if (sdl && sdl->sdl_family == AF_LINK) {
9025e39b809Smartijn 		if (sdl->sdl_nlen >= sizeof(kif->k.if_name))
9035e39b809Smartijn 			memcpy(kif->k.if_name, sdl->sdl_data,
9045e39b809Smartijn 			    sizeof(kif->k.if_name) - 1);
9055e39b809Smartijn 		else if (sdl->sdl_nlen > 0)
9065e39b809Smartijn 			memcpy(kif->k.if_name, sdl->sdl_data,
9075e39b809Smartijn 			    sdl->sdl_nlen);
9085e39b809Smartijn 		/* string already terminated via calloc() */
9095e39b809Smartijn 
9105e39b809Smartijn 		if ((ea = (struct ether_addr *)LLADDR(sdl)) != NULL)
9115e39b809Smartijn 			bcopy(&ea->ether_addr_octet, kif->k.if_lladdr,
9125e39b809Smartijn 			    ETHER_ADDR_LEN);
9135e39b809Smartijn 	}
9145e39b809Smartijn 
9155e39b809Smartijn 	bzero(&ifr, sizeof(ifr));
9165e39b809Smartijn 	strlcpy(ifr.ifr_name, kif->k.if_name, sizeof(ifr.ifr_name));
9175e39b809Smartijn 	ifr.ifr_data = (caddr_t)&kif->k.if_descr;
9185e39b809Smartijn 	if (ioctl(kr_state.ks_ifd, SIOCGIFDESCR, &ifr) == -1)
9195e39b809Smartijn 		bzero(&kif->k.if_descr, sizeof(kif->k.if_descr));
9205e39b809Smartijn 
9215e39b809Smartijn 	return (&kif->k);
9225e39b809Smartijn }
9235e39b809Smartijn 
9245e39b809Smartijn void
ka_insert(u_short if_index,struct kif_addr * ka)9255e39b809Smartijn ka_insert(u_short if_index, struct kif_addr *ka)
9265e39b809Smartijn {
9275e39b809Smartijn 	if (ka->addr.sa.sa_len == 0)
9285e39b809Smartijn 		return;
9295e39b809Smartijn 
9305e39b809Smartijn 	ka->if_index = if_index;
9315e39b809Smartijn 	RB_INSERT(ka_tree, &kat, ka);
9325e39b809Smartijn }
9335e39b809Smartijn 
9345e39b809Smartijn struct kif_addr	*
ka_find(struct sockaddr * sa)9355e39b809Smartijn ka_find(struct sockaddr *sa)
9365e39b809Smartijn {
9375e39b809Smartijn 	struct kif_addr		ka;
9385e39b809Smartijn 
9395e39b809Smartijn 	if (sa == NULL)
9405e39b809Smartijn 		return (RB_MIN(ka_tree, &kat));
9415e39b809Smartijn 	bzero(&ka.addr, sizeof(ka.addr));
9425e39b809Smartijn 	bcopy(sa, &ka.addr.sa, sa->sa_len);
9435e39b809Smartijn 	return (RB_FIND(ka_tree, &kat, &ka));
9445e39b809Smartijn }
9455e39b809Smartijn 
9465e39b809Smartijn int
ka_remove(struct kif_addr * ka)9475e39b809Smartijn ka_remove(struct kif_addr *ka)
9485e39b809Smartijn {
9495e39b809Smartijn 	RB_REMOVE(ka_tree, &kat, ka);
9505e39b809Smartijn 	free(ka);
9515e39b809Smartijn 	return (0);
9525e39b809Smartijn }
9535e39b809Smartijn 
9545e39b809Smartijn struct kif_addr *
kr_getaddr(struct sockaddr * sa)9555e39b809Smartijn kr_getaddr(struct sockaddr *sa)
9565e39b809Smartijn {
9575e39b809Smartijn 	return (ka_find(sa));
9585e39b809Smartijn }
9595e39b809Smartijn 
9605e39b809Smartijn struct kif_addr *
kr_getnextaddr(struct sockaddr * sa)9615e39b809Smartijn kr_getnextaddr(struct sockaddr *sa)
9625e39b809Smartijn {
9635e39b809Smartijn 	struct kif_addr	ka;
9645e39b809Smartijn 
9655e39b809Smartijn 	bzero(&ka.addr, sizeof(ka.addr));
9665e39b809Smartijn 	bcopy(sa, &ka.addr.sa, sa->sa_len);
9675e39b809Smartijn 	return RB_NFIND(ka_tree, &kat, &ka);
9685e39b809Smartijn }
9695e39b809Smartijn 
9705e39b809Smartijn /* misc */
9715e39b809Smartijn u_int8_t
prefixlen_classful(in_addr_t ina)9725e39b809Smartijn prefixlen_classful(in_addr_t ina)
9735e39b809Smartijn {
9745e39b809Smartijn 	/* it hurt to write this. */
9755e39b809Smartijn 
9765e39b809Smartijn 	if (ina >= 0xf0000000U)		/* class E */
9775e39b809Smartijn 		return (32);
9785e39b809Smartijn 	else if (ina >= 0xe0000000U)	/* class D */
9795e39b809Smartijn 		return (4);
9805e39b809Smartijn 	else if (ina >= 0xc0000000U)	/* class C */
9815e39b809Smartijn 		return (24);
9825e39b809Smartijn 	else if (ina >= 0x80000000U)	/* class B */
9835e39b809Smartijn 		return (16);
9845e39b809Smartijn 	else				/* class A */
9855e39b809Smartijn 		return (8);
9865e39b809Smartijn }
9875e39b809Smartijn 
9885e39b809Smartijn u_int8_t
mask2prefixlen(in_addr_t ina)9895e39b809Smartijn mask2prefixlen(in_addr_t ina)
9905e39b809Smartijn {
9915e39b809Smartijn 	if (ina == 0)
9925e39b809Smartijn 		return (0);
9935e39b809Smartijn 	else
9945e39b809Smartijn 		return (33 - ffs(ntohl(ina)));
9955e39b809Smartijn }
9965e39b809Smartijn 
9975e39b809Smartijn in_addr_t
prefixlen2mask(u_int8_t prefixlen)9985e39b809Smartijn prefixlen2mask(u_int8_t prefixlen)
9995e39b809Smartijn {
10005e39b809Smartijn 	if (prefixlen == 0)
10015e39b809Smartijn 		return (0);
10025e39b809Smartijn 
10035e39b809Smartijn 	return (htonl(0xffffffff << (32 - prefixlen)));
10045e39b809Smartijn }
10055e39b809Smartijn 
10065e39b809Smartijn u_int8_t
mask2prefixlen6(struct sockaddr_in6 * sa_in6)10075e39b809Smartijn mask2prefixlen6(struct sockaddr_in6 *sa_in6)
10085e39b809Smartijn {
10095e39b809Smartijn 	unsigned int	 l = 0;
10105e39b809Smartijn 	u_int8_t	*ap, *ep;
10115e39b809Smartijn 
10125e39b809Smartijn 	/*
10136d9ddefdSjmc 	 * sin6_len is the size of the sockaddr so subtract the offset of
10145e39b809Smartijn 	 * the possibly truncated sin6_addr struct.
10155e39b809Smartijn 	 */
10165e39b809Smartijn 	ap = (u_int8_t *)&sa_in6->sin6_addr;
10175e39b809Smartijn 	ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
10185e39b809Smartijn 	for (; ap < ep; ap++) {
10195e39b809Smartijn 		/* this "beauty" is adopted from sbin/route/show.c ... */
10205e39b809Smartijn 		switch (*ap) {
10215e39b809Smartijn 		case 0xff:
10225e39b809Smartijn 			l += 8;
10235e39b809Smartijn 			break;
10245e39b809Smartijn 		case 0xfe:
10255e39b809Smartijn 			l += 7;
10265e39b809Smartijn 			goto done;
10275e39b809Smartijn 		case 0xfc:
10285e39b809Smartijn 			l += 6;
10295e39b809Smartijn 			goto done;
10305e39b809Smartijn 		case 0xf8:
10315e39b809Smartijn 			l += 5;
10325e39b809Smartijn 			goto done;
10335e39b809Smartijn 		case 0xf0:
10345e39b809Smartijn 			l += 4;
10355e39b809Smartijn 			goto done;
10365e39b809Smartijn 		case 0xe0:
10375e39b809Smartijn 			l += 3;
10385e39b809Smartijn 			goto done;
10395e39b809Smartijn 		case 0xc0:
10405e39b809Smartijn 			l += 2;
10415e39b809Smartijn 			goto done;
10425e39b809Smartijn 		case 0x80:
10435e39b809Smartijn 			l += 1;
10445e39b809Smartijn 			goto done;
10455e39b809Smartijn 		case 0x00:
10465e39b809Smartijn 			goto done;
10475e39b809Smartijn 		default:
10485e39b809Smartijn 			fatalx("non contiguous inet6 netmask");
10495e39b809Smartijn 		}
10505e39b809Smartijn 	}
10515e39b809Smartijn 
10525e39b809Smartijn done:
10535e39b809Smartijn 	if (l > sizeof(struct in6_addr) * 8)
10545e39b809Smartijn 		fatalx("inet6 prefixlen out of bound");
10555e39b809Smartijn 	return (l);
10565e39b809Smartijn }
10575e39b809Smartijn 
10585e39b809Smartijn struct in6_addr *
prefixlen2mask6(u_int8_t prefixlen)10595e39b809Smartijn prefixlen2mask6(u_int8_t prefixlen)
10605e39b809Smartijn {
10615e39b809Smartijn 	static struct in6_addr	mask;
10625e39b809Smartijn 	int			i;
10635e39b809Smartijn 
10645e39b809Smartijn 	bzero(&mask, sizeof(mask));
10655e39b809Smartijn 	for (i = 0; i < prefixlen / 8; i++)
10665e39b809Smartijn 		mask.s6_addr[i] = 0xff;
10675e39b809Smartijn 	i = prefixlen % 8;
10685e39b809Smartijn 	if (i)
10695e39b809Smartijn 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
10705e39b809Smartijn 
10715e39b809Smartijn 	return (&mask);
10725e39b809Smartijn }
10735e39b809Smartijn 
10745e39b809Smartijn #define ROUNDUP(a) \
10755e39b809Smartijn 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
10765e39b809Smartijn 
10775e39b809Smartijn void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)10785e39b809Smartijn get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
10795e39b809Smartijn {
10805e39b809Smartijn 	int	i;
10815e39b809Smartijn 
10825e39b809Smartijn 	for (i = 0; i < RTAX_MAX; i++) {
10835e39b809Smartijn 		if (addrs & (1 << i)) {
10845e39b809Smartijn 			rti_info[i] = sa;
10855e39b809Smartijn 			sa = (struct sockaddr *)((char *)(sa) +
10865e39b809Smartijn 			    ROUNDUP(sa->sa_len));
10875e39b809Smartijn 		} else
10885e39b809Smartijn 			rti_info[i] = NULL;
10895e39b809Smartijn 
10905e39b809Smartijn 	}
10915e39b809Smartijn }
10925e39b809Smartijn 
10935e39b809Smartijn void
if_change(u_short if_index,int flags,struct if_data * ifd,struct sockaddr_dl * sdl)10945e39b809Smartijn if_change(u_short if_index, int flags, struct if_data *ifd,
10955e39b809Smartijn     struct sockaddr_dl *sdl)
10965e39b809Smartijn {
10975e39b809Smartijn 	if (kif_update(if_index, flags, ifd, sdl) == NULL)
10985e39b809Smartijn 		log_warn("%s: interface %u update failed", __func__, if_index);
10995e39b809Smartijn }
11005e39b809Smartijn 
11015e39b809Smartijn void
if_newaddr(u_short if_index,struct sockaddr * ifa,struct sockaddr * mask,struct sockaddr * brd)11025e39b809Smartijn if_newaddr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
11035e39b809Smartijn     struct sockaddr *brd)
11045e39b809Smartijn {
11055e39b809Smartijn 	struct kif_node *kif;
11065e39b809Smartijn 	struct kif_addr *ka;
11075e39b809Smartijn 
11085e39b809Smartijn 	if (ifa == NULL)
11095e39b809Smartijn 		return;
11105e39b809Smartijn 	if ((kif = kif_find(if_index)) == NULL) {
11115e39b809Smartijn 		log_warnx("%s: corresponding if %u not found", __func__,
11125e39b809Smartijn 		    if_index);
11135e39b809Smartijn 		return;
11145e39b809Smartijn 	}
11155e39b809Smartijn 	if ((ka = ka_find(ifa)) == NULL) {
11165e39b809Smartijn 		if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
11175e39b809Smartijn 			fatal("if_newaddr");
11185e39b809Smartijn 		bcopy(ifa, &ka->addr.sa, ifa->sa_len);
11195e39b809Smartijn 		TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
11205e39b809Smartijn 		ka_insert(if_index, ka);
11215e39b809Smartijn 	}
11225e39b809Smartijn 
11235e39b809Smartijn 	if (mask)
11245e39b809Smartijn 		bcopy(mask, &ka->mask.sa, mask->sa_len);
11255e39b809Smartijn 	else
11265e39b809Smartijn 		bzero(&ka->mask, sizeof(ka->mask));
11275e39b809Smartijn 	if (brd)
11285e39b809Smartijn 		bcopy(brd, &ka->dstbrd.sa, brd->sa_len);
11295e39b809Smartijn 	else
11305e39b809Smartijn 		bzero(&ka->dstbrd, sizeof(ka->dstbrd));
11315e39b809Smartijn }
11325e39b809Smartijn 
11335e39b809Smartijn void
if_deladdr(u_short if_index,struct sockaddr * ifa,struct sockaddr * mask,struct sockaddr * brd)11345e39b809Smartijn if_deladdr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
11355e39b809Smartijn     struct sockaddr *brd)
11365e39b809Smartijn {
11375e39b809Smartijn 	struct kif_node *kif;
11385e39b809Smartijn 	struct kif_addr *ka;
11395e39b809Smartijn 
11405e39b809Smartijn 	if (ifa == NULL)
11415e39b809Smartijn 		return;
11425e39b809Smartijn 	if ((kif = kif_find(if_index)) == NULL) {
11435e39b809Smartijn 		log_warnx("%s: corresponding if %u not found", __func__,
11445e39b809Smartijn 		    if_index);
11455e39b809Smartijn 		return;
11465e39b809Smartijn 	}
11475e39b809Smartijn 	if ((ka = ka_find(ifa)) == NULL)
11485e39b809Smartijn 		return;
11495e39b809Smartijn 
11505e39b809Smartijn 	TAILQ_REMOVE(&kif->addrs, ka, entry);
11515e39b809Smartijn 	ka_remove(ka);
11525e39b809Smartijn }
11535e39b809Smartijn 
11545e39b809Smartijn void
if_announce(void * msg)11555e39b809Smartijn if_announce(void *msg)
11565e39b809Smartijn {
11575e39b809Smartijn 	struct if_announcemsghdr	*ifan;
11585e39b809Smartijn 	struct kif_node			*kif;
11595e39b809Smartijn 
11605e39b809Smartijn 	ifan = msg;
11615e39b809Smartijn 
11625e39b809Smartijn 	switch (ifan->ifan_what) {
11635e39b809Smartijn 	case IFAN_ARRIVAL:
11645e39b809Smartijn 		kif = kif_insert(ifan->ifan_index);
11655e39b809Smartijn 		strlcpy(kif->k.if_name, ifan->ifan_name,
11665e39b809Smartijn 		    sizeof(kif->k.if_name));
11675e39b809Smartijn 		break;
11685e39b809Smartijn 	case IFAN_DEPARTURE:
11695e39b809Smartijn 		kif = kif_find(ifan->ifan_index);
11705e39b809Smartijn 		kif_remove(kif);
11715e39b809Smartijn 		break;
11725e39b809Smartijn 	}
11735e39b809Smartijn }
11745e39b809Smartijn 
11755e39b809Smartijn int
fetchtable(struct ktable * kt)11765e39b809Smartijn fetchtable(struct ktable *kt)
11775e39b809Smartijn {
11785e39b809Smartijn 	int			 mib[7];
11795e39b809Smartijn 	size_t			 len;
11805e39b809Smartijn 	char			*buf;
11815e39b809Smartijn 	int			 rv;
11825e39b809Smartijn 
11835e39b809Smartijn 	mib[0] = CTL_NET;
11845e39b809Smartijn 	mib[1] = PF_ROUTE;
11855e39b809Smartijn 	mib[2] = 0;
11865e39b809Smartijn 	mib[3] = AF_INET;
11875e39b809Smartijn 	mib[4] = NET_RT_DUMP;
11885e39b809Smartijn 	mib[5] = 0;
11895e39b809Smartijn 	mib[6] = kt->rtableid;
11905e39b809Smartijn 
11915e39b809Smartijn 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
11925e39b809Smartijn 		if (kt->rtableid != 0 && errno == EINVAL)
11935e39b809Smartijn 			/* table nonexistent */
11945e39b809Smartijn 			return (0);
11955e39b809Smartijn 		log_warn("%s: failed to fetch routing table %u size", __func__,
11965e39b809Smartijn 		    kt->rtableid);
11975e39b809Smartijn 		return (-1);
11985e39b809Smartijn 	}
11995e39b809Smartijn 	if (len == 0)
12005e39b809Smartijn 		return (0);
12015e39b809Smartijn 	if ((buf = malloc(len)) == NULL) {
12025e39b809Smartijn 		log_warn("%s: malloc", __func__);
12035e39b809Smartijn 		return (-1);
12045e39b809Smartijn 	}
12055e39b809Smartijn 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
12065e39b809Smartijn 		log_warn("%s: failed to fetch routing table %u", __func__,
12075e39b809Smartijn 		    kt->rtableid);
12085e39b809Smartijn 		free(buf);
12095e39b809Smartijn 		return (-1);
12105e39b809Smartijn 	}
12115e39b809Smartijn 
12125e39b809Smartijn 	rv = rtmsg_process(buf, len);
12135e39b809Smartijn 	free(buf);
12145e39b809Smartijn 
12155e39b809Smartijn 	return (rv);
12165e39b809Smartijn }
12175e39b809Smartijn 
12185e39b809Smartijn int
fetchifs(u_short if_index)12195e39b809Smartijn fetchifs(u_short if_index)
12205e39b809Smartijn {
12215e39b809Smartijn 	size_t			 len;
12225e39b809Smartijn 	int			 mib[6];
12235e39b809Smartijn 	char			*buf;
12245e39b809Smartijn 	int			 rv;
12255e39b809Smartijn 
12265e39b809Smartijn 	mib[0] = CTL_NET;
12275e39b809Smartijn 	mib[1] = PF_ROUTE;
12285e39b809Smartijn 	mib[2] = 0;
12295e39b809Smartijn 	mib[3] = 0;	/* wildcard address family */
12305e39b809Smartijn 	mib[4] = NET_RT_IFLIST;
12315e39b809Smartijn 	mib[5] = if_index;
12325e39b809Smartijn 
12335e39b809Smartijn 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
12345e39b809Smartijn 		log_warn("%s: failed to fetch address table size for %u",
12355e39b809Smartijn 		    __func__, if_index);
12365e39b809Smartijn 		return (-1);
12375e39b809Smartijn 	}
12385e39b809Smartijn 	if ((buf = malloc(len)) == NULL) {
12395e39b809Smartijn 		log_warn("%s: malloc", __func__);
12405e39b809Smartijn 		return (-1);
12415e39b809Smartijn 	}
12425e39b809Smartijn 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
12435e39b809Smartijn 		log_warn("%s: failed to fetch address table for %u",
12445e39b809Smartijn 		    __func__, if_index);
12455e39b809Smartijn 		free(buf);
12465e39b809Smartijn 		return (-1);
12475e39b809Smartijn 	}
12485e39b809Smartijn 
12495e39b809Smartijn 	rv = rtmsg_process(buf, len);
12505e39b809Smartijn 	free(buf);
12515e39b809Smartijn 
12525e39b809Smartijn 	return (rv);
12535e39b809Smartijn }
12545e39b809Smartijn 
12555e39b809Smartijn int
fetcharp(struct ktable * kt)12565e39b809Smartijn fetcharp(struct ktable *kt)
12575e39b809Smartijn {
12585e39b809Smartijn 	size_t			 len;
12595e39b809Smartijn 	int			 mib[7];
12605e39b809Smartijn 	char			*buf;
12615e39b809Smartijn 	int			 rv;
12625e39b809Smartijn 
12635e39b809Smartijn 	mib[0] = CTL_NET;
12645e39b809Smartijn 	mib[1] = PF_ROUTE;
12655e39b809Smartijn 	mib[2] = 0;
12665e39b809Smartijn 	mib[3] = AF_INET;
12675e39b809Smartijn 	mib[4] = NET_RT_FLAGS;
12685e39b809Smartijn 	mib[5] = RTF_LLINFO;
12695e39b809Smartijn 	mib[6] = kt->rtableid;
12705e39b809Smartijn 
12715e39b809Smartijn 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
12725e39b809Smartijn 		log_warn("%s: failed to fetch arp table %u size", __func__,
12735e39b809Smartijn 		    kt->rtableid);
12745e39b809Smartijn 		return (-1);
12755e39b809Smartijn 	}
12765e39b809Smartijn 	/* Empty table? */
12775e39b809Smartijn 	if (len == 0)
12785e39b809Smartijn 		return (0);
12795e39b809Smartijn 	if ((buf = malloc(len)) == NULL) {
12805e39b809Smartijn 		log_warn("%s: malloc", __func__);
12815e39b809Smartijn 		return (-1);
12825e39b809Smartijn 	}
12835e39b809Smartijn 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
12845e39b809Smartijn 		log_warn("%s: failed to fetch arp table %u", __func__,
12855e39b809Smartijn 		    kt->rtableid);
12865e39b809Smartijn 		free(buf);
12875e39b809Smartijn 		return (-1);
12885e39b809Smartijn 	}
12895e39b809Smartijn 
12905e39b809Smartijn 	rv = rtmsg_process(buf, len);
12915e39b809Smartijn 	free(buf);
12925e39b809Smartijn 
12935e39b809Smartijn 	return (rv);
12945e39b809Smartijn }
12955e39b809Smartijn 
12965e39b809Smartijn void
dispatch_rtmsg(int fd,short event,void * arg)12975e39b809Smartijn dispatch_rtmsg(int fd, short event, void *arg)
12985e39b809Smartijn {
12995e39b809Smartijn 	char			 buf[RT_BUF_SIZE];
13005e39b809Smartijn 	ssize_t			 n;
13015e39b809Smartijn 
13025e39b809Smartijn 	if ((n = read(fd, &buf, sizeof(buf))) == -1) {
13035e39b809Smartijn 		log_warn("%s: read error", __func__);
13045e39b809Smartijn 		return;
13055e39b809Smartijn 	}
13065e39b809Smartijn 
13075e39b809Smartijn 	if (n == 0) {
13085e39b809Smartijn 		log_warnx("%s: routing socket closed", __func__);
13095e39b809Smartijn 		return;
13105e39b809Smartijn 	}
13115e39b809Smartijn 
13125e39b809Smartijn 	rtmsg_process(buf, n);
13135e39b809Smartijn }
13145e39b809Smartijn 
13155e39b809Smartijn int
rtmsg_process(char * buf,int len)13165e39b809Smartijn rtmsg_process(char *buf, int len)
13175e39b809Smartijn {
13185e39b809Smartijn 	struct ktable		*kt;
13195e39b809Smartijn 	struct rt_msghdr	*rtm;
13205e39b809Smartijn 	struct if_msghdr	 ifm;
13215e39b809Smartijn 	struct ifa_msghdr	*ifam;
13225e39b809Smartijn 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
13235e39b809Smartijn 	int			 offset;
13245e39b809Smartijn 	char			*next;
13255e39b809Smartijn 
13265e39b809Smartijn 	for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
13275e39b809Smartijn 		next = buf + offset;
13285e39b809Smartijn 		rtm = (struct rt_msghdr *)next;
13295e39b809Smartijn 		if (rtm->rtm_version != RTM_VERSION)
13305e39b809Smartijn 			continue;
13315e39b809Smartijn 
13325e39b809Smartijn 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
13335e39b809Smartijn 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
13345e39b809Smartijn 
13355e39b809Smartijn 		switch (rtm->rtm_type) {
13365e39b809Smartijn 		case RTM_ADD:
13375e39b809Smartijn 		case RTM_GET:
13385e39b809Smartijn 		case RTM_CHANGE:
13395e39b809Smartijn 		case RTM_DELETE:
13405e39b809Smartijn 		case RTM_RESOLVE:
13415e39b809Smartijn 			if (rtm->rtm_errno)		 /* failed attempts */
13425e39b809Smartijn 				continue;
13435e39b809Smartijn 
13445e39b809Smartijn 			if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
13455e39b809Smartijn 				continue;
13465e39b809Smartijn 
13475e39b809Smartijn 			if (dispatch_rtmsg_addr(kt, rtm, rti_info) == -1)
13485e39b809Smartijn 				return (-1);
13495e39b809Smartijn 			break;
13505e39b809Smartijn 		case RTM_IFINFO:
13515e39b809Smartijn 			memcpy(&ifm, next, sizeof(ifm));
13525e39b809Smartijn 			if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
13535e39b809Smartijn 			    (struct sockaddr_dl *)rti_info[RTAX_IFP]);
13545e39b809Smartijn 			break;
13555e39b809Smartijn 		case RTM_DELADDR:
13565e39b809Smartijn 			ifam = (struct ifa_msghdr *)rtm;
13575e39b809Smartijn 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
13585e39b809Smartijn 			    RTA_BRD)) == 0)
13595e39b809Smartijn 				break;
13605e39b809Smartijn 
13615e39b809Smartijn 			if_deladdr(ifam->ifam_index, rti_info[RTAX_IFA],
13625e39b809Smartijn 			    rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
13635e39b809Smartijn 			break;
13645e39b809Smartijn 		case RTM_NEWADDR:
13655e39b809Smartijn 			ifam = (struct ifa_msghdr *)rtm;
13665e39b809Smartijn 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
13675e39b809Smartijn 			    RTA_BRD)) == 0)
13685e39b809Smartijn 				break;
13695e39b809Smartijn 
13705e39b809Smartijn 			if_newaddr(ifam->ifam_index, rti_info[RTAX_IFA],
13715e39b809Smartijn 			    rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
13725e39b809Smartijn 			break;
13735e39b809Smartijn 		case RTM_IFANNOUNCE:
13745e39b809Smartijn 			if_announce(next);
13755e39b809Smartijn 			break;
13765e39b809Smartijn 		case RTM_DESYNC:
13775e39b809Smartijn 			kr_shutdown();
13785e39b809Smartijn 			if (fetchifs(0) == -1)
13795e39b809Smartijn 				fatalx("rtmsg_process: fetchifs");
13805e39b809Smartijn 			ktable_init();
13815e39b809Smartijn 			break;
13825e39b809Smartijn 		default:
13835e39b809Smartijn 			/* ignore for now */
13845e39b809Smartijn 			break;
13855e39b809Smartijn 		}
13865e39b809Smartijn 	}
13875e39b809Smartijn 
13885e39b809Smartijn 	return (offset);
13895e39b809Smartijn }
13905e39b809Smartijn 
13915e39b809Smartijn int
dispatch_rtmsg_addr(struct ktable * kt,struct rt_msghdr * rtm,struct sockaddr * rti_info[RTAX_MAX])13925e39b809Smartijn dispatch_rtmsg_addr(struct ktable *kt, struct rt_msghdr *rtm,
13935e39b809Smartijn     struct sockaddr *rti_info[RTAX_MAX])
13945e39b809Smartijn {
13955e39b809Smartijn 	struct sockaddr		*sa, *psa;
13965e39b809Smartijn 	struct sockaddr_in	*sa_in, *psa_in = NULL;
13975e39b809Smartijn 	struct sockaddr_in6	*sa_in6, *psa_in6 = NULL;
13985e39b809Smartijn 	struct sockaddr_dl	*sa_dl;
13995e39b809Smartijn 	struct kroute_node	*kr;
14005e39b809Smartijn 	struct kroute6_node	*kr6;
14015e39b809Smartijn 	struct kif_arp		*ka;
14025e39b809Smartijn 	int			 flags, mpath = 0;
14035e39b809Smartijn 	u_int16_t		 ifindex;
14045e39b809Smartijn 	u_int8_t		 prefixlen;
14055e39b809Smartijn 	u_int8_t		 prio;
14065e39b809Smartijn 
14075e39b809Smartijn 	flags = 0;
14085e39b809Smartijn 	ifindex = 0;
14095e39b809Smartijn 	prefixlen = 0;
14105e39b809Smartijn 
14115e39b809Smartijn 	if ((psa = rti_info[RTAX_DST]) == NULL)
14125e39b809Smartijn 		return (-1);
14135e39b809Smartijn 
14145e39b809Smartijn 	if (rtm->rtm_flags & RTF_STATIC)
14155e39b809Smartijn 		flags |= F_STATIC;
14165e39b809Smartijn 	if (rtm->rtm_flags & RTF_BLACKHOLE)
14175e39b809Smartijn 		flags |= F_BLACKHOLE;
14185e39b809Smartijn 	if (rtm->rtm_flags & RTF_REJECT)
14195e39b809Smartijn 		flags |= F_REJECT;
14205e39b809Smartijn 	if (rtm->rtm_flags & RTF_DYNAMIC)
14215e39b809Smartijn 		flags |= F_DYNAMIC;
14225e39b809Smartijn #ifdef RTF_MPATH
14235e39b809Smartijn 	if (rtm->rtm_flags & RTF_MPATH)
14245e39b809Smartijn 		mpath = 1;
14255e39b809Smartijn #endif
14265e39b809Smartijn 
14275e39b809Smartijn 	prio = rtm->rtm_priority;
14285e39b809Smartijn 	switch (psa->sa_family) {
14295e39b809Smartijn 	case AF_INET:
14305e39b809Smartijn 		psa_in = (struct sockaddr_in *)psa;
14315e39b809Smartijn 		sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
14325e39b809Smartijn 		if (sa_in != NULL) {
14335e39b809Smartijn 			if (sa_in->sin_len != 0)
14345e39b809Smartijn 				prefixlen = mask2prefixlen(
14355e39b809Smartijn 				    sa_in->sin_addr.s_addr);
14365e39b809Smartijn 		} else if (rtm->rtm_flags & RTF_HOST)
14375e39b809Smartijn 			prefixlen = 32;
14385e39b809Smartijn 		else
14395e39b809Smartijn 			prefixlen =
14405e39b809Smartijn 			    prefixlen_classful(psa_in->sin_addr.s_addr);
14415e39b809Smartijn 		break;
14425e39b809Smartijn 	case AF_INET6:
14435e39b809Smartijn 		psa_in6 = (struct sockaddr_in6 *)psa;
14445e39b809Smartijn 		sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
14455e39b809Smartijn 		if (sa_in6 != NULL) {
14465e39b809Smartijn 			if (sa_in6->sin6_len != 0)
14475e39b809Smartijn 				prefixlen = mask2prefixlen6(sa_in6);
14485e39b809Smartijn 		} else if (rtm->rtm_flags & RTF_HOST)
14495e39b809Smartijn 			prefixlen = 128;
14505e39b809Smartijn 		else
14515e39b809Smartijn 			fatalx("in6 net addr without netmask");
14525e39b809Smartijn 		break;
14535e39b809Smartijn 	default:
14545e39b809Smartijn 		return (0);
14555e39b809Smartijn 	}
14565e39b809Smartijn 
14575e39b809Smartijn 	if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
14585e39b809Smartijn 		switch (sa->sa_family) {
14595e39b809Smartijn 		case AF_INET:
14605e39b809Smartijn 		case AF_INET6:
14615e39b809Smartijn 			if (rtm->rtm_flags & RTF_CONNECTED) {
14625e39b809Smartijn 				flags |= F_CONNECTED;
14635e39b809Smartijn 				ifindex = rtm->rtm_index;
14645e39b809Smartijn 			}
14655e39b809Smartijn 			mpath = 0;	/* link local stuff can't be mpath */
14665e39b809Smartijn 			break;
14675e39b809Smartijn 		case AF_LINK:
14685e39b809Smartijn 			/*
14695e39b809Smartijn 			 * Traditional BSD connected routes have
14705e39b809Smartijn 			 * a gateway of type AF_LINK.
14715e39b809Smartijn 			 */
14725e39b809Smartijn 			flags |= F_CONNECTED;
14735e39b809Smartijn 			ifindex = rtm->rtm_index;
14745e39b809Smartijn 			mpath = 0;	/* link local stuff can't be mpath */
14755e39b809Smartijn 			break;
14765e39b809Smartijn 		}
14775e39b809Smartijn 
14785e39b809Smartijn 	if (rtm->rtm_type == RTM_DELETE) {
14795e39b809Smartijn 		if (sa != NULL && sa->sa_family == AF_LINK &&
14805e39b809Smartijn 		    (rtm->rtm_flags & RTF_HOST) &&
14815e39b809Smartijn 		    psa->sa_family == AF_INET) {
14825e39b809Smartijn 			if ((ka = karp_find(psa, ifindex)) == NULL)
14835e39b809Smartijn 				return (0);
14845e39b809Smartijn 			if (karp_remove(NULL, ka) == -1)
14855e39b809Smartijn 				return (-1);
14865e39b809Smartijn 			return (0);
14875e39b809Smartijn 		} else if (sa == NULL && (rtm->rtm_flags & RTF_HOST) &&
14885e39b809Smartijn 		    psa->sa_family == AF_INET) {
14895e39b809Smartijn 			if ((ka = karp_find(psa, ifindex)) != NULL)
14905e39b809Smartijn 				karp_remove(NULL, ka);
14915e39b809Smartijn 			/* Continue to the route section below  */
14925e39b809Smartijn 		}
14935e39b809Smartijn 		switch (psa->sa_family) {
14945e39b809Smartijn 		case AF_INET:
14955e39b809Smartijn 			sa_in = (struct sockaddr_in *)sa;
14965e39b809Smartijn 			if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr,
14975e39b809Smartijn 			    prefixlen, prio)) == NULL)
14985e39b809Smartijn 				return (0);
14995e39b809Smartijn 
15005e39b809Smartijn 			if (mpath)
15015e39b809Smartijn 				/* get the correct route */
15025e39b809Smartijn 				if ((kr = kroute_matchgw(kr, sa_in)) == NULL) {
15035e39b809Smartijn 					log_warnx("%s[delete]: "
15045e39b809Smartijn 					    "mpath route not found", __func__);
15055e39b809Smartijn 					return (0);
15065e39b809Smartijn 				}
15075e39b809Smartijn 
15085e39b809Smartijn 			if (kroute_remove(kt, kr) == -1)
15095e39b809Smartijn 				return (-1);
15105e39b809Smartijn 			break;
15115e39b809Smartijn 		case AF_INET6:
15125e39b809Smartijn 			sa_in6 = (struct sockaddr_in6 *)sa;
15135e39b809Smartijn 			if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr,
15145e39b809Smartijn 			    prefixlen, prio)) == NULL)
15155e39b809Smartijn 				return (0);
15165e39b809Smartijn 
15175e39b809Smartijn 			if (mpath)
15185e39b809Smartijn 				/* get the correct route */
15195e39b809Smartijn 				if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
15205e39b809Smartijn 				    NULL) {
15215e39b809Smartijn 					log_warnx("%s[delete]: "
15225e39b809Smartijn 					    "IPv6 mpath route not found",
15235e39b809Smartijn 					    __func__);
15245e39b809Smartijn 					return (0);
15255e39b809Smartijn 				}
15265e39b809Smartijn 
15275e39b809Smartijn 			if (kroute6_remove(kt, kr6) == -1)
15285e39b809Smartijn 				return (-1);
15295e39b809Smartijn 			break;
15305e39b809Smartijn 		}
15315e39b809Smartijn 		return (0);
15325e39b809Smartijn 	}
15335e39b809Smartijn 
15345e39b809Smartijn 	if (sa == NULL && !(flags & F_CONNECTED))
15355e39b809Smartijn 		return (0);
15365e39b809Smartijn 
15375e39b809Smartijn 	/* Add or update an ARP entry */
15385e39b809Smartijn 	if ((rtm->rtm_flags & RTF_LLINFO) && (rtm->rtm_flags & RTF_HOST) &&
15395e39b809Smartijn 	    sa != NULL && sa->sa_family == AF_LINK &&
15405e39b809Smartijn 	    psa->sa_family == AF_INET) {
15415e39b809Smartijn 		sa_dl = (struct sockaddr_dl *)sa;
15425e39b809Smartijn 		/* ignore incomplete entries */
15435e39b809Smartijn 		if (!sa_dl->sdl_alen)
15445e39b809Smartijn 			return (0);
15455e39b809Smartijn 		/* ignore entries that do not specify an interface */
15465e39b809Smartijn 		if (ifindex == 0)
15475e39b809Smartijn 			return (0);
15485e39b809Smartijn 		if ((ka = karp_find(psa, ifindex)) != NULL) {
15495e39b809Smartijn 			memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
15505e39b809Smartijn 			if (rtm->rtm_flags & RTF_PERMANENT_ARP)
15515e39b809Smartijn 				flags |= F_STATIC;
15525e39b809Smartijn 			ka->flags = flags;
15535e39b809Smartijn 		} else {
15545e39b809Smartijn 			if ((ka = calloc(1, sizeof(struct kif_arp))) == NULL) {
15555e39b809Smartijn 				log_warn("%s: calloc", __func__);
15565e39b809Smartijn 				return (-1);
15575e39b809Smartijn 			}
15585e39b809Smartijn 			memcpy(&ka->addr.sa, psa, psa->sa_len);
15595e39b809Smartijn 			memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
15605e39b809Smartijn 			if (rtm->rtm_flags & RTF_PERMANENT_ARP)
15615e39b809Smartijn 				flags |= F_STATIC;
15625e39b809Smartijn 			ka->flags = flags;
15635e39b809Smartijn 			ka->if_index = ifindex;
15645e39b809Smartijn 			if (karp_insert(NULL, ka)) {
15655e39b809Smartijn 				free(ka);
15665e39b809Smartijn 				log_warnx("%s: failed to insert", __func__);
15675e39b809Smartijn 				return (-1);
15685e39b809Smartijn 			}
15695e39b809Smartijn 		}
15705e39b809Smartijn 		return (0);
15715e39b809Smartijn 	}
15725e39b809Smartijn 
15735e39b809Smartijn 	switch (psa->sa_family) {
15745e39b809Smartijn 	case AF_INET:
15755e39b809Smartijn 		sa_in = (struct sockaddr_in *)sa;
15765e39b809Smartijn 		if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr, prefixlen,
15775e39b809Smartijn 		    prio)) != NULL) {
15785e39b809Smartijn 			/* get the correct route */
15795e39b809Smartijn 			if (mpath && rtm->rtm_type == RTM_CHANGE &&
15805e39b809Smartijn 			    (kr = kroute_matchgw(kr, sa_in)) == NULL) {
15815e39b809Smartijn 				log_warnx("%s[change]: "
15825e39b809Smartijn 				    "mpath route not found", __func__);
15835e39b809Smartijn 				return (-1);
15845e39b809Smartijn 			} else if (mpath && rtm->rtm_type == RTM_ADD)
15855e39b809Smartijn 				goto add4;
15865e39b809Smartijn 
15875e39b809Smartijn 			if (sa_in != NULL)
15885e39b809Smartijn 				kr->r.nexthop.s_addr =
15895e39b809Smartijn 				    sa_in->sin_addr.s_addr;
15905e39b809Smartijn 			else
15915e39b809Smartijn 				kr->r.nexthop.s_addr = 0;
15925e39b809Smartijn 			kr->r.flags = flags;
15935e39b809Smartijn 			kr->r.if_index = ifindex;
15945e39b809Smartijn 			kr->r.ticks = smi_getticks();
15955e39b809Smartijn 		} else {
15965e39b809Smartijn add4:
15975e39b809Smartijn 			if ((kr = calloc(1,
15985e39b809Smartijn 			    sizeof(struct kroute_node))) == NULL) {
15995e39b809Smartijn 				log_warn("%s: calloc", __func__);
16005e39b809Smartijn 				return (-1);
16015e39b809Smartijn 			}
16025e39b809Smartijn 			kr->r.prefix.s_addr = psa_in->sin_addr.s_addr;
16035e39b809Smartijn 			kr->r.prefixlen = prefixlen;
16045e39b809Smartijn 			if (sa_in != NULL)
16055e39b809Smartijn 				kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr;
16065e39b809Smartijn 			else
16075e39b809Smartijn 				kr->r.nexthop.s_addr = 0;
16085e39b809Smartijn 			kr->r.flags = flags;
16095e39b809Smartijn 			kr->r.if_index = ifindex;
16105e39b809Smartijn 			kr->r.ticks = smi_getticks();
16115e39b809Smartijn 			kr->r.priority = prio;
16125e39b809Smartijn 
16135e39b809Smartijn 			kroute_insert(kt, kr);
16145e39b809Smartijn 		}
16155e39b809Smartijn 		break;
16165e39b809Smartijn 	case AF_INET6:
16175e39b809Smartijn 		sa_in6 = (struct sockaddr_in6 *)sa;
16185e39b809Smartijn 		if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr, prefixlen,
16195e39b809Smartijn 		    prio)) != NULL) {
16205e39b809Smartijn 			/* get the correct route */
16215e39b809Smartijn 			if (mpath && rtm->rtm_type == RTM_CHANGE &&
16225e39b809Smartijn 			    (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
16235e39b809Smartijn 			    NULL) {
16245e39b809Smartijn 				log_warnx("%s[change]: "
16255e39b809Smartijn 				    "IPv6 mpath route not found", __func__);
16265e39b809Smartijn 				return (-1);
16275e39b809Smartijn 			} else if (mpath && rtm->rtm_type == RTM_ADD)
16285e39b809Smartijn 				goto add6;
16295e39b809Smartijn 
16305e39b809Smartijn 			if (sa_in6 != NULL)
16315e39b809Smartijn 				memcpy(&kr6->r.nexthop,
16325e39b809Smartijn 				    &sa_in6->sin6_addr,
16335e39b809Smartijn 				    sizeof(struct in6_addr));
16345e39b809Smartijn 			else
16355e39b809Smartijn 				memcpy(&kr6->r.nexthop,
16365e39b809Smartijn 				    &in6addr_any,
16375e39b809Smartijn 				    sizeof(struct in6_addr));
16385e39b809Smartijn 
16395e39b809Smartijn 			kr6->r.flags = flags;
16405e39b809Smartijn 			kr6->r.if_index = ifindex;
16415e39b809Smartijn 			kr6->r.ticks = smi_getticks();
16425e39b809Smartijn 		} else {
16435e39b809Smartijn add6:
16445e39b809Smartijn 			if ((kr6 = calloc(1,
16455e39b809Smartijn 			    sizeof(struct kroute6_node))) == NULL) {
16465e39b809Smartijn 				log_warn("%s: calloc", __func__);
16475e39b809Smartijn 				return (-1);
16485e39b809Smartijn 			}
16495e39b809Smartijn 			memcpy(&kr6->r.prefix, &psa_in6->sin6_addr,
16505e39b809Smartijn 			    sizeof(struct in6_addr));
16515e39b809Smartijn 			kr6->r.prefixlen = prefixlen;
16525e39b809Smartijn 			if (sa_in6 != NULL)
16535e39b809Smartijn 				memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr,
16545e39b809Smartijn 				    sizeof(struct in6_addr));
16555e39b809Smartijn 			else
16565e39b809Smartijn 				memcpy(&kr6->r.nexthop, &in6addr_any,
16575e39b809Smartijn 				    sizeof(struct in6_addr));
16585e39b809Smartijn 			kr6->r.flags = flags;
16595e39b809Smartijn 			kr6->r.if_index = ifindex;
16605e39b809Smartijn 			kr6->r.ticks = smi_getticks();
16615e39b809Smartijn 			kr6->r.priority = prio;
16625e39b809Smartijn 
16635e39b809Smartijn 			kroute6_insert(kt, kr6);
16645e39b809Smartijn 		}
16655e39b809Smartijn 		break;
16665e39b809Smartijn 	}
16675e39b809Smartijn 
16685e39b809Smartijn 	return (0);
16695e39b809Smartijn }
16705e39b809Smartijn 
16715e39b809Smartijn struct kroute *
kroute_first(void)16725e39b809Smartijn kroute_first(void)
16735e39b809Smartijn {
16745e39b809Smartijn 	struct kroute_node	*kn;
16755e39b809Smartijn 	struct ktable		*kt;
16765e39b809Smartijn 
16775e39b809Smartijn 	if ((kt = ktable_get(0)) == NULL)
16785e39b809Smartijn 		return (NULL);
16795e39b809Smartijn 	kn = RB_MIN(kroute_tree, &kt->krt);
16805e39b809Smartijn 	return (&kn->r);
16815e39b809Smartijn }
16825e39b809Smartijn 
16835e39b809Smartijn struct kroute *
kroute_getaddr(in_addr_t prefix,u_int8_t prefixlen,u_int8_t prio,int next)16845e39b809Smartijn kroute_getaddr(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio, int next)
16855e39b809Smartijn {
16865e39b809Smartijn 	struct kroute_node	*kn;
16875e39b809Smartijn 	struct ktable		*kt;
16885e39b809Smartijn 
16895e39b809Smartijn 	if ((kt = ktable_get(0)) == NULL)
16905e39b809Smartijn 		return (NULL);
16915e39b809Smartijn 	kn = kroute_find(kt, prefix, prefixlen, prio);
16925e39b809Smartijn 	if (kn != NULL && next)
16935e39b809Smartijn 		kn = RB_NEXT(kroute_tree, &kt->krt, kn);
16945e39b809Smartijn 	if (kn != NULL)
16955e39b809Smartijn 		return (&kn->r);
16965e39b809Smartijn 	else
16975e39b809Smartijn 		return (NULL);
16985e39b809Smartijn }
1699