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