1/* $NetBSD: rtsock.c,v 1.139 2011/12/31 20:41:58 christos Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 1988, 1991, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 61 */ 62 63#include <sys/cdefs.h> 64__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.139 2011/12/31 20:41:58 christos Exp $"); 65 66#ifdef _KERNEL_OPT 67#include "opt_inet.h" 68#include "opt_mpls.h" 69#include "opt_compat_netbsd.h" 70#endif 71 72#include <sys/param.h> 73#include <sys/systm.h> 74#include <sys/proc.h> 75#include <sys/mbuf.h> 76#include <sys/socket.h> 77#include <sys/socketvar.h> 78#include <sys/domain.h> 79#include <sys/protosw.h> 80#include <sys/sysctl.h> 81#include <sys/kauth.h> 82#include <sys/intr.h> 83#ifdef RTSOCK_DEBUG 84#include <netinet/in.h> 85#endif /* RTSOCK_DEBUG */ 86 87#include <net/if.h> 88#include <net/route.h> 89#include <net/raw_cb.h> 90 91#include <netmpls/mpls.h> 92 93#if defined(COMPAT_14) || defined(COMPAT_50) 94#include <compat/net/if.h> 95#include <compat/net/route.h> 96#endif 97#ifdef COMPAT_RTSOCK 98#define RTM_XVERSION RTM_OVERSION 99#define RT_XADVANCE(a,b) RT_OADVANCE(a,b) 100#define RT_XROUNDUP(n) RT_OROUNDUP(n) 101#define PF_XROUTE PF_OROUTE 102#define rt_xmsghdr rt_msghdr50 103#define if_xmsghdr if_msghdr /* if_msghdr50 is for RTM_OIFINFO */ 104#define ifa_xmsghdr ifa_msghdr50 105#define if_xannouncemsghdr if_announcemsghdr50 106#define COMPATNAME(x) compat_50_ ## x 107#define DOMAINNAME "oroute" 108CTASSERT(sizeof(struct ifa_xmsghdr) == 20); 109DOMAIN_DEFINE(compat_50_routedomain); /* forward declare and add to link set */ 110#else 111#define RTM_XVERSION RTM_VERSION 112#define RT_XADVANCE(a,b) RT_ADVANCE(a,b) 113#define RT_XROUNDUP(n) RT_ROUNDUP(n) 114#define PF_XROUTE PF_ROUTE 115#define rt_xmsghdr rt_msghdr 116#define if_xmsghdr if_msghdr 117#define ifa_xmsghdr ifa_msghdr 118#define if_xannouncemsghdr if_announcemsghdr 119#define COMPATNAME(x) x 120#define DOMAINNAME "route" 121CTASSERT(sizeof(struct ifa_xmsghdr) == 24); 122#ifdef COMPAT_50 123#define COMPATCALL(name, args) compat_50_ ## name args 124#endif 125DOMAIN_DEFINE(routedomain); /* forward declare and add to link set */ 126#undef COMPAT_50 127#undef COMPAT_14 128#endif 129 130#ifndef COMPATCALL 131#define COMPATCALL(name, args) do { } while (/*CONSTCOND*/ 0) 132#endif 133 134struct route_info COMPATNAME(route_info) = { 135 .ri_dst = { .sa_len = 2, .sa_family = PF_XROUTE, }, 136 .ri_src = { .sa_len = 2, .sa_family = PF_XROUTE, }, 137 .ri_maxqlen = IFQ_MAXLEN, 138}; 139 140#define PRESERVED_RTF (RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_DONE | RTF_MASK) 141 142static void COMPATNAME(route_init)(void); 143static int COMPATNAME(route_output)(struct mbuf *, ...); 144static int COMPATNAME(route_usrreq)(struct socket *, 145 int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *); 146 147static int rt_msg2(int, struct rt_addrinfo *, void *, struct rt_walkarg *, int *); 148static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *); 149static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int, 150 struct rt_addrinfo *); 151static void rt_setmetrics(int, const struct rt_xmsghdr *, struct rtentry *); 152static void rtm_setmetrics(const struct rtentry *, struct rt_xmsghdr *); 153static void sysctl_net_route_setup(struct sysctllog **); 154static int sysctl_dumpentry(struct rtentry *, void *); 155static int sysctl_iflist(int, struct rt_walkarg *, int); 156static int sysctl_rtable(SYSCTLFN_PROTO); 157static void rt_adjustcount(int, int); 158 159static void 160rt_adjustcount(int af, int cnt) 161{ 162 struct route_cb * const cb = &COMPATNAME(route_info).ri_cb; 163 164 cb->any_count += cnt; 165 166 switch (af) { 167 case AF_INET: 168 cb->ip_count += cnt; 169 return; 170#ifdef INET6 171 case AF_INET6: 172 cb->ip6_count += cnt; 173 return; 174#endif 175 case AF_ISO: 176 cb->iso_count += cnt; 177 return; 178 case AF_MPLS: 179 cb->mpls_count += cnt; 180 return; 181 } 182} 183 184/*ARGSUSED*/ 185int 186COMPATNAME(route_usrreq)(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 187 struct mbuf *control, struct lwp *l) 188{ 189 int error = 0; 190 struct rawcb *rp = sotorawcb(so); 191 int s; 192 193 if (req == PRU_ATTACH) { 194 sosetlock(so); 195 rp = malloc(sizeof(*rp), M_PCB, M_WAITOK|M_ZERO); 196 so->so_pcb = rp; 197 } 198 if (req == PRU_DETACH && rp) 199 rt_adjustcount(rp->rcb_proto.sp_protocol, -1); 200 s = splsoftnet(); 201 202 /* 203 * Don't call raw_usrreq() in the attach case, because 204 * we want to allow non-privileged processes to listen on 205 * and send "safe" commands to the routing socket. 206 */ 207 if (req == PRU_ATTACH) { 208 if (l == NULL) 209 error = EACCES; 210 else 211 error = raw_attach(so, (int)(long)nam); 212 } else 213 error = raw_usrreq(so, req, m, nam, control, l); 214 215 rp = sotorawcb(so); 216 if (req == PRU_ATTACH && rp) { 217 if (error) { 218 free(rp, M_PCB); 219 splx(s); 220 return error; 221 } 222 rt_adjustcount(rp->rcb_proto.sp_protocol, 1); 223 rp->rcb_laddr = &COMPATNAME(route_info).ri_src; 224 rp->rcb_faddr = &COMPATNAME(route_info).ri_dst; 225 soisconnected(so); 226 so->so_options |= SO_USELOOPBACK; 227 } 228 splx(s); 229 return error; 230} 231 232/*ARGSUSED*/ 233int 234COMPATNAME(route_output)(struct mbuf *m, ...) 235{ 236 struct sockproto proto = { .sp_family = PF_XROUTE, }; 237 struct rt_xmsghdr *rtm = NULL; 238 struct rt_xmsghdr *old_rtm = NULL; 239 struct rtentry *rt = NULL; 240 struct rtentry *saved_nrt = NULL; 241 struct rt_addrinfo info; 242 int len, error = 0; 243 struct ifnet *ifp = NULL; 244 struct ifaddr *ifa = NULL; 245 struct socket *so; 246 va_list ap; 247 sa_family_t family; 248 249 va_start(ap, m); 250 so = va_arg(ap, struct socket *); 251 va_end(ap); 252 253#define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0) 254 if (m == NULL || ((m->m_len < sizeof(int32_t)) && 255 (m = m_pullup(m, sizeof(int32_t))) == NULL)) 256 return ENOBUFS; 257 if ((m->m_flags & M_PKTHDR) == 0) 258 panic("%s", __func__); 259 len = m->m_pkthdr.len; 260 if (len < sizeof(*rtm) || 261 len != mtod(m, struct rt_xmsghdr *)->rtm_msglen) { 262 info.rti_info[RTAX_DST] = NULL; 263 senderr(EINVAL); 264 } 265 R_Malloc(rtm, struct rt_xmsghdr *, len); 266 if (rtm == NULL) { 267 info.rti_info[RTAX_DST] = NULL; 268 senderr(ENOBUFS); 269 } 270 m_copydata(m, 0, len, rtm); 271 if (rtm->rtm_version != RTM_XVERSION) { 272 info.rti_info[RTAX_DST] = NULL; 273 senderr(EPROTONOSUPPORT); 274 } 275 rtm->rtm_pid = curproc->p_pid; 276 memset(&info, 0, sizeof(info)); 277 info.rti_addrs = rtm->rtm_addrs; 278 if (rt_xaddrs(rtm->rtm_type, (const char *)(rtm + 1), len + (char *)rtm, 279 &info)) { 280 senderr(EINVAL); 281 } 282 info.rti_flags = rtm->rtm_flags; 283#ifdef RTSOCK_DEBUG 284 if (info.rti_info[RTAX_DST]->sa_family == AF_INET) { 285 printf("%s: extracted info.rti_info[RTAX_DST] %s\n", __func__, 286 inet_ntoa(((const struct sockaddr_in *) 287 info.rti_info[RTAX_DST])->sin_addr)); 288 } 289#endif /* RTSOCK_DEBUG */ 290 if (info.rti_info[RTAX_DST] == NULL || 291 (info.rti_info[RTAX_DST]->sa_family >= AF_MAX)) { 292 senderr(EINVAL); 293 } 294 if (info.rti_info[RTAX_GATEWAY] != NULL && 295 (info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) { 296 senderr(EINVAL); 297 } 298 299 /* 300 * Verify that the caller has the appropriate privilege; RTM_GET 301 * is the only operation the non-superuser is allowed. 302 */ 303 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE, 304 0, rtm, NULL, NULL) != 0) 305 senderr(EACCES); 306 307 switch (rtm->rtm_type) { 308 309 case RTM_ADD: 310 if (info.rti_info[RTAX_GATEWAY] == NULL) { 311 senderr(EINVAL); 312 } 313 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 314 if (error == 0 && saved_nrt) { 315 rt_setmetrics(rtm->rtm_inits, rtm, saved_nrt); 316 saved_nrt->rt_refcnt--; 317 } 318 break; 319 320 case RTM_DELETE: 321 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 322 if (error == 0) { 323 (rt = saved_nrt)->rt_refcnt++; 324 goto report; 325 } 326 break; 327 328 case RTM_GET: 329 case RTM_CHANGE: 330 case RTM_LOCK: 331 /* XXX This will mask info.rti_info[RTAX_DST] with 332 * info.rti_info[RTAX_NETMASK] before 333 * searching. It did not used to do that. --dyoung 334 */ 335 error = rtrequest1(RTM_GET, &info, &rt); 336 if (error != 0) 337 senderr(error); 338 if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 339 if (memcmp(info.rti_info[RTAX_DST], rt_getkey(rt), 340 info.rti_info[RTAX_DST]->sa_len) != 0) 341 senderr(ESRCH); 342 if (info.rti_info[RTAX_NETMASK] == NULL && 343 rt_mask(rt) != NULL) 344 senderr(ETOOMANYREFS); 345 } 346 347 switch (rtm->rtm_type) { 348 case RTM_GET: 349 report: 350 info.rti_info[RTAX_DST] = rt_getkey(rt); 351 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 352 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 353 info.rti_info[RTAX_TAG] = rt_gettag(rt); 354 if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0) 355 ; 356 else if ((ifp = rt->rt_ifp) != NULL) { 357 const struct ifaddr *rtifa; 358 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 359 /* rtifa used to be simply rt->rt_ifa. 360 * If rt->rt_ifa != NULL, then 361 * rt_get_ifa() != NULL. So this 362 * ought to still be safe. --dyoung 363 */ 364 rtifa = rt_get_ifa(rt); 365 info.rti_info[RTAX_IFA] = rtifa->ifa_addr; 366#ifdef RTSOCK_DEBUG 367 if (info.rti_info[RTAX_IFA]->sa_family == 368 AF_INET) { 369 printf("%s: copying out RTAX_IFA %s ", 370 __func__, inet_ntoa( 371 ((const struct sockaddr_in *) 372 info.rti_info[RTAX_IFA])->sin_addr) 373 ); 374 printf("for info.rti_info[RTAX_DST] %s " 375 "ifa_getifa %p ifa_seqno %p\n", 376 inet_ntoa( 377 ((const struct sockaddr_in *) 378 info.rti_info[RTAX_DST])->sin_addr), 379 (void *)rtifa->ifa_getifa, 380 rtifa->ifa_seqno); 381 } 382#endif /* RTSOCK_DEBUG */ 383 if (ifp->if_flags & IFF_POINTOPOINT) { 384 info.rti_info[RTAX_BRD] = 385 rtifa->ifa_dstaddr; 386 } else 387 info.rti_info[RTAX_BRD] = NULL; 388 rtm->rtm_index = ifp->if_index; 389 } else { 390 info.rti_info[RTAX_IFP] = NULL; 391 info.rti_info[RTAX_IFA] = NULL; 392 } 393 (void)rt_msg2(rtm->rtm_type, &info, NULL, NULL, &len); 394 if (len > rtm->rtm_msglen) { 395 old_rtm = rtm; 396 R_Malloc(rtm, struct rt_xmsghdr *, len); 397 if (rtm == NULL) 398 senderr(ENOBUFS); 399 (void)memcpy(rtm, old_rtm, old_rtm->rtm_msglen); 400 } 401 (void)rt_msg2(rtm->rtm_type, &info, rtm, NULL, 0); 402 rtm->rtm_flags = rt->rt_flags; 403 rtm_setmetrics(rt, rtm); 404 rtm->rtm_addrs = info.rti_addrs; 405 break; 406 407 case RTM_CHANGE: 408 /* 409 * new gateway could require new ifaddr, ifp; 410 * flags may also be different; ifp may be specified 411 * by ll sockaddr when protocol address is ambiguous 412 */ 413 if ((error = rt_getifa(&info)) != 0) 414 senderr(error); 415 if (info.rti_info[RTAX_GATEWAY] && 416 rt_setgate(rt, info.rti_info[RTAX_GATEWAY])) 417 senderr(EDQUOT); 418 if (info.rti_info[RTAX_TAG]) 419 rt_settag(rt, info.rti_info[RTAX_TAG]); 420 /* new gateway could require new ifaddr, ifp; 421 flags may also be different; ifp may be specified 422 by ll sockaddr when protocol address is ambiguous */ 423 if (info.rti_info[RTAX_IFP] && 424 (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && 425 (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || 426 info.rti_info[RTAX_GATEWAY])) { 427 if (info.rti_info[RTAX_IFA] == NULL || 428 (ifa = ifa_ifwithaddr( 429 info.rti_info[RTAX_IFA])) == NULL) 430 ifa = ifaof_ifpforaddr( 431 info.rti_info[RTAX_IFA] ? 432 info.rti_info[RTAX_IFA] : 433 info.rti_info[RTAX_GATEWAY], ifp); 434 } else if ((info.rti_info[RTAX_IFA] && 435 (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || 436 (info.rti_info[RTAX_GATEWAY] && 437 (ifa = ifa_ifwithroute(rt->rt_flags, 438 rt_getkey(rt), info.rti_info[RTAX_GATEWAY])))) { 439 ifp = ifa->ifa_ifp; 440 } 441 if (ifa) { 442 struct ifaddr *oifa = rt->rt_ifa; 443 if (oifa != ifa) { 444 if (oifa && oifa->ifa_rtrequest) { 445 oifa->ifa_rtrequest(RTM_DELETE, 446 rt, &info); 447 } 448 rt_replace_ifa(rt, ifa); 449 rt->rt_ifp = ifp; 450 } 451 } 452 if (ifp && rt->rt_ifp != ifp) 453 rt->rt_ifp = ifp; 454 rt_setmetrics(rtm->rtm_inits, rtm, rt); 455 if (rt->rt_flags != info.rti_flags) 456 rt->rt_flags = (info.rti_flags & ~PRESERVED_RTF) 457 | (rt->rt_flags & PRESERVED_RTF); 458 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 459 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 460 /*FALLTHROUGH*/ 461 case RTM_LOCK: 462 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 463 rt->rt_rmx.rmx_locks |= 464 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 465 break; 466 } 467 break; 468 469 default: 470 senderr(EOPNOTSUPP); 471 } 472 473flush: 474 if (rtm) { 475 if (error) 476 rtm->rtm_errno = error; 477 else 478 rtm->rtm_flags |= RTF_DONE; 479 } 480 family = info.rti_info[RTAX_DST] ? info.rti_info[RTAX_DST]->sa_family : 481 0; 482 /* We cannot free old_rtm until we have stopped using the 483 * pointers in info, some of which may point to sockaddrs 484 * in old_rtm. 485 */ 486 if (old_rtm != NULL) 487 Free(old_rtm); 488 if (rt) 489 rtfree(rt); 490 { 491 struct rawcb *rp = NULL; 492 /* 493 * Check to see if we don't want our own messages. 494 */ 495 if ((so->so_options & SO_USELOOPBACK) == 0) { 496 if (COMPATNAME(route_info).ri_cb.any_count <= 1) { 497 if (rtm) 498 Free(rtm); 499 m_freem(m); 500 return error; 501 } 502 /* There is another listener, so construct message */ 503 rp = sotorawcb(so); 504 } 505 if (rtm) { 506 m_copyback(m, 0, rtm->rtm_msglen, rtm); 507 if (m->m_pkthdr.len < rtm->rtm_msglen) { 508 m_freem(m); 509 m = NULL; 510 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 511 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 512 Free(rtm); 513 } 514 if (rp) 515 rp->rcb_proto.sp_family = 0; /* Avoid us */ 516 if (family) 517 proto.sp_protocol = family; 518 if (m) 519 raw_input(m, &proto, &COMPATNAME(route_info).ri_src, 520 &COMPATNAME(route_info).ri_dst); 521 if (rp) 522 rp->rcb_proto.sp_family = PF_XROUTE; 523 } 524 return error; 525} 526 527static void 528rt_setmetrics(int which, const struct rt_xmsghdr *in, struct rtentry *out) 529{ 530#define metric(f, e) if (which & (f)) out->rt_rmx.e = in->rtm_rmx.e; 531 metric(RTV_RPIPE, rmx_recvpipe); 532 metric(RTV_SPIPE, rmx_sendpipe); 533 metric(RTV_SSTHRESH, rmx_ssthresh); 534 metric(RTV_RTT, rmx_rtt); 535 metric(RTV_RTTVAR, rmx_rttvar); 536 metric(RTV_HOPCOUNT, rmx_hopcount); 537 metric(RTV_MTU, rmx_mtu); 538 metric(RTV_EXPIRE, rmx_expire); 539#undef metric 540} 541 542static void 543rtm_setmetrics(const struct rtentry *in, struct rt_xmsghdr *out) 544{ 545#define metric(e) out->rtm_rmx.e = in->rt_rmx.e; 546 metric(rmx_recvpipe); 547 metric(rmx_sendpipe); 548 metric(rmx_ssthresh); 549 metric(rmx_rtt); 550 metric(rmx_rttvar); 551 metric(rmx_hopcount); 552 metric(rmx_mtu); 553 metric(rmx_expire); 554#undef metric 555} 556 557static int 558rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, 559 struct rt_addrinfo *rtinfo) 560{ 561 const struct sockaddr *sa = NULL; /* Quell compiler warning */ 562 int i; 563 564 for (i = 0; i < RTAX_MAX && cp < cplim; i++) { 565 if ((rtinfo->rti_addrs & (1 << i)) == 0) 566 continue; 567 rtinfo->rti_info[i] = sa = (const struct sockaddr *)cp; 568 RT_XADVANCE(cp, sa); 569 } 570 571 /* 572 * Check for extra addresses specified, except RTM_GET asking 573 * for interface info. 574 */ 575 if (rtmtype == RTM_GET) { 576 if (((rtinfo->rti_addrs & 577 (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0) 578 return 1; 579 } else if ((rtinfo->rti_addrs & (~0 << i)) != 0) 580 return 1; 581 /* Check for bad data length. */ 582 if (cp != cplim) { 583 if (i == RTAX_NETMASK + 1 && sa != NULL && 584 cp - RT_XROUNDUP(sa->sa_len) + sa->sa_len == cplim) 585 /* 586 * The last sockaddr was info.rti_info[RTAX_NETMASK]. 587 * We accept this for now for the sake of old 588 * binaries or third party softwares. 589 */ 590 ; 591 else 592 return 1; 593 } 594 return 0; 595} 596 597static int 598rt_getlen(int type) 599{ 600#ifndef COMPAT_RTSOCK 601 CTASSERT(__alignof(struct ifa_msghdr) >= sizeof(uint64_t)); 602 CTASSERT(__alignof(struct if_msghdr) >= sizeof(uint64_t)); 603 CTASSERT(__alignof(struct if_announcemsghdr) >= sizeof(uint64_t)); 604 CTASSERT(__alignof(struct rt_msghdr) >= sizeof(uint64_t)); 605#endif 606 607 switch (type) { 608 case RTM_DELADDR: 609 case RTM_NEWADDR: 610 case RTM_CHGADDR: 611 return sizeof(struct ifa_xmsghdr); 612 613 case RTM_OOIFINFO: 614#ifdef COMPAT_14 615 return sizeof(struct if_msghdr14); 616#else 617#ifdef DIAGNOSTIC 618 printf("RTM_OOIFINFO\n"); 619#endif 620 return -1; 621#endif 622 case RTM_OIFINFO: 623#ifdef COMPAT_50 624 return sizeof(struct if_msghdr50); 625#else 626#ifdef DIAGNOSTIC 627 printf("RTM_OIFINFO\n"); 628#endif 629 return -1; 630#endif 631 632 case RTM_IFINFO: 633 return sizeof(struct if_xmsghdr); 634 635 case RTM_IFANNOUNCE: 636 case RTM_IEEE80211: 637 return sizeof(struct if_xannouncemsghdr); 638 639 default: 640 return sizeof(struct rt_xmsghdr); 641 } 642} 643 644 645struct mbuf * 646COMPATNAME(rt_msg1)(int type, struct rt_addrinfo *rtinfo, void *data, int datalen) 647{ 648 struct rt_xmsghdr *rtm; 649 struct mbuf *m; 650 int i; 651 const struct sockaddr *sa; 652 int len, dlen; 653 654 m = m_gethdr(M_DONTWAIT, MT_DATA); 655 if (m == NULL) 656 return m; 657 MCLAIM(m, &COMPATNAME(routedomain).dom_mowner); 658 659 if ((len = rt_getlen(type)) == -1) 660 goto out; 661 if (len > MHLEN + MLEN) 662 panic("%s: message too long", __func__); 663 else if (len > MHLEN) { 664 m->m_next = m_get(M_DONTWAIT, MT_DATA); 665 if (m->m_next == NULL) 666 goto out; 667 MCLAIM(m->m_next, m->m_owner); 668 m->m_pkthdr.len = len; 669 m->m_len = MHLEN; 670 m->m_next->m_len = len - MHLEN; 671 } else { 672 m->m_pkthdr.len = m->m_len = len; 673 } 674 m->m_pkthdr.rcvif = NULL; 675 m_copyback(m, 0, datalen, data); 676 if (len > datalen) 677 (void)memset(mtod(m, char *) + datalen, 0, len - datalen); 678 rtm = mtod(m, struct rt_xmsghdr *); 679 for (i = 0; i < RTAX_MAX; i++) { 680 if ((sa = rtinfo->rti_info[i]) == NULL) 681 continue; 682 rtinfo->rti_addrs |= (1 << i); 683 dlen = RT_XROUNDUP(sa->sa_len); 684 m_copyback(m, len, sa->sa_len, sa); 685 if (dlen != sa->sa_len) { 686 /* 687 * Up to 6 + 1 nul's since roundup is to 688 * sizeof(uint64_t) (8 bytes) 689 */ 690 m_copyback(m, len + sa->sa_len, 691 dlen - sa->sa_len, "\0\0\0\0\0\0"); 692 } 693 len += dlen; 694 } 695 if (m->m_pkthdr.len != len) 696 goto out; 697 rtm->rtm_msglen = len; 698 rtm->rtm_version = RTM_XVERSION; 699 rtm->rtm_type = type; 700 return m; 701out: 702 m_freem(m); 703 return NULL; 704} 705 706/* 707 * rt_msg2 708 * 709 * fills 'cp' or 'w'.w_tmem with the routing socket message and 710 * returns the length of the message in 'lenp'. 711 * 712 * if walkarg is 0, cp is expected to be 0 or a buffer large enough to hold 713 * the message 714 * otherwise walkarg's w_needed is updated and if the user buffer is 715 * specified and w_needed indicates space exists the information is copied 716 * into the temp space (w_tmem). w_tmem is [re]allocated if necessary, 717 * if the allocation fails ENOBUFS is returned. 718 */ 719static int 720rt_msg2(int type, struct rt_addrinfo *rtinfo, void *cpv, struct rt_walkarg *w, 721 int *lenp) 722{ 723 int i; 724 int len, dlen, second_time = 0; 725 char *cp0, *cp = cpv; 726 727 rtinfo->rti_addrs = 0; 728again: 729 if ((len = rt_getlen(type)) == -1) 730 return EINVAL; 731 732 if ((cp0 = cp) != NULL) 733 cp += len; 734 for (i = 0; i < RTAX_MAX; i++) { 735 const struct sockaddr *sa; 736 737 if ((sa = rtinfo->rti_info[i]) == NULL) 738 continue; 739 rtinfo->rti_addrs |= (1 << i); 740 dlen = RT_XROUNDUP(sa->sa_len); 741 if (cp) { 742 int diff = dlen - sa->sa_len; 743 (void)memcpy(cp, sa, (size_t)sa->sa_len); 744 cp += sa->sa_len; 745 if (diff > 0) { 746 (void)memset(cp, 0, (size_t)diff); 747 cp += diff; 748 } 749 } 750 len += dlen; 751 } 752 if (cp == NULL && w != NULL && !second_time) { 753 struct rt_walkarg *rw = w; 754 755 rw->w_needed += len; 756 if (rw->w_needed <= 0 && rw->w_where) { 757 if (rw->w_tmemsize < len) { 758 if (rw->w_tmem) 759 free(rw->w_tmem, M_RTABLE); 760 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 761 if (rw->w_tmem) 762 rw->w_tmemsize = len; 763 else 764 rw->w_tmemsize = 0; 765 } 766 if (rw->w_tmem) { 767 cp = rw->w_tmem; 768 second_time = 1; 769 goto again; 770 } else { 771 rw->w_tmemneeded = len; 772 return ENOBUFS; 773 } 774 } 775 } 776 if (cp) { 777 struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)cp0; 778 779 rtm->rtm_version = RTM_XVERSION; 780 rtm->rtm_type = type; 781 rtm->rtm_msglen = len; 782 } 783 if (lenp) 784 *lenp = len; 785 return 0; 786} 787 788/* 789 * This routine is called to generate a message from the routing 790 * socket indicating that a redirect has occurred, a routing lookup 791 * has failed, or that a protocol has detected timeouts to a particular 792 * destination. 793 */ 794void 795COMPATNAME(rt_missmsg)(int type, const struct rt_addrinfo *rtinfo, int flags, 796 int error) 797{ 798 struct rt_xmsghdr rtm; 799 struct mbuf *m; 800 const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 801 struct rt_addrinfo info = *rtinfo; 802 803 COMPATCALL(rt_missmsg, (type, rtinfo, flags, error)); 804 if (COMPATNAME(route_info).ri_cb.any_count == 0) 805 return; 806 memset(&rtm, 0, sizeof(rtm)); 807 rtm.rtm_flags = RTF_DONE | flags; 808 rtm.rtm_errno = error; 809 m = COMPATNAME(rt_msg1)(type, &info, &rtm, sizeof(rtm)); 810 if (m == NULL) 811 return; 812 mtod(m, struct rt_xmsghdr *)->rtm_addrs = info.rti_addrs; 813 COMPATNAME(route_enqueue)(m, sa ? sa->sa_family : 0); 814} 815 816/* 817 * This routine is called to generate a message from the routing 818 * socket indicating that the status of a network interface has changed. 819 */ 820void 821COMPATNAME(rt_ifmsg)(struct ifnet *ifp) 822{ 823 struct if_xmsghdr ifm; 824 struct mbuf *m; 825 struct rt_addrinfo info; 826 827 COMPATCALL(rt_ifmsg, (ifp)); 828 if (COMPATNAME(route_info).ri_cb.any_count == 0) 829 return; 830 (void)memset(&info, 0, sizeof(info)); 831 (void)memset(&ifm, 0, sizeof(ifm)); 832 ifm.ifm_index = ifp->if_index; 833 ifm.ifm_flags = ifp->if_flags; 834 ifm.ifm_data = ifp->if_data; 835 ifm.ifm_addrs = 0; 836 m = COMPATNAME(rt_msg1)(RTM_IFINFO, &info, &ifm, sizeof(ifm)); 837 if (m == NULL) 838 return; 839 COMPATNAME(route_enqueue)(m, 0); 840#ifdef COMPAT_14 841 compat_14_rt_oifmsg(ifp); 842#endif 843#ifdef COMPAT_50 844 compat_50_rt_oifmsg(ifp); 845#endif 846} 847 848 849/* 850 * This is called to generate messages from the routing socket 851 * indicating a network interface has had addresses associated with it. 852 * if we ever reverse the logic and replace messages TO the routing 853 * socket indicate a request to configure interfaces, then it will 854 * be unnecessary as the routing socket will automatically generate 855 * copies of it. 856 */ 857void 858COMPATNAME(rt_newaddrmsg)(int cmd, struct ifaddr *ifa, int error, 859 struct rtentry *rt) 860{ 861#define cmdpass(__cmd, __pass) (((__cmd) << 2) | (__pass)) 862 struct rt_addrinfo info; 863 const struct sockaddr *sa; 864 int pass; 865 struct mbuf *m; 866 struct ifnet *ifp; 867 struct rt_xmsghdr rtm; 868 struct ifa_xmsghdr ifam; 869 int ncmd; 870 871 KASSERT(ifa != NULL); 872 ifp = ifa->ifa_ifp; 873 COMPATCALL(rt_newaddrmsg, (cmd, ifa, error, rt)); 874 if (COMPATNAME(route_info).ri_cb.any_count == 0) 875 return; 876 for (pass = 1; pass < 3; pass++) { 877 memset(&info, 0, sizeof(info)); 878 switch (cmdpass(cmd, pass)) { 879 case cmdpass(RTM_ADD, 1): 880 case cmdpass(RTM_CHANGE, 1): 881 case cmdpass(RTM_DELETE, 2): 882 case cmdpass(RTM_NEWADDR, 1): 883 case cmdpass(RTM_DELADDR, 1): 884 case cmdpass(RTM_CHGADDR, 1): 885 switch (cmd) { 886 case RTM_ADD: 887 ncmd = RTM_NEWADDR; 888 break; 889 case RTM_DELETE: 890 ncmd = RTM_DELADDR; 891 break; 892 case RTM_CHANGE: 893 ncmd = RTM_CHGADDR; 894 break; 895 default: 896 ncmd = cmd; 897 } 898 info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; 899 KASSERT(ifp->if_dl != NULL); 900 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 901 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 902 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 903 memset(&ifam, 0, sizeof(ifam)); 904 ifam.ifam_index = ifp->if_index; 905 ifam.ifam_metric = ifa->ifa_metric; 906 ifam.ifam_flags = ifa->ifa_flags; 907 m = COMPATNAME(rt_msg1)(ncmd, &info, &ifam, sizeof(ifam)); 908 if (m == NULL) 909 continue; 910 mtod(m, struct ifa_xmsghdr *)->ifam_addrs = 911 info.rti_addrs; 912 break; 913 case cmdpass(RTM_ADD, 2): 914 case cmdpass(RTM_CHANGE, 2): 915 case cmdpass(RTM_DELETE, 1): 916 if (rt == NULL) 917 continue; 918 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 919 info.rti_info[RTAX_DST] = sa = rt_getkey(rt); 920 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 921 memset(&rtm, 0, sizeof(rtm)); 922 rtm.rtm_index = ifp->if_index; 923 rtm.rtm_flags |= rt->rt_flags; 924 rtm.rtm_errno = error; 925 m = COMPATNAME(rt_msg1)(cmd, &info, &rtm, sizeof(rtm)); 926 if (m == NULL) 927 continue; 928 mtod(m, struct rt_xmsghdr *)->rtm_addrs = info.rti_addrs; 929 break; 930 default: 931 continue; 932 } 933#ifdef DIAGNOSTIC 934 if (m == NULL) 935 panic("%s: called with wrong command", __func__); 936#endif 937 COMPATNAME(route_enqueue)(m, sa ? sa->sa_family : 0); 938 } 939#undef cmdpass 940} 941 942static struct mbuf * 943rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, 944 struct rt_addrinfo *info) 945{ 946 struct if_xannouncemsghdr ifan; 947 948 memset(info, 0, sizeof(*info)); 949 memset(&ifan, 0, sizeof(ifan)); 950 ifan.ifan_index = ifp->if_index; 951 strlcpy(ifan.ifan_name, ifp->if_xname, sizeof(ifan.ifan_name)); 952 ifan.ifan_what = what; 953 return COMPATNAME(rt_msg1)(type, info, &ifan, sizeof(ifan)); 954} 955 956/* 957 * This is called to generate routing socket messages indicating 958 * network interface arrival and departure. 959 */ 960void 961COMPATNAME(rt_ifannouncemsg)(struct ifnet *ifp, int what) 962{ 963 struct mbuf *m; 964 struct rt_addrinfo info; 965 966 COMPATCALL(rt_ifannouncemsg, (ifp, what)); 967 if (COMPATNAME(route_info).ri_cb.any_count == 0) 968 return; 969 m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info); 970 if (m == NULL) 971 return; 972 COMPATNAME(route_enqueue)(m, 0); 973} 974 975/* 976 * This is called to generate routing socket messages indicating 977 * IEEE80211 wireless events. 978 * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. 979 */ 980void 981COMPATNAME(rt_ieee80211msg)(struct ifnet *ifp, int what, void *data, 982 size_t data_len) 983{ 984 struct mbuf *m; 985 struct rt_addrinfo info; 986 987 COMPATCALL(rt_ieee80211msg, (ifp, what, data, data_len)); 988 if (COMPATNAME(route_info).ri_cb.any_count == 0) 989 return; 990 m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); 991 if (m == NULL) 992 return; 993 /* 994 * Append the ieee80211 data. Try to stick it in the 995 * mbuf containing the ifannounce msg; otherwise allocate 996 * a new mbuf and append. 997 * 998 * NB: we assume m is a single mbuf. 999 */ 1000 if (data_len > M_TRAILINGSPACE(m)) { 1001 struct mbuf *n = m_get(M_NOWAIT, MT_DATA); 1002 if (n == NULL) { 1003 m_freem(m); 1004 return; 1005 } 1006 (void)memcpy(mtod(n, void *), data, data_len); 1007 n->m_len = data_len; 1008 m->m_next = n; 1009 } else if (data_len > 0) { 1010 (void)memcpy(mtod(m, uint8_t *) + m->m_len, data, data_len); 1011 m->m_len += data_len; 1012 } 1013 if (m->m_flags & M_PKTHDR) 1014 m->m_pkthdr.len += data_len; 1015 mtod(m, struct if_xannouncemsghdr *)->ifan_msglen += data_len; 1016 COMPATNAME(route_enqueue)(m, 0); 1017} 1018 1019/* 1020 * This is used in dumping the kernel table via sysctl(). 1021 */ 1022static int 1023sysctl_dumpentry(struct rtentry *rt, void *v) 1024{ 1025 struct rt_walkarg *w = v; 1026 int error = 0, size; 1027 struct rt_addrinfo info; 1028 1029 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1030 return 0; 1031 memset(&info, 0, sizeof(info)); 1032 info.rti_info[RTAX_DST] = rt_getkey(rt); 1033 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1034 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1035 if (rt->rt_ifp) { 1036 const struct ifaddr *rtifa; 1037 info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr; 1038 /* rtifa used to be simply rt->rt_ifa. If rt->rt_ifa != NULL, 1039 * then rt_get_ifa() != NULL. So this ought to still be safe. 1040 * --dyoung 1041 */ 1042 rtifa = rt_get_ifa(rt); 1043 info.rti_info[RTAX_IFA] = rtifa->ifa_addr; 1044 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1045 info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr; 1046 } 1047 if ((error = rt_msg2(RTM_GET, &info, 0, w, &size))) 1048 return error; 1049 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1050 struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)w->w_tmem; 1051 1052 rtm->rtm_flags = rt->rt_flags; 1053 rtm->rtm_use = rt->rt_use; 1054 rtm_setmetrics(rt, rtm); 1055 KASSERT(rt->rt_ifp != NULL); 1056 rtm->rtm_index = rt->rt_ifp->if_index; 1057 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 1058 rtm->rtm_addrs = info.rti_addrs; 1059 if ((error = copyout(rtm, w->w_where, size)) != 0) 1060 w->w_where = NULL; 1061 else 1062 w->w_where = (char *)w->w_where + size; 1063 } 1064 return error; 1065} 1066 1067static int 1068sysctl_iflist(int af, struct rt_walkarg *w, int type) 1069{ 1070 struct ifnet *ifp; 1071 struct ifaddr *ifa; 1072 struct rt_addrinfo info; 1073 int len, error = 0; 1074 1075 memset(&info, 0, sizeof(info)); 1076 IFNET_FOREACH(ifp) { 1077 if (w->w_arg && w->w_arg != ifp->if_index) 1078 continue; 1079 if (IFADDR_EMPTY(ifp)) 1080 continue; 1081 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; 1082 switch (type) { 1083 case NET_RT_IFLIST: 1084 error = rt_msg2(RTM_IFINFO, &info, NULL, w, &len); 1085 break; 1086#ifdef COMPAT_14 1087 case NET_RT_OOIFLIST: 1088 error = rt_msg2(RTM_OOIFINFO, &info, NULL, w, &len); 1089 break; 1090#endif 1091#ifdef COMPAT_50 1092 case NET_RT_OIFLIST: 1093 error = rt_msg2(RTM_OIFINFO, &info, NULL, w, &len); 1094 break; 1095#endif 1096 default: 1097 panic("sysctl_iflist(1)"); 1098 } 1099 if (error) 1100 return error; 1101 info.rti_info[RTAX_IFP] = NULL; 1102 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1103 switch (type) { 1104 case NET_RT_IFLIST: { 1105 struct if_xmsghdr *ifm; 1106 1107 ifm = (struct if_xmsghdr *)w->w_tmem; 1108 ifm->ifm_index = ifp->if_index; 1109 ifm->ifm_flags = ifp->if_flags; 1110 ifm->ifm_data = ifp->if_data; 1111 ifm->ifm_addrs = info.rti_addrs; 1112 error = copyout(ifm, w->w_where, len); 1113 if (error) 1114 return error; 1115 w->w_where = (char *)w->w_where + len; 1116 break; 1117 } 1118 1119#ifdef COMPAT_14 1120 case NET_RT_OOIFLIST: 1121 error = compat_14_iflist(ifp, w, &info, len); 1122 if (error) 1123 return error; 1124 break; 1125#endif 1126#ifdef COMPAT_50 1127 case NET_RT_OIFLIST: 1128 error = compat_50_iflist(ifp, w, &info, len); 1129 if (error) 1130 return error; 1131 break; 1132#endif 1133 default: 1134 panic("sysctl_iflist(2)"); 1135 } 1136 } 1137 IFADDR_FOREACH(ifa, ifp) { 1138 if (af && af != ifa->ifa_addr->sa_family) 1139 continue; 1140 info.rti_info[RTAX_IFA] = ifa->ifa_addr; 1141 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1142 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1143 if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len))) 1144 return error; 1145 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1146 struct ifa_xmsghdr *ifam; 1147 1148 ifam = (struct ifa_xmsghdr *)w->w_tmem; 1149 ifam->ifam_index = ifa->ifa_ifp->if_index; 1150 ifam->ifam_flags = ifa->ifa_flags; 1151 ifam->ifam_metric = ifa->ifa_metric; 1152 ifam->ifam_addrs = info.rti_addrs; 1153 error = copyout(w->w_tmem, w->w_where, len); 1154 if (error) 1155 return error; 1156 w->w_where = (char *)w->w_where + len; 1157 } 1158 } 1159 info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = 1160 info.rti_info[RTAX_BRD] = NULL; 1161 } 1162 return 0; 1163} 1164 1165static int 1166sysctl_rtable(SYSCTLFN_ARGS) 1167{ 1168 void *where = oldp; 1169 size_t *given = oldlenp; 1170 const void *new = newp; 1171 int i, s, error = EINVAL; 1172 u_char af; 1173 struct rt_walkarg w; 1174 1175 if (namelen == 1 && name[0] == CTL_QUERY) 1176 return sysctl_query(SYSCTLFN_CALL(rnode)); 1177 1178 if (new) 1179 return EPERM; 1180 if (namelen != 3) 1181 return EINVAL; 1182 af = name[0]; 1183 w.w_tmemneeded = 0; 1184 w.w_tmemsize = 0; 1185 w.w_tmem = NULL; 1186again: 1187 /* we may return here if a later [re]alloc of the t_mem buffer fails */ 1188 if (w.w_tmemneeded) { 1189 w.w_tmem = malloc(w.w_tmemneeded, M_RTABLE, M_WAITOK); 1190 w.w_tmemsize = w.w_tmemneeded; 1191 w.w_tmemneeded = 0; 1192 } 1193 w.w_op = name[1]; 1194 w.w_arg = name[2]; 1195 w.w_given = *given; 1196 w.w_needed = 0 - w.w_given; 1197 w.w_where = where; 1198 1199 s = splsoftnet(); 1200 switch (w.w_op) { 1201 1202 case NET_RT_DUMP: 1203 case NET_RT_FLAGS: 1204 for (i = 1; i <= AF_MAX; i++) 1205 if ((af == 0 || af == i) && 1206 (error = rt_walktree(i, sysctl_dumpentry, &w))) 1207 break; 1208 break; 1209 1210#ifdef COMPAT_14 1211 case NET_RT_OOIFLIST: 1212 error = sysctl_iflist(af, &w, w.w_op); 1213 break; 1214#endif 1215#ifdef COMPAT_50 1216 case NET_RT_OIFLIST: 1217 error = sysctl_iflist(af, &w, w.w_op); 1218 break; 1219#endif 1220 case NET_RT_IFLIST: 1221 error = sysctl_iflist(af, &w, w.w_op); 1222 break; 1223 } 1224 splx(s); 1225 1226 /* check to see if we couldn't allocate memory with NOWAIT */ 1227 if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded) 1228 goto again; 1229 1230 if (w.w_tmem) 1231 free(w.w_tmem, M_RTABLE); 1232 w.w_needed += w.w_given; 1233 if (where) { 1234 *given = (char *)w.w_where - (char *)where; 1235 if (*given < w.w_needed) 1236 return ENOMEM; 1237 } else { 1238 *given = (11 * w.w_needed) / 10; 1239 } 1240 return error; 1241} 1242 1243/* 1244 * Routing message software interrupt routine 1245 */ 1246static void 1247COMPATNAME(route_intr)(void *cookie) 1248{ 1249 struct sockproto proto = { .sp_family = PF_XROUTE, }; 1250 struct route_info * const ri = &COMPATNAME(route_info); 1251 struct mbuf *m; 1252 int s; 1253 1254 mutex_enter(softnet_lock); 1255 KERNEL_LOCK(1, NULL); 1256 while (!IF_IS_EMPTY(&ri->ri_intrq)) { 1257 s = splnet(); 1258 IF_DEQUEUE(&ri->ri_intrq, m); 1259 splx(s); 1260 if (m == NULL) 1261 break; 1262 proto.sp_protocol = M_GETCTX(m, uintptr_t); 1263 raw_input(m, &proto, &ri->ri_src, &ri->ri_dst); 1264 } 1265 KERNEL_UNLOCK_ONE(NULL); 1266 mutex_exit(softnet_lock); 1267} 1268 1269/* 1270 * Enqueue a message to the software interrupt routine. 1271 */ 1272void 1273COMPATNAME(route_enqueue)(struct mbuf *m, int family) 1274{ 1275 struct route_info * const ri = &COMPATNAME(route_info); 1276 int s, wasempty; 1277 1278 s = splnet(); 1279 if (IF_QFULL(&ri->ri_intrq)) { 1280 IF_DROP(&ri->ri_intrq); 1281 m_freem(m); 1282 } else { 1283 wasempty = IF_IS_EMPTY(&ri->ri_intrq); 1284 M_SETCTX(m, (uintptr_t)family); 1285 IF_ENQUEUE(&ri->ri_intrq, m); 1286 if (wasempty) 1287 softint_schedule(ri->ri_sih); 1288 } 1289 splx(s); 1290} 1291 1292static void 1293COMPATNAME(route_init)(void) 1294{ 1295 struct route_info * const ri = &COMPATNAME(route_info); 1296 1297#ifndef COMPAT_RTSOCK 1298 rt_init(); 1299#endif 1300 1301 sysctl_net_route_setup(NULL); 1302 ri->ri_intrq.ifq_maxlen = ri->ri_maxqlen; 1303 ri->ri_sih = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, 1304 COMPATNAME(route_intr), NULL); 1305} 1306 1307/* 1308 * Definitions of protocols supported in the ROUTE domain. 1309 */ 1310#ifndef COMPAT_RTSOCK 1311PR_WRAP_USRREQ(route_usrreq); 1312#else 1313PR_WRAP_USRREQ(compat_50_route_usrreq); 1314#endif 1315 1316static const struct protosw COMPATNAME(route_protosw)[] = { 1317 { 1318 .pr_type = SOCK_RAW, 1319 .pr_domain = &COMPATNAME(routedomain), 1320 .pr_flags = PR_ATOMIC|PR_ADDR, 1321 .pr_input = raw_input, 1322 .pr_output = COMPATNAME(route_output), 1323 .pr_ctlinput = raw_ctlinput, 1324 .pr_usrreq = COMPATNAME(route_usrreq_wrapper), 1325 .pr_init = raw_init, 1326 }, 1327}; 1328 1329struct domain COMPATNAME(routedomain) = { 1330 .dom_family = PF_XROUTE, 1331 .dom_name = DOMAINNAME, 1332 .dom_init = COMPATNAME(route_init), 1333 .dom_protosw = COMPATNAME(route_protosw), 1334 .dom_protoswNPROTOSW = 1335 &COMPATNAME(route_protosw)[__arraycount(COMPATNAME(route_protosw))], 1336}; 1337 1338static void 1339sysctl_net_route_setup(struct sysctllog **clog) 1340{ 1341 const struct sysctlnode *rnode = NULL; 1342 1343 sysctl_createv(clog, 0, NULL, NULL, 1344 CTLFLAG_PERMANENT, 1345 CTLTYPE_NODE, "net", NULL, 1346 NULL, 0, NULL, 0, 1347 CTL_NET, CTL_EOL); 1348 1349 sysctl_createv(clog, 0, NULL, &rnode, 1350 CTLFLAG_PERMANENT, 1351 CTLTYPE_NODE, DOMAINNAME, 1352 SYSCTL_DESCR("PF_ROUTE information"), 1353 NULL, 0, NULL, 0, 1354 CTL_NET, PF_XROUTE, CTL_EOL); 1355 1356 sysctl_createv(clog, 0, NULL, NULL, 1357 CTLFLAG_PERMANENT, 1358 CTLTYPE_NODE, "rtable", 1359 SYSCTL_DESCR("Routing table information"), 1360 sysctl_rtable, 0, NULL, 0, 1361 CTL_NET, PF_XROUTE, 0 /* any protocol */, CTL_EOL); 1362 1363 sysctl_createv(clog, 0, &rnode, NULL, 1364 CTLFLAG_PERMANENT, 1365 CTLTYPE_STRUCT, "stats", 1366 SYSCTL_DESCR("Routing statistics"), 1367 NULL, 0, &rtstat, sizeof(rtstat), 1368 CTL_CREATE, CTL_EOL); 1369} 1370