1 /* 2 * Copyright (c) 2004, 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Jeffrey M. Hsu. 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 DragonFly Project nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific, prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1988, 1991, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 66 * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $ 67 * $DragonFly: src/sys/net/rtsock.c,v 1.38 2007/04/21 02:26:47 dillon Exp $ 68 */ 69 70 #include "opt_sctp.h" 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/kernel.h> 75 #include <sys/sysctl.h> 76 #include <sys/proc.h> 77 #include <sys/malloc.h> 78 #include <sys/mbuf.h> 79 #include <sys/protosw.h> 80 #include <sys/socket.h> 81 #include <sys/socketvar.h> 82 #include <sys/domain.h> 83 #include <sys/thread2.h> 84 85 #include <net/if.h> 86 #include <net/route.h> 87 #include <net/raw_cb.h> 88 89 #ifdef SCTP 90 extern void sctp_add_ip_address(struct ifaddr *ifa); 91 extern void sctp_delete_ip_address(struct ifaddr *ifa); 92 #endif /* SCTP */ 93 94 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables"); 95 96 static struct route_cb { 97 int ip_count; 98 int ip6_count; 99 int ipx_count; 100 int ns_count; 101 int any_count; 102 } route_cb; 103 104 static const struct sockaddr route_src = { 2, PF_ROUTE, }; 105 106 struct walkarg { 107 int w_tmemsize; 108 int w_op, w_arg; 109 void *w_tmem; 110 struct sysctl_req *w_req; 111 }; 112 113 static struct mbuf * 114 rt_msg_mbuf (int, struct rt_addrinfo *); 115 static void rt_msg_buffer (int, struct rt_addrinfo *, void *buf, int len); 116 static int rt_msgsize (int type, struct rt_addrinfo *rtinfo); 117 static int rt_xaddrs (char *, char *, struct rt_addrinfo *); 118 static int sysctl_dumpentry (struct radix_node *rn, void *vw); 119 static int sysctl_iflist (int af, struct walkarg *w); 120 static int route_output(struct mbuf *, struct socket *, ...); 121 static void rt_setmetrics (u_long, struct rt_metrics *, 122 struct rt_metrics *); 123 124 /* 125 * It really doesn't make any sense at all for this code to share much 126 * with raw_usrreq.c, since its functionality is so restricted. XXX 127 */ 128 static int 129 rts_abort(struct socket *so) 130 { 131 int error; 132 133 crit_enter(); 134 error = raw_usrreqs.pru_abort(so); 135 crit_exit(); 136 return error; 137 } 138 139 /* pru_accept is EOPNOTSUPP */ 140 141 static int 142 rts_attach(struct socket *so, int proto, struct pru_attach_info *ai) 143 { 144 struct rawcb *rp; 145 int error; 146 147 if (sotorawcb(so) != NULL) 148 return EISCONN; /* XXX panic? */ 149 150 rp = kmalloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO); 151 if (rp == NULL) 152 return ENOBUFS; 153 154 /* 155 * The critical section is necessary to block protocols from sending 156 * error notifications (like RTM_REDIRECT or RTM_LOSING) while 157 * this PCB is extant but incompletely initialized. 158 * Probably we should try to do more of this work beforehand and 159 * eliminate the critical section. 160 */ 161 crit_enter(); 162 so->so_pcb = rp; 163 error = raw_attach(so, proto, ai->sb_rlimit); 164 rp = sotorawcb(so); 165 if (error) { 166 crit_exit(); 167 kfree(rp, M_PCB); 168 return error; 169 } 170 switch(rp->rcb_proto.sp_protocol) { 171 case AF_INET: 172 route_cb.ip_count++; 173 break; 174 case AF_INET6: 175 route_cb.ip6_count++; 176 break; 177 case AF_IPX: 178 route_cb.ipx_count++; 179 break; 180 case AF_NS: 181 route_cb.ns_count++; 182 break; 183 } 184 rp->rcb_faddr = &route_src; 185 route_cb.any_count++; 186 soisconnected(so); 187 so->so_options |= SO_USELOOPBACK; 188 crit_exit(); 189 return 0; 190 } 191 192 static int 193 rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 194 { 195 int error; 196 197 crit_enter(); 198 error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */ 199 crit_exit(); 200 return error; 201 } 202 203 static int 204 rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 205 { 206 int error; 207 208 crit_enter(); 209 error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */ 210 crit_exit(); 211 return error; 212 } 213 214 /* pru_connect2 is EOPNOTSUPP */ 215 /* pru_control is EOPNOTSUPP */ 216 217 static int 218 rts_detach(struct socket *so) 219 { 220 struct rawcb *rp = sotorawcb(so); 221 int error; 222 223 crit_enter(); 224 if (rp != NULL) { 225 switch(rp->rcb_proto.sp_protocol) { 226 case AF_INET: 227 route_cb.ip_count--; 228 break; 229 case AF_INET6: 230 route_cb.ip6_count--; 231 break; 232 case AF_IPX: 233 route_cb.ipx_count--; 234 break; 235 case AF_NS: 236 route_cb.ns_count--; 237 break; 238 } 239 route_cb.any_count--; 240 } 241 error = raw_usrreqs.pru_detach(so); 242 crit_exit(); 243 return error; 244 } 245 246 static int 247 rts_disconnect(struct socket *so) 248 { 249 int error; 250 251 crit_enter(); 252 error = raw_usrreqs.pru_disconnect(so); 253 crit_exit(); 254 return error; 255 } 256 257 /* pru_listen is EOPNOTSUPP */ 258 259 static int 260 rts_peeraddr(struct socket *so, struct sockaddr **nam) 261 { 262 int error; 263 264 crit_enter(); 265 error = raw_usrreqs.pru_peeraddr(so, nam); 266 crit_exit(); 267 return error; 268 } 269 270 /* pru_rcvd is EOPNOTSUPP */ 271 /* pru_rcvoob is EOPNOTSUPP */ 272 273 static int 274 rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 275 struct mbuf *control, struct thread *td) 276 { 277 int error; 278 279 crit_enter(); 280 error = raw_usrreqs.pru_send(so, flags, m, nam, control, td); 281 crit_exit(); 282 return error; 283 } 284 285 /* pru_sense is null */ 286 287 static int 288 rts_shutdown(struct socket *so) 289 { 290 int error; 291 292 crit_enter(); 293 error = raw_usrreqs.pru_shutdown(so); 294 crit_exit(); 295 return error; 296 } 297 298 static int 299 rts_sockaddr(struct socket *so, struct sockaddr **nam) 300 { 301 int error; 302 303 crit_enter(); 304 error = raw_usrreqs.pru_sockaddr(so, nam); 305 crit_exit(); 306 return error; 307 } 308 309 static struct pr_usrreqs route_usrreqs = { 310 .pru_abort = rts_abort, 311 .pru_accept = pru_accept_notsupp, 312 .pru_attach = rts_attach, 313 .pru_bind = rts_bind, 314 .pru_connect = rts_connect, 315 .pru_connect2 = pru_connect2_notsupp, 316 .pru_control = pru_control_notsupp, 317 .pru_detach = rts_detach, 318 .pru_disconnect = rts_disconnect, 319 .pru_listen = pru_listen_notsupp, 320 .pru_peeraddr = rts_peeraddr, 321 .pru_rcvd = pru_rcvd_notsupp, 322 .pru_rcvoob = pru_rcvoob_notsupp, 323 .pru_send = rts_send, 324 .pru_sense = pru_sense_null, 325 .pru_shutdown = rts_shutdown, 326 .pru_sockaddr = rts_sockaddr, 327 .pru_sosend = sosend, 328 .pru_soreceive = soreceive, 329 .pru_sopoll = sopoll 330 }; 331 332 static __inline sa_family_t 333 familyof(struct sockaddr *sa) 334 { 335 return (sa != NULL ? sa->sa_family : 0); 336 } 337 338 static void 339 rts_input(struct mbuf *m, sa_family_t family) 340 { 341 static const struct sockaddr route_dst = { 2, PF_ROUTE, }; 342 struct sockproto route_proto = { PF_ROUTE, family }; 343 344 raw_input(m, &route_proto, &route_src, &route_dst); 345 } 346 347 static void * 348 reallocbuf(void *ptr, size_t len, size_t olen) 349 { 350 void *newptr; 351 352 newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); 353 if (newptr == NULL) 354 return NULL; 355 bcopy(ptr, newptr, olen); 356 kfree(ptr, M_RTABLE); 357 return (newptr); 358 } 359 360 /* 361 * Internal helper routine for route_output(). 362 */ 363 static int 364 fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt, 365 struct rt_addrinfo *rtinfo) 366 { 367 int msglen; 368 struct rt_msghdr *rtm = *prtm; 369 370 /* Fill in rt_addrinfo for call to rt_msg_buffer(). */ 371 rtinfo->rti_dst = rt_key(rt); 372 rtinfo->rti_gateway = rt->rt_gateway; 373 rtinfo->rti_netmask = rt_mask(rt); /* might be NULL */ 374 rtinfo->rti_genmask = rt->rt_genmask; /* might be NULL */ 375 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 376 if (rt->rt_ifp != NULL) { 377 rtinfo->rti_ifpaddr = 378 TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr; 379 rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr; 380 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 381 rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr; 382 rtm->rtm_index = rt->rt_ifp->if_index; 383 } else { 384 rtinfo->rti_ifpaddr = NULL; 385 rtinfo->rti_ifaaddr = NULL; 386 } 387 } 388 389 msglen = rt_msgsize(rtm->rtm_type, rtinfo); 390 if (rtm->rtm_msglen < msglen) { 391 rtm = reallocbuf(rtm, msglen, rtm->rtm_msglen); 392 if (rtm == NULL) 393 return (ENOBUFS); 394 *prtm = rtm; 395 } 396 rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen); 397 398 rtm->rtm_flags = rt->rt_flags; 399 rtm->rtm_rmx = rt->rt_rmx; 400 rtm->rtm_addrs = rtinfo->rti_addrs; 401 402 return (0); 403 } 404 405 static void route_output_add_callback(int, int, struct rt_addrinfo *, 406 struct rtentry *, void *); 407 static void route_output_delete_callback(int, int, struct rt_addrinfo *, 408 struct rtentry *, void *); 409 static void route_output_change_callback(int, int, struct rt_addrinfo *, 410 struct rtentry *, void *); 411 static void route_output_lock_callback(int, int, struct rt_addrinfo *, 412 struct rtentry *, void *); 413 414 /*ARGSUSED*/ 415 static int 416 route_output(struct mbuf *m, struct socket *so, ...) 417 { 418 struct rt_msghdr *rtm = NULL; 419 struct rtentry *rt; 420 struct radix_node_head *rnh; 421 struct rawcb *rp = NULL; 422 struct pr_output_info *oi; 423 struct rt_addrinfo rtinfo; 424 int len, error = 0; 425 __va_list ap; 426 427 __va_start(ap, so); 428 oi = __va_arg(ap, struct pr_output_info *); 429 __va_end(ap); 430 431 #define gotoerr(e) { error = e; goto flush;} 432 433 if (m == NULL || 434 (m->m_len < sizeof(long) && 435 (m = m_pullup(m, sizeof(long))) == NULL)) 436 return (ENOBUFS); 437 if (!(m->m_flags & M_PKTHDR)) 438 panic("route_output"); 439 len = m->m_pkthdr.len; 440 if (len < sizeof(struct rt_msghdr) || 441 len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 442 rtinfo.rti_dst = NULL; 443 gotoerr(EINVAL); 444 } 445 rtm = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); 446 if (rtm == NULL) { 447 rtinfo.rti_dst = NULL; 448 gotoerr(ENOBUFS); 449 } 450 m_copydata(m, 0, len, (caddr_t)rtm); 451 if (rtm->rtm_version != RTM_VERSION) { 452 rtinfo.rti_dst = NULL; 453 gotoerr(EPROTONOSUPPORT); 454 } 455 rtm->rtm_pid = oi->p_pid; 456 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 457 rtinfo.rti_addrs = rtm->rtm_addrs; 458 if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0) { 459 rtinfo.rti_dst = NULL; 460 gotoerr(EINVAL); 461 } 462 rtinfo.rti_flags = rtm->rtm_flags; 463 if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX || 464 (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX)) 465 gotoerr(EINVAL); 466 467 if (rtinfo.rti_genmask != NULL) { 468 struct radix_node *n; 469 470 #define clen(s) (*(u_char *)(s)) 471 n = rn_addmask((char *)rtinfo.rti_genmask, TRUE, 1); 472 if (n != NULL && 473 rtinfo.rti_genmask->sa_len >= clen(n->rn_key) && 474 bcmp((char *)rtinfo.rti_genmask + 1, 475 (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0) 476 rtinfo.rti_genmask = (struct sockaddr *)n->rn_key; 477 else 478 gotoerr(ENOBUFS); 479 } 480 481 /* 482 * Verify that the caller has the appropriate privilege; RTM_GET 483 * is the only operation the non-superuser is allowed. 484 */ 485 if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0) 486 gotoerr(EPERM); 487 488 switch (rtm->rtm_type) { 489 case RTM_ADD: 490 if (rtinfo.rti_gateway == NULL) { 491 error = EINVAL; 492 } else { 493 error = rtrequest1_global(RTM_ADD, &rtinfo, 494 route_output_add_callback, rtm); 495 } 496 break; 497 case RTM_DELETE: 498 /* 499 * note: &rtm passed as argument so 'rtm' can be replaced. 500 */ 501 error = rtrequest1_global(RTM_DELETE, &rtinfo, 502 route_output_delete_callback, &rtm); 503 break; 504 case RTM_GET: 505 rnh = rt_tables[mycpuid][rtinfo.rti_dst->sa_family]; 506 if (rnh == NULL) { 507 error = EAFNOSUPPORT; 508 break; 509 } 510 rt = (struct rtentry *) 511 rnh->rnh_lookup((char *)rtinfo.rti_dst, 512 (char *)rtinfo.rti_netmask, rnh); 513 if (rt == NULL) { 514 error = ESRCH; 515 break; 516 } 517 rt->rt_refcnt++; 518 if (fillrtmsg(&rtm, rt, &rtinfo) != 0) 519 gotoerr(ENOBUFS); 520 --rt->rt_refcnt; 521 break; 522 case RTM_CHANGE: 523 error = rtrequest1_global(RTM_GET, &rtinfo, 524 route_output_change_callback, rtm); 525 break; 526 case RTM_LOCK: 527 error = rtrequest1_global(RTM_GET, &rtinfo, 528 route_output_lock_callback, rtm); 529 break; 530 default: 531 error = EOPNOTSUPP; 532 break; 533 } 534 535 flush: 536 if (rtm != NULL) { 537 if (error != 0) 538 rtm->rtm_errno = error; 539 else 540 rtm->rtm_flags |= RTF_DONE; 541 } 542 543 /* 544 * Check to see if we don't want our own messages. 545 */ 546 if (!(so->so_options & SO_USELOOPBACK)) { 547 if (route_cb.any_count <= 1) { 548 if (rtm != NULL) 549 kfree(rtm, M_RTABLE); 550 m_freem(m); 551 return (error); 552 } 553 /* There is another listener, so construct message */ 554 rp = sotorawcb(so); 555 } 556 if (rtm != NULL) { 557 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 558 if (m->m_pkthdr.len < rtm->rtm_msglen) { 559 m_freem(m); 560 m = NULL; 561 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 562 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 563 kfree(rtm, M_RTABLE); 564 } 565 if (rp != NULL) 566 rp->rcb_proto.sp_family = 0; /* Avoid us */ 567 if (m != NULL) 568 rts_input(m, familyof(rtinfo.rti_dst)); 569 if (rp != NULL) 570 rp->rcb_proto.sp_family = PF_ROUTE; 571 return (error); 572 } 573 574 static void 575 route_output_add_callback(int cmd, int error, struct rt_addrinfo *rtinfo, 576 struct rtentry *rt, void *arg) 577 { 578 struct rt_msghdr *rtm = arg; 579 580 if (error == 0 && rt != NULL) { 581 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 582 &rt->rt_rmx); 583 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 584 rt->rt_rmx.rmx_locks |= 585 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 586 rt->rt_genmask = rtinfo->rti_genmask; 587 } 588 } 589 590 static void 591 route_output_delete_callback(int cmd, int error, struct rt_addrinfo *rtinfo, 592 struct rtentry *rt, void *arg) 593 { 594 struct rt_msghdr **rtm = arg; 595 596 if (error == 0 && rt) { 597 ++rt->rt_refcnt; 598 if (fillrtmsg(rtm, rt, rtinfo) != 0) { 599 error = ENOBUFS; 600 /* XXX no way to return the error */ 601 } 602 --rt->rt_refcnt; 603 } 604 } 605 606 static void 607 route_output_change_callback(int cmd, int error, struct rt_addrinfo *rtinfo, 608 struct rtentry *rt, void *arg) 609 { 610 struct rt_msghdr *rtm = arg; 611 struct ifaddr *ifa; 612 613 if (error) 614 goto done; 615 616 /* 617 * new gateway could require new ifaddr, ifp; 618 * flags may also be different; ifp may be specified 619 * by ll sockaddr when protocol address is ambiguous 620 */ 621 if (((rt->rt_flags & RTF_GATEWAY) && rtinfo->rti_gateway != NULL) || 622 rtinfo->rti_ifpaddr != NULL || (rtinfo->rti_ifaaddr != NULL && 623 sa_equal(rtinfo->rti_ifaaddr, rt->rt_ifa->ifa_addr)) 624 ) { 625 error = rt_getifa(rtinfo); 626 if (error != 0) 627 goto done; 628 } 629 if (rtinfo->rti_gateway != NULL) { 630 error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway); 631 if (error != 0) 632 goto done; 633 } 634 if ((ifa = rtinfo->rti_ifa) != NULL) { 635 struct ifaddr *oifa = rt->rt_ifa; 636 637 if (oifa != ifa) { 638 if (oifa && oifa->ifa_rtrequest) 639 oifa->ifa_rtrequest(RTM_DELETE, rt, rtinfo); 640 IFAFREE(rt->rt_ifa); 641 IFAREF(ifa); 642 rt->rt_ifa = ifa; 643 rt->rt_ifp = rtinfo->rti_ifp; 644 } 645 } 646 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); 647 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 648 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, rtinfo); 649 if (rtinfo->rti_genmask != NULL) 650 rt->rt_genmask = rtinfo->rti_genmask; 651 done: 652 /* XXX no way to return error */ 653 ; 654 } 655 656 static void 657 route_output_lock_callback(int cmd, int error, struct rt_addrinfo *rtinfo, 658 struct rtentry *rt, void *arg) 659 { 660 struct rt_msghdr *rtm = arg; 661 662 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 663 rt->rt_rmx.rmx_locks |= 664 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 665 } 666 667 static void 668 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out) 669 { 670 #define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt; 671 setmetric(RTV_RPIPE, rmx_recvpipe); 672 setmetric(RTV_SPIPE, rmx_sendpipe); 673 setmetric(RTV_SSTHRESH, rmx_ssthresh); 674 setmetric(RTV_RTT, rmx_rtt); 675 setmetric(RTV_RTTVAR, rmx_rttvar); 676 setmetric(RTV_HOPCOUNT, rmx_hopcount); 677 setmetric(RTV_MTU, rmx_mtu); 678 setmetric(RTV_EXPIRE, rmx_expire); 679 #undef setmetric 680 } 681 682 #define ROUNDUP(a) \ 683 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 684 685 /* 686 * Extract the addresses of the passed sockaddrs. 687 * Do a little sanity checking so as to avoid bad memory references. 688 * This data is derived straight from userland. 689 */ 690 static int 691 rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo) 692 { 693 struct sockaddr *sa; 694 int i; 695 696 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 697 if ((rtinfo->rti_addrs & (1 << i)) == 0) 698 continue; 699 sa = (struct sockaddr *)cp; 700 /* 701 * It won't fit. 702 */ 703 if ((cp + sa->sa_len) > cplim) { 704 return (EINVAL); 705 } 706 707 /* 708 * There are no more... Quit now. 709 * If there are more bits, they are in error. 710 * I've seen this. route(1) can evidently generate these. 711 * This causes kernel to core dump. 712 * For compatibility, if we see this, point to a safe address. 713 */ 714 if (sa->sa_len == 0) { 715 static struct sockaddr sa_zero = { 716 sizeof sa_zero, AF_INET, 717 }; 718 719 rtinfo->rti_info[i] = &sa_zero; 720 return (0); /* should be EINVAL but for compat */ 721 } 722 723 /* Accept the sockaddr. */ 724 rtinfo->rti_info[i] = sa; 725 cp += ROUNDUP(sa->sa_len); 726 } 727 return (0); 728 } 729 730 static int 731 rt_msghdrsize(int type) 732 { 733 switch (type) { 734 case RTM_DELADDR: 735 case RTM_NEWADDR: 736 return sizeof(struct ifa_msghdr); 737 case RTM_DELMADDR: 738 case RTM_NEWMADDR: 739 return sizeof(struct ifma_msghdr); 740 case RTM_IFINFO: 741 return sizeof(struct if_msghdr); 742 case RTM_IFANNOUNCE: 743 case RTM_IEEE80211: 744 return sizeof(struct if_announcemsghdr); 745 default: 746 return sizeof(struct rt_msghdr); 747 } 748 } 749 750 static int 751 rt_msgsize(int type, struct rt_addrinfo *rtinfo) 752 { 753 int len, i; 754 755 len = rt_msghdrsize(type); 756 for (i = 0; i < RTAX_MAX; i++) { 757 if (rtinfo->rti_info[i] != NULL) 758 len += ROUNDUP(rtinfo->rti_info[i]->sa_len); 759 } 760 len = ALIGN(len); 761 return len; 762 } 763 764 /* 765 * Build a routing message in a buffer. 766 * Copy the addresses in the rtinfo->rti_info[] sockaddr array 767 * to the end of the buffer after the message header. 768 * 769 * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[]. 770 * This side-effect can be avoided if we reorder the addrs bitmask field in all 771 * the route messages to line up so we can set it here instead of back in the 772 * calling routine. 773 */ 774 static void 775 rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen) 776 { 777 struct rt_msghdr *rtm; 778 char *cp; 779 int dlen, i; 780 781 rtm = (struct rt_msghdr *) buf; 782 rtm->rtm_version = RTM_VERSION; 783 rtm->rtm_type = type; 784 rtm->rtm_msglen = msglen; 785 786 cp = (char *)buf + rt_msghdrsize(type); 787 rtinfo->rti_addrs = 0; 788 for (i = 0; i < RTAX_MAX; i++) { 789 struct sockaddr *sa; 790 791 if ((sa = rtinfo->rti_info[i]) == NULL) 792 continue; 793 rtinfo->rti_addrs |= (1 << i); 794 dlen = ROUNDUP(sa->sa_len); 795 bcopy(sa, cp, dlen); 796 cp += dlen; 797 } 798 } 799 800 /* 801 * Build a routing message in a mbuf chain. 802 * Copy the addresses in the rtinfo->rti_info[] sockaddr array 803 * to the end of the mbuf after the message header. 804 * 805 * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[]. 806 * This side-effect can be avoided if we reorder the addrs bitmask field in all 807 * the route messages to line up so we can set it here instead of back in the 808 * calling routine. 809 */ 810 static struct mbuf * 811 rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo) 812 { 813 struct mbuf *m; 814 struct rt_msghdr *rtm; 815 int hlen, len; 816 int i; 817 818 hlen = rt_msghdrsize(type); 819 KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen)); 820 821 m = m_getl(hlen, MB_DONTWAIT, MT_DATA, M_PKTHDR, NULL); 822 if (m == NULL) 823 return (NULL); 824 m->m_pkthdr.len = m->m_len = hlen; 825 m->m_pkthdr.rcvif = NULL; 826 rtinfo->rti_addrs = 0; 827 len = hlen; 828 for (i = 0; i < RTAX_MAX; i++) { 829 struct sockaddr *sa; 830 int dlen; 831 832 if ((sa = rtinfo->rti_info[i]) == NULL) 833 continue; 834 rtinfo->rti_addrs |= (1 << i); 835 dlen = ROUNDUP(sa->sa_len); 836 m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */ 837 len += dlen; 838 } 839 if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */ 840 m_freem(m); 841 return (NULL); 842 } 843 rtm = mtod(m, struct rt_msghdr *); 844 bzero(rtm, hlen); 845 rtm->rtm_msglen = len; 846 rtm->rtm_version = RTM_VERSION; 847 rtm->rtm_type = type; 848 return (m); 849 } 850 851 /* 852 * This routine is called to generate a message from the routing 853 * socket indicating that a redirect has occurred, a routing lookup 854 * has failed, or that a protocol has detected timeouts to a particular 855 * destination. 856 */ 857 void 858 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) 859 { 860 struct sockaddr *dst = rtinfo->rti_info[RTAX_DST]; 861 struct rt_msghdr *rtm; 862 struct mbuf *m; 863 864 if (route_cb.any_count == 0) 865 return; 866 m = rt_msg_mbuf(type, rtinfo); 867 if (m == NULL) 868 return; 869 rtm = mtod(m, struct rt_msghdr *); 870 rtm->rtm_flags = RTF_DONE | flags; 871 rtm->rtm_errno = error; 872 rtm->rtm_addrs = rtinfo->rti_addrs; 873 rts_input(m, familyof(dst)); 874 } 875 876 void 877 rt_dstmsg(int type, struct sockaddr *dst, int error) 878 { 879 struct rt_msghdr *rtm; 880 struct rt_addrinfo addrs; 881 struct mbuf *m; 882 883 if (route_cb.any_count == 0) 884 return; 885 bzero(&addrs, sizeof(struct rt_addrinfo)); 886 addrs.rti_info[RTAX_DST] = dst; 887 m = rt_msg_mbuf(type, &addrs); 888 if (m == NULL) 889 return; 890 rtm = mtod(m, struct rt_msghdr *); 891 rtm->rtm_flags = RTF_DONE; 892 rtm->rtm_errno = error; 893 rtm->rtm_addrs = addrs.rti_addrs; 894 rts_input(m, familyof(dst)); 895 } 896 897 /* 898 * This routine is called to generate a message from the routing 899 * socket indicating that the status of a network interface has changed. 900 */ 901 void 902 rt_ifmsg(struct ifnet *ifp) 903 { 904 struct if_msghdr *ifm; 905 struct mbuf *m; 906 struct rt_addrinfo rtinfo; 907 908 if (route_cb.any_count == 0) 909 return; 910 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 911 m = rt_msg_mbuf(RTM_IFINFO, &rtinfo); 912 if (m == NULL) 913 return; 914 ifm = mtod(m, struct if_msghdr *); 915 ifm->ifm_index = ifp->if_index; 916 ifm->ifm_flags = ifp->if_flags; 917 ifm->ifm_data = ifp->if_data; 918 ifm->ifm_addrs = 0; 919 rts_input(m, 0); 920 } 921 922 static void 923 rt_ifamsg(int cmd, struct ifaddr *ifa) 924 { 925 struct ifa_msghdr *ifam; 926 struct rt_addrinfo rtinfo; 927 struct mbuf *m; 928 struct ifnet *ifp = ifa->ifa_ifp; 929 930 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 931 rtinfo.rti_ifaaddr = ifa->ifa_addr; 932 rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; 933 rtinfo.rti_netmask = ifa->ifa_netmask; 934 rtinfo.rti_bcastaddr = ifa->ifa_dstaddr; 935 936 m = rt_msg_mbuf(cmd, &rtinfo); 937 if (m == NULL) 938 return; 939 940 ifam = mtod(m, struct ifa_msghdr *); 941 ifam->ifam_index = ifp->if_index; 942 ifam->ifam_metric = ifa->ifa_metric; 943 ifam->ifam_flags = ifa->ifa_flags; 944 ifam->ifam_addrs = rtinfo.rti_addrs; 945 946 rts_input(m, familyof(ifa->ifa_addr)); 947 } 948 949 void 950 rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error) 951 { 952 struct rt_msghdr *rtm; 953 struct rt_addrinfo rtinfo; 954 struct mbuf *m; 955 struct sockaddr *dst; 956 957 if (rt == NULL) 958 return; 959 960 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 961 rtinfo.rti_dst = dst = rt_key(rt); 962 rtinfo.rti_gateway = rt->rt_gateway; 963 rtinfo.rti_netmask = rt_mask(rt); 964 if (ifp != NULL) 965 rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; 966 rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr; 967 968 m = rt_msg_mbuf(cmd, &rtinfo); 969 if (m == NULL) 970 return; 971 972 rtm = mtod(m, struct rt_msghdr *); 973 if (ifp != NULL) 974 rtm->rtm_index = ifp->if_index; 975 rtm->rtm_flags |= rt->rt_flags; 976 rtm->rtm_errno = error; 977 rtm->rtm_addrs = rtinfo.rti_addrs; 978 979 rts_input(m, familyof(dst)); 980 } 981 982 /* 983 * This is called to generate messages from the routing socket 984 * indicating a network interface has had addresses associated with it. 985 * if we ever reverse the logic and replace messages TO the routing 986 * socket indicate a request to configure interfaces, then it will 987 * be unnecessary as the routing socket will automatically generate 988 * copies of it. 989 */ 990 void 991 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 992 { 993 #ifdef SCTP 994 /* 995 * notify the SCTP stack 996 * this will only get called when an address is added/deleted 997 * XXX pass the ifaddr struct instead if ifa->ifa_addr... 998 */ 999 if (cmd == RTM_ADD) 1000 sctp_add_ip_address(ifa); 1001 else if (cmd == RTM_DELETE) 1002 sctp_delete_ip_address(ifa); 1003 #endif /* SCTP */ 1004 1005 if (route_cb.any_count == 0) 1006 return; 1007 1008 if (cmd == RTM_ADD) { 1009 rt_ifamsg(RTM_NEWADDR, ifa); 1010 rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error); 1011 } else { 1012 KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd)); 1013 rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error); 1014 rt_ifamsg(RTM_DELADDR, ifa); 1015 } 1016 } 1017 1018 /* 1019 * This is the analogue to the rt_newaddrmsg which performs the same 1020 * function but for multicast group memberhips. This is easier since 1021 * there is no route state to worry about. 1022 */ 1023 void 1024 rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma) 1025 { 1026 struct rt_addrinfo rtinfo; 1027 struct mbuf *m = NULL; 1028 struct ifnet *ifp = ifma->ifma_ifp; 1029 struct ifma_msghdr *ifmam; 1030 1031 if (route_cb.any_count == 0) 1032 return; 1033 1034 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 1035 rtinfo.rti_ifaaddr = ifma->ifma_addr; 1036 if (ifp != NULL && !TAILQ_EMPTY(&ifp->if_addrhead)) 1037 rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; 1038 /* 1039 * If a link-layer address is present, present it as a ``gateway'' 1040 * (similarly to how ARP entries, e.g., are presented). 1041 */ 1042 rtinfo.rti_gateway = ifma->ifma_lladdr; 1043 1044 m = rt_msg_mbuf(cmd, &rtinfo); 1045 if (m == NULL) 1046 return; 1047 1048 ifmam = mtod(m, struct ifma_msghdr *); 1049 ifmam->ifmam_index = ifp->if_index; 1050 ifmam->ifmam_addrs = rtinfo.rti_addrs; 1051 1052 rts_input(m, familyof(ifma->ifma_addr)); 1053 } 1054 1055 static struct mbuf * 1056 rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, 1057 struct rt_addrinfo *info) 1058 { 1059 struct if_announcemsghdr *ifan; 1060 struct mbuf *m; 1061 1062 if (route_cb.any_count == 0) 1063 return NULL; 1064 1065 bzero(info, sizeof(*info)); 1066 m = rt_msg_mbuf(type, info); 1067 if (m == NULL) 1068 return NULL; 1069 1070 ifan = mtod(m, struct if_announcemsghdr *); 1071 ifan->ifan_index = ifp->if_index; 1072 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name); 1073 ifan->ifan_what = what; 1074 return m; 1075 } 1076 1077 /* 1078 * This is called to generate routing socket messages indicating 1079 * IEEE80211 wireless events. 1080 * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. 1081 */ 1082 void 1083 rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len) 1084 { 1085 struct rt_addrinfo info; 1086 struct mbuf *m; 1087 1088 m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); 1089 if (m == NULL) 1090 return; 1091 1092 /* 1093 * Append the ieee80211 data. Try to stick it in the 1094 * mbuf containing the ifannounce msg; otherwise allocate 1095 * a new mbuf and append. 1096 * 1097 * NB: we assume m is a single mbuf. 1098 */ 1099 if (data_len > M_TRAILINGSPACE(m)) { 1100 struct mbuf *n = m_get(MB_DONTWAIT, MT_DATA); 1101 if (n == NULL) { 1102 m_freem(m); 1103 return; 1104 } 1105 bcopy(data, mtod(n, void *), data_len); 1106 n->m_len = data_len; 1107 m->m_next = n; 1108 } else if (data_len > 0) { 1109 bcopy(data, mtod(m, u_int8_t *) + m->m_len, data_len); 1110 m->m_len += data_len; 1111 } 1112 if (m->m_flags & M_PKTHDR) 1113 m->m_pkthdr.len += data_len; 1114 mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len; 1115 rts_input(m, 0); 1116 } 1117 1118 /* 1119 * This is called to generate routing socket messages indicating 1120 * network interface arrival and departure. 1121 */ 1122 void 1123 rt_ifannouncemsg(struct ifnet *ifp, int what) 1124 { 1125 struct rt_addrinfo addrinfo; 1126 struct mbuf *m; 1127 1128 m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &addrinfo); 1129 if (m != NULL) 1130 rts_input(m, 0); 1131 } 1132 1133 static int 1134 resizewalkarg(struct walkarg *w, int len) 1135 { 1136 void *newptr; 1137 1138 newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); 1139 if (newptr == NULL) 1140 return (ENOMEM); 1141 if (w->w_tmem != NULL) 1142 kfree(w->w_tmem, M_RTABLE); 1143 w->w_tmem = newptr; 1144 w->w_tmemsize = len; 1145 return (0); 1146 } 1147 1148 /* 1149 * This is used in dumping the kernel table via sysctl(). 1150 */ 1151 int 1152 sysctl_dumpentry(struct radix_node *rn, void *vw) 1153 { 1154 struct walkarg *w = vw; 1155 struct rtentry *rt = (struct rtentry *)rn; 1156 struct rt_addrinfo rtinfo; 1157 int error, msglen; 1158 1159 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1160 return 0; 1161 1162 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 1163 rtinfo.rti_dst = rt_key(rt); 1164 rtinfo.rti_gateway = rt->rt_gateway; 1165 rtinfo.rti_netmask = rt_mask(rt); 1166 rtinfo.rti_genmask = rt->rt_genmask; 1167 if (rt->rt_ifp != NULL) { 1168 rtinfo.rti_ifpaddr = 1169 TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr; 1170 rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr; 1171 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1172 rtinfo.rti_bcastaddr = rt->rt_ifa->ifa_dstaddr; 1173 } 1174 msglen = rt_msgsize(RTM_GET, &rtinfo); 1175 if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) 1176 return (ENOMEM); 1177 rt_msg_buffer(RTM_GET, &rtinfo, w->w_tmem, msglen); 1178 if (w->w_req != NULL) { 1179 struct rt_msghdr *rtm = w->w_tmem; 1180 1181 rtm->rtm_flags = rt->rt_flags; 1182 rtm->rtm_use = rt->rt_use; 1183 rtm->rtm_rmx = rt->rt_rmx; 1184 rtm->rtm_index = rt->rt_ifp->if_index; 1185 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 1186 rtm->rtm_addrs = rtinfo.rti_addrs; 1187 error = SYSCTL_OUT(w->w_req, rtm, msglen); 1188 return (error); 1189 } 1190 return (0); 1191 } 1192 1193 static int 1194 sysctl_iflist(int af, struct walkarg *w) 1195 { 1196 struct ifnet *ifp; 1197 struct ifaddr *ifa; 1198 struct rt_addrinfo rtinfo; 1199 int msglen, error; 1200 1201 bzero(&rtinfo, sizeof(struct rt_addrinfo)); 1202 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1203 if (w->w_arg && w->w_arg != ifp->if_index) 1204 continue; 1205 ifa = TAILQ_FIRST(&ifp->if_addrhead); 1206 rtinfo.rti_ifpaddr = ifa->ifa_addr; 1207 msglen = rt_msgsize(RTM_IFINFO, &rtinfo); 1208 if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) 1209 return (ENOMEM); 1210 rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen); 1211 rtinfo.rti_ifpaddr = NULL; 1212 if (w->w_req != NULL && w->w_tmem != NULL) { 1213 struct if_msghdr *ifm = w->w_tmem; 1214 1215 ifm->ifm_index = ifp->if_index; 1216 ifm->ifm_flags = ifp->if_flags; 1217 ifm->ifm_data = ifp->if_data; 1218 ifm->ifm_addrs = rtinfo.rti_addrs; 1219 error = SYSCTL_OUT(w->w_req, ifm, msglen); 1220 if (error) 1221 return (error); 1222 } 1223 while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) { 1224 if (af && af != ifa->ifa_addr->sa_family) 1225 continue; 1226 if (curproc->p_ucred->cr_prison && 1227 prison_if(curproc->p_ucred, ifa->ifa_addr)) 1228 continue; 1229 rtinfo.rti_ifaaddr = ifa->ifa_addr; 1230 rtinfo.rti_netmask = ifa->ifa_netmask; 1231 rtinfo.rti_bcastaddr = ifa->ifa_dstaddr; 1232 msglen = rt_msgsize(RTM_NEWADDR, &rtinfo); 1233 if (w->w_tmemsize < msglen && 1234 resizewalkarg(w, msglen) != 0) 1235 return (ENOMEM); 1236 rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen); 1237 if (w->w_req != NULL) { 1238 struct ifa_msghdr *ifam = w->w_tmem; 1239 1240 ifam->ifam_index = ifa->ifa_ifp->if_index; 1241 ifam->ifam_flags = ifa->ifa_flags; 1242 ifam->ifam_metric = ifa->ifa_metric; 1243 ifam->ifam_addrs = rtinfo.rti_addrs; 1244 error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen); 1245 if (error) 1246 return (error); 1247 } 1248 } 1249 rtinfo.rti_netmask = NULL; 1250 rtinfo.rti_ifaaddr = NULL; 1251 rtinfo.rti_bcastaddr = NULL; 1252 } 1253 return (0); 1254 } 1255 1256 static int 1257 sysctl_rtsock(SYSCTL_HANDLER_ARGS) 1258 { 1259 int *name = (int *)arg1; 1260 u_int namelen = arg2; 1261 struct radix_node_head *rnh; 1262 int i, error = EINVAL; 1263 int origcpu; 1264 u_char af; 1265 struct walkarg w; 1266 1267 name ++; 1268 namelen--; 1269 if (req->newptr) 1270 return (EPERM); 1271 if (namelen != 3 && namelen != 4) 1272 return (EINVAL); 1273 af = name[0]; 1274 bzero(&w, sizeof w); 1275 w.w_op = name[1]; 1276 w.w_arg = name[2]; 1277 w.w_req = req; 1278 1279 /* 1280 * Optional third argument specifies cpu, used primarily for 1281 * debugging the route table. 1282 */ 1283 if (namelen == 4) { 1284 if (name[3] < 0 || name[3] >= ncpus) 1285 return (EINVAL); 1286 origcpu = mycpuid; 1287 lwkt_migratecpu(name[3]); 1288 } else { 1289 origcpu = -1; 1290 } 1291 crit_enter(); 1292 switch (w.w_op) { 1293 case NET_RT_DUMP: 1294 case NET_RT_FLAGS: 1295 for (i = 1; i <= AF_MAX; i++) 1296 if ((rnh = rt_tables[mycpuid][i]) && 1297 (af == 0 || af == i) && 1298 (error = rnh->rnh_walktree(rnh, 1299 sysctl_dumpentry, &w))) 1300 break; 1301 break; 1302 1303 case NET_RT_IFLIST: 1304 error = sysctl_iflist(af, &w); 1305 } 1306 crit_exit(); 1307 if (w.w_tmem != NULL) 1308 kfree(w.w_tmem, M_RTABLE); 1309 if (origcpu >= 0) 1310 lwkt_migratecpu(origcpu); 1311 return (error); 1312 } 1313 1314 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, ""); 1315 1316 /* 1317 * Definitions of protocols supported in the ROUTE domain. 1318 */ 1319 1320 static struct domain routedomain; /* or at least forward */ 1321 1322 static struct protosw routesw[] = { 1323 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 1324 0, route_output, raw_ctlinput, 0, 1325 cpu0_soport, 1326 raw_init, 0, 0, 0, 1327 &route_usrreqs 1328 } 1329 }; 1330 1331 static struct domain routedomain = { 1332 PF_ROUTE, "route", NULL, NULL, NULL, 1333 routesw, &routesw[(sizeof routesw)/(sizeof routesw[0])], 1334 }; 1335 1336 DOMAIN_SET(route); 1337