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