1139823Simp/*- 21541Srgrimes * Copyright (c) 1988, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 2985053Sru * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 3050477Speter * $FreeBSD$ 311541Srgrimes */ 32207194Skib#include "opt_compat.h" 33178167Sqingli#include "opt_mpath.h" 34185435Sbz#include "opt_inet.h" 35185435Sbz#include "opt_inet6.h" 36178167Sqingli 371541Srgrimes#include <sys/param.h> 38185435Sbz#include <sys/jail.h> 398426Swollman#include <sys/kernel.h> 40195837Srwatson#include <sys/domain.h> 41185751Simp#include <sys/lock.h> 4229024Sbde#include <sys/malloc.h> 431541Srgrimes#include <sys/mbuf.h> 44164033Srwatson#include <sys/priv.h> 4595759Stanimura#include <sys/proc.h> 4695759Stanimura#include <sys/protosw.h> 47185747Skmacy#include <sys/rwlock.h> 4895759Stanimura#include <sys/signalvar.h> 491541Srgrimes#include <sys/socket.h> 501541Srgrimes#include <sys/socketvar.h> 5195759Stanimura#include <sys/sysctl.h> 5295759Stanimura#include <sys/systm.h> 531541Srgrimes 54264076Sglebius#define _IN_NET_RTSOCK_C 551541Srgrimes#include <net/if.h> 56186500Sqingli#include <net/if_dl.h> 57186119Sqingli#include <net/if_llatbl.h> 58208553Sqingli#include <net/if_types.h> 59130256Srwatson#include <net/netisr.h> 6095759Stanimura#include <net/raw_cb.h> 611541Srgrimes#include <net/route.h> 62185571Sbz#include <net/vnet.h> 631541Srgrimes 64128664Sbmilekic#include <netinet/in.h> 65201282Sqingli#include <netinet/if_ether.h> 66228571Sglebius#include <netinet/ip_carp.h> 67185435Sbz#ifdef INET6 68243903Shrs#include <netinet6/ip6_var.h> 69185435Sbz#include <netinet6/scope6_var.h> 70185435Sbz#endif 71128664Sbmilekic 72207194Skib#ifdef COMPAT_FREEBSD32 73207194Skib#include <sys/mount.h> 74207194Skib#include <compat/freebsd32/freebsd32.h> 75207194Skib 76207194Skibstruct if_data32 { 77207194Skib uint8_t ifi_type; 78207194Skib uint8_t ifi_physical; 79207194Skib uint8_t ifi_addrlen; 80207194Skib uint8_t ifi_hdrlen; 81207194Skib uint8_t ifi_link_state; 82228571Sglebius uint8_t ifi_vhid; 83254569Sbz uint8_t ifi_baudrate_pf; 84207194Skib uint8_t ifi_datalen; 85207194Skib uint32_t ifi_mtu; 86207194Skib uint32_t ifi_metric; 87207194Skib uint32_t ifi_baudrate; 88207194Skib uint32_t ifi_ipackets; 89207194Skib uint32_t ifi_ierrors; 90207194Skib uint32_t ifi_opackets; 91207194Skib uint32_t ifi_oerrors; 92207194Skib uint32_t ifi_collisions; 93207194Skib uint32_t ifi_ibytes; 94207194Skib uint32_t ifi_obytes; 95207194Skib uint32_t ifi_imcasts; 96207194Skib uint32_t ifi_omcasts; 97207194Skib uint32_t ifi_iqdrops; 98207194Skib uint32_t ifi_noproto; 99207194Skib uint32_t ifi_hwassist; 100207194Skib int32_t ifi_epoch; 101207194Skib struct timeval32 ifi_lastchange; 102264076Sglebius uint32_t ifi_oqdrops; 103207194Skib}; 104207194Skib 105207194Skibstruct if_msghdr32 { 106207194Skib uint16_t ifm_msglen; 107207194Skib uint8_t ifm_version; 108207194Skib uint8_t ifm_type; 109207194Skib int32_t ifm_addrs; 110207194Skib int32_t ifm_flags; 111207194Skib uint16_t ifm_index; 112207194Skib struct if_data32 ifm_data; 113207194Skib}; 114207194Skib 115231505Sbzstruct if_msghdrl32 { 116231505Sbz uint16_t ifm_msglen; 117231505Sbz uint8_t ifm_version; 118231505Sbz uint8_t ifm_type; 119231505Sbz int32_t ifm_addrs; 120231505Sbz int32_t ifm_flags; 121231505Sbz uint16_t ifm_index; 122231505Sbz uint16_t _ifm_spare1; 123231505Sbz uint16_t ifm_len; 124231505Sbz uint16_t ifm_data_off; 125231505Sbz struct if_data32 ifm_data; 126231505Sbz}; 127231505Sbz 128231505Sbzstruct ifa_msghdrl32 { 129231505Sbz uint16_t ifam_msglen; 130231505Sbz uint8_t ifam_version; 131231505Sbz uint8_t ifam_type; 132231505Sbz int32_t ifam_addrs; 133231505Sbz int32_t ifam_flags; 134231505Sbz uint16_t ifam_index; 135231505Sbz uint16_t _ifam_spare1; 136231505Sbz uint16_t ifam_len; 137231505Sbz uint16_t ifam_data_off; 138231505Sbz int32_t ifam_metric; 139231505Sbz struct if_data32 ifam_data; 140231505Sbz}; 141231505Sbz#endif /* COMPAT_FREEBSD32 */ 142231505Sbz 14330354SphkMALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables"); 14430354Sphk 145120701Ssam/* NB: these are not modified */ 14612340Sphkstatic struct sockaddr route_src = { 2, PF_ROUTE, }; 14727504Sjulianstatic struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, }; 1481541Srgrimes 149228571Sglebius/* These are external hooks for CARP. */ 150228571Sglebiusint (*carp_get_vhid_p)(struct ifaddr *); 151228571Sglebius 152225837Sbz/* 153225837Sbz * Used by rtsock/raw_input callback code to decide whether to filter the update 154225837Sbz * notification to a socket bound to a particular FIB. 155225837Sbz */ 156225837Sbz#define RTS_FILTER_FIB M_PROTO8 157225837Sbz 158120701Ssamstatic struct { 159134241Sroam int ip_count; /* attached w/ AF_INET */ 160120701Ssam int ip6_count; /* attached w/ AF_INET6 */ 161120701Ssam int ipx_count; /* attached w/ AF_IPX */ 162120701Ssam int any_count; /* total attached */ 163120701Ssam} route_cb; 164120701Ssam 165120703Ssamstruct mtx rtsock_mtx; 166120703SsamMTX_SYSINIT(rtsock, &rtsock_mtx, "rtsock route_cb lock", MTX_DEF); 167120703Ssam 168120703Ssam#define RTSOCK_LOCK() mtx_lock(&rtsock_mtx) 169120703Ssam#define RTSOCK_UNLOCK() mtx_unlock(&rtsock_mtx) 170120703Ssam#define RTSOCK_LOCK_ASSERT() mtx_assert(&rtsock_mtx, MA_OWNED) 171120703Ssam 172227309Sedstatic SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD, 0, ""); 173134137Srwatson 1741541Srgrimesstruct walkarg { 17512340Sphk int w_tmemsize; 17612340Sphk int w_op, w_arg; 17712340Sphk caddr_t w_tmem; 17812340Sphk struct sysctl_req *w_req; 1791541Srgrimes}; 1801541Srgrimes 181130256Srwatsonstatic void rts_input(struct mbuf *m); 182128373Sluigistatic struct mbuf *rt_msg1(int type, struct rt_addrinfo *rtinfo); 183128373Sluigistatic int rt_msg2(int type, struct rt_addrinfo *rtinfo, 184128373Sluigi caddr_t cp, struct walkarg *w); 185128373Sluigistatic int rt_xaddrs(caddr_t cp, caddr_t cplim, 186128373Sluigi struct rt_addrinfo *rtinfo); 18792725Salfredstatic int sysctl_dumpentry(struct radix_node *rn, void *vw); 18892725Salfredstatic int sysctl_iflist(int af, struct walkarg *w); 189122685Sbmsstatic int sysctl_ifmalist(int af, struct walkarg *w); 190128373Sluigistatic int route_output(struct mbuf *m, struct socket *so); 191263478Sglebiusstatic void rt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt); 192263478Sglebiusstatic void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out); 193227061Smlaierstatic void rt_dispatch(struct mbuf *, sa_family_t); 1941541Srgrimes 195193219Srwatsonstatic struct netisr_handler rtsock_nh = { 196193219Srwatson .nh_name = "rtsock", 197193219Srwatson .nh_handler = rts_input, 198193219Srwatson .nh_proto = NETISR_ROUTE, 199193219Srwatson .nh_policy = NETISR_POLICY_SOURCE, 200193219Srwatson}; 201193219Srwatson 202193219Srwatsonstatic int 203193219Srwatsonsysctl_route_netisr_maxqlen(SYSCTL_HANDLER_ARGS) 204193219Srwatson{ 205193219Srwatson int error, qlimit; 206193219Srwatson 207193219Srwatson netisr_getqlimit(&rtsock_nh, &qlimit); 208193219Srwatson error = sysctl_handle_int(oidp, &qlimit, 0, req); 209193219Srwatson if (error || !req->newptr) 210193219Srwatson return (error); 211193219Srwatson if (qlimit < 1) 212193219Srwatson return (EINVAL); 213193219Srwatson return (netisr_setqlimit(&rtsock_nh, qlimit)); 214193219Srwatson} 215193219SrwatsonSYSCTL_PROC(_net_route, OID_AUTO, netisr_maxqlen, CTLTYPE_INT|CTLFLAG_RW, 216193219Srwatson 0, 0, sysctl_route_netisr_maxqlen, "I", 217193219Srwatson "maximum routing socket dispatch queue length"); 218193219Srwatson 219130256Srwatsonstatic void 220130256Srwatsonrts_init(void) 221130256Srwatson{ 222134138Srwatson int tmp; 223130256Srwatson 224134138Srwatson if (TUNABLE_INT_FETCH("net.route.netisr_maxqlen", &tmp)) 225193219Srwatson rtsock_nh.nh_qlimit = tmp; 226193219Srwatson netisr_register(&rtsock_nh); 227130256Srwatson} 228177253SrwatsonSYSINIT(rtsock, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rts_init, 0); 229130256Srwatson 230225837Sbzstatic int 231225837Sbzraw_input_rts_cb(struct mbuf *m, struct sockproto *proto, struct sockaddr *src, 232225837Sbz struct rawcb *rp) 233225837Sbz{ 234225837Sbz int fibnum; 235225837Sbz 236225837Sbz KASSERT(m != NULL, ("%s: m is NULL", __func__)); 237225837Sbz KASSERT(proto != NULL, ("%s: proto is NULL", __func__)); 238225837Sbz KASSERT(rp != NULL, ("%s: rp is NULL", __func__)); 239225837Sbz 240225837Sbz /* No filtering requested. */ 241225837Sbz if ((m->m_flags & RTS_FILTER_FIB) == 0) 242225837Sbz return (0); 243225837Sbz 244225837Sbz /* Check if it is a rts and the fib matches the one of the socket. */ 245225837Sbz fibnum = M_GETFIB(m); 246225837Sbz if (proto->sp_family != PF_ROUTE || 247225837Sbz rp->rcb_socket == NULL || 248225837Sbz rp->rcb_socket->so_fibnum == fibnum) 249225837Sbz return (0); 250225837Sbz 251225837Sbz /* Filtering requested and no match, the socket shall be skipped. */ 252225837Sbz return (1); 253225837Sbz} 254225837Sbz 255130256Srwatsonstatic void 256130256Srwatsonrts_input(struct mbuf *m) 257130256Srwatson{ 258130256Srwatson struct sockproto route_proto; 259130256Srwatson unsigned short *family; 260130256Srwatson struct m_tag *tag; 261130256Srwatson 262130256Srwatson route_proto.sp_family = PF_ROUTE; 263130256Srwatson tag = m_tag_find(m, PACKET_TAG_RTSOCKFAM, NULL); 264130256Srwatson if (tag != NULL) { 265130256Srwatson family = (unsigned short *)(tag + 1); 266130256Srwatson route_proto.sp_protocol = *family; 267130256Srwatson m_tag_delete(m, tag); 268130256Srwatson } else 269130256Srwatson route_proto.sp_protocol = 0; 270130256Srwatson 271225837Sbz raw_input_ext(m, &route_proto, &route_src, raw_input_rts_cb); 272130256Srwatson} 273130256Srwatson 27425201Swollman/* 27525201Swollman * It really doesn't make any sense at all for this code to share much 27625201Swollman * with raw_usrreq.c, since its functionality is so restricted. XXX 27725201Swollman */ 278157366Srwatsonstatic void 27925201Swollmanrts_abort(struct socket *so) 2801541Srgrimes{ 281149452Srwatson 282157366Srwatson raw_usrreqs.pru_abort(so); 28325201Swollman} 2841541Srgrimes 285160549Srwatsonstatic void 286160549Srwatsonrts_close(struct socket *so) 287160549Srwatson{ 288160549Srwatson 289160549Srwatson raw_usrreqs.pru_close(so); 290160549Srwatson} 291160549Srwatson 29225201Swollman/* pru_accept is EOPNOTSUPP */ 29325201Swollman 29425201Swollmanstatic int 29583366Sjulianrts_attach(struct socket *so, int proto, struct thread *td) 29625201Swollman{ 29725201Swollman struct rawcb *rp; 298241686Sandre int error; 29925201Swollman 300157370Srwatson KASSERT(so->so_pcb == NULL, ("rts_attach: so_pcb != NULL")); 301157370Srwatson 30269781Sdwmalone /* XXX */ 303184205Sdes rp = malloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO); 30425201Swollman 30525201Swollman so->so_pcb = (caddr_t)rp; 306178888Sjulian so->so_fibnum = td->td_proc->p_fibnum; 30782651Sru error = raw_attach(so, proto); 30825201Swollman rp = sotorawcb(so); 30925201Swollman if (error) { 31081065Sjon so->so_pcb = NULL; 31125201Swollman free(rp, M_PCB); 31225201Swollman return error; 3131541Srgrimes } 314120703Ssam RTSOCK_LOCK(); 31525201Swollman switch(rp->rcb_proto.sp_protocol) { 31625201Swollman case AF_INET: 31725201Swollman route_cb.ip_count++; 31825201Swollman break; 31956761Sshin case AF_INET6: 32056761Sshin route_cb.ip6_count++; 32156761Sshin break; 32225201Swollman case AF_IPX: 32325201Swollman route_cb.ipx_count++; 32425201Swollman break; 32525201Swollman } 32625201Swollman route_cb.any_count++; 327120703Ssam RTSOCK_UNLOCK(); 32898385Stanimura soisconnected(so); 32925201Swollman so->so_options |= SO_USELOOPBACK; 33025201Swollman return 0; 33125201Swollman} 33225201Swollman 33325201Swollmanstatic int 33483366Sjulianrts_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 33525201Swollman{ 336149452Srwatson 337149452Srwatson return (raw_usrreqs.pru_bind(so, nam, td)); /* xxx just EINVAL */ 33825201Swollman} 33925201Swollman 34025201Swollmanstatic int 34183366Sjulianrts_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 34225201Swollman{ 343149452Srwatson 344149452Srwatson return (raw_usrreqs.pru_connect(so, nam, td)); /* XXX just EINVAL */ 34525201Swollman} 34625201Swollman 34725201Swollman/* pru_connect2 is EOPNOTSUPP */ 34825201Swollman/* pru_control is EOPNOTSUPP */ 34925201Swollman 350157370Srwatsonstatic void 35125201Swollmanrts_detach(struct socket *so) 35225201Swollman{ 35325201Swollman struct rawcb *rp = sotorawcb(so); 35425201Swollman 355157370Srwatson KASSERT(rp != NULL, ("rts_detach: rp == NULL")); 356157370Srwatson 357157370Srwatson RTSOCK_LOCK(); 358157370Srwatson switch(rp->rcb_proto.sp_protocol) { 359157370Srwatson case AF_INET: 360157370Srwatson route_cb.ip_count--; 361157370Srwatson break; 362157370Srwatson case AF_INET6: 363157370Srwatson route_cb.ip6_count--; 364157370Srwatson break; 365157370Srwatson case AF_IPX: 366157370Srwatson route_cb.ipx_count--; 367157370Srwatson break; 3681541Srgrimes } 369157370Srwatson route_cb.any_count--; 370157370Srwatson RTSOCK_UNLOCK(); 371157370Srwatson raw_usrreqs.pru_detach(so); 37225201Swollman} 37325201Swollman 37425201Swollmanstatic int 37525201Swollmanrts_disconnect(struct socket *so) 37625201Swollman{ 377149452Srwatson 378149452Srwatson return (raw_usrreqs.pru_disconnect(so)); 3791541Srgrimes} 3801541Srgrimes 38125201Swollman/* pru_listen is EOPNOTSUPP */ 38225201Swollman 38325201Swollmanstatic int 38428270Swollmanrts_peeraddr(struct socket *so, struct sockaddr **nam) 38525201Swollman{ 386149452Srwatson 387149452Srwatson return (raw_usrreqs.pru_peeraddr(so, nam)); 38825201Swollman} 38925201Swollman 39025201Swollman/* pru_rcvd is EOPNOTSUPP */ 39125201Swollman/* pru_rcvoob is EOPNOTSUPP */ 39225201Swollman 39325201Swollmanstatic int 39428270Swollmanrts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 39583366Sjulian struct mbuf *control, struct thread *td) 39625201Swollman{ 397149452Srwatson 398149452Srwatson return (raw_usrreqs.pru_send(so, flags, m, nam, control, td)); 39925201Swollman} 40025201Swollman 40125201Swollman/* pru_sense is null */ 40225201Swollman 40325201Swollmanstatic int 40425201Swollmanrts_shutdown(struct socket *so) 40525201Swollman{ 406149452Srwatson 407149452Srwatson return (raw_usrreqs.pru_shutdown(so)); 40825201Swollman} 40925201Swollman 41025201Swollmanstatic int 41128270Swollmanrts_sockaddr(struct socket *so, struct sockaddr **nam) 41225201Swollman{ 413149452Srwatson 414149452Srwatson return (raw_usrreqs.pru_sockaddr(so, nam)); 41525201Swollman} 41625201Swollman 41725201Swollmanstatic struct pr_usrreqs route_usrreqs = { 418137386Sphk .pru_abort = rts_abort, 419137386Sphk .pru_attach = rts_attach, 420137386Sphk .pru_bind = rts_bind, 421137386Sphk .pru_connect = rts_connect, 422137386Sphk .pru_detach = rts_detach, 423137386Sphk .pru_disconnect = rts_disconnect, 424137386Sphk .pru_peeraddr = rts_peeraddr, 425137386Sphk .pru_send = rts_send, 426137386Sphk .pru_shutdown = rts_shutdown, 427137386Sphk .pru_sockaddr = rts_sockaddr, 428160549Srwatson .pru_close = rts_close, 42925201Swollman}; 43025201Swollman 431185435Sbz#ifndef _SOCKADDR_UNION_DEFINED 432185435Sbz#define _SOCKADDR_UNION_DEFINED 433185435Sbz/* 434185435Sbz * The union of all possible address formats we handle. 435185435Sbz */ 436185435Sbzunion sockaddr_union { 437185435Sbz struct sockaddr sa; 438185435Sbz struct sockaddr_in sin; 439185435Sbz struct sockaddr_in6 sin6; 440185435Sbz}; 441185435Sbz#endif /* _SOCKADDR_UNION_DEFINED */ 442185435Sbz 443185435Sbzstatic int 444185435Sbzrtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, 445185435Sbz struct rtentry *rt, union sockaddr_union *saun, struct ucred *cred) 446185435Sbz{ 447185435Sbz 448188149Sjamie /* First, see if the returned address is part of the jail. */ 449188149Sjamie if (prison_if(cred, rt->rt_ifa->ifa_addr) == 0) { 450188149Sjamie info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 451188149Sjamie return (0); 452188149Sjamie } 453188149Sjamie 454185435Sbz switch (info->rti_info[RTAX_DST]->sa_family) { 455185435Sbz#ifdef INET 456185435Sbz case AF_INET: 457185435Sbz { 458185435Sbz struct in_addr ia; 459188149Sjamie struct ifaddr *ifa; 460188149Sjamie int found; 461185435Sbz 462188149Sjamie found = 0; 463185435Sbz /* 464188149Sjamie * Try to find an address on the given outgoing interface 465188149Sjamie * that belongs to the jail. 466185435Sbz */ 467229621Sjhb IF_ADDR_RLOCK(ifp); 468188149Sjamie TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 469188149Sjamie struct sockaddr *sa; 470188149Sjamie sa = ifa->ifa_addr; 471188149Sjamie if (sa->sa_family != AF_INET) 472188149Sjamie continue; 473188149Sjamie ia = ((struct sockaddr_in *)sa)->sin_addr; 474188149Sjamie if (prison_check_ip4(cred, &ia) == 0) { 475188149Sjamie found = 1; 476188149Sjamie break; 477188149Sjamie } 478188149Sjamie } 479229621Sjhb IF_ADDR_RUNLOCK(ifp); 480188149Sjamie if (!found) { 481185435Sbz /* 482188149Sjamie * As a last resort return the 'default' jail address. 483185435Sbz */ 484192895Sjamie ia = ((struct sockaddr_in *)rt->rt_ifa->ifa_addr)-> 485192895Sjamie sin_addr; 486188149Sjamie if (prison_get_ip4(cred, &ia) != 0) 487188149Sjamie return (ESRCH); 488185435Sbz } 489188149Sjamie bzero(&saun->sin, sizeof(struct sockaddr_in)); 490188149Sjamie saun->sin.sin_len = sizeof(struct sockaddr_in); 491188149Sjamie saun->sin.sin_family = AF_INET; 492188149Sjamie saun->sin.sin_addr.s_addr = ia.s_addr; 493188149Sjamie info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin; 494185435Sbz break; 495185435Sbz } 496185435Sbz#endif 497185435Sbz#ifdef INET6 498185435Sbz case AF_INET6: 499185435Sbz { 500185435Sbz struct in6_addr ia6; 501188149Sjamie struct ifaddr *ifa; 502188149Sjamie int found; 503185435Sbz 504188149Sjamie found = 0; 505185435Sbz /* 506188149Sjamie * Try to find an address on the given outgoing interface 507188149Sjamie * that belongs to the jail. 508185435Sbz */ 509229621Sjhb IF_ADDR_RLOCK(ifp); 510188149Sjamie TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 511188149Sjamie struct sockaddr *sa; 512188149Sjamie sa = ifa->ifa_addr; 513188149Sjamie if (sa->sa_family != AF_INET6) 514188149Sjamie continue; 515188149Sjamie bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 516188149Sjamie &ia6, sizeof(struct in6_addr)); 517188149Sjamie if (prison_check_ip6(cred, &ia6) == 0) { 518188149Sjamie found = 1; 519188149Sjamie break; 520188149Sjamie } 521188149Sjamie } 522229621Sjhb IF_ADDR_RUNLOCK(ifp); 523188149Sjamie if (!found) { 524185435Sbz /* 525188149Sjamie * As a last resort return the 'default' jail address. 526185435Sbz */ 527192895Sjamie ia6 = ((struct sockaddr_in6 *)rt->rt_ifa->ifa_addr)-> 528192895Sjamie sin6_addr; 529188149Sjamie if (prison_get_ip6(cred, &ia6) != 0) 530185435Sbz return (ESRCH); 531185435Sbz } 532188149Sjamie bzero(&saun->sin6, sizeof(struct sockaddr_in6)); 533188149Sjamie saun->sin6.sin6_len = sizeof(struct sockaddr_in6); 534188149Sjamie saun->sin6.sin6_family = AF_INET6; 535188149Sjamie bcopy(&ia6, &saun->sin6.sin6_addr, sizeof(struct in6_addr)); 536188149Sjamie if (sa6_recoverscope(&saun->sin6) != 0) 537188149Sjamie return (ESRCH); 538188149Sjamie info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin6; 539185435Sbz break; 540185435Sbz } 541185435Sbz#endif 542185435Sbz default: 543185435Sbz return (ESRCH); 544185435Sbz } 545185435Sbz return (0); 546185435Sbz} 547185435Sbz 5481541Srgrimes/*ARGSUSED*/ 54912340Sphkstatic int 550128373Sluigiroute_output(struct mbuf *m, struct socket *so) 5511541Srgrimes{ 552120701Ssam#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) 553128373Sluigi struct rt_msghdr *rtm = NULL; 554128373Sluigi struct rtentry *rt = NULL; 5558412Swollman struct radix_node_head *rnh; 5561541Srgrimes struct rt_addrinfo info; 557243187Shrs#ifdef INET6 558243903Shrs struct sockaddr_storage ss; 559243187Shrs struct sockaddr_in6 *sin6; 560243903Shrs int i, rti_need_deembed = 0; 561243187Shrs#endif 5621541Srgrimes int len, error = 0; 563128373Sluigi struct ifnet *ifp = NULL; 564185435Sbz union sockaddr_union saun; 565227061Smlaier sa_family_t saf = AF_UNSPEC; 5661541Srgrimes 5671541Srgrimes#define senderr(e) { error = e; goto flush;} 568128373Sluigi if (m == NULL || ((m->m_len < sizeof(long)) && 569128373Sluigi (m = m_pullup(m, sizeof(long))) == NULL)) 5701541Srgrimes return (ENOBUFS); 5711541Srgrimes if ((m->m_flags & M_PKTHDR) == 0) 5721541Srgrimes panic("route_output"); 5731541Srgrimes len = m->m_pkthdr.len; 5741541Srgrimes if (len < sizeof(*rtm) || 5751541Srgrimes len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 576128373Sluigi info.rti_info[RTAX_DST] = NULL; 5771541Srgrimes senderr(EINVAL); 5781541Srgrimes } 5791541Srgrimes R_Malloc(rtm, struct rt_msghdr *, len); 580128373Sluigi if (rtm == NULL) { 581128373Sluigi info.rti_info[RTAX_DST] = NULL; 5821541Srgrimes senderr(ENOBUFS); 5831541Srgrimes } 5841541Srgrimes m_copydata(m, 0, len, (caddr_t)rtm); 5851541Srgrimes if (rtm->rtm_version != RTM_VERSION) { 586128373Sluigi info.rti_info[RTAX_DST] = NULL; 5871541Srgrimes senderr(EPROTONOSUPPORT); 5881541Srgrimes } 5891541Srgrimes rtm->rtm_pid = curproc->p_pid; 59085074Sru bzero(&info, sizeof(info)); 5911541Srgrimes info.rti_addrs = rtm->rtm_addrs; 592243903Shrs /* 593243903Shrs * rt_xaddrs() performs s6_addr[2] := sin6_scope_id for AF_INET6 594243903Shrs * link-local address because rtrequest requires addresses with 595243903Shrs * embedded scope id. 596243903Shrs */ 59727504Sjulian if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { 598128373Sluigi info.rti_info[RTAX_DST] = NULL; 59927504Sjulian senderr(EINVAL); 60027504Sjulian } 60185074Sru info.rti_flags = rtm->rtm_flags; 602128373Sluigi if (info.rti_info[RTAX_DST] == NULL || 603120701Ssam info.rti_info[RTAX_DST]->sa_family >= AF_MAX || 604128373Sluigi (info.rti_info[RTAX_GATEWAY] != NULL && 605120701Ssam info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) 6061541Srgrimes senderr(EINVAL); 607227061Smlaier saf = info.rti_info[RTAX_DST]->sa_family; 60882651Sru /* 60982651Sru * Verify that the caller has the appropriate privilege; RTM_GET 61082651Sru * is the only operation the non-superuser is allowed. 61182651Sru */ 612164033Srwatson if (rtm->rtm_type != RTM_GET) { 613164033Srwatson error = priv_check(curthread, PRIV_NET_ROUTE); 614164033Srwatson if (error) 615164033Srwatson senderr(error); 616164033Srwatson } 61782651Sru 618196609Sqingli /* 619196609Sqingli * The given gateway address may be an interface address. 620196609Sqingli * For example, issuing a "route change" command on a route 621196609Sqingli * entry that was created from a tunnel, and the gateway 622196609Sqingli * address given is the local end point. In this case the 623196609Sqingli * RTF_GATEWAY flag must be cleared or the destination will 624196609Sqingli * not be reachable even though there is no error message. 625196609Sqingli */ 626196609Sqingli if (info.rti_info[RTAX_GATEWAY] != NULL && 627196609Sqingli info.rti_info[RTAX_GATEWAY]->sa_family != AF_LINK) { 628196609Sqingli struct route gw_ro; 629196609Sqingli 630196609Sqingli bzero(&gw_ro, sizeof(gw_ro)); 631196609Sqingli gw_ro.ro_dst = *info.rti_info[RTAX_GATEWAY]; 632196678Sqingli rtalloc_ign_fib(&gw_ro, 0, so->so_fibnum); 633196609Sqingli /* 634196609Sqingli * A host route through the loopback interface is 635196609Sqingli * installed for each interface adddress. In pre 8.0 636196609Sqingli * releases the interface address of a PPP link type 637196609Sqingli * is not reachable locally. This behavior is fixed as 638196609Sqingli * part of the new L2/L3 redesign and rewrite work. The 639196609Sqingli * signature of this interface address route is the 640196609Sqingli * AF_LINK sa_family type of the rt_gateway, and the 641196609Sqingli * rt_ifp has the IFF_LOOPBACK flag set. 642196609Sqingli */ 643196609Sqingli if (gw_ro.ro_rt != NULL && 644196609Sqingli gw_ro.ro_rt->rt_gateway->sa_family == AF_LINK && 645252184Sqingli gw_ro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) { 646196609Sqingli info.rti_flags &= ~RTF_GATEWAY; 647252184Sqingli info.rti_flags |= RTF_GWFLAG_COMPAT; 648252184Sqingli } 649196609Sqingli if (gw_ro.ro_rt != NULL) 650196609Sqingli RTFREE(gw_ro.ro_rt); 651196609Sqingli } 652196609Sqingli 6531541Srgrimes switch (rtm->rtm_type) { 654120701Ssam struct rtentry *saved_nrt; 6551541Srgrimes 6561541Srgrimes case RTM_ADD: 657128373Sluigi if (info.rti_info[RTAX_GATEWAY] == NULL) 6581541Srgrimes senderr(EINVAL); 659128373Sluigi saved_nrt = NULL; 660186500Sqingli 661186119Sqingli /* support for new ARP code */ 662186500Sqingli if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK && 663186500Sqingli (rtm->rtm_flags & RTF_LLDATA) != 0) { 664186119Sqingli error = lla_rt_output(rtm, &info); 665243903Shrs#ifdef INET6 666243903Shrs if (error == 0) 667243903Shrs rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 668243903Shrs#endif 669186119Sqingli break; 670186119Sqingli } 671178888Sjulian error = rtrequest1_fib(RTM_ADD, &info, &saved_nrt, 672178888Sjulian so->so_fibnum); 6731541Srgrimes if (error == 0 && saved_nrt) { 674243903Shrs#ifdef INET6 675243903Shrs rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 676243903Shrs#endif 677120727Ssam RT_LOCK(saved_nrt); 678263478Sglebius rt_setmetrics(rtm, saved_nrt); 679156750Sandre rtm->rtm_index = saved_nrt->rt_ifp->if_index; 680122334Ssam RT_REMREF(saved_nrt); 681120727Ssam RT_UNLOCK(saved_nrt); 6821541Srgrimes } 6831541Srgrimes break; 6841541Srgrimes 6851541Srgrimes case RTM_DELETE: 686128373Sluigi saved_nrt = NULL; 687186119Sqingli /* support for new ARP code */ 688186119Sqingli if (info.rti_info[RTAX_GATEWAY] && 689186500Sqingli (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) && 690186500Sqingli (rtm->rtm_flags & RTF_LLDATA) != 0) { 691186119Sqingli error = lla_rt_output(rtm, &info); 692243903Shrs#ifdef INET6 693243903Shrs if (error == 0) 694243903Shrs rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 695243903Shrs#endif 696186119Sqingli break; 697186119Sqingli } 698178888Sjulian error = rtrequest1_fib(RTM_DELETE, &info, &saved_nrt, 699178888Sjulian so->so_fibnum); 7008412Swollman if (error == 0) { 701120727Ssam RT_LOCK(saved_nrt); 702108269Sru rt = saved_nrt; 7038412Swollman goto report; 7048412Swollman } 705243903Shrs#ifdef INET6 706243903Shrs /* rt_msg2() will not be used when RTM_DELETE fails. */ 707243903Shrs rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; 708243903Shrs#endif 7091541Srgrimes break; 7101541Srgrimes 7111541Srgrimes case RTM_GET: 7121541Srgrimes case RTM_CHANGE: 7131541Srgrimes case RTM_LOCK: 714193232Sbz rnh = rt_tables_get_rnh(so->so_fibnum, 715193232Sbz info.rti_info[RTAX_DST]->sa_family); 716128373Sluigi if (rnh == NULL) 7178412Swollman senderr(EAFNOSUPPORT); 718265708Smelifaro 719185747Skmacy RADIX_NODE_HEAD_RLOCK(rnh); 720265708Smelifaro 721265708Smelifaro if (info.rti_info[RTAX_NETMASK] == NULL && 722265708Smelifaro rtm->rtm_type == RTM_GET) { 723265708Smelifaro /* 724265708Smelifaro * Provide logest prefix match for 725265708Smelifaro * address lookup (no mask). 726265708Smelifaro * 'route -n get addr' 727265708Smelifaro */ 728265708Smelifaro rt = (struct rtentry *) rnh->rnh_matchaddr( 729265708Smelifaro info.rti_info[RTAX_DST], rnh); 730265708Smelifaro } else 731265708Smelifaro rt = (struct rtentry *) rnh->rnh_lookup( 732265708Smelifaro info.rti_info[RTAX_DST], 733265708Smelifaro info.rti_info[RTAX_NETMASK], rnh); 734265708Smelifaro 735265708Smelifaro if (rt == NULL) { 736185747Skmacy RADIX_NODE_HEAD_RUNLOCK(rnh); 7371541Srgrimes senderr(ESRCH); 738148956Sglebius } 739178167Sqingli#ifdef RADIX_MPATH 740178167Sqingli /* 741178167Sqingli * for RTM_CHANGE/LOCK, if we got multipath routes, 742178167Sqingli * we require users to specify a matching RTAX_GATEWAY. 743178167Sqingli * 744178167Sqingli * for RTM_GET, gate is optional even with multipath. 745178167Sqingli * if gate == NULL the first match is returned. 746178167Sqingli * (no need to call rt_mpath_matchgate if gate == NULL) 747178167Sqingli */ 748178167Sqingli if (rn_mpath_capable(rnh) && 749178167Sqingli (rtm->rtm_type != RTM_GET || info.rti_info[RTAX_GATEWAY])) { 750178167Sqingli rt = rt_mpath_matchgate(rt, info.rti_info[RTAX_GATEWAY]); 751178167Sqingli if (!rt) { 752185747Skmacy RADIX_NODE_HEAD_RUNLOCK(rnh); 753178167Sqingli senderr(ESRCH); 754178167Sqingli } 755178167Sqingli } 756178167Sqingli#endif 757201282Sqingli /* 758201282Sqingli * If performing proxied L2 entry insertion, and 759201282Sqingli * the actual PPP host entry is found, perform 760201282Sqingli * another search to retrieve the prefix route of 761201282Sqingli * the local end point of the PPP link. 762201282Sqingli */ 763208553Sqingli if (rtm->rtm_flags & RTF_ANNOUNCE) { 764201282Sqingli struct sockaddr laddr; 765208553Sqingli 766208553Sqingli if (rt->rt_ifp != NULL && 767208553Sqingli rt->rt_ifp->if_type == IFT_PROPVIRTUAL) { 768208553Sqingli struct ifaddr *ifa; 769208553Sqingli 770208553Sqingli ifa = ifa_ifwithnet(info.rti_info[RTAX_DST], 1); 771208553Sqingli if (ifa != NULL) 772208553Sqingli rt_maskedcopy(ifa->ifa_addr, 773208553Sqingli &laddr, 774208553Sqingli ifa->ifa_netmask); 775208553Sqingli } else 776208553Sqingli rt_maskedcopy(rt->rt_ifa->ifa_addr, 777208553Sqingli &laddr, 778208553Sqingli rt->rt_ifa->ifa_netmask); 779201282Sqingli /* 780201282Sqingli * refactor rt and no lock operation necessary 781201282Sqingli */ 782201282Sqingli rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, rnh); 783201282Sqingli if (rt == NULL) { 784201282Sqingli RADIX_NODE_HEAD_RUNLOCK(rnh); 785201282Sqingli senderr(ESRCH); 786201282Sqingli } 787201282Sqingli } 788120727Ssam RT_LOCK(rt); 789122334Ssam RT_ADDREF(rt); 790185747Skmacy RADIX_NODE_HEAD_RUNLOCK(rnh); 791108250Shsu 7921541Srgrimes switch(rtm->rtm_type) { 7931541Srgrimes 7941541Srgrimes case RTM_GET: 7958412Swollman report: 796120727Ssam RT_LOCK_ASSERT(rt); 797188144Sjamie if ((rt->rt_flags & RTF_HOST) == 0 798200473Sbz ? jailed_without_vnet(curthread->td_ucred) 799188144Sjamie : prison_if(curthread->td_ucred, 800188144Sjamie rt_key(rt)) != 0) { 801186980Sbz RT_UNLOCK(rt); 802186980Sbz senderr(ESRCH); 803186980Sbz } 804120701Ssam info.rti_info[RTAX_DST] = rt_key(rt); 805120701Ssam info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 806120701Ssam info.rti_info[RTAX_NETMASK] = rt_mask(rt); 807186119Sqingli info.rti_info[RTAX_GENMASK] = 0; 8081541Srgrimes if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 8093443Sphk ifp = rt->rt_ifp; 8103443Sphk if (ifp) { 811128311Sluigi info.rti_info[RTAX_IFP] = 812152315Sru ifp->if_addr->ifa_addr; 813188149Sjamie error = rtm_get_jailed(&info, ifp, rt, 814188149Sjamie &saun, curthread->td_ucred); 815188149Sjamie if (error != 0) { 816188149Sjamie RT_UNLOCK(rt); 817188149Sjamie senderr(error); 818185435Sbz } 81985053Sru if (ifp->if_flags & IFF_POINTOPOINT) 820128880Smaxim info.rti_info[RTAX_BRD] = 821128880Smaxim rt->rt_ifa->ifa_dstaddr; 8221541Srgrimes rtm->rtm_index = ifp->if_index; 8231541Srgrimes } else { 824128373Sluigi info.rti_info[RTAX_IFP] = NULL; 825128373Sluigi info.rti_info[RTAX_IFA] = NULL; 826104302Sphk } 827147165Sharti } else if ((ifp = rt->rt_ifp) != NULL) { 828147165Sharti rtm->rtm_index = ifp->if_index; 8291541Srgrimes } 830128356Sluigi len = rt_msg2(rtm->rtm_type, &info, NULL, NULL); 8311541Srgrimes if (len > rtm->rtm_msglen) { 8321541Srgrimes struct rt_msghdr *new_rtm; 8331541Srgrimes R_Malloc(new_rtm, struct rt_msghdr *, len); 834128373Sluigi if (new_rtm == NULL) { 835120727Ssam RT_UNLOCK(rt); 8361541Srgrimes senderr(ENOBUFS); 837120701Ssam } 838128400Sluigi bcopy(rtm, new_rtm, rtm->rtm_msglen); 8391541Srgrimes Free(rtm); rtm = new_rtm; 8401541Srgrimes } 841128356Sluigi (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL); 842252184Sqingli if (rt->rt_flags & RTF_GWFLAG_COMPAT) 843252184Sqingli rtm->rtm_flags = RTF_GATEWAY | 844252184Sqingli (rt->rt_flags & ~RTF_GWFLAG_COMPAT); 845252184Sqingli else 846252184Sqingli rtm->rtm_flags = rt->rt_flags; 847263478Sglebius rt_getmetrics(rt, &rtm->rtm_rmx); 8481541Srgrimes rtm->rtm_addrs = info.rti_addrs; 8491541Srgrimes break; 8501541Srgrimes 8511541Srgrimes case RTM_CHANGE: 852120701Ssam /* 853120701Ssam * New gateway could require new ifaddr, ifp; 854120701Ssam * flags may also be different; ifp may be specified 855120701Ssam * by ll sockaddr when protocol address is ambiguous 856120701Ssam */ 857120701Ssam if (((rt->rt_flags & RTF_GATEWAY) && 858120701Ssam info.rti_info[RTAX_GATEWAY] != NULL) || 859120701Ssam info.rti_info[RTAX_IFP] != NULL || 860120701Ssam (info.rti_info[RTAX_IFA] != NULL && 861120701Ssam !sa_equal(info.rti_info[RTAX_IFA], 862120701Ssam rt->rt_ifa->ifa_addr))) { 863150331Sglebius RT_UNLOCK(rt); 864185849Skmacy RADIX_NODE_HEAD_LOCK(rnh); 865186061Sthompsa error = rt_getifa_fib(&info, rt->rt_fibnum); 866194760Srwatson /* 867194760Srwatson * XXXRW: Really we should release this 868194760Srwatson * reference later, but this maintains 869194760Srwatson * historical behavior. 870194760Srwatson */ 871194760Srwatson if (info.rti_ifa != NULL) 872194760Srwatson ifa_free(info.rti_ifa); 873186061Sthompsa RADIX_NODE_HEAD_UNLOCK(rnh); 874186061Sthompsa if (error != 0) 87588196Sbrian senderr(error); 876150331Sglebius RT_LOCK(rt); 87788196Sbrian } 878167949Sglebius if (info.rti_ifa != NULL && 879167949Sglebius info.rti_ifa != rt->rt_ifa && 880167949Sglebius rt->rt_ifa != NULL && 881167797Sglebius rt->rt_ifa->ifa_rtrequest != NULL) { 882167797Sglebius rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, 883167797Sglebius &info); 884194602Srwatson ifa_free(rt->rt_ifa); 885167797Sglebius } 886167797Sglebius if (info.rti_info[RTAX_GATEWAY] != NULL) { 887185849Skmacy RT_UNLOCK(rt); 888185849Skmacy RADIX_NODE_HEAD_LOCK(rnh); 889185849Skmacy RT_LOCK(rt); 890185849Skmacy 891185849Skmacy error = rt_setgate(rt, rt_key(rt), 892185849Skmacy info.rti_info[RTAX_GATEWAY]); 893185849Skmacy RADIX_NODE_HEAD_UNLOCK(rnh); 894185849Skmacy if (error != 0) { 895167797Sglebius RT_UNLOCK(rt); 896167797Sglebius senderr(error); 897167797Sglebius } 898252184Sqingli rt->rt_flags &= ~RTF_GATEWAY; 899196609Sqingli rt->rt_flags |= (RTF_GATEWAY & info.rti_flags); 900120701Ssam } 901167949Sglebius if (info.rti_ifa != NULL && 902167949Sglebius info.rti_ifa != rt->rt_ifa) { 903194602Srwatson ifa_ref(info.rti_ifa); 904167797Sglebius rt->rt_ifa = info.rti_ifa; 905167949Sglebius rt->rt_ifp = info.rti_ifp; 9061541Srgrimes } 907156750Sandre /* Allow some flags to be toggled on change. */ 908191080Skmacy rt->rt_flags = (rt->rt_flags & ~RTF_FMASK) | 909191080Skmacy (rtm->rtm_flags & RTF_FMASK); 910263478Sglebius rt_setmetrics(rtm, rt); 911156750Sandre rtm->rtm_index = rt->rt_ifp->if_index; 9121541Srgrimes if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 91385074Sru rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 914102412Scharnier /* FALLTHROUGH */ 9151541Srgrimes case RTM_LOCK: 916122922Sandre /* We don't support locks anymore */ 9171541Srgrimes break; 9181541Srgrimes } 919120727Ssam RT_UNLOCK(rt); 9201541Srgrimes break; 9211541Srgrimes 9221541Srgrimes default: 9231541Srgrimes senderr(EOPNOTSUPP); 9241541Srgrimes } 9251541Srgrimes 9261541Srgrimesflush: 9271541Srgrimes if (rtm) { 9281541Srgrimes if (error) 9291541Srgrimes rtm->rtm_errno = error; 9308876Srgrimes else 9311541Srgrimes rtm->rtm_flags |= RTF_DONE; 9321541Srgrimes } 933120701Ssam if (rt) /* XXX can this be true? */ 934120701Ssam RTFREE(rt); 9351541Srgrimes { 936128373Sluigi struct rawcb *rp = NULL; 9371541Srgrimes /* 9381541Srgrimes * Check to see if we don't want our own messages. 9391541Srgrimes */ 9401541Srgrimes if ((so->so_options & SO_USELOOPBACK) == 0) { 9411541Srgrimes if (route_cb.any_count <= 1) { 9421541Srgrimes if (rtm) 9431541Srgrimes Free(rtm); 9441541Srgrimes m_freem(m); 9451541Srgrimes return (error); 9461541Srgrimes } 9471541Srgrimes /* There is another listener, so construct message */ 9481541Srgrimes rp = sotorawcb(so); 94997658Stanimura } 9501541Srgrimes if (rtm) { 951243903Shrs#ifdef INET6 952243903Shrs if (rti_need_deembed) { 953243903Shrs /* sin6_scope_id is recovered before sending rtm. */ 954253753Shrs sin6 = (struct sockaddr_in6 *)&ss; 955243903Shrs for (i = 0; i < RTAX_MAX; i++) { 956243903Shrs if (info.rti_info[i] == NULL) 957243903Shrs continue; 958243903Shrs if (info.rti_info[i]->sa_family != AF_INET6) 959243903Shrs continue; 960243903Shrs bcopy(info.rti_info[i], sin6, sizeof(*sin6)); 961243903Shrs if (sa6_recoverscope(sin6) == 0) 962243903Shrs bcopy(sin6, info.rti_info[i], 963243903Shrs sizeof(*sin6)); 964243903Shrs } 965243903Shrs } 966243903Shrs#endif 9671541Srgrimes m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 96879198Sume if (m->m_pkthdr.len < rtm->rtm_msglen) { 96979198Sume m_freem(m); 97079198Sume m = NULL; 97179198Sume } else if (m->m_pkthdr.len > rtm->rtm_msglen) 97279198Sume m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 9731541Srgrimes } 974120701Ssam if (m) { 975225837Sbz M_SETFIB(m, so->so_fibnum); 976225837Sbz m->m_flags |= RTS_FILTER_FIB; 977120701Ssam if (rp) { 978120701Ssam /* 979120701Ssam * XXX insure we don't get a copy by 980120701Ssam * invalidating our protocol 981120701Ssam */ 982120701Ssam unsigned short family = rp->rcb_proto.sp_family; 983120701Ssam rp->rcb_proto.sp_family = 0; 984227061Smlaier rt_dispatch(m, saf); 985120701Ssam rp->rcb_proto.sp_family = family; 986120701Ssam } else 987227061Smlaier rt_dispatch(m, saf); 988120701Ssam } 989218503Smlaier /* info.rti_info[RTAX_DST] (used above) can point inside of rtm */ 990218503Smlaier if (rtm) 991218503Smlaier Free(rtm); 9921541Srgrimes } 9931541Srgrimes return (error); 994120701Ssam#undef sa_equal 9951541Srgrimes} 9961541Srgrimes 99712340Sphkstatic void 998263478Sglebiusrt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt) 9991541Srgrimes{ 1000263478Sglebius 1001263478Sglebius if (rtm->rtm_inits & RTV_MTU) 1002263478Sglebius rt->rt_mtu = rtm->rtm_rmx.rmx_mtu; 1003263478Sglebius if (rtm->rtm_inits & RTV_WEIGHT) 1004263478Sglebius rt->rt_weight = rtm->rtm_rmx.rmx_weight; 1005263478Sglebius /* Kernel -> userland timebase conversion. */ 1006263478Sglebius if (rtm->rtm_inits & RTV_EXPIRE) 1007263478Sglebius rt->rt_expire = rtm->rtm_rmx.rmx_expire ? 1008263478Sglebius rtm->rtm_rmx.rmx_expire - time_second + time_uptime : 0; 10091541Srgrimes} 10101541Srgrimes 1011122922Sandrestatic void 1012263478Sglebiusrt_getmetrics(const struct rtentry *rt, struct rt_metrics *out) 1013122922Sandre{ 1014263478Sglebius 1015122922Sandre bzero(out, sizeof(*out)); 1016263478Sglebius out->rmx_mtu = rt->rt_mtu; 1017263478Sglebius out->rmx_weight = rt->rt_weight; 1018263478Sglebius out->rmx_pksent = counter_u64_fetch(rt->rt_pksent); 1019160124Soleg /* Kernel -> userland timebase conversion. */ 1020263478Sglebius out->rmx_expire = rt->rt_expire ? 1021263478Sglebius rt->rt_expire - time_uptime + time_second : 0; 1022122922Sandre} 1023122922Sandre 102427431Sjulian/* 102527431Sjulian * Extract the addresses of the passed sockaddrs. 102627431Sjulian * Do a little sanity checking so as to avoid bad memory references. 102727504Sjulian * This data is derived straight from userland. 102827431Sjulian */ 102927504Sjulianstatic int 1030120701Ssamrt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 10311541Srgrimes{ 1032128185Sluigi struct sockaddr *sa; 1033128185Sluigi int i; 10341541Srgrimes 1035120701Ssam for (i = 0; i < RTAX_MAX && cp < cplim; i++) { 10361541Srgrimes if ((rtinfo->rti_addrs & (1 << i)) == 0) 10371541Srgrimes continue; 103827458Sjulian sa = (struct sockaddr *)cp; 103927431Sjulian /* 104027504Sjulian * It won't fit. 104127431Sjulian */ 1042120701Ssam if (cp + sa->sa_len > cplim) 104327504Sjulian return (EINVAL); 104427431Sjulian /* 104527431Sjulian * there are no more.. quit now 104627431Sjulian * If there are more bits, they are in error. 104727431Sjulian * I've seen this. route(1) can evidently generate these. 104827431Sjulian * This causes kernel to core dump. 104927504Sjulian * for compatibility, If we see this, point to a safe address. 105027431Sjulian */ 105127504Sjulian if (sa->sa_len == 0) { 105227504Sjulian rtinfo->rti_info[i] = &sa_zero; 105327504Sjulian return (0); /* should be EINVAL but for compat */ 105427504Sjulian } 105527504Sjulian /* accept it */ 1056243903Shrs#ifdef INET6 1057243903Shrs if (sa->sa_family == AF_INET6) 1058243903Shrs sa6_embedscope((struct sockaddr_in6 *)sa, 1059243903Shrs V_ip6_use_defzone); 1060243903Shrs#endif 106127504Sjulian rtinfo->rti_info[i] = sa; 1062128185Sluigi cp += SA_SIZE(sa); 10631541Srgrimes } 106427504Sjulian return (0); 10651541Srgrimes} 10661541Srgrimes 1067231505Sbz/* 1068231505Sbz * Used by the routing socket. 1069231505Sbz */ 10701541Srgrimesstatic struct mbuf * 1071120701Ssamrt_msg1(int type, struct rt_addrinfo *rtinfo) 10721541Srgrimes{ 1073128373Sluigi struct rt_msghdr *rtm; 1074128373Sluigi struct mbuf *m; 1075128373Sluigi int i; 1076128373Sluigi struct sockaddr *sa; 1077243187Shrs#ifdef INET6 1078243187Shrs struct sockaddr_storage ss; 1079243187Shrs struct sockaddr_in6 *sin6; 1080243187Shrs#endif 10811541Srgrimes int len, dlen; 10821541Srgrimes 10831541Srgrimes switch (type) { 10841541Srgrimes 10851541Srgrimes case RTM_DELADDR: 10861541Srgrimes case RTM_NEWADDR: 10871541Srgrimes len = sizeof(struct ifa_msghdr); 10881541Srgrimes break; 10891541Srgrimes 109021666Swollman case RTM_DELMADDR: 109121666Swollman case RTM_NEWMADDR: 109221666Swollman len = sizeof(struct ifma_msghdr); 109321666Swollman break; 109421666Swollman 10951541Srgrimes case RTM_IFINFO: 10961541Srgrimes len = sizeof(struct if_msghdr); 10971541Srgrimes break; 10981541Srgrimes 109989498Sru case RTM_IFANNOUNCE: 1100136155Ssam case RTM_IEEE80211: 110189498Sru len = sizeof(struct if_announcemsghdr); 110289498Sru break; 110389498Sru 11041541Srgrimes default: 11051541Srgrimes len = sizeof(struct rt_msghdr); 11061541Srgrimes } 1107248322Sglebius 1108248322Sglebius /* XXXGL: can we use MJUMPAGESIZE cluster here? */ 1109248322Sglebius KASSERT(len <= MCLBYTES, ("%s: message too big", __func__)); 1110248322Sglebius if (len > MHLEN) 1111248322Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1112248322Sglebius else 1113248322Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 1114128373Sluigi if (m == NULL) 111578064Sume return (m); 1116248322Sglebius 11171541Srgrimes m->m_pkthdr.len = m->m_len = len; 11181541Srgrimes rtm = mtod(m, struct rt_msghdr *); 11191541Srgrimes bzero((caddr_t)rtm, len); 11201541Srgrimes for (i = 0; i < RTAX_MAX; i++) { 11211541Srgrimes if ((sa = rtinfo->rti_info[i]) == NULL) 11221541Srgrimes continue; 11231541Srgrimes rtinfo->rti_addrs |= (1 << i); 1124128185Sluigi dlen = SA_SIZE(sa); 1125243187Shrs#ifdef INET6 1126243866Shrs if (V_deembed_scopeid && sa->sa_family == AF_INET6) { 1127243187Shrs sin6 = (struct sockaddr_in6 *)&ss; 1128243187Shrs bcopy(sa, sin6, sizeof(*sin6)); 1129243187Shrs if (sa6_recoverscope(sin6) == 0) 1130243187Shrs sa = (struct sockaddr *)sin6; 1131243187Shrs } 1132243187Shrs#endif 11331541Srgrimes m_copyback(m, len, dlen, (caddr_t)sa); 11341541Srgrimes len += dlen; 11351541Srgrimes } 11361541Srgrimes if (m->m_pkthdr.len != len) { 11371541Srgrimes m_freem(m); 11381541Srgrimes return (NULL); 11391541Srgrimes } 11401541Srgrimes rtm->rtm_msglen = len; 11411541Srgrimes rtm->rtm_version = RTM_VERSION; 11421541Srgrimes rtm->rtm_type = type; 11431541Srgrimes return (m); 11441541Srgrimes} 11451541Srgrimes 1146231505Sbz/* 1147231505Sbz * Used by the sysctl code and routing socket. 1148231505Sbz */ 11491541Srgrimesstatic int 1150120701Ssamrt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w) 11511541Srgrimes{ 1152128373Sluigi int i; 11531541Srgrimes int len, dlen, second_time = 0; 11541541Srgrimes caddr_t cp0; 1155243187Shrs#ifdef INET6 1156243187Shrs struct sockaddr_storage ss; 1157243187Shrs struct sockaddr_in6 *sin6; 1158243187Shrs#endif 11591541Srgrimes 11601541Srgrimes rtinfo->rti_addrs = 0; 11611541Srgrimesagain: 11621541Srgrimes switch (type) { 11631541Srgrimes 11641541Srgrimes case RTM_DELADDR: 11651541Srgrimes case RTM_NEWADDR: 1166231505Sbz if (w != NULL && w->w_op == NET_RT_IFLISTL) { 1167231505Sbz#ifdef COMPAT_FREEBSD32 1168231505Sbz if (w->w_req->flags & SCTL_MASK32) 1169231505Sbz len = sizeof(struct ifa_msghdrl32); 1170231505Sbz else 1171231505Sbz#endif 1172231505Sbz len = sizeof(struct ifa_msghdrl); 1173231505Sbz } else 1174231505Sbz len = sizeof(struct ifa_msghdr); 11751541Srgrimes break; 11761541Srgrimes 11771541Srgrimes case RTM_IFINFO: 1178207194Skib#ifdef COMPAT_FREEBSD32 1179207194Skib if (w != NULL && w->w_req->flags & SCTL_MASK32) { 1180231505Sbz if (w->w_op == NET_RT_IFLISTL) 1181231505Sbz len = sizeof(struct if_msghdrl32); 1182231505Sbz else 1183231505Sbz len = sizeof(struct if_msghdr32); 1184207194Skib break; 1185207194Skib } 1186207194Skib#endif 1187231505Sbz if (w != NULL && w->w_op == NET_RT_IFLISTL) 1188231505Sbz len = sizeof(struct if_msghdrl); 1189231505Sbz else 1190231505Sbz len = sizeof(struct if_msghdr); 11911541Srgrimes break; 11921541Srgrimes 1193122685Sbms case RTM_NEWMADDR: 1194122685Sbms len = sizeof(struct ifma_msghdr); 1195122685Sbms break; 1196122685Sbms 11971541Srgrimes default: 11981541Srgrimes len = sizeof(struct rt_msghdr); 11991541Srgrimes } 12003443Sphk cp0 = cp; 12013443Sphk if (cp0) 12021541Srgrimes cp += len; 12031541Srgrimes for (i = 0; i < RTAX_MAX; i++) { 1204128373Sluigi struct sockaddr *sa; 12051541Srgrimes 1206128373Sluigi if ((sa = rtinfo->rti_info[i]) == NULL) 12071541Srgrimes continue; 12081541Srgrimes rtinfo->rti_addrs |= (1 << i); 1209128185Sluigi dlen = SA_SIZE(sa); 1210243903Shrs if (cp) { 1211243187Shrs#ifdef INET6 1212243903Shrs if (V_deembed_scopeid && sa->sa_family == AF_INET6) { 1213243903Shrs sin6 = (struct sockaddr_in6 *)&ss; 1214243903Shrs bcopy(sa, sin6, sizeof(*sin6)); 1215243903Shrs if (sa6_recoverscope(sin6) == 0) 1216243903Shrs sa = (struct sockaddr *)sin6; 1217243903Shrs } 1218243187Shrs#endif 12191541Srgrimes bcopy((caddr_t)sa, cp, (unsigned)dlen); 12201541Srgrimes cp += dlen; 12211541Srgrimes } 12221541Srgrimes len += dlen; 12231541Srgrimes } 122489883Sgallatin len = ALIGN(len); 1225128373Sluigi if (cp == NULL && w != NULL && !second_time) { 1226128373Sluigi struct walkarg *rw = w; 12271541Srgrimes 122812340Sphk if (rw->w_req) { 12291541Srgrimes if (rw->w_tmemsize < len) { 12301541Srgrimes if (rw->w_tmem) 12311541Srgrimes free(rw->w_tmem, M_RTABLE); 12323443Sphk rw->w_tmem = (caddr_t) 12333443Sphk malloc(len, M_RTABLE, M_NOWAIT); 12343443Sphk if (rw->w_tmem) 12351541Srgrimes rw->w_tmemsize = len; 12361541Srgrimes } 12371541Srgrimes if (rw->w_tmem) { 12381541Srgrimes cp = rw->w_tmem; 12391541Srgrimes second_time = 1; 12401541Srgrimes goto again; 124112340Sphk } 12421541Srgrimes } 12431541Srgrimes } 12441541Srgrimes if (cp) { 1245128373Sluigi struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 12461541Srgrimes 12471541Srgrimes rtm->rtm_version = RTM_VERSION; 12481541Srgrimes rtm->rtm_type = type; 12491541Srgrimes rtm->rtm_msglen = len; 12501541Srgrimes } 12511541Srgrimes return (len); 12521541Srgrimes} 12531541Srgrimes 12541541Srgrimes/* 12551541Srgrimes * This routine is called to generate a message from the routing 12561541Srgrimes * socket indicating that a redirect has occured, a routing lookup 12571541Srgrimes * has failed, or that a protocol has detected timeouts to a particular 12581541Srgrimes * destination. 12591541Srgrimes */ 12601541Srgrimesvoid 1261225837Sbzrt_missmsg_fib(int type, struct rt_addrinfo *rtinfo, int flags, int error, 1262225837Sbz int fibnum) 12631541Srgrimes{ 1264120701Ssam struct rt_msghdr *rtm; 1265120701Ssam struct mbuf *m; 12661541Srgrimes struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 12671541Srgrimes 12681541Srgrimes if (route_cb.any_count == 0) 12691541Srgrimes return; 12701541Srgrimes m = rt_msg1(type, rtinfo); 1271128373Sluigi if (m == NULL) 12721541Srgrimes return; 1273225837Sbz 1274265711Smelifaro if (fibnum != RT_ALL_FIBS) { 1275225837Sbz KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: fibnum out " 1276225837Sbz "of range 0 <= %d < %d", __func__, fibnum, rt_numfibs)); 1277225837Sbz M_SETFIB(m, fibnum); 1278225837Sbz m->m_flags |= RTS_FILTER_FIB; 1279225837Sbz } 1280225837Sbz 12811541Srgrimes rtm = mtod(m, struct rt_msghdr *); 12821541Srgrimes rtm->rtm_flags = RTF_DONE | flags; 12831541Srgrimes rtm->rtm_errno = error; 12841541Srgrimes rtm->rtm_addrs = rtinfo->rti_addrs; 1285227061Smlaier rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC); 12861541Srgrimes} 12871541Srgrimes 1288225837Sbzvoid 1289225837Sbzrt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) 1290225837Sbz{ 1291225837Sbz 1292265711Smelifaro rt_missmsg_fib(type, rtinfo, flags, error, RT_ALL_FIBS); 1293225837Sbz} 1294225837Sbz 12951541Srgrimes/* 12961541Srgrimes * This routine is called to generate a message from the routing 12971541Srgrimes * socket indicating that the status of a network interface has changed. 12981541Srgrimes */ 12991541Srgrimesvoid 1300120701Ssamrt_ifmsg(struct ifnet *ifp) 13011541Srgrimes{ 1302120701Ssam struct if_msghdr *ifm; 13031541Srgrimes struct mbuf *m; 13041541Srgrimes struct rt_addrinfo info; 13051541Srgrimes 13061541Srgrimes if (route_cb.any_count == 0) 13071541Srgrimes return; 13081541Srgrimes bzero((caddr_t)&info, sizeof(info)); 13091541Srgrimes m = rt_msg1(RTM_IFINFO, &info); 1310128373Sluigi if (m == NULL) 13111541Srgrimes return; 13121541Srgrimes ifm = mtod(m, struct if_msghdr *); 13131541Srgrimes ifm->ifm_index = ifp->if_index; 1314148886Srwatson ifm->ifm_flags = ifp->if_flags | ifp->if_drv_flags; 13151541Srgrimes ifm->ifm_data = ifp->if_data; 13161541Srgrimes ifm->ifm_addrs = 0; 1317227061Smlaier rt_dispatch(m, AF_UNSPEC); 13181541Srgrimes} 13191541Srgrimes 13201541Srgrimes/* 1321265717Smelifaro * Announce interface address arrival/withdraw. 1322265717Smelifaro * Please do not call directly, use rt_addrmsg(). 1323265717Smelifaro * Assume input data to be valid. 1324265717Smelifaro * Returns 0 on success. 13251541Srgrimes */ 1326265717Smelifaroint 1327265717Smelifarortsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 13281541Srgrimes{ 13291541Srgrimes struct rt_addrinfo info; 1330265717Smelifaro struct sockaddr *sa; 1331265717Smelifaro int ncmd; 1332265717Smelifaro struct mbuf *m; 1333265717Smelifaro struct ifa_msghdr *ifam; 13341541Srgrimes struct ifnet *ifp = ifa->ifa_ifp; 13351541Srgrimes 13361541Srgrimes if (route_cb.any_count == 0) 1337265717Smelifaro return (0); 13381541Srgrimes 1339265717Smelifaro ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 13408876Srgrimes 1341265717Smelifaro bzero((caddr_t)&info, sizeof(info)); 1342265717Smelifaro info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; 1343265717Smelifaro info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr; 1344265717Smelifaro info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1345265717Smelifaro info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1346265717Smelifaro if ((m = rt_msg1(ncmd, &info)) == NULL) 1347265717Smelifaro return (ENOBUFS); 1348265717Smelifaro ifam = mtod(m, struct ifa_msghdr *); 1349265717Smelifaro ifam->ifam_index = ifp->if_index; 1350265717Smelifaro ifam->ifam_metric = ifa->ifa_metric; 1351265717Smelifaro ifam->ifam_flags = ifa->ifa_flags; 1352265717Smelifaro ifam->ifam_addrs = info.rti_addrs; 1353265717Smelifaro 1354265717Smelifaro if (fibnum != RT_ALL_FIBS) { 1355265717Smelifaro M_SETFIB(m, fibnum); 1356265717Smelifaro m->m_flags |= RTS_FILTER_FIB; 13571541Srgrimes } 1358265717Smelifaro 1359265717Smelifaro rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC); 1360265717Smelifaro 1361265717Smelifaro return (0); 13621541Srgrimes} 13631541Srgrimes 1364265717Smelifaro/* 1365265717Smelifaro * Announce route addition/removal. 1366265717Smelifaro * Please do not call directly, use rt_routemsg(). 1367265717Smelifaro * Note that @rt data MAY be inconsistent/invalid: 1368265717Smelifaro * if some userland app sends us "invalid" route message (invalid mask, 1369265717Smelifaro * no dst, wrong address families, etc...) we need to pass it back 1370265717Smelifaro * to app (and any other rtsock consumers) with rtm_errno field set to 1371265717Smelifaro * non-zero value. 1372265717Smelifaro * 1373265717Smelifaro * Returns 0 on success. 1374265717Smelifaro */ 1375265717Smelifaroint 1376265717Smelifarortsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt, 1377265717Smelifaro int fibnum) 1378225837Sbz{ 1379265717Smelifaro struct rt_addrinfo info; 1380265717Smelifaro struct sockaddr *sa; 1381265717Smelifaro struct mbuf *m; 1382265717Smelifaro struct rt_msghdr *rtm; 1383225837Sbz 1384265717Smelifaro if (route_cb.any_count == 0) 1385265717Smelifaro return (0); 1386265717Smelifaro 1387265717Smelifaro bzero((caddr_t)&info, sizeof(info)); 1388265717Smelifaro info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1389265717Smelifaro info.rti_info[RTAX_DST] = sa = rt_key(rt); 1390265717Smelifaro info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1391265717Smelifaro if ((m = rt_msg1(cmd, &info)) == NULL) 1392265717Smelifaro return (ENOBUFS); 1393265717Smelifaro rtm = mtod(m, struct rt_msghdr *); 1394265717Smelifaro rtm->rtm_index = ifp->if_index; 1395265717Smelifaro rtm->rtm_flags |= rt->rt_flags; 1396265717Smelifaro rtm->rtm_errno = error; 1397265717Smelifaro rtm->rtm_addrs = info.rti_addrs; 1398265717Smelifaro 1399265717Smelifaro if (fibnum != RT_ALL_FIBS) { 1400265717Smelifaro M_SETFIB(m, fibnum); 1401265717Smelifaro m->m_flags |= RTS_FILTER_FIB; 1402265717Smelifaro } 1403265717Smelifaro 1404265717Smelifaro rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC); 1405265717Smelifaro 1406265717Smelifaro return (0); 1407225837Sbz} 1408225837Sbz 140921666Swollman/* 141021666Swollman * This is the analogue to the rt_newaddrmsg which performs the same 141121666Swollman * function but for multicast group memberhips. This is easier since 141221666Swollman * there is no route state to worry about. 141321666Swollman */ 141421666Swollmanvoid 1415120701Ssamrt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma) 141621666Swollman{ 141721666Swollman struct rt_addrinfo info; 1418128373Sluigi struct mbuf *m = NULL; 141921666Swollman struct ifnet *ifp = ifma->ifma_ifp; 142021666Swollman struct ifma_msghdr *ifmam; 142112340Sphk 142221666Swollman if (route_cb.any_count == 0) 142321666Swollman return; 142421666Swollman 142521666Swollman bzero((caddr_t)&info, sizeof(info)); 1426120701Ssam info.rti_info[RTAX_IFA] = ifma->ifma_addr; 1427152315Sru info.rti_info[RTAX_IFP] = ifp ? ifp->if_addr->ifa_addr : NULL; 142821666Swollman /* 142921666Swollman * If a link-layer address is present, present it as a ``gateway'' 143021666Swollman * (similarly to how ARP entries, e.g., are presented). 143121666Swollman */ 1432120701Ssam info.rti_info[RTAX_GATEWAY] = ifma->ifma_lladdr; 1433120701Ssam m = rt_msg1(cmd, &info); 1434120701Ssam if (m == NULL) 143521666Swollman return; 143621666Swollman ifmam = mtod(m, struct ifma_msghdr *); 1437167943Sbms KASSERT(ifp != NULL, ("%s: link-layer multicast address w/o ifp\n", 1438167943Sbms __func__)); 143921666Swollman ifmam->ifmam_index = ifp->if_index; 144021666Swollman ifmam->ifmam_addrs = info.rti_addrs; 1441227061Smlaier rt_dispatch(m, ifma->ifma_addr ? ifma->ifma_addr->sa_family : AF_UNSPEC); 144221666Swollman} 144321666Swollman 1444136155Ssamstatic struct mbuf * 1445136155Ssamrt_makeifannouncemsg(struct ifnet *ifp, int type, int what, 1446136155Ssam struct rt_addrinfo *info) 1447136155Ssam{ 1448136155Ssam struct if_announcemsghdr *ifan; 1449136155Ssam struct mbuf *m; 1450136155Ssam 1451136155Ssam if (route_cb.any_count == 0) 1452136155Ssam return NULL; 1453136155Ssam bzero((caddr_t)info, sizeof(*info)); 1454136155Ssam m = rt_msg1(type, info); 1455136155Ssam if (m != NULL) { 1456136155Ssam ifan = mtod(m, struct if_announcemsghdr *); 1457136155Ssam ifan->ifan_index = ifp->if_index; 1458136155Ssam strlcpy(ifan->ifan_name, ifp->if_xname, 1459136155Ssam sizeof(ifan->ifan_name)); 1460136155Ssam ifan->ifan_what = what; 1461136155Ssam } 1462136155Ssam return m; 1463136155Ssam} 1464136155Ssam 14651541Srgrimes/* 146689498Sru * This is called to generate routing socket messages indicating 1467136155Ssam * IEEE80211 wireless events. 1468136155Ssam * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. 1469136155Ssam */ 1470136155Ssamvoid 1471136155Ssamrt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len) 1472136155Ssam{ 1473136155Ssam struct mbuf *m; 1474136155Ssam struct rt_addrinfo info; 1475136155Ssam 1476136155Ssam m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); 1477136155Ssam if (m != NULL) { 1478136155Ssam /* 1479136155Ssam * Append the ieee80211 data. Try to stick it in the 1480136155Ssam * mbuf containing the ifannounce msg; otherwise allocate 1481136155Ssam * a new mbuf and append. 1482136155Ssam * 1483136155Ssam * NB: we assume m is a single mbuf. 1484136155Ssam */ 1485136155Ssam if (data_len > M_TRAILINGSPACE(m)) { 1486136155Ssam struct mbuf *n = m_get(M_NOWAIT, MT_DATA); 1487136155Ssam if (n == NULL) { 1488136155Ssam m_freem(m); 1489136155Ssam return; 1490136155Ssam } 1491136155Ssam bcopy(data, mtod(n, void *), data_len); 1492136155Ssam n->m_len = data_len; 1493136155Ssam m->m_next = n; 1494136155Ssam } else if (data_len > 0) { 1495136155Ssam bcopy(data, mtod(m, u_int8_t *) + m->m_len, data_len); 1496136155Ssam m->m_len += data_len; 1497136155Ssam } 1498136155Ssam if (m->m_flags & M_PKTHDR) 1499136155Ssam m->m_pkthdr.len += data_len; 1500136155Ssam mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len; 1501227061Smlaier rt_dispatch(m, AF_UNSPEC); 1502136155Ssam } 1503136155Ssam} 1504136155Ssam 1505136155Ssam/* 1506136155Ssam * This is called to generate routing socket messages indicating 150789498Sru * network interface arrival and departure. 150889498Sru */ 150989498Sruvoid 1510120701Ssamrt_ifannouncemsg(struct ifnet *ifp, int what) 151189498Sru{ 151289498Sru struct mbuf *m; 151389498Sru struct rt_addrinfo info; 151489498Sru 1515136155Ssam m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info); 1516136155Ssam if (m != NULL) 1517227061Smlaier rt_dispatch(m, AF_UNSPEC); 1518136155Ssam} 151989498Sru 1520120701Ssamstatic void 1521227061Smlaierrt_dispatch(struct mbuf *m, sa_family_t saf) 1522120701Ssam{ 1523130256Srwatson struct m_tag *tag; 1524120701Ssam 1525130256Srwatson /* 1526130256Srwatson * Preserve the family from the sockaddr, if any, in an m_tag for 1527130256Srwatson * use when injecting the mbuf into the routing socket buffer from 1528130256Srwatson * the netisr. 1529130256Srwatson */ 1530227061Smlaier if (saf != AF_UNSPEC) { 1531130256Srwatson tag = m_tag_get(PACKET_TAG_RTSOCKFAM, sizeof(unsigned short), 1532130256Srwatson M_NOWAIT); 1533130256Srwatson if (tag == NULL) { 1534130256Srwatson m_freem(m); 1535130256Srwatson return; 1536130256Srwatson } 1537227061Smlaier *(unsigned short *)(tag + 1) = saf; 1538130256Srwatson m_tag_prepend(m, tag); 1539130256Srwatson } 1540191816Szec#ifdef VIMAGE 1541191816Szec if (V_loif) 1542191816Szec m->m_pkthdr.rcvif = V_loif; 1543191816Szec else { 1544191816Szec m_freem(m); 1545191816Szec return; 1546191816Szec } 1547191816Szec#endif 1548134391Sandre netisr_queue(NETISR_ROUTE, m); /* mbuf is free'd on failure. */ 1549120701Ssam} 1550120701Ssam 155189498Sru/* 15521541Srgrimes * This is used in dumping the kernel table via sysctl(). 15531541Srgrimes */ 1554104094Sphkstatic int 1555120701Ssamsysctl_dumpentry(struct radix_node *rn, void *vw) 15561541Srgrimes{ 1557120701Ssam struct walkarg *w = vw; 1558120701Ssam struct rtentry *rt = (struct rtentry *)rn; 15591541Srgrimes int error = 0, size; 15601541Srgrimes struct rt_addrinfo info; 15611541Srgrimes 15621541Srgrimes if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 15631541Srgrimes return 0; 1564188144Sjamie if ((rt->rt_flags & RTF_HOST) == 0 1565200473Sbz ? jailed_without_vnet(w->w_req->td->td_ucred) 1566188144Sjamie : prison_if(w->w_req->td->td_ucred, rt_key(rt)) != 0) 1567186980Sbz return (0); 15681541Srgrimes bzero((caddr_t)&info, sizeof(info)); 1569120701Ssam info.rti_info[RTAX_DST] = rt_key(rt); 1570120701Ssam info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1571120701Ssam info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1572186119Sqingli info.rti_info[RTAX_GENMASK] = 0; 157385053Sru if (rt->rt_ifp) { 1574152315Sru info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr; 1575120701Ssam info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 157685053Sru if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1577120701Ssam info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; 157885053Sru } 1579128356Sluigi size = rt_msg2(RTM_GET, &info, NULL, w); 158012340Sphk if (w->w_req && w->w_tmem) { 1581120701Ssam struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 15821541Srgrimes 1583252184Sqingli if (rt->rt_flags & RTF_GWFLAG_COMPAT) 1584252184Sqingli rtm->rtm_flags = RTF_GATEWAY | 1585252184Sqingli (rt->rt_flags & ~RTF_GWFLAG_COMPAT); 1586252184Sqingli else 1587252184Sqingli rtm->rtm_flags = rt->rt_flags; 1588263478Sglebius rt_getmetrics(rt, &rtm->rtm_rmx); 15891541Srgrimes rtm->rtm_index = rt->rt_ifp->if_index; 15901541Srgrimes rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 15911541Srgrimes rtm->rtm_addrs = info.rti_addrs; 159212340Sphk error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size); 159312340Sphk return (error); 15941541Srgrimes } 15951541Srgrimes return (error); 15961541Srgrimes} 15971541Srgrimes 1598207194Skib#ifdef COMPAT_FREEBSD32 1599207194Skibstatic void 1600207194Skibcopy_ifdata32(struct if_data *src, struct if_data32 *dst) 1601207194Skib{ 1602207194Skib 1603207194Skib bzero(dst, sizeof(*dst)); 1604207194Skib CP(*src, *dst, ifi_type); 1605207194Skib CP(*src, *dst, ifi_physical); 1606207194Skib CP(*src, *dst, ifi_addrlen); 1607207194Skib CP(*src, *dst, ifi_hdrlen); 1608207194Skib CP(*src, *dst, ifi_link_state); 1609228571Sglebius CP(*src, *dst, ifi_vhid); 1610254569Sbz CP(*src, *dst, ifi_baudrate_pf); 1611210805Skib dst->ifi_datalen = sizeof(struct if_data32); 1612207194Skib CP(*src, *dst, ifi_mtu); 1613207194Skib CP(*src, *dst, ifi_metric); 1614207194Skib CP(*src, *dst, ifi_baudrate); 1615207194Skib CP(*src, *dst, ifi_ipackets); 1616207194Skib CP(*src, *dst, ifi_ierrors); 1617207194Skib CP(*src, *dst, ifi_opackets); 1618207194Skib CP(*src, *dst, ifi_oerrors); 1619207194Skib CP(*src, *dst, ifi_collisions); 1620207194Skib CP(*src, *dst, ifi_ibytes); 1621207194Skib CP(*src, *dst, ifi_obytes); 1622207194Skib CP(*src, *dst, ifi_imcasts); 1623207194Skib CP(*src, *dst, ifi_omcasts); 1624207194Skib CP(*src, *dst, ifi_iqdrops); 1625207194Skib CP(*src, *dst, ifi_noproto); 1626207194Skib CP(*src, *dst, ifi_hwassist); 1627207194Skib CP(*src, *dst, ifi_epoch); 1628207194Skib TV_CP(*src, *dst, ifi_lastchange); 1629207194Skib} 1630207194Skib#endif 1631207194Skib 1632104094Sphkstatic int 1633231505Sbzsysctl_iflist_ifml(struct ifnet *ifp, struct rt_addrinfo *info, 1634231505Sbz struct walkarg *w, int len) 1635231505Sbz{ 1636231505Sbz struct if_msghdrl *ifm; 1637231505Sbz 1638231505Sbz#ifdef COMPAT_FREEBSD32 1639231505Sbz if (w->w_req->flags & SCTL_MASK32) { 1640231505Sbz struct if_msghdrl32 *ifm32; 1641231505Sbz 1642231505Sbz ifm32 = (struct if_msghdrl32 *)w->w_tmem; 1643231505Sbz ifm32->ifm_addrs = info->rti_addrs; 1644231505Sbz ifm32->ifm_flags = ifp->if_flags | ifp->if_drv_flags; 1645231505Sbz ifm32->ifm_index = ifp->if_index; 1646231505Sbz ifm32->_ifm_spare1 = 0; 1647231505Sbz ifm32->ifm_len = sizeof(*ifm32); 1648231505Sbz ifm32->ifm_data_off = offsetof(struct if_msghdrl32, ifm_data); 1649231505Sbz 1650231505Sbz copy_ifdata32(&ifp->if_data, &ifm32->ifm_data); 1651231505Sbz /* Fixup if_data carp(4) vhid. */ 1652231505Sbz if (carp_get_vhid_p != NULL) 1653231505Sbz ifm32->ifm_data.ifi_vhid = 1654231505Sbz (*carp_get_vhid_p)(ifp->if_addr); 1655264076Sglebius ifm32->ifm_data.ifi_oqdrops = ifp->if_snd.ifq_drops; 1656231505Sbz 1657231505Sbz return (SYSCTL_OUT(w->w_req, (caddr_t)ifm32, len)); 1658231505Sbz } 1659231505Sbz#endif 1660231505Sbz ifm = (struct if_msghdrl *)w->w_tmem; 1661231505Sbz ifm->ifm_addrs = info->rti_addrs; 1662231505Sbz ifm->ifm_flags = ifp->if_flags | ifp->if_drv_flags; 1663231505Sbz ifm->ifm_index = ifp->if_index; 1664231505Sbz ifm->_ifm_spare1 = 0; 1665231505Sbz ifm->ifm_len = sizeof(*ifm); 1666231505Sbz ifm->ifm_data_off = offsetof(struct if_msghdrl, ifm_data); 1667231505Sbz 1668231505Sbz ifm->ifm_data = ifp->if_data; 1669231505Sbz /* Fixup if_data carp(4) vhid. */ 1670231505Sbz if (carp_get_vhid_p != NULL) 1671231505Sbz ifm->ifm_data.ifi_vhid = (*carp_get_vhid_p)(ifp->if_addr); 1672231505Sbz 1673264076Sglebius ifm->ifm_data.ifi_datalen += sizeof(u_long); 1674264076Sglebius ifm->ifi_oqdrops = ifp->if_snd.ifq_drops; 1675264076Sglebius 1676231505Sbz return (SYSCTL_OUT(w->w_req, (caddr_t)ifm, len)); 1677231505Sbz} 1678231505Sbz 1679231505Sbzstatic int 1680231505Sbzsysctl_iflist_ifm(struct ifnet *ifp, struct rt_addrinfo *info, 1681231505Sbz struct walkarg *w, int len) 1682231505Sbz{ 1683231505Sbz struct if_msghdr *ifm; 1684231505Sbz 1685231505Sbz#ifdef COMPAT_FREEBSD32 1686231505Sbz if (w->w_req->flags & SCTL_MASK32) { 1687231505Sbz struct if_msghdr32 *ifm32; 1688231505Sbz 1689231505Sbz ifm32 = (struct if_msghdr32 *)w->w_tmem; 1690231505Sbz ifm32->ifm_addrs = info->rti_addrs; 1691231505Sbz ifm32->ifm_flags = ifp->if_flags | ifp->if_drv_flags; 1692231505Sbz ifm32->ifm_index = ifp->if_index; 1693231505Sbz 1694231505Sbz copy_ifdata32(&ifp->if_data, &ifm32->ifm_data); 1695231505Sbz /* Fixup if_data carp(4) vhid. */ 1696231505Sbz if (carp_get_vhid_p != NULL) 1697231505Sbz ifm32->ifm_data.ifi_vhid = 1698231505Sbz (*carp_get_vhid_p)(ifp->if_addr); 1699231505Sbz 1700231505Sbz return (SYSCTL_OUT(w->w_req, (caddr_t)ifm32, len)); 1701231505Sbz } 1702231505Sbz#endif 1703231505Sbz ifm = (struct if_msghdr *)w->w_tmem; 1704231505Sbz ifm->ifm_addrs = info->rti_addrs; 1705231505Sbz ifm->ifm_flags = ifp->if_flags | ifp->if_drv_flags; 1706231505Sbz ifm->ifm_index = ifp->if_index; 1707231505Sbz 1708231505Sbz ifm->ifm_data = ifp->if_data; 1709231505Sbz /* Fixup if_data carp(4) vhid. */ 1710231505Sbz if (carp_get_vhid_p != NULL) 1711231505Sbz ifm->ifm_data.ifi_vhid = (*carp_get_vhid_p)(ifp->if_addr); 1712231505Sbz 1713231505Sbz return (SYSCTL_OUT(w->w_req, (caddr_t)ifm, len)); 1714231505Sbz} 1715231505Sbz 1716231505Sbzstatic int 1717231505Sbzsysctl_iflist_ifaml(struct ifaddr *ifa, struct rt_addrinfo *info, 1718231505Sbz struct walkarg *w, int len) 1719231505Sbz{ 1720231505Sbz struct ifa_msghdrl *ifam; 1721231505Sbz 1722231505Sbz#ifdef COMPAT_FREEBSD32 1723231505Sbz if (w->w_req->flags & SCTL_MASK32) { 1724231505Sbz struct ifa_msghdrl32 *ifam32; 1725231505Sbz 1726231505Sbz ifam32 = (struct ifa_msghdrl32 *)w->w_tmem; 1727231505Sbz ifam32->ifam_addrs = info->rti_addrs; 1728231505Sbz ifam32->ifam_flags = ifa->ifa_flags; 1729231505Sbz ifam32->ifam_index = ifa->ifa_ifp->if_index; 1730231505Sbz ifam32->_ifam_spare1 = 0; 1731231505Sbz ifam32->ifam_len = sizeof(*ifam32); 1732231505Sbz ifam32->ifam_data_off = 1733231505Sbz offsetof(struct ifa_msghdrl32, ifam_data); 1734231505Sbz ifam32->ifam_metric = ifa->ifa_metric; 1735231505Sbz 1736231505Sbz copy_ifdata32(&ifa->ifa_ifp->if_data, &ifam32->ifam_data); 1737231505Sbz /* Fixup if_data carp(4) vhid. */ 1738231505Sbz if (carp_get_vhid_p != NULL) 1739231505Sbz ifam32->ifam_data.ifi_vhid = (*carp_get_vhid_p)(ifa); 1740231505Sbz 1741231505Sbz return (SYSCTL_OUT(w->w_req, (caddr_t)ifam32, len)); 1742231505Sbz } 1743231505Sbz#endif 1744231505Sbz 1745231505Sbz ifam = (struct ifa_msghdrl *)w->w_tmem; 1746231505Sbz ifam->ifam_addrs = info->rti_addrs; 1747231505Sbz ifam->ifam_flags = ifa->ifa_flags; 1748231505Sbz ifam->ifam_index = ifa->ifa_ifp->if_index; 1749231505Sbz ifam->_ifam_spare1 = 0; 1750231505Sbz ifam->ifam_len = sizeof(*ifam); 1751231505Sbz ifam->ifam_data_off = offsetof(struct ifa_msghdrl, ifam_data); 1752231505Sbz ifam->ifam_metric = ifa->ifa_metric; 1753231505Sbz 1754231505Sbz ifam->ifam_data = ifa->if_data; 1755231505Sbz /* Fixup if_data carp(4) vhid. */ 1756231505Sbz if (carp_get_vhid_p != NULL) 1757231505Sbz ifam->ifam_data.ifi_vhid = (*carp_get_vhid_p)(ifa); 1758231505Sbz 1759231505Sbz return (SYSCTL_OUT(w->w_req, w->w_tmem, len)); 1760231505Sbz} 1761231505Sbz 1762231505Sbzstatic int 1763231505Sbzsysctl_iflist_ifam(struct ifaddr *ifa, struct rt_addrinfo *info, 1764231505Sbz struct walkarg *w, int len) 1765231505Sbz{ 1766231505Sbz struct ifa_msghdr *ifam; 1767231505Sbz 1768231505Sbz ifam = (struct ifa_msghdr *)w->w_tmem; 1769231505Sbz ifam->ifam_addrs = info->rti_addrs; 1770231505Sbz ifam->ifam_flags = ifa->ifa_flags; 1771231505Sbz ifam->ifam_index = ifa->ifa_ifp->if_index; 1772231505Sbz ifam->ifam_metric = ifa->ifa_metric; 1773231505Sbz 1774231505Sbz return (SYSCTL_OUT(w->w_req, w->w_tmem, len)); 1775231505Sbz} 1776231505Sbz 1777231505Sbzstatic int 1778120701Ssamsysctl_iflist(int af, struct walkarg *w) 17791541Srgrimes{ 1780120701Ssam struct ifnet *ifp; 1781120701Ssam struct ifaddr *ifa; 1782120701Ssam struct rt_addrinfo info; 1783120701Ssam int len, error = 0; 17841541Srgrimes 17851541Srgrimes bzero((caddr_t)&info, sizeof(info)); 1786243866Shrs IFNET_RLOCK_NOSLEEP(); 1787181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 17881541Srgrimes if (w->w_arg && w->w_arg != ifp->if_index) 17891541Srgrimes continue; 1790229621Sjhb IF_ADDR_RLOCK(ifp); 1791152315Sru ifa = ifp->if_addr; 1792120701Ssam info.rti_info[RTAX_IFP] = ifa->ifa_addr; 1793128356Sluigi len = rt_msg2(RTM_IFINFO, &info, NULL, w); 1794128373Sluigi info.rti_info[RTAX_IFP] = NULL; 179512340Sphk if (w->w_req && w->w_tmem) { 1796231505Sbz if (w->w_op == NET_RT_IFLISTL) 1797231505Sbz error = sysctl_iflist_ifml(ifp, &info, w, len); 1798231505Sbz else 1799231505Sbz error = sysctl_iflist_ifm(ifp, &info, w, len); 18003443Sphk if (error) 180184105Sjlemon goto done; 18021541Srgrimes } 1803128373Sluigi while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) { 18041541Srgrimes if (af && af != ifa->ifa_addr->sa_family) 18051541Srgrimes continue; 1806188144Sjamie if (prison_if(w->w_req->td->td_ucred, 1807188144Sjamie ifa->ifa_addr) != 0) 180846155Sphk continue; 1809120701Ssam info.rti_info[RTAX_IFA] = ifa->ifa_addr; 1810120701Ssam info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1811120701Ssam info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1812128356Sluigi len = rt_msg2(RTM_NEWADDR, &info, NULL, w); 181312340Sphk if (w->w_req && w->w_tmem) { 1814231505Sbz if (w->w_op == NET_RT_IFLISTL) 1815231505Sbz error = sysctl_iflist_ifaml(ifa, &info, 1816231505Sbz w, len); 1817231505Sbz else 1818231505Sbz error = sysctl_iflist_ifam(ifa, &info, 1819231505Sbz w, len); 18203443Sphk if (error) 182184105Sjlemon goto done; 18221541Srgrimes } 18231541Srgrimes } 1824229621Sjhb IF_ADDR_RUNLOCK(ifp); 1825120701Ssam info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = 1826128373Sluigi info.rti_info[RTAX_BRD] = NULL; 18271541Srgrimes } 182884105Sjlemondone: 1829213930Sbz if (ifp != NULL) 1830229621Sjhb IF_ADDR_RUNLOCK(ifp); 1831243866Shrs IFNET_RUNLOCK_NOSLEEP(); 183284105Sjlemon return (error); 18331541Srgrimes} 18341541Srgrimes 1835186956Sbzstatic int 1836128311Sluigisysctl_ifmalist(int af, struct walkarg *w) 1837122685Sbms{ 1838128311Sluigi struct ifnet *ifp; 1839122685Sbms struct ifmultiaddr *ifma; 1840122685Sbms struct rt_addrinfo info; 1841122685Sbms int len, error = 0; 1842128311Sluigi struct ifaddr *ifa; 1843122685Sbms 1844122685Sbms bzero((caddr_t)&info, sizeof(info)); 1845243866Shrs IFNET_RLOCK_NOSLEEP(); 1846181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1847122685Sbms if (w->w_arg && w->w_arg != ifp->if_index) 1848122685Sbms continue; 1849152315Sru ifa = ifp->if_addr; 1850128356Sluigi info.rti_info[RTAX_IFP] = ifa ? ifa->ifa_addr : NULL; 1851229621Sjhb IF_ADDR_RLOCK(ifp); 1852122685Sbms TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1853122685Sbms if (af && af != ifma->ifma_addr->sa_family) 1854122685Sbms continue; 1855188144Sjamie if (prison_if(w->w_req->td->td_ucred, 1856188144Sjamie ifma->ifma_addr) != 0) 1857122685Sbms continue; 1858122685Sbms info.rti_info[RTAX_IFA] = ifma->ifma_addr; 1859128356Sluigi info.rti_info[RTAX_GATEWAY] = 1860128356Sluigi (ifma->ifma_addr->sa_family != AF_LINK) ? 1861128356Sluigi ifma->ifma_lladdr : NULL; 1862128356Sluigi len = rt_msg2(RTM_NEWMADDR, &info, NULL, w); 1863122685Sbms if (w->w_req && w->w_tmem) { 1864128311Sluigi struct ifma_msghdr *ifmam; 1865122685Sbms 1866122685Sbms ifmam = (struct ifma_msghdr *)w->w_tmem; 1867122685Sbms ifmam->ifmam_index = ifma->ifma_ifp->if_index; 1868122685Sbms ifmam->ifmam_flags = 0; 1869122685Sbms ifmam->ifmam_addrs = info.rti_addrs; 1870122685Sbms error = SYSCTL_OUT(w->w_req, w->w_tmem, len); 1871149943Scsjp if (error) { 1872229621Sjhb IF_ADDR_RUNLOCK(ifp); 1873122685Sbms goto done; 1874149943Scsjp } 1875122685Sbms } 1876122685Sbms } 1877229621Sjhb IF_ADDR_RUNLOCK(ifp); 1878122685Sbms } 1879122685Sbmsdone: 1880243866Shrs IFNET_RUNLOCK_NOSLEEP(); 1881122685Sbms return (error); 1882122685Sbms} 1883122685Sbms 188412340Sphkstatic int 188562573Sphksysctl_rtsock(SYSCTL_HANDLER_ARGS) 18861541Srgrimes{ 188712340Sphk int *name = (int *)arg1; 188812340Sphk u_int namelen = arg2; 1889193232Sbz struct radix_node_head *rnh = NULL; /* silence compiler. */ 1890149943Scsjp int i, lim, error = EINVAL; 1891253262Shrs int fib = 0; 1892128168Sluigi u_char af; 18931541Srgrimes struct walkarg w; 18941541Srgrimes 189512340Sphk name ++; 189612340Sphk namelen--; 189712340Sphk if (req->newptr) 18981541Srgrimes return (EPERM); 1899253262Shrs if (name[1] == NET_RT_DUMP) { 1900253262Shrs if (namelen == 3) 1901253262Shrs fib = req->td->td_proc->p_fibnum; 1902253262Shrs else if (namelen == 4) 1903265711Smelifaro fib = (name[3] == RT_ALL_FIBS) ? 1904253262Shrs req->td->td_proc->p_fibnum : name[3]; 1905253262Shrs else 1906253262Shrs return ((namelen < 3) ? EISDIR : ENOTDIR); 1907253262Shrs if (fib < 0 || fib >= rt_numfibs) 1908253262Shrs return (EINVAL); 1909253262Shrs } else if (namelen != 3) 191089768Scjc return ((namelen < 3) ? EISDIR : ENOTDIR); 19111541Srgrimes af = name[0]; 1912108271Shsu if (af > AF_MAX) 1913108271Shsu return (EINVAL); 1914128400Sluigi bzero(&w, sizeof(w)); 19151541Srgrimes w.w_op = name[1]; 19161541Srgrimes w.w_arg = name[2]; 191712340Sphk w.w_req = req; 19181541Srgrimes 1919149943Scsjp error = sysctl_wire_old_buffer(req, 0); 1920149943Scsjp if (error) 1921149943Scsjp return (error); 19221541Srgrimes switch (w.w_op) { 19231541Srgrimes 19241541Srgrimes case NET_RT_DUMP: 19251541Srgrimes case NET_RT_FLAGS: 1926128168Sluigi if (af == 0) { /* dump all tables */ 1927128168Sluigi i = 1; 1928128168Sluigi lim = AF_MAX; 1929128168Sluigi } else /* dump only one table */ 1930128168Sluigi i = lim = af; 1931186500Sqingli 1932186500Sqingli /* 1933186500Sqingli * take care of llinfo entries, the caller must 1934186500Sqingli * specify an AF 1935186500Sqingli */ 1936187094Sqingli if (w.w_op == NET_RT_FLAGS && 1937187328Sqingli (w.w_arg == 0 || w.w_arg & RTF_LLINFO)) { 1938186500Sqingli if (af != 0) 1939186500Sqingli error = lltable_sysctl_dumparp(af, w.w_req); 1940186500Sqingli else 1941186500Sqingli error = EINVAL; 1942186500Sqingli break; 1943186500Sqingli } 1944186500Sqingli /* 1945186500Sqingli * take care of routing entries 1946186500Sqingli */ 1947196174Sbz for (error = 0; error == 0 && i <= lim; i++) { 1948253262Shrs rnh = rt_tables_get_rnh(fib, i); 1949193232Sbz if (rnh != NULL) { 1950234572Smelifaro RADIX_NODE_HEAD_RLOCK(rnh); 1951108250Shsu error = rnh->rnh_walktree(rnh, 1952149943Scsjp sysctl_dumpentry, &w); 1953234572Smelifaro RADIX_NODE_HEAD_RUNLOCK(rnh); 1954128168Sluigi } else if (af != 0) 1955108250Shsu error = EAFNOSUPPORT; 1956196174Sbz } 19571541Srgrimes break; 19581541Srgrimes 19591541Srgrimes case NET_RT_IFLIST: 1960231505Sbz case NET_RT_IFLISTL: 19611541Srgrimes error = sysctl_iflist(af, &w); 1962122685Sbms break; 1963122685Sbms 1964122685Sbms case NET_RT_IFMALIST: 1965122685Sbms error = sysctl_ifmalist(af, &w); 1966122685Sbms break; 19671541Srgrimes } 19681541Srgrimes if (w.w_tmem) 19691541Srgrimes free(w.w_tmem, M_RTABLE); 19701541Srgrimes return (error); 19711541Srgrimes} 19721541Srgrimes 1973227309Sedstatic SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, ""); 197412340Sphk 19751541Srgrimes/* 19761541Srgrimes * Definitions of protocols supported in the ROUTE domain. 19771541Srgrimes */ 19781541Srgrimes 1979149848Sobrienstatic struct domain routedomain; /* or at least forward */ 19801541Srgrimes 198112340Sphkstatic struct protosw routesw[] = { 1982152242Sru{ 1983152242Sru .pr_type = SOCK_RAW, 1984152242Sru .pr_domain = &routedomain, 1985152242Sru .pr_flags = PR_ATOMIC|PR_ADDR, 1986152242Sru .pr_output = route_output, 1987152242Sru .pr_ctlinput = raw_ctlinput, 1988152242Sru .pr_init = raw_init, 1989152242Sru .pr_usrreqs = &route_usrreqs 19901541Srgrimes} 19911541Srgrimes}; 19921541Srgrimes 1993152242Srustatic struct domain routedomain = { 1994152242Sru .dom_family = PF_ROUTE, 1995152242Sru .dom_name = "route", 1996152242Sru .dom_protosw = routesw, 1997152242Sru .dom_protoswNPROTOSW = &routesw[sizeof(routesw)/sizeof(routesw[0])] 1998152242Sru}; 19998412Swollman 2000195837SrwatsonVNET_DOMAIN_SET(route); 2001