1 /* $OpenBSD: rtsock.c,v 1.95 2009/11/03 10:59:04 claudio 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/mbuf.h> 68 #include <sys/socket.h> 69 #include <sys/socketvar.h> 70 #include <sys/domain.h> 71 #include <sys/protosw.h> 72 73 #include <uvm/uvm_extern.h> 74 #include <sys/sysctl.h> 75 76 #include <net/if.h> 77 #include <net/route.h> 78 #include <net/raw_cb.h> 79 80 #ifdef MPLS 81 #include <netmpls/mpls.h> 82 #endif /* MPLS */ 83 84 #include <sys/stdarg.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 /* Sleazy use of local variables throughout file, warning!!!! */ 104 #define dst info.rti_info[RTAX_DST] 105 #define gate info.rti_info[RTAX_GATEWAY] 106 #define netmask info.rti_info[RTAX_NETMASK] 107 #define genmask info.rti_info[RTAX_GENMASK] 108 #define ifpaddr info.rti_info[RTAX_IFP] 109 #define ifaaddr info.rti_info[RTAX_IFA] 110 #define brdaddr info.rti_info[RTAX_BRD] 111 112 struct routecb { 113 struct rawcb rcb; 114 unsigned int msgfilter; 115 }; 116 #define sotoroutecb(so) ((struct routecb *)(so)->so_pcb) 117 118 119 int 120 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 121 struct mbuf *control, struct proc *p) 122 { 123 struct rawcb *rp; 124 int s, af; 125 int error = 0; 126 127 s = splsoftnet(); 128 rp = sotorawcb(so); 129 130 switch (req) { 131 case PRU_ATTACH: 132 /* 133 * use the rawcb but allocate a routecb, this 134 * code does not care about the additional fields 135 * and works directly on the raw socket. 136 */ 137 rp = malloc(sizeof(struct routecb), M_PCB, M_WAITOK|M_ZERO); 138 so->so_pcb = rp; 139 /* 140 * Don't call raw_usrreq() in the attach case, because 141 * we want to allow non-privileged processes to listen 142 * on and send "safe" commands to the routing socket. 143 */ 144 if (curproc == 0) 145 error = EACCES; 146 else 147 error = raw_attach(so, (int)(long)nam); 148 if (error) { 149 free(rp, M_PCB); 150 splx(s); 151 return (error); 152 } 153 af = rp->rcb_proto.sp_protocol; 154 if (af == AF_INET) 155 route_cb.ip_count++; 156 else if (af == AF_INET6) 157 route_cb.ip6_count++; 158 #ifdef MPLS 159 else if (af == AF_MPLS) 160 route_cb.mpls_count++; 161 #endif /* MPLS */ 162 rp->rcb_faddr = &route_src; 163 route_cb.any_count++; 164 soisconnected(so); 165 so->so_options |= SO_USELOOPBACK; 166 break; 167 168 case PRU_DETACH: 169 if (rp) { 170 af = rp->rcb_proto.sp_protocol; 171 if (af == AF_INET) 172 route_cb.ip_count--; 173 else if (af == AF_INET6) 174 route_cb.ip6_count--; 175 #ifdef MPLS 176 else if (af == AF_MPLS) 177 route_cb.mpls_count--; 178 #endif /* MPLS */ 179 route_cb.any_count--; 180 } 181 /* FALLTHROUGH */ 182 default: 183 error = raw_usrreq(so, req, m, nam, control, p); 184 } 185 186 splx(s); 187 return (error); 188 } 189 190 int 191 route_ctloutput(int op, struct socket *so, int level, int optname, 192 struct mbuf **mp) 193 { 194 struct routecb *rop = sotoroutecb(so); 195 struct mbuf *m = *mp; 196 int error = 0; 197 198 if (level != AF_ROUTE) { 199 error = EINVAL; 200 if (op == PRCO_SETOPT && *mp) 201 m_free(*mp); 202 return (error); 203 } 204 205 switch (op) { 206 case PRCO_SETOPT: 207 switch (optname) { 208 case ROUTE_MSGFILTER: 209 if (m == NULL || m->m_len != sizeof(unsigned int)) 210 error = EINVAL; 211 else 212 rop->msgfilter = *mtod(m, unsigned int *); 213 break; 214 default: 215 error = ENOPROTOOPT; 216 break; 217 } 218 if (m) 219 m_free(m); 220 break; 221 case PRCO_GETOPT: 222 switch (optname) { 223 case ROUTE_MSGFILTER: 224 *mp = m = m_get(M_WAIT, MT_SOOPTS); 225 m->m_len = sizeof(int); 226 *mtod(m, unsigned int *) = rop->msgfilter; 227 break; 228 default: 229 error = ENOPROTOOPT; 230 break; 231 } 232 } 233 return (error); 234 } 235 236 void 237 route_input(struct mbuf *m0, ...) 238 { 239 struct rawcb *rp; 240 struct routecb *rop; 241 struct mbuf *m = m0; 242 int sockets = 0; 243 struct socket *last; 244 va_list ap; 245 struct sockproto *proto; 246 struct sockaddr *sosrc, *sodst; 247 248 va_start(ap, m0); 249 proto = va_arg(ap, struct sockproto *); 250 sosrc = va_arg(ap, struct sockaddr *); 251 sodst = va_arg(ap, struct sockaddr *); 252 va_end(ap); 253 254 /* ensure that we can access the rtm_type via mtod() */ 255 if (m->m_len < offsetof(struct rt_msghdr, rtm_type) + 1) { 256 m_freem(m); 257 return; 258 } 259 260 last = 0; 261 LIST_FOREACH(rp, &rawcb, rcb_list) { 262 if (rp->rcb_proto.sp_family != proto->sp_family) 263 continue; 264 if (rp->rcb_proto.sp_protocol && 265 rp->rcb_proto.sp_protocol != proto->sp_protocol) 266 continue; 267 /* 268 * We assume the lower level routines have 269 * placed the address in a canonical format 270 * suitable for a structure comparison. 271 * 272 * Note that if the lengths are not the same 273 * the comparison will fail at the first byte. 274 */ 275 #define equal(a1, a2) \ 276 (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) 277 if (rp->rcb_laddr && !equal(rp->rcb_laddr, sodst)) 278 continue; 279 if (rp->rcb_faddr && !equal(rp->rcb_faddr, sosrc)) 280 continue; 281 282 /* filter messages that the process does not want */ 283 rop = (struct routecb *)rp; 284 if (rop->msgfilter != 0 && !(rop->msgfilter & (1 << 285 mtod(m, struct rt_msghdr *)->rtm_type))) 286 continue; 287 288 if (last) { 289 struct mbuf *n; 290 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 291 if (sbappendaddr(&last->so_rcv, sosrc, 292 n, (struct mbuf *)0) == 0) 293 /* should notify about lost packet */ 294 m_freem(n); 295 else { 296 sorwakeup(last); 297 sockets++; 298 } 299 } 300 } 301 last = rp->rcb_socket; 302 } 303 if (last) { 304 if (sbappendaddr(&last->so_rcv, sosrc, 305 m, (struct mbuf *)0) == 0) 306 m_freem(m); 307 else { 308 sorwakeup(last); 309 sockets++; 310 } 311 } else 312 m_freem(m); 313 } 314 315 int 316 route_output(struct mbuf *m, ...) 317 { 318 struct rt_msghdr *rtm = NULL; 319 struct radix_node *rn = NULL; 320 struct rtentry *rt = NULL; 321 struct rtentry *saved_nrt = NULL; 322 struct radix_node_head *rnh; 323 struct rt_addrinfo info; 324 int len, error = 0; 325 struct ifnet *ifp = NULL; 326 struct ifaddr *ifa = NULL; 327 struct socket *so; 328 struct rawcb *rp = NULL; 329 struct sockaddr_rtlabel sa_rt; 330 #ifdef MPLS 331 struct sockaddr_mpls sa_mpls, *psa_mpls; 332 #endif 333 const char *label; 334 va_list ap; 335 u_int tableid; 336 u_int8_t prio; 337 338 va_start(ap, m); 339 so = va_arg(ap, struct socket *); 340 va_end(ap); 341 342 dst = NULL; /* for error handling (goto flush) */ 343 if (m == 0 || ((m->m_len < sizeof(int32_t)) && 344 (m = m_pullup(m, sizeof(int32_t))) == 0)) 345 return (ENOBUFS); 346 if ((m->m_flags & M_PKTHDR) == 0) 347 panic("route_output"); 348 len = m->m_pkthdr.len; 349 if (len < offsetof(struct rt_msghdr, rtm_type) + 1 || 350 len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 351 error = EINVAL; 352 goto flush; 353 } 354 switch (mtod(m, struct rt_msghdr *)->rtm_version) { 355 case RTM_VERSION: 356 if (len < sizeof(struct rt_msghdr)) { 357 error = EINVAL; 358 goto flush; 359 } 360 R_Malloc(rtm, struct rt_msghdr *, len); 361 if (rtm == 0) { 362 error = ENOBUFS; 363 goto flush; 364 } 365 m_copydata(m, 0, len, (caddr_t)rtm); 366 break; 367 default: 368 error = EPROTONOSUPPORT; 369 goto flush; 370 } 371 rtm->rtm_pid = curproc->p_pid; 372 if (rtm->rtm_hdrlen == 0) /* old client */ 373 rtm->rtm_hdrlen = sizeof(struct rt_msghdr); 374 if (len < rtm->rtm_hdrlen) { 375 error = EINVAL; 376 goto flush; 377 } 378 379 tableid = rtm->rtm_tableid; 380 if (!rtable_exists(tableid)) { 381 if (rtm->rtm_type == RTM_ADD) { 382 if (rtable_add(tableid)) { 383 error = EINVAL; 384 goto flush; 385 } 386 } else { 387 error = EINVAL; 388 goto flush; 389 } 390 } 391 392 /* make sure that kernel-only bits are not set */ 393 rtm->rtm_priority &= RTP_MASK; 394 395 if (rtm->rtm_priority != 0) { 396 if (rtm->rtm_priority > RTP_MAX) { 397 error = EINVAL; 398 goto flush; 399 } 400 prio = rtm->rtm_priority; 401 } else if (rtm->rtm_type != RTM_ADD) 402 prio = RTP_ANY; 403 else if (rtm->rtm_flags & RTF_STATIC) 404 prio = 0; 405 else 406 prio = RTP_DEFAULT; 407 408 bzero(&info, sizeof(info)); 409 info.rti_addrs = rtm->rtm_addrs; 410 rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info); 411 info.rti_flags = rtm->rtm_flags; 412 if (dst == 0 || dst->sa_family >= AF_MAX || 413 (gate != 0 && gate->sa_family >= AF_MAX)) { 414 error = EINVAL; 415 goto flush; 416 } 417 if (genmask) { 418 struct radix_node *t; 419 t = rn_addmask(genmask, 0, 1); 420 if (t && genmask->sa_len >= 421 ((struct sockaddr *)t->rn_key)->sa_len && 422 Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1, 423 ((struct sockaddr *)t->rn_key)->sa_len) - 1) 424 genmask = (struct sockaddr *)(t->rn_key); 425 else { 426 error = ENOBUFS; 427 goto flush; 428 } 429 } 430 #ifdef MPLS 431 info.rti_mpls = rtm->rtm_mpls; 432 #endif 433 434 /* 435 * Verify that the caller has the appropriate privilege; RTM_GET 436 * is the only operation the non-superuser is allowed. 437 */ 438 if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) { 439 error = EACCES; 440 goto flush; 441 } 442 443 switch (rtm->rtm_type) { 444 case RTM_ADD: 445 if (gate == 0) { 446 error = EINVAL; 447 goto flush; 448 } 449 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 450 tableid); 451 if (error == 0 && saved_nrt) { 452 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 453 &saved_nrt->rt_rmx); 454 saved_nrt->rt_refcnt--; 455 saved_nrt->rt_genmask = genmask; 456 /* write back the priority the kernel used */ 457 rtm->rtm_index = saved_nrt->rt_ifp->if_index; 458 rtm->rtm_priority = saved_nrt->rt_priority & RTP_MASK; 459 } 460 break; 461 case RTM_DELETE: 462 error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt, 463 tableid); 464 if (error == 0) { 465 (rt = saved_nrt)->rt_refcnt++; 466 goto report; 467 } 468 break; 469 case RTM_GET: 470 case RTM_CHANGE: 471 case RTM_LOCK: 472 if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) { 473 error = EAFNOSUPPORT; 474 goto flush; 475 } 476 rn = rt_lookup(dst, netmask, tableid); 477 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) { 478 error = ESRCH; 479 goto flush; 480 } 481 rt = (struct rtentry *)rn; 482 #ifndef SMALL_KERNEL 483 /* 484 * for RTM_CHANGE/LOCK, if we got multipath routes, 485 * we require users to specify a matching RTAX_GATEWAY. 486 * 487 * for RTM_GET, gate is optional even with multipath. 488 * if gate == NULL the first match is returned. 489 * (no need to call rt_mpath_matchgate if gate == NULL) 490 */ 491 if (rn_mpath_capable(rnh)) { 492 /* first find correct priority bucket */ 493 rn = rn_mpath_prio(rn, prio); 494 rt = (struct rtentry *)rn; 495 if (prio != RTP_ANY && 496 (rt->rt_priority & RTP_MASK) != prio) { 497 error = ESRCH; 498 rt->rt_refcnt++; 499 goto flush; 500 } 501 502 /* if multipath routes */ 503 if (rn_mpath_next(rn, 0)) { 504 if (gate) 505 rt = rt_mpath_matchgate(rt, gate, prio); 506 else if (rtm->rtm_type != RTM_GET) 507 /* 508 * only RTM_GET may use an empty gate 509 * on multipath ... 510 */ 511 rt = NULL; 512 } else if (gate && (rtm->rtm_type == RTM_GET || 513 rtm->rtm_type == RTM_LOCK)) 514 /* 515 * ... but if a gate is specified RTM_GET 516 * and RTM_LOCK must match the gate no matter 517 * what. 518 */ 519 rt = rt_mpath_matchgate(rt, gate, prio); 520 521 if (!rt) { 522 error = ESRCH; 523 goto flush; 524 } 525 rn = (struct radix_node *)rt; 526 } 527 #endif 528 rt->rt_refcnt++; 529 530 /* 531 * RTM_CHANGE/LOCK need a perfect match, rn_lookup() 532 * returns a perfect match in case a netmask is specified. 533 * For host routes only a longest prefix match is returned 534 * so it is necessary to compare the existence of the netmaks. 535 * If both have a netmask rn_lookup() did a perfect match and 536 * if none of them have a netmask both are host routes which is 537 * also a perfect match. 538 */ 539 if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) { 540 error = ESRCH; 541 goto flush; 542 } 543 544 switch (rtm->rtm_type) { 545 case RTM_GET: 546 report: 547 dst = rt_key(rt); 548 gate = rt->rt_gateway; 549 netmask = rt_mask(rt); 550 genmask = rt->rt_genmask; 551 552 if (rt->rt_labelid) { 553 bzero(&sa_rt, sizeof(sa_rt)); 554 sa_rt.sr_len = sizeof(sa_rt); 555 label = rtlabel_id2name(rt->rt_labelid); 556 if (label != NULL) 557 strlcpy(sa_rt.sr_label, label, 558 sizeof(sa_rt.sr_label)); 559 info.rti_info[RTAX_LABEL] = 560 (struct sockaddr *)&sa_rt; 561 } 562 #ifdef MPLS 563 if (rt->rt_flags & RTF_MPLS) { 564 bzero(&sa_mpls, sizeof(sa_mpls)); 565 sa_mpls.smpls_family = AF_MPLS; 566 sa_mpls.smpls_len = sizeof(sa_mpls); 567 sa_mpls.smpls_label = ((struct rt_mpls *) 568 rt->rt_llinfo)->mpls_label; 569 info.rti_info[RTAX_SRC] = 570 (struct sockaddr *)&sa_mpls; 571 info.rti_mpls = ((struct rt_mpls *) 572 rt->rt_llinfo)->mpls_operation; 573 } 574 #endif 575 ifpaddr = 0; 576 ifaaddr = 0; 577 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) && 578 (ifp = rt->rt_ifp) != NULL) { 579 ifpaddr = 580 TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 581 ifaaddr = rt->rt_ifa->ifa_addr; 582 if (ifp->if_flags & IFF_POINTOPOINT) 583 brdaddr = rt->rt_ifa->ifa_dstaddr; 584 else 585 brdaddr = 0; 586 rtm->rtm_index = ifp->if_index; 587 } 588 len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL, 589 NULL); 590 if (len > rtm->rtm_msglen) { 591 struct rt_msghdr *new_rtm; 592 R_Malloc(new_rtm, struct rt_msghdr *, len); 593 if (new_rtm == 0) { 594 error = ENOBUFS; 595 goto flush; 596 } 597 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 598 Free(rtm); rtm = new_rtm; 599 } 600 rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm, 601 NULL); 602 rtm->rtm_flags = rt->rt_flags; 603 rtm->rtm_use = 0; 604 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 605 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 606 rtm->rtm_addrs = info.rti_addrs; 607 break; 608 609 case RTM_CHANGE: 610 /* 611 * new gateway could require new ifaddr, ifp; 612 * flags may also be different; ifp may be specified 613 * by ll sockaddr when protocol address is ambiguous 614 */ 615 if ((error = rt_getifa(&info, tableid)) != 0) 616 goto flush; 617 if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) { 618 error = EDQUOT; 619 goto flush; 620 } 621 if (ifpaddr && 622 (ifa = ifa_ifwithnet(ifpaddr, tableid)) && 623 (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) 624 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 625 ifp); 626 else if ((ifaaddr && 627 (ifa = ifa_ifwithaddr(ifaaddr, tableid))) || 628 (gate && (ifa = ifa_ifwithroute(rt->rt_flags, 629 rt_key(rt), gate, tableid)))) 630 ifp = ifa->ifa_ifp; 631 if (ifa) { 632 struct ifaddr *oifa = rt->rt_ifa; 633 if (oifa != ifa) { 634 if (oifa && oifa->ifa_rtrequest) 635 oifa->ifa_rtrequest(RTM_DELETE, rt, 636 &info); 637 IFAFREE(rt->rt_ifa); 638 rt->rt_ifa = ifa; 639 ifa->ifa_refcnt++; 640 rt->rt_ifp = ifp; 641 } 642 } 643 644 /* XXX Hack to allow some flags to be toggled */ 645 if (rtm->rtm_fmask & RTF_FMASK) 646 rt->rt_flags = (rt->rt_flags & 647 ~rtm->rtm_fmask) | 648 (rtm->rtm_flags & rtm->rtm_fmask); 649 650 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 651 &rt->rt_rmx); 652 rtm->rtm_index = rt->rt_ifp->if_index; 653 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 654 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 655 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 656 if (genmask) 657 rt->rt_genmask = genmask; 658 if (info.rti_info[RTAX_LABEL] != NULL) { 659 char *rtlabel = ((struct sockaddr_rtlabel *) 660 info.rti_info[RTAX_LABEL])->sr_label; 661 rtlabel_unref(rt->rt_labelid); 662 rt->rt_labelid = 663 rtlabel_name2id(rtlabel); 664 } 665 #ifdef MPLS 666 if (info.rti_info[RTAX_SRC] != NULL) { 667 struct rt_mpls *rt_mpls; 668 669 psa_mpls = (struct sockaddr_mpls *) 670 info.rti_info[RTAX_SRC]; 671 672 if (rt->rt_llinfo == NULL) { 673 rt->rt_llinfo = (caddr_t) 674 malloc(sizeof(struct rt_mpls), 675 M_TEMP, M_NOWAIT|M_ZERO); 676 } 677 if (rt->rt_llinfo == NULL) { 678 error = ENOMEM; 679 goto flush; 680 } 681 682 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 683 684 if (psa_mpls != NULL) { 685 rt_mpls->mpls_label = 686 psa_mpls->smpls_label; 687 } 688 689 rt_mpls->mpls_operation = info.rti_mpls; 690 691 /* XXX: set experimental bits */ 692 693 rt->rt_flags |= RTF_MPLS; 694 } else { 695 if (rt->rt_llinfo != NULL && 696 rt->rt_flags & RTF_MPLS) { 697 free(rt->rt_llinfo, M_TEMP); 698 rt->rt_llinfo = NULL; 699 700 rt->rt_flags &= (~RTF_MPLS); 701 } 702 } 703 #endif 704 if_group_routechange(dst, netmask); 705 /* FALLTHROUGH */ 706 case RTM_LOCK: 707 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 708 rt->rt_rmx.rmx_locks |= 709 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 710 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 711 break; 712 } 713 break; 714 715 default: 716 error = EOPNOTSUPP; 717 break; 718 } 719 720 flush: 721 if (rtm) { 722 if (error) 723 rtm->rtm_errno = error; 724 else { 725 #ifdef MPLS 726 if (rt && rt->rt_flags & RTF_MPLS) 727 rtm->rtm_flags |= RTF_MPLS; 728 #endif 729 rtm->rtm_flags |= RTF_DONE; 730 } 731 } 732 if (rt) 733 rtfree(rt); 734 735 /* 736 * Check to see if we don't want our own messages. 737 */ 738 if (!(so->so_options & SO_USELOOPBACK)) { 739 if (route_cb.any_count <= 1) { 740 if (rtm) 741 Free(rtm); 742 m_freem(m); 743 return (error); 744 } 745 /* There is another listener, so construct message */ 746 rp = sotorawcb(so); 747 } 748 if (rp) 749 rp->rcb_proto.sp_family = 0; /* Avoid us */ 750 if (dst) 751 route_proto.sp_protocol = dst->sa_family; 752 if (rtm) { 753 m_copyback(m, 0, rtm->rtm_msglen, rtm); 754 if (m->m_pkthdr.len < rtm->rtm_msglen) { 755 m_freem(m); 756 m = NULL; 757 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 758 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 759 Free(rtm); 760 } 761 if (m) 762 route_input(m, &route_proto, &route_src, &route_dst); 763 if (rp) 764 rp->rcb_proto.sp_family = PF_ROUTE; 765 766 return (error); 767 } 768 769 void 770 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out) 771 { 772 if (which & RTV_MTU) 773 out->rmx_mtu = in->rmx_mtu; 774 if (which & RTV_EXPIRE) 775 out->rmx_expire = in->rmx_expire; 776 /* RTV_PRIORITY handled befor */ 777 } 778 779 void 780 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out) 781 { 782 bzero(out, sizeof(*out)); 783 out->rmx_locks = in->rmx_locks; 784 out->rmx_mtu = in->rmx_mtu; 785 out->rmx_expire = in->rmx_expire; 786 out->rmx_pksent = in->rmx_pksent; 787 } 788 789 #define ROUNDUP(a) \ 790 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 791 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 792 793 void 794 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 795 { 796 struct sockaddr *sa; 797 int i; 798 799 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 800 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 801 if ((rtinfo->rti_addrs & (1 << i)) == 0) 802 continue; 803 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 804 ADVANCE(cp, sa); 805 } 806 } 807 808 struct mbuf * 809 rt_msg1(int type, struct rt_addrinfo *rtinfo) 810 { 811 struct rt_msghdr *rtm; 812 struct mbuf *m; 813 int i; 814 struct sockaddr *sa; 815 int len, dlen, hlen; 816 817 switch (type) { 818 case RTM_DELADDR: 819 case RTM_NEWADDR: 820 len = sizeof(struct ifa_msghdr); 821 break; 822 case RTM_IFINFO: 823 len = sizeof(struct if_msghdr); 824 break; 825 case RTM_IFANNOUNCE: 826 len = sizeof(struct if_announcemsghdr); 827 break; 828 default: 829 len = sizeof(struct rt_msghdr); 830 break; 831 } 832 if (len > MCLBYTES) 833 panic("rt_msg1"); 834 m = m_gethdr(M_DONTWAIT, MT_DATA); 835 if (m && len > MHLEN) { 836 MCLGET(m, M_DONTWAIT); 837 if ((m->m_flags & M_EXT) == 0) { 838 m_free(m); 839 m = NULL; 840 } 841 } 842 if (m == 0) 843 return (m); 844 m->m_pkthdr.len = m->m_len = hlen = len; 845 m->m_pkthdr.rcvif = NULL; 846 rtm = mtod(m, struct rt_msghdr *); 847 bzero(rtm, len); 848 for (i = 0; i < RTAX_MAX; i++) { 849 if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL) 850 continue; 851 rtinfo->rti_addrs |= (1 << i); 852 dlen = ROUNDUP(sa->sa_len); 853 m_copyback(m, len, dlen, sa); 854 len += dlen; 855 } 856 if (m->m_pkthdr.len != len) { 857 m_freem(m); 858 return (NULL); 859 } 860 rtm->rtm_msglen = len; 861 rtm->rtm_hdrlen = hlen; 862 rtm->rtm_version = RTM_VERSION; 863 rtm->rtm_type = type; 864 return (m); 865 } 866 867 int 868 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp, 869 struct walkarg *w) 870 { 871 int i; 872 int len, dlen, hlen, second_time = 0; 873 caddr_t cp0; 874 875 rtinfo->rti_addrs = 0; 876 again: 877 switch (type) { 878 case RTM_DELADDR: 879 case RTM_NEWADDR: 880 len = sizeof(struct ifa_msghdr); 881 break; 882 case RTM_IFINFO: 883 len = sizeof(struct if_msghdr); 884 break; 885 default: 886 len = sizeof(struct rt_msghdr); 887 break; 888 } 889 hlen = len; 890 if ((cp0 = cp) != NULL) 891 cp += len; 892 for (i = 0; i < RTAX_MAX; i++) { 893 struct sockaddr *sa; 894 895 if ((sa = rtinfo->rti_info[i]) == 0) 896 continue; 897 rtinfo->rti_addrs |= (1 << i); 898 dlen = ROUNDUP(sa->sa_len); 899 if (cp) { 900 bcopy(sa, cp, (size_t)dlen); 901 cp += dlen; 902 } 903 len += dlen; 904 } 905 /* align message length to the next natural boundary */ 906 len = ALIGN(len); 907 if (cp == 0 && w != NULL && !second_time) { 908 struct walkarg *rw = w; 909 910 rw->w_needed += len; 911 if (rw->w_needed <= 0 && rw->w_where) { 912 if (rw->w_tmemsize < len) { 913 if (rw->w_tmem) 914 free(rw->w_tmem, M_RTABLE); 915 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 916 if (rw->w_tmem) 917 rw->w_tmemsize = len; 918 } 919 if (rw->w_tmem) { 920 cp = rw->w_tmem; 921 second_time = 1; 922 goto again; 923 } else 924 rw->w_where = 0; 925 } 926 } 927 if (cp && w) /* clear the message header */ 928 bzero(cp0, hlen); 929 930 if (cp) { 931 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 932 933 rtm->rtm_version = RTM_VERSION; 934 rtm->rtm_type = type; 935 rtm->rtm_msglen = len; 936 rtm->rtm_hdrlen = hlen; 937 } 938 return (len); 939 } 940 941 /* 942 * This routine is called to generate a message from the routing 943 * socket indicating that a redirect has occurred, a routing lookup 944 * has failed, or that a protocol has detected timeouts to a particular 945 * destination. 946 */ 947 void 948 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, 949 struct ifnet *ifp, int error, u_int tableid) 950 { 951 struct rt_msghdr *rtm; 952 struct mbuf *m; 953 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 954 955 if (route_cb.any_count == 0) 956 return; 957 m = rt_msg1(type, rtinfo); 958 if (m == 0) 959 return; 960 rtm = mtod(m, struct rt_msghdr *); 961 rtm->rtm_flags = RTF_DONE | flags; 962 rtm->rtm_errno = error; 963 rtm->rtm_tableid = tableid; 964 rtm->rtm_addrs = rtinfo->rti_addrs; 965 if (ifp != NULL) 966 rtm->rtm_index = ifp->if_index; 967 if (sa == NULL) 968 route_proto.sp_protocol = 0; 969 else 970 route_proto.sp_protocol = sa->sa_family; 971 route_input(m, &route_proto, &route_src, &route_dst); 972 } 973 974 /* 975 * This routine is called to generate a message from the routing 976 * socket indicating that the status of a network interface has changed. 977 */ 978 void 979 rt_ifmsg(struct ifnet *ifp) 980 { 981 struct if_msghdr *ifm; 982 struct mbuf *m; 983 984 if (route_cb.any_count == 0) 985 return; 986 m = rt_msg1(RTM_IFINFO, NULL); 987 if (m == 0) 988 return; 989 ifm = mtod(m, struct if_msghdr *); 990 ifm->ifm_index = ifp->if_index; 991 ifm->ifm_flags = ifp->if_flags; 992 ifm->ifm_xflags = ifp->if_xflags; 993 ifm->ifm_data = ifp->if_data; 994 ifm->ifm_addrs = 0; 995 route_proto.sp_protocol = 0; 996 route_input(m, &route_proto, &route_src, &route_dst); 997 } 998 999 /* 1000 * This is called to generate messages from the routing socket 1001 * indicating a network interface has had addresses associated with it. 1002 * if we ever reverse the logic and replace messages TO the routing 1003 * socket indicate a request to configure interfaces, then it will 1004 * be unnecessary as the routing socket will automatically generate 1005 * copies of it. 1006 */ 1007 void 1008 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 1009 { 1010 struct rt_addrinfo info; 1011 struct sockaddr *sa = NULL; 1012 int pass; 1013 struct mbuf *m = NULL; 1014 struct ifnet *ifp = ifa->ifa_ifp; 1015 1016 if (route_cb.any_count == 0) 1017 return; 1018 for (pass = 1; pass < 3; pass++) { 1019 bzero(&info, sizeof(info)); 1020 if ((cmd == RTM_ADD && pass == 1) || 1021 (cmd == RTM_DELETE && pass == 2)) { 1022 struct ifa_msghdr *ifam; 1023 int ncmd; 1024 1025 if (cmd == RTM_ADD) 1026 ncmd = RTM_NEWADDR; 1027 else 1028 ncmd = RTM_DELADDR; 1029 1030 ifaaddr = sa = ifa->ifa_addr; 1031 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 1032 netmask = ifa->ifa_netmask; 1033 brdaddr = ifa->ifa_dstaddr; 1034 if ((m = rt_msg1(ncmd, &info)) == NULL) 1035 continue; 1036 ifam = mtod(m, struct ifa_msghdr *); 1037 ifam->ifam_index = ifp->if_index; 1038 ifam->ifam_metric = ifa->ifa_metric; 1039 ifam->ifam_flags = ifa->ifa_flags; 1040 ifam->ifam_addrs = info.rti_addrs; 1041 ifam->ifam_tableid = ifp->if_rdomain; 1042 } 1043 if ((cmd == RTM_ADD && pass == 2) || 1044 (cmd == RTM_DELETE && pass == 1)) { 1045 struct rt_msghdr *rtm; 1046 1047 if (rt == 0) 1048 continue; 1049 netmask = rt_mask(rt); 1050 dst = sa = rt_key(rt); 1051 gate = rt->rt_gateway; 1052 if ((m = rt_msg1(cmd, &info)) == NULL) 1053 continue; 1054 rtm = mtod(m, struct rt_msghdr *); 1055 rtm->rtm_index = ifp->if_index; 1056 rtm->rtm_flags |= rt->rt_flags; 1057 rtm->rtm_errno = error; 1058 rtm->rtm_addrs = info.rti_addrs; 1059 rtm->rtm_tableid = ifp->if_rdomain; 1060 } 1061 if (sa == NULL) 1062 route_proto.sp_protocol = 0; 1063 else 1064 route_proto.sp_protocol = sa->sa_family; 1065 route_input(m, &route_proto, &route_src, &route_dst); 1066 } 1067 } 1068 1069 /* 1070 * This is called to generate routing socket messages indicating 1071 * network interface arrival and departure. 1072 */ 1073 void 1074 rt_ifannouncemsg(struct ifnet *ifp, int what) 1075 { 1076 struct if_announcemsghdr *ifan; 1077 struct mbuf *m; 1078 1079 if (route_cb.any_count == 0) 1080 return; 1081 m = rt_msg1(RTM_IFANNOUNCE, NULL); 1082 if (m == 0) 1083 return; 1084 ifan = mtod(m, struct if_announcemsghdr *); 1085 ifan->ifan_index = ifp->if_index; 1086 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name)); 1087 ifan->ifan_what = what; 1088 route_proto.sp_protocol = 0; 1089 route_input(m, &route_proto, &route_src, &route_dst); 1090 } 1091 1092 /* 1093 * This is used in dumping the kernel table via sysctl(). 1094 */ 1095 int 1096 sysctl_dumpentry(struct radix_node *rn, void *v) 1097 { 1098 struct walkarg *w = v; 1099 struct rtentry *rt = (struct rtentry *)rn; 1100 int error = 0, size; 1101 struct rt_addrinfo info; 1102 #ifdef MPLS 1103 struct sockaddr_mpls sa_mpls; 1104 #endif 1105 struct sockaddr_rtlabel sa_rt; 1106 const char *label; 1107 1108 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1109 return 0; 1110 bzero(&info, sizeof(info)); 1111 dst = rt_key(rt); 1112 gate = rt->rt_gateway; 1113 netmask = rt_mask(rt); 1114 genmask = rt->rt_genmask; 1115 if (rt->rt_ifp) { 1116 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 1117 ifaaddr = rt->rt_ifa->ifa_addr; 1118 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1119 brdaddr = rt->rt_ifa->ifa_dstaddr; 1120 } 1121 if (rt->rt_labelid) { 1122 bzero(&sa_rt, sizeof(sa_rt)); 1123 sa_rt.sr_len = sizeof(sa_rt); 1124 label = rtlabel_id2name(rt->rt_labelid); 1125 if (label != NULL) { 1126 strlcpy(sa_rt.sr_label, label, 1127 sizeof(sa_rt.sr_label)); 1128 info.rti_info[RTAX_LABEL] = 1129 (struct sockaddr *)&sa_rt; 1130 } 1131 } 1132 #ifdef MPLS 1133 if (rt->rt_flags & RTF_MPLS) { 1134 bzero(&sa_mpls, sizeof(sa_mpls)); 1135 sa_mpls.smpls_family = AF_MPLS; 1136 sa_mpls.smpls_len = sizeof(sa_mpls); 1137 sa_mpls.smpls_label = ((struct rt_mpls *) 1138 rt->rt_llinfo)->mpls_label; 1139 info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls; 1140 info.rti_mpls = ((struct rt_mpls *) 1141 rt->rt_llinfo)->mpls_operation; 1142 } 1143 #endif 1144 1145 size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w); 1146 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1147 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 1148 1149 rtm->rtm_flags = rt->rt_flags; 1150 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 1151 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 1152 rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt; 1153 rtm->rtm_index = rt->rt_ifp->if_index; 1154 rtm->rtm_addrs = info.rti_addrs; 1155 #ifdef MPLS 1156 rtm->rtm_mpls = info.rti_mpls; 1157 #endif 1158 if ((error = copyout(rtm, w->w_where, size)) != 0) 1159 w->w_where = NULL; 1160 else 1161 w->w_where += size; 1162 } 1163 return (error); 1164 } 1165 1166 int 1167 sysctl_iflist(int af, struct walkarg *w) 1168 { 1169 struct ifnet *ifp; 1170 struct ifaddr *ifa; 1171 struct rt_addrinfo info; 1172 int len, error = 0; 1173 1174 bzero(&info, sizeof(info)); 1175 TAILQ_FOREACH(ifp, &ifnet, if_list) { 1176 if (w->w_arg && w->w_arg != ifp->if_index) 1177 continue; 1178 ifa = TAILQ_FIRST(&ifp->if_addrlist); 1179 if (!ifa) 1180 continue; 1181 ifpaddr = ifa->ifa_addr; 1182 len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w); 1183 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1184 struct if_msghdr *ifm; 1185 1186 ifm = (struct if_msghdr *)w->w_tmem; 1187 ifm->ifm_index = ifp->if_index; 1188 ifm->ifm_flags = ifp->if_flags; 1189 ifm->ifm_data = ifp->if_data; 1190 ifm->ifm_addrs = info.rti_addrs; 1191 error = copyout(ifm, w->w_where, len); 1192 if (error) 1193 return (error); 1194 w->w_where += len; 1195 } 1196 ifpaddr = 0; 1197 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) != 1198 TAILQ_END(&ifp->if_addrlist)) { 1199 if (af && af != ifa->ifa_addr->sa_family) 1200 continue; 1201 ifaaddr = ifa->ifa_addr; 1202 netmask = ifa->ifa_netmask; 1203 brdaddr = ifa->ifa_dstaddr; 1204 len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w); 1205 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1206 struct ifa_msghdr *ifam; 1207 1208 ifam = (struct ifa_msghdr *)w->w_tmem; 1209 ifam->ifam_index = ifa->ifa_ifp->if_index; 1210 ifam->ifam_flags = ifa->ifa_flags; 1211 ifam->ifam_metric = ifa->ifa_metric; 1212 ifam->ifam_addrs = info.rti_addrs; 1213 error = copyout(w->w_tmem, w->w_where, len); 1214 if (error) 1215 return (error); 1216 w->w_where += len; 1217 } 1218 } 1219 ifaaddr = netmask = brdaddr = 0; 1220 } 1221 return (0); 1222 } 1223 1224 int 1225 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, 1226 size_t newlen) 1227 { 1228 struct radix_node_head *rnh; 1229 int i, s, error = EINVAL; 1230 u_char af; 1231 struct walkarg w; 1232 u_int tableid = 0; 1233 1234 if (new) 1235 return (EPERM); 1236 if (namelen < 3 || namelen > 4) 1237 return (EINVAL); 1238 af = name[0]; 1239 bzero(&w, sizeof(w)); 1240 w.w_where = where; 1241 w.w_given = *given; 1242 w.w_needed = 0 - w.w_given; 1243 w.w_op = name[1]; 1244 w.w_arg = name[2]; 1245 1246 if (namelen == 4) { 1247 tableid = name[3]; 1248 if (!rtable_exists(tableid)) 1249 return (EINVAL); 1250 } 1251 1252 s = splsoftnet(); 1253 switch (w.w_op) { 1254 1255 case NET_RT_DUMP: 1256 case NET_RT_FLAGS: 1257 for (i = 1; i <= AF_MAX; i++) 1258 if ((rnh = rt_gettable(i, tableid)) != NULL && 1259 (af == 0 || af == i) && 1260 (error = (*rnh->rnh_walktree)(rnh, 1261 sysctl_dumpentry, &w))) 1262 break; 1263 break; 1264 1265 case NET_RT_IFLIST: 1266 error = sysctl_iflist(af, &w); 1267 break; 1268 1269 case NET_RT_STATS: 1270 error = sysctl_rdstruct(where, given, new, 1271 &rtstat, sizeof(rtstat)); 1272 splx(s); 1273 return (error); 1274 } 1275 splx(s); 1276 if (w.w_tmem) 1277 free(w.w_tmem, M_RTABLE); 1278 w.w_needed += w.w_given; 1279 if (where) { 1280 *given = w.w_where - (caddr_t)where; 1281 if (*given < w.w_needed) 1282 return (ENOMEM); 1283 } else 1284 *given = (11 * w.w_needed) / 10; 1285 1286 return (error); 1287 } 1288 1289 /* 1290 * Definitions of protocols supported in the ROUTE domain. 1291 */ 1292 1293 extern struct domain routedomain; /* or at least forward */ 1294 1295 struct protosw routesw[] = { 1296 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 1297 route_input, route_output, raw_ctlinput, route_ctloutput, 1298 route_usrreq, 1299 raw_init, 0, 0, 0, 1300 sysctl_rtable, 1301 } 1302 }; 1303 1304 struct domain routedomain = 1305 { PF_ROUTE, "route", route_init, 0, 0, 1306 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 1307