1 /* $OpenBSD: rtsock.c,v 1.149 2014/07/12 18:44:22 tedu Exp $ */ 2 /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT 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. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)rtsock.c 8.6 (Berkeley) 2/11/95 62 */ 63 64 #include <sys/param.h> 65 #include <sys/systm.h> 66 #include <sys/proc.h> 67 #include <sys/sysctl.h> 68 #include <sys/mbuf.h> 69 #include <sys/socket.h> 70 #include <sys/socketvar.h> 71 #include <sys/domain.h> 72 #include <sys/protosw.h> 73 74 #include <net/if.h> 75 #include <net/route.h> 76 #include <net/raw_cb.h> 77 78 #ifdef MPLS 79 #include <netmpls/mpls.h> 80 #endif 81 82 #include <sys/stdarg.h> 83 #include <sys/kernel.h> 84 #include <sys/timeout.h> 85 86 struct sockaddr route_dst = { 2, PF_ROUTE, }; 87 struct sockaddr route_src = { 2, PF_ROUTE, }; 88 struct sockproto route_proto = { PF_ROUTE, }; 89 90 struct walkarg { 91 int w_op, w_arg, w_given, w_needed, w_tmemsize; 92 caddr_t w_where, w_tmem; 93 }; 94 95 int route_ctloutput(int, struct socket *, int, int, struct mbuf **); 96 void route_input(struct mbuf *m0, ...); 97 98 struct mbuf *rt_msg1(int, struct rt_addrinfo *); 99 int rt_msg2(int, int, struct rt_addrinfo *, caddr_t, 100 struct walkarg *); 101 void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); 102 103 struct routecb { 104 struct rawcb rcb; 105 struct timeout timeout; 106 unsigned int msgfilter; 107 unsigned int flags; 108 u_int rtableid; 109 }; 110 #define sotoroutecb(so) ((struct routecb *)(so)->so_pcb) 111 112 /* 113 * These flags and timeout are used for indicating to userland (via a 114 * RTM_DESYNC msg) when the route socket has overflowed and messages 115 * have been lost. 116 */ 117 #define ROUTECB_FLAG_DESYNC 0x1 /* Route socket out of memory */ 118 #define ROUTECB_FLAG_FLUSH 0x2 /* Wait until socket is empty before 119 queueing more packets */ 120 121 #define ROUTE_DESYNC_RESEND_TIMEOUT (hz / 5) /* In hz */ 122 123 void rt_senddesync(void *); 124 125 int 126 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 127 struct mbuf *control, struct proc *p) 128 { 129 struct rawcb *rp; 130 struct routecb *rop; 131 int s, af; 132 int error = 0; 133 134 s = splsoftnet(); 135 rp = sotorawcb(so); 136 137 switch (req) { 138 case PRU_ATTACH: 139 /* 140 * use the rawcb but allocate a routecb, this 141 * code does not care about the additional fields 142 * and works directly on the raw socket. 143 */ 144 rop = malloc(sizeof(struct routecb), M_PCB, M_WAITOK|M_ZERO); 145 rp = &rop->rcb; 146 so->so_pcb = rp; 147 /* Init the timeout structure */ 148 timeout_set(&((struct routecb *)rp)->timeout, rt_senddesync, rp); 149 /* 150 * Don't call raw_usrreq() in the attach case, because 151 * we want to allow non-privileged processes to listen 152 * on and send "safe" commands to the routing socket. 153 */ 154 if (curproc == 0) 155 error = EACCES; 156 else 157 error = raw_attach(so, (int)(long)nam); 158 if (error) { 159 free(rp, M_PCB, 0); 160 splx(s); 161 return (error); 162 } 163 rop->rtableid = curproc->p_p->ps_rtableid; 164 af = rp->rcb_proto.sp_protocol; 165 if (af == AF_INET) 166 route_cb.ip_count++; 167 else if (af == AF_INET6) 168 route_cb.ip6_count++; 169 #ifdef MPLS 170 else if (af == AF_MPLS) 171 route_cb.mpls_count++; 172 #endif 173 rp->rcb_faddr = &route_src; 174 route_cb.any_count++; 175 soisconnected(so); 176 so->so_options |= SO_USELOOPBACK; 177 break; 178 179 case PRU_RCVD: 180 rop = (struct routecb *)rp; 181 182 /* 183 * If we are in a FLUSH state, check if the buffer is 184 * empty so that we can clear the flag. 185 */ 186 if (((rop->flags & ROUTECB_FLAG_FLUSH) != 0) && 187 ((sbspace(&rp->rcb_socket->so_rcv) == 188 rp->rcb_socket->so_rcv.sb_hiwat))) 189 rop->flags &= ~ROUTECB_FLAG_FLUSH; 190 break; 191 192 case PRU_DETACH: 193 if (rp) { 194 timeout_del(&((struct routecb *)rp)->timeout); 195 af = rp->rcb_proto.sp_protocol; 196 if (af == AF_INET) 197 route_cb.ip_count--; 198 else if (af == AF_INET6) 199 route_cb.ip6_count--; 200 #ifdef MPLS 201 else if (af == AF_MPLS) 202 route_cb.mpls_count--; 203 #endif 204 route_cb.any_count--; 205 } 206 /* FALLTHROUGH */ 207 default: 208 error = raw_usrreq(so, req, m, nam, control, p); 209 } 210 211 splx(s); 212 return (error); 213 } 214 215 int 216 route_ctloutput(int op, struct socket *so, int level, int optname, 217 struct mbuf **mp) 218 { 219 struct routecb *rop = sotoroutecb(so); 220 struct mbuf *m = *mp; 221 int error = 0; 222 unsigned int tid; 223 224 if (level != AF_ROUTE) { 225 error = EINVAL; 226 if (op == PRCO_SETOPT && *mp) 227 m_free(*mp); 228 return (error); 229 } 230 231 switch (op) { 232 case PRCO_SETOPT: 233 switch (optname) { 234 case ROUTE_MSGFILTER: 235 if (m == NULL || m->m_len != sizeof(unsigned int)) 236 error = EINVAL; 237 else 238 rop->msgfilter = *mtod(m, unsigned int *); 239 break; 240 case ROUTE_TABLEFILTER: 241 if (m == NULL || m->m_len != sizeof(unsigned int)) { 242 error = EINVAL; 243 break; 244 } 245 tid = *mtod(m, unsigned int *); 246 if (tid != RTABLE_ANY && !rtable_exists(tid)) 247 error = ENOENT; 248 else 249 rop->rtableid = tid; 250 break; 251 default: 252 error = ENOPROTOOPT; 253 break; 254 } 255 if (m) 256 m_free(m); 257 break; 258 case PRCO_GETOPT: 259 switch (optname) { 260 case ROUTE_MSGFILTER: 261 *mp = m = m_get(M_WAIT, MT_SOOPTS); 262 m->m_len = sizeof(unsigned int); 263 *mtod(m, unsigned int *) = rop->msgfilter; 264 break; 265 case ROUTE_TABLEFILTER: 266 *mp = m = m_get(M_WAIT, MT_SOOPTS); 267 m->m_len = sizeof(unsigned int); 268 *mtod(m, unsigned int *) = rop->rtableid; 269 break; 270 default: 271 error = ENOPROTOOPT; 272 break; 273 } 274 } 275 return (error); 276 } 277 278 void 279 rt_senddesync(void *data) 280 { 281 struct rawcb *rp; 282 struct routecb *rop; 283 struct mbuf *desync_mbuf; 284 285 rp = (struct rawcb *)data; 286 rop = (struct routecb *)rp; 287 288 /* If we are in a DESYNC state, try to send a RTM_DESYNC packet */ 289 if ((rop->flags & ROUTECB_FLAG_DESYNC) != 0) { 290 /* 291 * If we fail to alloc memory or if sbappendaddr() 292 * fails, re-add timeout and try again. 293 */ 294 desync_mbuf = rt_msg1(RTM_DESYNC, NULL); 295 if ((desync_mbuf != NULL) && 296 (sbappendaddr(&rp->rcb_socket->so_rcv, &route_src, 297 desync_mbuf, (struct mbuf *)0) != 0)) { 298 rop->flags &= ~ROUTECB_FLAG_DESYNC; 299 sorwakeup(rp->rcb_socket); 300 } else { 301 if (desync_mbuf) 302 m_freem(desync_mbuf); 303 /* Re-add timeout to try sending msg again */ 304 timeout_add(&rop->timeout, ROUTE_DESYNC_RESEND_TIMEOUT); 305 } 306 } 307 } 308 309 void 310 route_input(struct mbuf *m0, ...) 311 { 312 struct rawcb *rp; 313 struct routecb *rop; 314 struct rt_msghdr *rtm; 315 struct mbuf *m = m0; 316 int sockets = 0; 317 struct socket *last = NULL; 318 va_list ap; 319 struct sockproto *proto; 320 struct sockaddr *sosrc, *sodst; 321 322 va_start(ap, m0); 323 proto = va_arg(ap, struct sockproto *); 324 sosrc = va_arg(ap, struct sockaddr *); 325 sodst = va_arg(ap, struct sockaddr *); 326 va_end(ap); 327 328 /* ensure that we can access the rtm_type via mtod() */ 329 if (m->m_len < offsetof(struct rt_msghdr, rtm_type) + 1) { 330 m_freem(m); 331 return; 332 } 333 334 LIST_FOREACH(rp, &rawcb, rcb_list) { 335 if (rp->rcb_socket->so_state & SS_CANTRCVMORE) 336 continue; 337 if (rp->rcb_proto.sp_family != proto->sp_family) 338 continue; 339 if (rp->rcb_proto.sp_protocol && proto->sp_protocol && 340 rp->rcb_proto.sp_protocol != proto->sp_protocol) 341 continue; 342 /* 343 * We assume the lower level routines have 344 * placed the address in a canonical format 345 * suitable for a structure comparison. 346 * 347 * Note that if the lengths are not the same 348 * the comparison will fail at the first byte. 349 */ 350 #define equal(a1, a2) \ 351 (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) 352 if (rp->rcb_laddr && !equal(rp->rcb_laddr, sodst)) 353 continue; 354 if (rp->rcb_faddr && !equal(rp->rcb_faddr, sosrc)) 355 continue; 356 357 /* filter messages that the process does not want */ 358 rop = (struct routecb *)rp; 359 rtm = mtod(m, struct rt_msghdr *); 360 /* but RTM_DESYNC can't be filtered */ 361 if (rtm->rtm_type != RTM_DESYNC && rop->msgfilter != 0 && 362 !(rop->msgfilter & (1 << rtm->rtm_type))) 363 continue; 364 switch (rtm->rtm_type) { 365 case RTM_IFANNOUNCE: 366 case RTM_DESYNC: 367 /* no tableid */ 368 break; 369 case RTM_RESOLVE: 370 case RTM_NEWADDR: 371 case RTM_DELADDR: 372 case RTM_IFINFO: 373 /* check against rdomain id */ 374 if (rop->rtableid != RTABLE_ANY && 375 rtable_l2(rop->rtableid) != rtm->rtm_tableid) 376 continue; 377 break; 378 default: 379 /* check against rtable id */ 380 if (rop->rtableid != RTABLE_ANY && 381 rop->rtableid != rtm->rtm_tableid) 382 continue; 383 break; 384 } 385 386 /* 387 * Check to see if the flush flag is set. If so, don't queue 388 * any more messages until the flag is cleared. 389 */ 390 if ((rop->flags & ROUTECB_FLAG_FLUSH) != 0) 391 continue; 392 393 if (last) { 394 struct mbuf *n; 395 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 396 if (sbspace(&last->so_rcv) < (2 * MSIZE) || 397 sbappendaddr(&last->so_rcv, sosrc, 398 n, (struct mbuf *)0) == 0) { 399 /* 400 * Flag socket as desync'ed and 401 * flush required 402 */ 403 sotoroutecb(last)->flags |= 404 ROUTECB_FLAG_DESYNC | 405 ROUTECB_FLAG_FLUSH; 406 rt_senddesync((void *) sotorawcb(last)); 407 m_freem(n); 408 } else { 409 sorwakeup(last); 410 sockets++; 411 } 412 } 413 } 414 last = rp->rcb_socket; 415 } 416 if (last) { 417 if (sbspace(&last->so_rcv) < (2 * MSIZE) || 418 sbappendaddr(&last->so_rcv, sosrc, 419 m, (struct mbuf *)0) == 0) { 420 /* Flag socket as desync'ed and flush required */ 421 sotoroutecb(last)->flags |= 422 ROUTECB_FLAG_DESYNC | ROUTECB_FLAG_FLUSH; 423 rt_senddesync((void *) sotorawcb(last)); 424 m_freem(m); 425 } else { 426 sorwakeup(last); 427 sockets++; 428 } 429 } else 430 m_freem(m); 431 } 432 433 int 434 route_output(struct mbuf *m, ...) 435 { 436 struct rt_msghdr *rtm = NULL; 437 struct radix_node *rn = NULL; 438 struct rtentry *rt = NULL; 439 struct rtentry *saved_nrt = NULL; 440 struct radix_node_head *rnh; 441 struct rt_addrinfo info; 442 int len, newgate, error = 0; 443 struct ifnet *ifp = NULL; 444 struct ifaddr *ifa = NULL; 445 struct socket *so; 446 struct rawcb *rp = NULL; 447 struct sockaddr_rtlabel sa_rl; 448 #ifdef MPLS 449 struct sockaddr_mpls sa_mpls, *psa_mpls; 450 #endif 451 va_list ap; 452 u_int tableid; 453 u_int8_t prio; 454 u_char vers; 455 456 va_start(ap, m); 457 so = va_arg(ap, struct socket *); 458 va_end(ap); 459 460 info.rti_info[RTAX_DST] = NULL; /* for error handling (goto flush) */ 461 if (m == 0 || ((m->m_len < sizeof(int32_t)) && 462 (m = m_pullup(m, sizeof(int32_t))) == 0)) 463 return (ENOBUFS); 464 if ((m->m_flags & M_PKTHDR) == 0) 465 panic("route_output"); 466 len = m->m_pkthdr.len; 467 if (len < offsetof(struct rt_msghdr, rtm_type) + 1 || 468 len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 469 error = EINVAL; 470 goto fail; 471 } 472 vers = mtod(m, struct rt_msghdr *)->rtm_version; 473 switch (vers) { 474 case RTM_VERSION: 475 if (len < sizeof(struct rt_msghdr)) { 476 error = EINVAL; 477 goto fail; 478 } 479 if (len > RTM_MAXSIZE) { 480 error = EMSGSIZE; 481 goto fail; 482 } 483 rtm = malloc(len, M_RTABLE, M_NOWAIT); 484 if (rtm == NULL) { 485 error = ENOBUFS; 486 goto fail; 487 } 488 m_copydata(m, 0, len, (caddr_t)rtm); 489 break; 490 default: 491 error = EPROTONOSUPPORT; 492 goto fail; 493 } 494 rtm->rtm_pid = curproc->p_p->ps_pid; 495 if (rtm->rtm_hdrlen == 0) /* old client */ 496 rtm->rtm_hdrlen = sizeof(struct rt_msghdr); 497 if (len < rtm->rtm_hdrlen) { 498 error = EINVAL; 499 goto fail; 500 } 501 502 /* Verify that the caller is sending an appropriate message early */ 503 switch (rtm->rtm_type) { 504 case RTM_ADD: 505 case RTM_DELETE: 506 case RTM_GET: 507 case RTM_CHANGE: 508 case RTM_LOCK: 509 break; 510 default: 511 error = EOPNOTSUPP; 512 goto fail; 513 } 514 515 /* 516 * Verify that the caller has the appropriate privilege; RTM_GET 517 * is the only operation the non-superuser is allowed. 518 */ 519 if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) { 520 error = EACCES; 521 goto fail; 522 } 523 524 tableid = rtm->rtm_tableid; 525 if (!rtable_exists(tableid)) { 526 if (rtm->rtm_type == RTM_ADD) { 527 if ((error = rtable_add(tableid)) != 0) 528 goto flush; 529 } else { 530 error = EINVAL; 531 goto flush; 532 } 533 } 534 535 536 /* Do not let userland play with kernel-only flags. */ 537 if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) { 538 error = EINVAL; 539 goto fail; 540 } 541 542 /* make sure that kernel-only bits are not set */ 543 rtm->rtm_priority &= RTP_MASK; 544 rtm->rtm_flags &= ~(RTF_DONE|RTF_CLONED); 545 rtm->rtm_fmask &= RTF_FMASK; 546 547 if (rtm->rtm_priority != 0) { 548 if (rtm->rtm_priority > RTP_MAX || 549 rtm->rtm_priority == RTP_LOCAL) { 550 error = EINVAL; 551 goto fail; 552 } 553 prio = rtm->rtm_priority; 554 } else if (rtm->rtm_type != RTM_ADD) 555 prio = RTP_ANY; 556 else if (rtm->rtm_flags & RTF_STATIC) 557 prio = 0; 558 else 559 prio = RTP_DEFAULT; 560 561 bzero(&info, sizeof(info)); 562 info.rti_addrs = rtm->rtm_addrs; 563 rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info); 564 info.rti_flags = rtm->rtm_flags; 565 if (info.rti_info[RTAX_DST] == NULL || 566 info.rti_info[RTAX_DST]->sa_family >= AF_MAX || 567 (info.rti_info[RTAX_GATEWAY] != NULL && 568 info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX) || 569 info.rti_info[RTAX_GENMASK] != NULL) { 570 error = EINVAL; 571 goto flush; 572 } 573 #ifdef MPLS 574 info.rti_mpls = rtm->rtm_mpls; 575 #endif 576 577 switch (rtm->rtm_type) { 578 case RTM_ADD: 579 if (info.rti_info[RTAX_GATEWAY] == NULL) { 580 error = EINVAL; 581 goto flush; 582 } 583 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 584 tableid); 585 if (error == 0 && saved_nrt) { 586 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 587 &saved_nrt->rt_rmx); 588 saved_nrt->rt_refcnt--; 589 /* write back the priority the kernel used */ 590 rtm->rtm_priority = saved_nrt->rt_priority & RTP_MASK; 591 rtm->rtm_index = saved_nrt->rt_ifp->if_index; 592 rtm->rtm_flags = saved_nrt->rt_flags; 593 } 594 break; 595 case RTM_DELETE: 596 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 597 tableid); 598 if (error == 0) { 599 (rt = saved_nrt)->rt_refcnt++; 600 goto report; 601 } 602 break; 603 case RTM_GET: 604 case RTM_CHANGE: 605 case RTM_LOCK: 606 rnh = rtable_get(tableid, info.rti_info[RTAX_DST]->sa_family); 607 if (rnh == NULL) { 608 error = EAFNOSUPPORT; 609 goto flush; 610 } 611 rt = rt_lookup(info.rti_info[RTAX_DST], 612 info.rti_info[RTAX_NETMASK], tableid); 613 rn = (struct radix_node *)rt; 614 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) { 615 error = ESRCH; 616 rt = NULL; 617 goto flush; 618 } 619 #ifndef SMALL_KERNEL 620 if (rn_mpath_capable(rnh)) { 621 /* first find the right priority */ 622 rt = rt_mpath_matchgate(rt, NULL, prio); 623 if (!rt) { 624 error = ESRCH; 625 goto flush; 626 } 627 /* 628 * For RTM_CHANGE/LOCK, if we got multipath routes, 629 * a matching RTAX_GATEWAY is required. 630 * OR 631 * If a gateway is specified then RTM_GET and 632 * RTM_LOCK must match the gateway no matter 633 * what even in the non multipath case. 634 */ 635 if ((rt->rt_flags & RTF_MPATH) || 636 (info.rti_info[RTAX_GATEWAY] && rtm->rtm_type != 637 RTM_CHANGE)) { 638 rt = rt_mpath_matchgate(rt, 639 info.rti_info[RTAX_GATEWAY], prio); 640 if (!rt) { 641 error = ESRCH; 642 goto flush; 643 } 644 /* 645 * only RTM_GET may use an empty gateway 646 * on multipath routes 647 */ 648 if (!info.rti_info[RTAX_GATEWAY] && 649 rtm->rtm_type != RTM_GET) { 650 rt = NULL; 651 error = ESRCH; 652 goto flush; 653 } 654 } 655 rn = (struct radix_node *)rt; 656 } 657 #endif 658 rt->rt_refcnt++; 659 660 /* 661 * RTM_CHANGE/LOCK need a perfect match, rn_lookup() 662 * returns a perfect match in case a netmask is specified. 663 * For host routes only a longest prefix match is returned 664 * so it is necessary to compare the existence of the netmaks. 665 * If both have a netmask rn_lookup() did a perfect match and 666 * if none of them have a netmask both are host routes which is 667 * also a perfect match. 668 */ 669 if (rtm->rtm_type != RTM_GET && 670 !rt_mask(rt) != !info.rti_info[RTAX_NETMASK]) { 671 error = ESRCH; 672 goto flush; 673 } 674 675 switch (rtm->rtm_type) { 676 case RTM_GET: 677 report: 678 info.rti_info[RTAX_DST] = rt_key(rt); 679 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 680 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 681 info.rti_info[RTAX_LABEL] = 682 rtlabel_id2sa(rt->rt_labelid, &sa_rl); 683 #ifdef MPLS 684 if (rt->rt_flags & RTF_MPLS) { 685 bzero(&sa_mpls, sizeof(sa_mpls)); 686 sa_mpls.smpls_family = AF_MPLS; 687 sa_mpls.smpls_len = sizeof(sa_mpls); 688 sa_mpls.smpls_label = ((struct rt_mpls *) 689 rt->rt_llinfo)->mpls_label; 690 info.rti_info[RTAX_SRC] = 691 (struct sockaddr *)&sa_mpls; 692 info.rti_mpls = ((struct rt_mpls *) 693 rt->rt_llinfo)->mpls_operation; 694 rtm->rtm_mpls = info.rti_mpls; 695 } 696 #endif 697 info.rti_info[RTAX_IFP] = NULL; 698 info.rti_info[RTAX_IFA] = NULL; 699 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) && 700 (ifp = rt->rt_ifp) != NULL) { 701 info.rti_info[RTAX_IFP] = 702 (struct sockaddr *)ifp->if_sadl; 703 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 704 if (ifp->if_flags & IFF_POINTOPOINT) 705 info.rti_info[RTAX_BRD] = 706 rt->rt_ifa->ifa_dstaddr; 707 else 708 info.rti_info[RTAX_BRD] = NULL; 709 rtm->rtm_index = ifp->if_index; 710 } 711 len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL, 712 NULL); 713 if (len > rtm->rtm_msglen) { 714 struct rt_msghdr *new_rtm; 715 new_rtm = malloc(len, M_RTABLE, M_NOWAIT); 716 if (new_rtm == NULL) { 717 error = ENOBUFS; 718 goto flush; 719 } 720 memcpy(new_rtm, rtm, rtm->rtm_msglen); 721 free(rtm, M_RTABLE, 0); 722 rtm = new_rtm; 723 } 724 rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm, 725 NULL); 726 rtm->rtm_flags = rt->rt_flags; 727 rtm->rtm_use = 0; 728 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 729 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 730 rtm->rtm_addrs = info.rti_addrs; 731 break; 732 733 case RTM_CHANGE: 734 /* 735 * new gateway could require new ifaddr, ifp; 736 * flags may also be different; ifp may be specified 737 * by ll sockaddr when protocol address is ambiguous 738 */ 739 if ((error = rt_getifa(&info, tableid)) != 0) 740 goto flush; 741 newgate = 0; 742 if (info.rti_info[RTAX_GATEWAY] != NULL) 743 if (rt->rt_gateway == NULL || 744 bcmp(rt->rt_gateway, 745 info.rti_info[RTAX_GATEWAY], 746 info.rti_info[RTAX_GATEWAY]->sa_len)) { 747 newgate = 1; 748 } 749 if (info.rti_info[RTAX_GATEWAY] != NULL && 750 rt_setgate(rt, rt_key(rt), 751 info.rti_info[RTAX_GATEWAY], tableid)) { 752 error = EDQUOT; 753 goto flush; 754 } 755 ifa = info.rti_ifa; 756 if (ifa) { 757 if (rt->rt_ifa != ifa) { 758 if (rt->rt_ifa->ifa_rtrequest) 759 rt->rt_ifa->ifa_rtrequest( 760 RTM_DELETE, rt); 761 ifafree(rt->rt_ifa); 762 rt->rt_ifa = ifa; 763 ifa->ifa_refcnt++; 764 rt->rt_ifp = ifa->ifa_ifp; 765 #ifndef SMALL_KERNEL 766 /* recheck link state after ifp change*/ 767 rt_if_linkstate_change( 768 (struct radix_node *)rt, rt->rt_ifp, 769 tableid); 770 #endif 771 } 772 } 773 #ifdef MPLS 774 if ((rtm->rtm_flags & RTF_MPLS) && 775 info.rti_info[RTAX_SRC] != NULL) { 776 struct rt_mpls *rt_mpls; 777 778 psa_mpls = (struct sockaddr_mpls *) 779 info.rti_info[RTAX_SRC]; 780 781 if (rt->rt_llinfo == NULL) { 782 rt->rt_llinfo = 783 malloc(sizeof(struct rt_mpls), 784 M_TEMP, M_NOWAIT|M_ZERO); 785 } 786 if (rt->rt_llinfo == NULL) { 787 error = ENOMEM; 788 goto flush; 789 } 790 791 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 792 793 if (psa_mpls != NULL) { 794 rt_mpls->mpls_label = 795 psa_mpls->smpls_label; 796 } 797 798 rt_mpls->mpls_operation = info.rti_mpls; 799 800 /* XXX: set experimental bits */ 801 802 rt->rt_flags |= RTF_MPLS; 803 } else if (newgate || ((rtm->rtm_fmask & RTF_MPLS) && 804 !(rtm->rtm_flags & RTF_MPLS))) { 805 /* if gateway changed remove MPLS information */ 806 if (rt->rt_llinfo != NULL && 807 rt->rt_flags & RTF_MPLS) { 808 free(rt->rt_llinfo, M_TEMP, 0); 809 rt->rt_llinfo = NULL; 810 rt->rt_flags &= ~RTF_MPLS; 811 } 812 } 813 #endif 814 /* Hack to allow some flags to be toggled */ 815 if (rtm->rtm_fmask) 816 rt->rt_flags = 817 (rt->rt_flags & ~rtm->rtm_fmask) | 818 (rtm->rtm_flags & rtm->rtm_fmask); 819 820 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 821 &rt->rt_rmx); 822 rtm->rtm_index = rt->rt_ifp->if_index; 823 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 824 rtm->rtm_flags = rt->rt_flags; 825 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 826 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt); 827 if (info.rti_info[RTAX_LABEL] != NULL) { 828 char *rtlabel = ((struct sockaddr_rtlabel *) 829 info.rti_info[RTAX_LABEL])->sr_label; 830 rtlabel_unref(rt->rt_labelid); 831 rt->rt_labelid = 832 rtlabel_name2id(rtlabel); 833 } 834 if_group_routechange(info.rti_info[RTAX_DST], 835 info.rti_info[RTAX_NETMASK]); 836 /* FALLTHROUGH */ 837 case RTM_LOCK: 838 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 839 rt->rt_rmx.rmx_locks |= 840 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 841 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 842 break; 843 } 844 break; 845 } 846 847 flush: 848 if (rtm) { 849 if (error) 850 rtm->rtm_errno = error; 851 else { 852 rtm->rtm_flags |= RTF_DONE; 853 } 854 } 855 if (info.rti_info[RTAX_DST]) 856 route_proto.sp_protocol = info.rti_info[RTAX_DST]->sa_family; 857 if (rt) 858 rtfree(rt); 859 860 /* 861 * Check to see if we don't want our own messages. 862 */ 863 if (!(so->so_options & SO_USELOOPBACK)) { 864 if (route_cb.any_count <= 1) { 865 fail: 866 free(rtm, M_RTABLE, 0); 867 m_freem(m); 868 return (error); 869 } 870 /* There is another listener, so construct message */ 871 rp = sotorawcb(so); 872 } 873 if (rp) 874 rp->rcb_proto.sp_family = 0; /* Avoid us */ 875 if (rtm) { 876 if (m_copyback(m, 0, rtm->rtm_msglen, rtm, M_NOWAIT)) { 877 m_freem(m); 878 m = NULL; 879 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 880 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 881 free(rtm, M_RTABLE, 0); 882 } 883 if (m) 884 route_input(m, &route_proto, &route_src, &route_dst); 885 if (rp) 886 rp->rcb_proto.sp_family = PF_ROUTE; 887 888 return (error); 889 } 890 891 void 892 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out) 893 { 894 if (which & RTV_MTU) 895 out->rmx_mtu = in->rmx_mtu; 896 if (which & RTV_EXPIRE) 897 out->rmx_expire = in->rmx_expire; 898 /* RTV_PRIORITY handled before */ 899 } 900 901 void 902 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out) 903 { 904 bzero(out, sizeof(*out)); 905 out->rmx_locks = in->rmx_locks; 906 out->rmx_mtu = in->rmx_mtu; 907 out->rmx_expire = in->rmx_expire; 908 out->rmx_pksent = in->rmx_pksent; 909 } 910 911 #define ROUNDUP(a) \ 912 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 913 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 914 915 void 916 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 917 { 918 struct sockaddr *sa; 919 int i; 920 921 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 922 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 923 if ((rtinfo->rti_addrs & (1 << i)) == 0) 924 continue; 925 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 926 ADVANCE(cp, sa); 927 } 928 } 929 930 struct mbuf * 931 rt_msg1(int type, struct rt_addrinfo *rtinfo) 932 { 933 struct rt_msghdr *rtm; 934 struct mbuf *m; 935 int i; 936 struct sockaddr *sa; 937 int len, dlen, hlen; 938 939 switch (type) { 940 case RTM_DELADDR: 941 case RTM_NEWADDR: 942 len = sizeof(struct ifa_msghdr); 943 break; 944 case RTM_IFINFO: 945 len = sizeof(struct if_msghdr); 946 break; 947 case RTM_IFANNOUNCE: 948 len = sizeof(struct if_announcemsghdr); 949 break; 950 default: 951 len = sizeof(struct rt_msghdr); 952 break; 953 } 954 if (len > MCLBYTES) 955 panic("rt_msg1"); 956 m = m_gethdr(M_DONTWAIT, MT_DATA); 957 if (m && len > MHLEN) { 958 MCLGET(m, M_DONTWAIT); 959 if ((m->m_flags & M_EXT) == 0) { 960 m_free(m); 961 m = NULL; 962 } 963 } 964 if (m == 0) 965 return (m); 966 m->m_pkthdr.len = m->m_len = hlen = len; 967 m->m_pkthdr.rcvif = NULL; 968 rtm = mtod(m, struct rt_msghdr *); 969 bzero(rtm, len); 970 for (i = 0; i < RTAX_MAX; i++) { 971 if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL) 972 continue; 973 rtinfo->rti_addrs |= (1 << i); 974 dlen = ROUNDUP(sa->sa_len); 975 if (m_copyback(m, len, dlen, sa, M_NOWAIT)) { 976 m_freem(m); 977 return (NULL); 978 } 979 len += dlen; 980 } 981 rtm->rtm_msglen = len; 982 rtm->rtm_hdrlen = hlen; 983 rtm->rtm_version = RTM_VERSION; 984 rtm->rtm_type = type; 985 return (m); 986 } 987 988 int 989 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp, 990 struct walkarg *w) 991 { 992 int i; 993 int len, dlen, hlen, second_time = 0; 994 caddr_t cp0; 995 996 rtinfo->rti_addrs = 0; 997 again: 998 switch (type) { 999 case RTM_DELADDR: 1000 case RTM_NEWADDR: 1001 len = sizeof(struct ifa_msghdr); 1002 break; 1003 case RTM_IFINFO: 1004 len = sizeof(struct if_msghdr); 1005 break; 1006 default: 1007 len = sizeof(struct rt_msghdr); 1008 break; 1009 } 1010 hlen = len; 1011 if ((cp0 = cp) != NULL) 1012 cp += len; 1013 for (i = 0; i < RTAX_MAX; i++) { 1014 struct sockaddr *sa; 1015 1016 if ((sa = rtinfo->rti_info[i]) == NULL) 1017 continue; 1018 rtinfo->rti_addrs |= (1 << i); 1019 dlen = ROUNDUP(sa->sa_len); 1020 if (cp) { 1021 bcopy(sa, cp, (size_t)dlen); 1022 cp += dlen; 1023 } 1024 len += dlen; 1025 } 1026 /* align message length to the next natural boundary */ 1027 len = ALIGN(len); 1028 if (cp == 0 && w != NULL && !second_time) { 1029 struct walkarg *rw = w; 1030 1031 rw->w_needed += len; 1032 if (rw->w_needed <= 0 && rw->w_where) { 1033 if (rw->w_tmemsize < len) { 1034 free(rw->w_tmem, M_RTABLE, 0); 1035 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 1036 if (rw->w_tmem) 1037 rw->w_tmemsize = len; 1038 } 1039 if (rw->w_tmem) { 1040 cp = rw->w_tmem; 1041 second_time = 1; 1042 goto again; 1043 } else 1044 rw->w_where = 0; 1045 } 1046 } 1047 if (cp && w) /* clear the message header */ 1048 bzero(cp0, hlen); 1049 1050 if (cp) { 1051 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 1052 1053 rtm->rtm_version = RTM_VERSION; 1054 rtm->rtm_type = type; 1055 rtm->rtm_msglen = len; 1056 rtm->rtm_hdrlen = hlen; 1057 } 1058 return (len); 1059 } 1060 1061 /* 1062 * This routine is called to generate a message from the routing 1063 * socket indicating that a redirect has occurred, a routing lookup 1064 * has failed, or that a protocol has detected timeouts to a particular 1065 * destination. 1066 */ 1067 void 1068 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, 1069 struct ifnet *ifp, int error, u_int tableid) 1070 { 1071 struct rt_msghdr *rtm; 1072 struct mbuf *m; 1073 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 1074 1075 if (route_cb.any_count == 0) 1076 return; 1077 m = rt_msg1(type, rtinfo); 1078 if (m == 0) 1079 return; 1080 rtm = mtod(m, struct rt_msghdr *); 1081 rtm->rtm_flags = RTF_DONE | flags; 1082 rtm->rtm_errno = error; 1083 rtm->rtm_tableid = tableid; 1084 rtm->rtm_addrs = rtinfo->rti_addrs; 1085 if (ifp != NULL) 1086 rtm->rtm_index = ifp->if_index; 1087 if (sa == NULL) 1088 route_proto.sp_protocol = 0; 1089 else 1090 route_proto.sp_protocol = sa->sa_family; 1091 route_input(m, &route_proto, &route_src, &route_dst); 1092 } 1093 1094 /* 1095 * This routine is called to generate a message from the routing 1096 * socket indicating that the status of a network interface has changed. 1097 */ 1098 void 1099 rt_ifmsg(struct ifnet *ifp) 1100 { 1101 struct if_msghdr *ifm; 1102 struct mbuf *m; 1103 1104 if (route_cb.any_count == 0) 1105 return; 1106 m = rt_msg1(RTM_IFINFO, NULL); 1107 if (m == 0) 1108 return; 1109 ifm = mtod(m, struct if_msghdr *); 1110 ifm->ifm_index = ifp->if_index; 1111 ifm->ifm_tableid = ifp->if_rdomain; 1112 ifm->ifm_flags = ifp->if_flags; 1113 ifm->ifm_xflags = ifp->if_xflags; 1114 ifm->ifm_data = ifp->if_data; 1115 ifm->ifm_addrs = 0; 1116 route_proto.sp_protocol = 0; 1117 route_input(m, &route_proto, &route_src, &route_dst); 1118 } 1119 1120 /* 1121 * This is called to generate messages from the routing socket 1122 * indicating a network interface has had addresses associated with it. 1123 * if we ever reverse the logic and replace messages TO the routing 1124 * socket indicate a request to configure interfaces, then it will 1125 * be unnecessary as the routing socket will automatically generate 1126 * copies of it. 1127 */ 1128 void 1129 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 1130 { 1131 struct rt_addrinfo info; 1132 struct sockaddr *sa = NULL; 1133 int pass; 1134 struct mbuf *m = NULL; 1135 struct ifnet *ifp = ifa->ifa_ifp; 1136 1137 if (route_cb.any_count == 0) 1138 return; 1139 for (pass = 1; pass < 3; pass++) { 1140 bzero(&info, sizeof(info)); 1141 if ((cmd == RTM_ADD && pass == 1) || 1142 (cmd == RTM_DELETE && pass == 2)) { 1143 struct ifa_msghdr *ifam; 1144 int ncmd; 1145 1146 if (cmd == RTM_ADD) 1147 ncmd = RTM_NEWADDR; 1148 else 1149 ncmd = RTM_DELADDR; 1150 1151 info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; 1152 info.rti_info[RTAX_IFP] = 1153 (struct sockaddr *)ifp->if_sadl; 1154 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1155 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1156 if ((m = rt_msg1(ncmd, &info)) == NULL) 1157 continue; 1158 ifam = mtod(m, struct ifa_msghdr *); 1159 ifam->ifam_index = ifp->if_index; 1160 ifam->ifam_metric = ifa->ifa_metric; 1161 ifam->ifam_flags = ifa->ifa_flags; 1162 ifam->ifam_addrs = info.rti_addrs; 1163 ifam->ifam_tableid = ifp->if_rdomain; 1164 } 1165 if ((cmd == RTM_ADD && pass == 2) || 1166 (cmd == RTM_DELETE && pass == 1)) { 1167 struct rt_msghdr *rtm; 1168 struct sockaddr_rtlabel sa_rl; 1169 1170 if (rt == 0) 1171 continue; 1172 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1173 info.rti_info[RTAX_DST] = sa = rt_key(rt); 1174 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1175 info.rti_info[RTAX_LABEL] = 1176 rtlabel_id2sa(rt->rt_labelid, &sa_rl); 1177 if ((m = rt_msg1(cmd, &info)) == NULL) 1178 continue; 1179 rtm = mtod(m, struct rt_msghdr *); 1180 rtm->rtm_index = ifp->if_index; 1181 rtm->rtm_flags |= rt->rt_flags; 1182 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 1183 rtm->rtm_errno = error; 1184 rtm->rtm_addrs = info.rti_addrs; 1185 rtm->rtm_tableid = ifp->if_rdomain; 1186 } 1187 if (sa == NULL) 1188 route_proto.sp_protocol = 0; 1189 else 1190 route_proto.sp_protocol = sa->sa_family; 1191 route_input(m, &route_proto, &route_src, &route_dst); 1192 } 1193 } 1194 1195 /* 1196 * This is called to generate routing socket messages indicating 1197 * network interface arrival and departure. 1198 */ 1199 void 1200 rt_ifannouncemsg(struct ifnet *ifp, int what) 1201 { 1202 struct if_announcemsghdr *ifan; 1203 struct mbuf *m; 1204 1205 if (route_cb.any_count == 0) 1206 return; 1207 m = rt_msg1(RTM_IFANNOUNCE, NULL); 1208 if (m == 0) 1209 return; 1210 ifan = mtod(m, struct if_announcemsghdr *); 1211 ifan->ifan_index = ifp->if_index; 1212 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name)); 1213 ifan->ifan_what = what; 1214 route_proto.sp_protocol = 0; 1215 route_input(m, &route_proto, &route_src, &route_dst); 1216 } 1217 1218 /* 1219 * This is used in dumping the kernel table via sysctl(). 1220 */ 1221 int 1222 sysctl_dumpentry(struct radix_node *rn, void *v, u_int id) 1223 { 1224 struct walkarg *w = v; 1225 struct rtentry *rt = (struct rtentry *)rn; 1226 int error = 0, size; 1227 struct rt_addrinfo info; 1228 #ifdef MPLS 1229 struct sockaddr_mpls sa_mpls; 1230 #endif 1231 struct sockaddr_rtlabel sa_rl; 1232 1233 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1234 return 0; 1235 bzero(&info, sizeof(info)); 1236 info.rti_info[RTAX_DST] = rt_key(rt); 1237 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1238 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1239 if (rt->rt_ifp) { 1240 info.rti_info[RTAX_IFP] = 1241 (struct sockaddr *)rt->rt_ifp->if_sadl; 1242 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 1243 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1244 info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; 1245 } 1246 info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); 1247 #ifdef MPLS 1248 if (rt->rt_flags & RTF_MPLS) { 1249 bzero(&sa_mpls, sizeof(sa_mpls)); 1250 sa_mpls.smpls_family = AF_MPLS; 1251 sa_mpls.smpls_len = sizeof(sa_mpls); 1252 sa_mpls.smpls_label = ((struct rt_mpls *) 1253 rt->rt_llinfo)->mpls_label; 1254 info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls; 1255 info.rti_mpls = ((struct rt_mpls *) 1256 rt->rt_llinfo)->mpls_operation; 1257 } 1258 #endif 1259 1260 size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w); 1261 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1262 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 1263 1264 rtm->rtm_flags = rt->rt_flags; 1265 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 1266 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 1267 rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt; 1268 rtm->rtm_index = rt->rt_ifp->if_index; 1269 rtm->rtm_addrs = info.rti_addrs; 1270 rtm->rtm_tableid = id; 1271 #ifdef MPLS 1272 rtm->rtm_mpls = info.rti_mpls; 1273 #endif 1274 if ((error = copyout(rtm, w->w_where, size)) != 0) 1275 w->w_where = NULL; 1276 else 1277 w->w_where += size; 1278 } 1279 return (error); 1280 } 1281 1282 int 1283 sysctl_iflist(int af, struct walkarg *w) 1284 { 1285 struct ifnet *ifp; 1286 struct ifaddr *ifa; 1287 struct rt_addrinfo info; 1288 int len, error = 0; 1289 1290 bzero(&info, sizeof(info)); 1291 TAILQ_FOREACH(ifp, &ifnet, if_list) { 1292 if (w->w_arg && w->w_arg != ifp->if_index) 1293 continue; 1294 /* Copy the link-layer address first */ 1295 info.rti_info[RTAX_IFP] = (struct sockaddr *)ifp->if_sadl; 1296 len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w); 1297 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1298 struct if_msghdr *ifm; 1299 1300 ifm = (struct if_msghdr *)w->w_tmem; 1301 ifm->ifm_index = ifp->if_index; 1302 ifm->ifm_tableid = ifp->if_rdomain; 1303 ifm->ifm_flags = ifp->if_flags; 1304 ifm->ifm_data = ifp->if_data; 1305 ifm->ifm_addrs = info.rti_addrs; 1306 error = copyout(ifm, w->w_where, len); 1307 if (error) 1308 return (error); 1309 w->w_where += len; 1310 } 1311 info.rti_info[RTAX_IFP] = NULL; 1312 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1313 KASSERT(ifa->ifa_addr->sa_family != AF_LINK); 1314 if (af && af != ifa->ifa_addr->sa_family) 1315 continue; 1316 info.rti_info[RTAX_IFA] = ifa->ifa_addr; 1317 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 1318 info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; 1319 len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w); 1320 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1321 struct ifa_msghdr *ifam; 1322 1323 ifam = (struct ifa_msghdr *)w->w_tmem; 1324 ifam->ifam_index = ifa->ifa_ifp->if_index; 1325 ifam->ifam_flags = ifa->ifa_flags; 1326 ifam->ifam_metric = ifa->ifa_metric; 1327 ifam->ifam_addrs = info.rti_addrs; 1328 error = copyout(w->w_tmem, w->w_where, len); 1329 if (error) 1330 return (error); 1331 w->w_where += len; 1332 } 1333 } 1334 info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = 1335 info.rti_info[RTAX_BRD] = NULL; 1336 } 1337 return (0); 1338 } 1339 1340 int 1341 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, 1342 size_t newlen) 1343 { 1344 struct radix_node_head *rnh; 1345 int i, s, error = EINVAL; 1346 u_char af; 1347 struct walkarg w; 1348 struct rt_tableinfo tableinfo; 1349 u_int tableid = 0; 1350 1351 if (new) 1352 return (EPERM); 1353 if (namelen < 3 || namelen > 4) 1354 return (EINVAL); 1355 af = name[0]; 1356 bzero(&w, sizeof(w)); 1357 w.w_where = where; 1358 w.w_given = *given; 1359 w.w_needed = 0 - w.w_given; 1360 w.w_op = name[1]; 1361 w.w_arg = name[2]; 1362 1363 if (namelen == 4) { 1364 tableid = name[3]; 1365 if (!rtable_exists(tableid)) 1366 return (ENOENT); 1367 } else 1368 tableid = curproc->p_p->ps_rtableid; 1369 1370 s = splsoftnet(); 1371 switch (w.w_op) { 1372 1373 case NET_RT_DUMP: 1374 case NET_RT_FLAGS: 1375 for (i = 1; i <= AF_MAX; i++) 1376 if ((rnh = rtable_get(tableid, i)) != NULL && 1377 (af == 0 || af == i) && 1378 (error = (*rnh->rnh_walktree)(rnh, 1379 sysctl_dumpentry, &w))) 1380 break; 1381 break; 1382 1383 case NET_RT_IFLIST: 1384 error = sysctl_iflist(af, &w); 1385 break; 1386 1387 case NET_RT_STATS: 1388 error = sysctl_rdstruct(where, given, new, 1389 &rtstat, sizeof(rtstat)); 1390 splx(s); 1391 return (error); 1392 case NET_RT_TABLE: 1393 tableid = w.w_arg; 1394 if (!rtable_exists(tableid)) { 1395 splx(s); 1396 return (ENOENT); 1397 } 1398 tableinfo.rti_tableid = tableid; 1399 tableinfo.rti_domainid = rtable_l2(tableid); 1400 error = sysctl_rdstruct(where, given, new, 1401 &tableinfo, sizeof(tableinfo)); 1402 splx(s); 1403 return (error); 1404 } 1405 splx(s); 1406 free(w.w_tmem, M_RTABLE, 0); 1407 w.w_needed += w.w_given; 1408 if (where) { 1409 *given = w.w_where - (caddr_t)where; 1410 if (*given < w.w_needed) 1411 return (ENOMEM); 1412 } else 1413 *given = (11 * w.w_needed) / 10; 1414 1415 return (error); 1416 } 1417 1418 /* 1419 * Definitions of protocols supported in the ROUTE domain. 1420 */ 1421 1422 extern struct domain routedomain; /* or at least forward */ 1423 1424 struct protosw routesw[] = { 1425 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR|PR_WANTRCVD, 1426 route_input, route_output, raw_ctlinput, route_ctloutput, 1427 route_usrreq, 1428 raw_init, 0, 0, 0, 1429 sysctl_rtable, 1430 } 1431 }; 1432 1433 struct domain routedomain = 1434 { PF_ROUTE, "route", route_init, 0, 0, 1435 routesw, &routesw[nitems(routesw)] }; 1436