15c4d2252SAlexander V. Chernikov /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35c4d2252SAlexander V. Chernikov *
45c4d2252SAlexander V. Chernikov * Copyright (c) 2021-2022 Alexander V. Chernikov
55c4d2252SAlexander V. Chernikov *
65c4d2252SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without
75c4d2252SAlexander V. Chernikov * modification, are permitted provided that the following conditions
85c4d2252SAlexander V. Chernikov * are met:
95c4d2252SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright
105c4d2252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer.
115c4d2252SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright
125c4d2252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the
135c4d2252SAlexander V. Chernikov * documentation and/or other materials provided with the distribution.
145c4d2252SAlexander V. Chernikov *
155c4d2252SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165c4d2252SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175c4d2252SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185c4d2252SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195c4d2252SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205c4d2252SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215c4d2252SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225c4d2252SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235c4d2252SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245c4d2252SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255c4d2252SAlexander V. Chernikov * SUCH DAMAGE.
265c4d2252SAlexander V. Chernikov */
275c4d2252SAlexander V. Chernikov
285c4d2252SAlexander V. Chernikov #include <sys/cdefs.h>
295c4d2252SAlexander V. Chernikov #include "opt_inet.h"
305c4d2252SAlexander V. Chernikov #include "opt_inet6.h"
315c4d2252SAlexander V. Chernikov #include "opt_route.h"
325c4d2252SAlexander V. Chernikov
335c4d2252SAlexander V. Chernikov #include <sys/param.h>
345c4d2252SAlexander V. Chernikov #include <sys/systm.h>
355c4d2252SAlexander V. Chernikov #include <sys/malloc.h>
365c4d2252SAlexander V. Chernikov #include <sys/socket.h>
372cda6a2fSAlexander V. Chernikov #include <sys/jail.h>
385c4d2252SAlexander V. Chernikov #include <sys/kernel.h>
395c4d2252SAlexander V. Chernikov #include <sys/lock.h>
405c4d2252SAlexander V. Chernikov #include <sys/rmlock.h>
415c4d2252SAlexander V. Chernikov
425c4d2252SAlexander V. Chernikov #include <net/if.h>
435c4d2252SAlexander V. Chernikov #include <net/if_var.h>
445c4d2252SAlexander V. Chernikov #include <net/vnet.h>
455c4d2252SAlexander V. Chernikov #include <net/route.h>
465c4d2252SAlexander V. Chernikov #include <net/route/route_ctl.h>
475c4d2252SAlexander V. Chernikov #include <net/route/route_var.h>
485c4d2252SAlexander V. Chernikov #include <net/route/nhop.h>
495c4d2252SAlexander V. Chernikov #include <netinet/in.h>
505c4d2252SAlexander V. Chernikov #include <netinet6/scope6_var.h>
515c4d2252SAlexander V. Chernikov
525c4d2252SAlexander V. Chernikov #include <vm/uma.h>
535c4d2252SAlexander V. Chernikov
545c4d2252SAlexander V. Chernikov /* Routing table UMA zone */
555c4d2252SAlexander V. Chernikov VNET_DEFINE_STATIC(uma_zone_t, rtzone);
565c4d2252SAlexander V. Chernikov #define V_rtzone VNET(rtzone)
575c4d2252SAlexander V. Chernikov
585c4d2252SAlexander V. Chernikov void
vnet_rtzone_init(void)595c4d2252SAlexander V. Chernikov vnet_rtzone_init(void)
605c4d2252SAlexander V. Chernikov {
615c4d2252SAlexander V. Chernikov
625c4d2252SAlexander V. Chernikov V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry),
635c4d2252SAlexander V. Chernikov NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
645c4d2252SAlexander V. Chernikov }
655c4d2252SAlexander V. Chernikov
665c4d2252SAlexander V. Chernikov #ifdef VIMAGE
675c4d2252SAlexander V. Chernikov void
vnet_rtzone_destroy(void)685c4d2252SAlexander V. Chernikov vnet_rtzone_destroy(void)
695c4d2252SAlexander V. Chernikov {
705c4d2252SAlexander V. Chernikov
715c4d2252SAlexander V. Chernikov uma_zdestroy(V_rtzone);
725c4d2252SAlexander V. Chernikov }
735c4d2252SAlexander V. Chernikov #endif
745c4d2252SAlexander V. Chernikov
755c4d2252SAlexander V. Chernikov /*
765c4d2252SAlexander V. Chernikov * Creates rtentry and based on @dst/@netmask data.
775c4d2252SAlexander V. Chernikov * Return 0 and fills in rtentry into @prt on success,
785c4d2252SAlexander V. Chernikov * Note: rtentry mask ptr will be set to @netmask , thus its pointer is required
795c4d2252SAlexander V. Chernikov * to be stable till the end of the operation (radix rt insertion/change/removal).
805c4d2252SAlexander V. Chernikov */
815c4d2252SAlexander V. Chernikov struct rtentry *
rt_alloc(struct rib_head * rnh,const struct sockaddr * dst,struct sockaddr * netmask)825c4d2252SAlexander V. Chernikov rt_alloc(struct rib_head *rnh, const struct sockaddr *dst,
835c4d2252SAlexander V. Chernikov struct sockaddr *netmask)
845c4d2252SAlexander V. Chernikov {
855c4d2252SAlexander V. Chernikov MPASS(dst->sa_len <= sizeof(((struct rtentry *)NULL)->rt_dstb));
865c4d2252SAlexander V. Chernikov
875c4d2252SAlexander V. Chernikov struct rtentry *rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO);
885c4d2252SAlexander V. Chernikov if (rt == NULL)
895c4d2252SAlexander V. Chernikov return (NULL);
905c4d2252SAlexander V. Chernikov rt->rte_flags = RTF_UP | (netmask == NULL ? RTF_HOST : 0);
915c4d2252SAlexander V. Chernikov
925c4d2252SAlexander V. Chernikov /* Fill in dst, ensuring it's masked if needed. */
935c4d2252SAlexander V. Chernikov if (netmask != NULL) {
945c4d2252SAlexander V. Chernikov rt_maskedcopy(dst, &rt->rt_dst, netmask);
955c4d2252SAlexander V. Chernikov } else
965c4d2252SAlexander V. Chernikov bcopy(dst, &rt->rt_dst, dst->sa_len);
975c4d2252SAlexander V. Chernikov rt_key(rt) = &rt->rt_dst;
985c4d2252SAlexander V. Chernikov /* Set netmask to the storage from info. It will be updated upon insertion */
995c4d2252SAlexander V. Chernikov rt_mask(rt) = netmask;
1005c4d2252SAlexander V. Chernikov
1015c4d2252SAlexander V. Chernikov return (rt);
1025c4d2252SAlexander V. Chernikov }
1035c4d2252SAlexander V. Chernikov
1045c4d2252SAlexander V. Chernikov static void
destroy_rtentry(struct rtentry * rt)1055c4d2252SAlexander V. Chernikov destroy_rtentry(struct rtentry *rt)
1065c4d2252SAlexander V. Chernikov {
1075c4d2252SAlexander V. Chernikov #ifdef VIMAGE
1085c4d2252SAlexander V. Chernikov struct nhop_object *nh = rt->rt_nhop;
1095c4d2252SAlexander V. Chernikov
1105c4d2252SAlexander V. Chernikov /*
1115c4d2252SAlexander V. Chernikov * At this moment rnh, nh_control may be already freed.
1125c4d2252SAlexander V. Chernikov * nhop interface may have been migrated to a different vnet.
1135c4d2252SAlexander V. Chernikov * Use vnet stored in the nexthop to delete the entry.
1145c4d2252SAlexander V. Chernikov */
1155c4d2252SAlexander V. Chernikov #ifdef ROUTE_MPATH
1165c4d2252SAlexander V. Chernikov if (NH_IS_NHGRP(nh)) {
1175c4d2252SAlexander V. Chernikov const struct weightened_nhop *wn;
1185c4d2252SAlexander V. Chernikov uint32_t num_nhops;
1195c4d2252SAlexander V. Chernikov wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops);
1205c4d2252SAlexander V. Chernikov nh = wn[0].nh;
1215c4d2252SAlexander V. Chernikov }
1225c4d2252SAlexander V. Chernikov #endif
1235c4d2252SAlexander V. Chernikov CURVNET_SET(nhop_get_vnet(nh));
1245c4d2252SAlexander V. Chernikov #endif
1255c4d2252SAlexander V. Chernikov
1265c4d2252SAlexander V. Chernikov /* Unreference nexthop */
1275c4d2252SAlexander V. Chernikov nhop_free_any(rt->rt_nhop);
1285c4d2252SAlexander V. Chernikov
1295c4d2252SAlexander V. Chernikov rt_free_immediate(rt);
1305c4d2252SAlexander V. Chernikov
1315c4d2252SAlexander V. Chernikov CURVNET_RESTORE();
1325c4d2252SAlexander V. Chernikov }
1335c4d2252SAlexander V. Chernikov
1345c4d2252SAlexander V. Chernikov /*
1355c4d2252SAlexander V. Chernikov * Epoch callback indicating rtentry is safe to destroy
1365c4d2252SAlexander V. Chernikov */
1375c4d2252SAlexander V. Chernikov static void
destroy_rtentry_epoch(epoch_context_t ctx)1385c4d2252SAlexander V. Chernikov destroy_rtentry_epoch(epoch_context_t ctx)
1395c4d2252SAlexander V. Chernikov {
1405c4d2252SAlexander V. Chernikov struct rtentry *rt;
1415c4d2252SAlexander V. Chernikov
1425c4d2252SAlexander V. Chernikov rt = __containerof(ctx, struct rtentry, rt_epoch_ctx);
1435c4d2252SAlexander V. Chernikov
1445c4d2252SAlexander V. Chernikov destroy_rtentry(rt);
1455c4d2252SAlexander V. Chernikov }
1465c4d2252SAlexander V. Chernikov
1475c4d2252SAlexander V. Chernikov /*
1485c4d2252SAlexander V. Chernikov * Schedule rtentry deletion
1495c4d2252SAlexander V. Chernikov */
1505c4d2252SAlexander V. Chernikov void
rt_free(struct rtentry * rt)1515c4d2252SAlexander V. Chernikov rt_free(struct rtentry *rt)
1525c4d2252SAlexander V. Chernikov {
1535c4d2252SAlexander V. Chernikov
1545c4d2252SAlexander V. Chernikov KASSERT(rt != NULL, ("%s: NULL rt", __func__));
1555c4d2252SAlexander V. Chernikov
15673336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_rtentry_epoch, &rt->rt_epoch_ctx);
1575c4d2252SAlexander V. Chernikov }
1585c4d2252SAlexander V. Chernikov
1595c4d2252SAlexander V. Chernikov void
rt_free_immediate(struct rtentry * rt)1605c4d2252SAlexander V. Chernikov rt_free_immediate(struct rtentry *rt)
1615c4d2252SAlexander V. Chernikov {
1625c4d2252SAlexander V. Chernikov uma_zfree(V_rtzone, rt);
1635c4d2252SAlexander V. Chernikov }
1645c4d2252SAlexander V. Chernikov
1655c4d2252SAlexander V. Chernikov bool
rt_is_host(const struct rtentry * rt)1665c4d2252SAlexander V. Chernikov rt_is_host(const struct rtentry *rt)
1675c4d2252SAlexander V. Chernikov {
1685c4d2252SAlexander V. Chernikov
1695c4d2252SAlexander V. Chernikov return (rt->rte_flags & RTF_HOST);
1705c4d2252SAlexander V. Chernikov }
1715c4d2252SAlexander V. Chernikov
1725c4d2252SAlexander V. Chernikov sa_family_t
rt_get_family(const struct rtentry * rt)1735c4d2252SAlexander V. Chernikov rt_get_family(const struct rtentry *rt)
1745c4d2252SAlexander V. Chernikov {
1755c4d2252SAlexander V. Chernikov const struct sockaddr *dst;
1765c4d2252SAlexander V. Chernikov
1775c4d2252SAlexander V. Chernikov dst = (const struct sockaddr *)rt_key_const(rt);
1785c4d2252SAlexander V. Chernikov
1795c4d2252SAlexander V. Chernikov return (dst->sa_family);
1805c4d2252SAlexander V. Chernikov }
1815c4d2252SAlexander V. Chernikov
1825c4d2252SAlexander V. Chernikov /*
1835c4d2252SAlexander V. Chernikov * Returns pointer to nexthop or nexthop group
1845c4d2252SAlexander V. Chernikov * associated with @rt
1855c4d2252SAlexander V. Chernikov */
1865c4d2252SAlexander V. Chernikov struct nhop_object *
rt_get_raw_nhop(const struct rtentry * rt)1875c4d2252SAlexander V. Chernikov rt_get_raw_nhop(const struct rtentry *rt)
1885c4d2252SAlexander V. Chernikov {
1895c4d2252SAlexander V. Chernikov
1905c4d2252SAlexander V. Chernikov return (rt->rt_nhop);
1915c4d2252SAlexander V. Chernikov }
1925c4d2252SAlexander V. Chernikov
193fe05d1ddSAlexander V. Chernikov void
rt_get_rnd(const struct rtentry * rt,struct route_nhop_data * rnd)194fe05d1ddSAlexander V. Chernikov rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd)
195fe05d1ddSAlexander V. Chernikov {
196fe05d1ddSAlexander V. Chernikov rnd->rnd_nhop = rt->rt_nhop;
197fe05d1ddSAlexander V. Chernikov rnd->rnd_weight = rt->rt_weight;
198fe05d1ddSAlexander V. Chernikov }
199fe05d1ddSAlexander V. Chernikov
2002cda6a2fSAlexander V. Chernikov /*
2012cda6a2fSAlexander V. Chernikov * If the process in in jail w/o VNET, export only host routes for the
2022cda6a2fSAlexander V. Chernikov * addresses assigned to the jail.
2032cda6a2fSAlexander V. Chernikov * Otherwise, allow exporting the entire table.
2042cda6a2fSAlexander V. Chernikov */
2052cda6a2fSAlexander V. Chernikov bool
rt_is_exportable(const struct rtentry * rt,struct ucred * cred)2062cda6a2fSAlexander V. Chernikov rt_is_exportable(const struct rtentry *rt, struct ucred *cred)
2072cda6a2fSAlexander V. Chernikov {
2082cda6a2fSAlexander V. Chernikov if (!rt_is_host(rt)) {
2092cda6a2fSAlexander V. Chernikov /*
2102cda6a2fSAlexander V. Chernikov * Performance optimisation: only host routes are allowed
2112cda6a2fSAlexander V. Chernikov * in the jail w/o vnet.
2122cda6a2fSAlexander V. Chernikov */
2132cda6a2fSAlexander V. Chernikov if (jailed_without_vnet(cred))
2142cda6a2fSAlexander V. Chernikov return (false);
2152cda6a2fSAlexander V. Chernikov } else {
2162cda6a2fSAlexander V. Chernikov if (prison_if(cred, rt_key_const(rt)) != 0)
2172cda6a2fSAlexander V. Chernikov return (false);
2182cda6a2fSAlexander V. Chernikov }
2192cda6a2fSAlexander V. Chernikov
2202cda6a2fSAlexander V. Chernikov return (true);
2212cda6a2fSAlexander V. Chernikov }
2222cda6a2fSAlexander V. Chernikov
2235c4d2252SAlexander V. Chernikov #ifdef INET
2245c4d2252SAlexander V. Chernikov /*
2255c4d2252SAlexander V. Chernikov * Stores IPv4 address and prefix length of @rt inside
2265c4d2252SAlexander V. Chernikov * @paddr and @plen.
2275c4d2252SAlexander V. Chernikov * @pscopeid is currently always set to 0.
2285c4d2252SAlexander V. Chernikov */
2295c4d2252SAlexander V. Chernikov void
rt_get_inet_prefix_plen(const struct rtentry * rt,struct in_addr * paddr,int * plen,uint32_t * pscopeid)2305c4d2252SAlexander V. Chernikov rt_get_inet_prefix_plen(const struct rtentry *rt, struct in_addr *paddr,
2315c4d2252SAlexander V. Chernikov int *plen, uint32_t *pscopeid)
2325c4d2252SAlexander V. Chernikov {
2335c4d2252SAlexander V. Chernikov const struct sockaddr_in *dst;
2345c4d2252SAlexander V. Chernikov
2355c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in *)rt_key_const(rt);
2365c4d2252SAlexander V. Chernikov KASSERT((dst->sin_family == AF_INET),
2375c4d2252SAlexander V. Chernikov ("rt family is %d, not inet", dst->sin_family));
2385c4d2252SAlexander V. Chernikov *paddr = dst->sin_addr;
2395c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in *)rt_mask_const(rt);
2405c4d2252SAlexander V. Chernikov if (dst == NULL)
2415c4d2252SAlexander V. Chernikov *plen = 32;
2425c4d2252SAlexander V. Chernikov else
2435c4d2252SAlexander V. Chernikov *plen = bitcount32(dst->sin_addr.s_addr);
2445c4d2252SAlexander V. Chernikov *pscopeid = 0;
2455c4d2252SAlexander V. Chernikov }
2465c4d2252SAlexander V. Chernikov
2475c4d2252SAlexander V. Chernikov /*
2485c4d2252SAlexander V. Chernikov * Stores IPv4 address and prefix mask of @rt inside
2495c4d2252SAlexander V. Chernikov * @paddr and @pmask. Sets mask to INADDR_ANY for host routes.
2505c4d2252SAlexander V. Chernikov * @pscopeid is currently always set to 0.
2515c4d2252SAlexander V. Chernikov */
2525c4d2252SAlexander V. Chernikov void
rt_get_inet_prefix_pmask(const struct rtentry * rt,struct in_addr * paddr,struct in_addr * pmask,uint32_t * pscopeid)2535c4d2252SAlexander V. Chernikov rt_get_inet_prefix_pmask(const struct rtentry *rt, struct in_addr *paddr,
2545c4d2252SAlexander V. Chernikov struct in_addr *pmask, uint32_t *pscopeid)
2555c4d2252SAlexander V. Chernikov {
2565c4d2252SAlexander V. Chernikov const struct sockaddr_in *dst;
2575c4d2252SAlexander V. Chernikov
2585c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in *)rt_key_const(rt);
2595c4d2252SAlexander V. Chernikov KASSERT((dst->sin_family == AF_INET),
2605c4d2252SAlexander V. Chernikov ("rt family is %d, not inet", dst->sin_family));
2615c4d2252SAlexander V. Chernikov *paddr = dst->sin_addr;
2625c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in *)rt_mask_const(rt);
2635c4d2252SAlexander V. Chernikov if (dst == NULL)
2645c4d2252SAlexander V. Chernikov pmask->s_addr = INADDR_BROADCAST;
2655c4d2252SAlexander V. Chernikov else
2665c4d2252SAlexander V. Chernikov *pmask = dst->sin_addr;
2675c4d2252SAlexander V. Chernikov *pscopeid = 0;
2685c4d2252SAlexander V. Chernikov }
2695c4d2252SAlexander V. Chernikov #endif
2705c4d2252SAlexander V. Chernikov
2715c4d2252SAlexander V. Chernikov #ifdef INET6
2725c4d2252SAlexander V. Chernikov static int
inet6_get_plen(const struct in6_addr * addr)2735c4d2252SAlexander V. Chernikov inet6_get_plen(const struct in6_addr *addr)
2745c4d2252SAlexander V. Chernikov {
2755c4d2252SAlexander V. Chernikov
2765c4d2252SAlexander V. Chernikov return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) +
2775c4d2252SAlexander V. Chernikov bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3]));
2785c4d2252SAlexander V. Chernikov }
2795c4d2252SAlexander V. Chernikov
2805c4d2252SAlexander V. Chernikov /*
2815c4d2252SAlexander V. Chernikov * Stores IPv6 address and prefix length of @rt inside
2825c4d2252SAlexander V. Chernikov * @paddr and @plen. Addresses are returned in de-embedded form.
2835c4d2252SAlexander V. Chernikov * Scopeid is set to 0 for non-LL addresses.
2845c4d2252SAlexander V. Chernikov */
2855c4d2252SAlexander V. Chernikov void
rt_get_inet6_prefix_plen(const struct rtentry * rt,struct in6_addr * paddr,int * plen,uint32_t * pscopeid)2865c4d2252SAlexander V. Chernikov rt_get_inet6_prefix_plen(const struct rtentry *rt, struct in6_addr *paddr,
2875c4d2252SAlexander V. Chernikov int *plen, uint32_t *pscopeid)
2885c4d2252SAlexander V. Chernikov {
2895c4d2252SAlexander V. Chernikov const struct sockaddr_in6 *dst;
2905c4d2252SAlexander V. Chernikov
2915c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in6 *)rt_key_const(rt);
2925c4d2252SAlexander V. Chernikov KASSERT((dst->sin6_family == AF_INET6),
2935c4d2252SAlexander V. Chernikov ("rt family is %d, not inet6", dst->sin6_family));
2945c4d2252SAlexander V. Chernikov if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
2955c4d2252SAlexander V. Chernikov in6_splitscope(&dst->sin6_addr, paddr, pscopeid);
2965c4d2252SAlexander V. Chernikov else
2975c4d2252SAlexander V. Chernikov *paddr = dst->sin6_addr;
2985c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in6 *)rt_mask_const(rt);
2995c4d2252SAlexander V. Chernikov if (dst == NULL)
3005c4d2252SAlexander V. Chernikov *plen = 128;
3015c4d2252SAlexander V. Chernikov else
3025c4d2252SAlexander V. Chernikov *plen = inet6_get_plen(&dst->sin6_addr);
3035c4d2252SAlexander V. Chernikov }
3045c4d2252SAlexander V. Chernikov
3055c4d2252SAlexander V. Chernikov /*
3065c4d2252SAlexander V. Chernikov * Stores IPv6 address and prefix mask of @rt inside
3075c4d2252SAlexander V. Chernikov * @paddr and @pmask. Addresses are returned in de-embedded form.
3085c4d2252SAlexander V. Chernikov * Scopeid is set to 0 for non-LL addresses.
3095c4d2252SAlexander V. Chernikov */
3105c4d2252SAlexander V. Chernikov void
rt_get_inet6_prefix_pmask(const struct rtentry * rt,struct in6_addr * paddr,struct in6_addr * pmask,uint32_t * pscopeid)3115c4d2252SAlexander V. Chernikov rt_get_inet6_prefix_pmask(const struct rtentry *rt, struct in6_addr *paddr,
3125c4d2252SAlexander V. Chernikov struct in6_addr *pmask, uint32_t *pscopeid)
3135c4d2252SAlexander V. Chernikov {
3145c4d2252SAlexander V. Chernikov const struct sockaddr_in6 *dst;
3155c4d2252SAlexander V. Chernikov
3165c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in6 *)rt_key_const(rt);
3175c4d2252SAlexander V. Chernikov KASSERT((dst->sin6_family == AF_INET6),
3185c4d2252SAlexander V. Chernikov ("rt family is %d, not inet", dst->sin6_family));
3195c4d2252SAlexander V. Chernikov if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
3205c4d2252SAlexander V. Chernikov in6_splitscope(&dst->sin6_addr, paddr, pscopeid);
3215c4d2252SAlexander V. Chernikov else
3225c4d2252SAlexander V. Chernikov *paddr = dst->sin6_addr;
3235c4d2252SAlexander V. Chernikov dst = (const struct sockaddr_in6 *)rt_mask_const(rt);
3245c4d2252SAlexander V. Chernikov if (dst == NULL)
3255c4d2252SAlexander V. Chernikov memset(pmask, 0xFF, sizeof(struct in6_addr));
3265c4d2252SAlexander V. Chernikov else
3275c4d2252SAlexander V. Chernikov *pmask = dst->sin6_addr;
3285c4d2252SAlexander V. Chernikov }
3295c4d2252SAlexander V. Chernikov #endif
3305c4d2252SAlexander V. Chernikov
3315c4d2252SAlexander V. Chernikov
332