1 /* $OpenBSD: rtsock.c,v 1.94 2009/09/17 13:27:24 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, 616 /* XXX wrong, only rdomain */ tableid)) != 0) 617 goto flush; 618 if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) { 619 error = EDQUOT; 620 goto flush; 621 } 622 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr, 623 /* XXX again rtable vs. rdomain */ tableid)) && 624 (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) 625 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 626 ifp); 627 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr, 628 /* XXX one more time */ tableid))) || 629 (gate && (ifa = ifa_ifwithroute(rt->rt_flags, 630 rt_key(rt), gate, /* XXX again */ tableid)))) 631 ifp = ifa->ifa_ifp; 632 if (ifa) { 633 struct ifaddr *oifa = rt->rt_ifa; 634 if (oifa != ifa) { 635 if (oifa && oifa->ifa_rtrequest) 636 oifa->ifa_rtrequest(RTM_DELETE, rt, 637 &info); 638 IFAFREE(rt->rt_ifa); 639 rt->rt_ifa = ifa; 640 ifa->ifa_refcnt++; 641 rt->rt_ifp = ifp; 642 } 643 } 644 645 /* XXX Hack to allow some flags to be toggled */ 646 if (rtm->rtm_fmask & RTF_FMASK) 647 rt->rt_flags = (rt->rt_flags & 648 ~rtm->rtm_fmask) | 649 (rtm->rtm_flags & rtm->rtm_fmask); 650 651 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 652 &rt->rt_rmx); 653 rtm->rtm_index = rt->rt_ifp->if_index; 654 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 655 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 656 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 657 if (genmask) 658 rt->rt_genmask = genmask; 659 if (info.rti_info[RTAX_LABEL] != NULL) { 660 char *rtlabel = ((struct sockaddr_rtlabel *) 661 info.rti_info[RTAX_LABEL])->sr_label; 662 rtlabel_unref(rt->rt_labelid); 663 rt->rt_labelid = 664 rtlabel_name2id(rtlabel); 665 } 666 #ifdef MPLS 667 if (info.rti_info[RTAX_SRC] != NULL) { 668 struct rt_mpls *rt_mpls; 669 670 psa_mpls = (struct sockaddr_mpls *) 671 info.rti_info[RTAX_SRC]; 672 673 if (rt->rt_llinfo == NULL) { 674 rt->rt_llinfo = (caddr_t) 675 malloc(sizeof(struct rt_mpls), 676 M_TEMP, M_NOWAIT|M_ZERO); 677 } 678 if (rt->rt_llinfo == NULL) { 679 error = ENOMEM; 680 goto flush; 681 } 682 683 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 684 685 if (psa_mpls != NULL) { 686 rt_mpls->mpls_label = 687 psa_mpls->smpls_label; 688 } 689 690 rt_mpls->mpls_operation = info.rti_mpls; 691 692 /* XXX: set experimental bits */ 693 694 rt->rt_flags |= RTF_MPLS; 695 } else { 696 if (rt->rt_llinfo != NULL && 697 rt->rt_flags & RTF_MPLS) { 698 free(rt->rt_llinfo, M_TEMP); 699 rt->rt_llinfo = NULL; 700 701 rt->rt_flags &= (~RTF_MPLS); 702 } 703 } 704 #endif 705 if_group_routechange(dst, netmask); 706 /* FALLTHROUGH */ 707 case RTM_LOCK: 708 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 709 rt->rt_rmx.rmx_locks |= 710 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 711 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 712 break; 713 } 714 break; 715 716 default: 717 error = EOPNOTSUPP; 718 break; 719 } 720 721 flush: 722 if (rtm) { 723 if (error) 724 rtm->rtm_errno = error; 725 else { 726 #ifdef MPLS 727 if (rt && rt->rt_flags & RTF_MPLS) 728 rtm->rtm_flags |= RTF_MPLS; 729 #endif 730 rtm->rtm_flags |= RTF_DONE; 731 } 732 } 733 if (rt) 734 rtfree(rt); 735 736 /* 737 * Check to see if we don't want our own messages. 738 */ 739 if (!(so->so_options & SO_USELOOPBACK)) { 740 if (route_cb.any_count <= 1) { 741 if (rtm) 742 Free(rtm); 743 m_freem(m); 744 return (error); 745 } 746 /* There is another listener, so construct message */ 747 rp = sotorawcb(so); 748 } 749 if (rp) 750 rp->rcb_proto.sp_family = 0; /* Avoid us */ 751 if (dst) 752 route_proto.sp_protocol = dst->sa_family; 753 if (rtm) { 754 m_copyback(m, 0, rtm->rtm_msglen, rtm); 755 if (m->m_pkthdr.len < rtm->rtm_msglen) { 756 m_freem(m); 757 m = NULL; 758 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 759 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 760 Free(rtm); 761 } 762 if (m) 763 route_input(m, &route_proto, &route_src, &route_dst); 764 if (rp) 765 rp->rcb_proto.sp_family = PF_ROUTE; 766 767 return (error); 768 } 769 770 void 771 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out) 772 { 773 if (which & RTV_MTU) 774 out->rmx_mtu = in->rmx_mtu; 775 if (which & RTV_EXPIRE) 776 out->rmx_expire = in->rmx_expire; 777 /* RTV_PRIORITY handled befor */ 778 } 779 780 void 781 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out) 782 { 783 bzero(out, sizeof(*out)); 784 out->rmx_locks = in->rmx_locks; 785 out->rmx_mtu = in->rmx_mtu; 786 out->rmx_expire = in->rmx_expire; 787 out->rmx_pksent = in->rmx_pksent; 788 } 789 790 #define ROUNDUP(a) \ 791 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 792 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 793 794 void 795 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 796 { 797 struct sockaddr *sa; 798 int i; 799 800 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 801 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 802 if ((rtinfo->rti_addrs & (1 << i)) == 0) 803 continue; 804 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 805 ADVANCE(cp, sa); 806 } 807 } 808 809 struct mbuf * 810 rt_msg1(int type, struct rt_addrinfo *rtinfo) 811 { 812 struct rt_msghdr *rtm; 813 struct mbuf *m; 814 int i; 815 struct sockaddr *sa; 816 int len, dlen, hlen; 817 818 switch (type) { 819 case RTM_DELADDR: 820 case RTM_NEWADDR: 821 len = sizeof(struct ifa_msghdr); 822 break; 823 case RTM_IFINFO: 824 len = sizeof(struct if_msghdr); 825 break; 826 case RTM_IFANNOUNCE: 827 len = sizeof(struct if_announcemsghdr); 828 break; 829 default: 830 len = sizeof(struct rt_msghdr); 831 break; 832 } 833 if (len > MCLBYTES) 834 panic("rt_msg1"); 835 m = m_gethdr(M_DONTWAIT, MT_DATA); 836 if (m && len > MHLEN) { 837 MCLGET(m, M_DONTWAIT); 838 if ((m->m_flags & M_EXT) == 0) { 839 m_free(m); 840 m = NULL; 841 } 842 } 843 if (m == 0) 844 return (m); 845 m->m_pkthdr.len = m->m_len = hlen = len; 846 m->m_pkthdr.rcvif = NULL; 847 rtm = mtod(m, struct rt_msghdr *); 848 bzero(rtm, len); 849 for (i = 0; i < RTAX_MAX; i++) { 850 if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL) 851 continue; 852 rtinfo->rti_addrs |= (1 << i); 853 dlen = ROUNDUP(sa->sa_len); 854 m_copyback(m, len, dlen, sa); 855 len += dlen; 856 } 857 if (m->m_pkthdr.len != len) { 858 m_freem(m); 859 return (NULL); 860 } 861 rtm->rtm_msglen = len; 862 rtm->rtm_hdrlen = hlen; 863 rtm->rtm_version = RTM_VERSION; 864 rtm->rtm_type = type; 865 return (m); 866 } 867 868 int 869 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp, 870 struct walkarg *w) 871 { 872 int i; 873 int len, dlen, hlen, second_time = 0; 874 caddr_t cp0; 875 876 rtinfo->rti_addrs = 0; 877 again: 878 switch (type) { 879 case RTM_DELADDR: 880 case RTM_NEWADDR: 881 len = sizeof(struct ifa_msghdr); 882 break; 883 case RTM_IFINFO: 884 len = sizeof(struct if_msghdr); 885 break; 886 default: 887 len = sizeof(struct rt_msghdr); 888 break; 889 } 890 hlen = len; 891 if ((cp0 = cp) != NULL) 892 cp += len; 893 for (i = 0; i < RTAX_MAX; i++) { 894 struct sockaddr *sa; 895 896 if ((sa = rtinfo->rti_info[i]) == 0) 897 continue; 898 rtinfo->rti_addrs |= (1 << i); 899 dlen = ROUNDUP(sa->sa_len); 900 if (cp) { 901 bcopy(sa, cp, (size_t)dlen); 902 cp += dlen; 903 } 904 len += dlen; 905 } 906 /* align message length to the next natural boundary */ 907 len = ALIGN(len); 908 if (cp == 0 && w != NULL && !second_time) { 909 struct walkarg *rw = w; 910 911 rw->w_needed += len; 912 if (rw->w_needed <= 0 && rw->w_where) { 913 if (rw->w_tmemsize < len) { 914 if (rw->w_tmem) 915 free(rw->w_tmem, M_RTABLE); 916 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); 917 if (rw->w_tmem) 918 rw->w_tmemsize = len; 919 } 920 if (rw->w_tmem) { 921 cp = rw->w_tmem; 922 second_time = 1; 923 goto again; 924 } else 925 rw->w_where = 0; 926 } 927 } 928 if (cp && w) /* clear the message header */ 929 bzero(cp0, hlen); 930 931 if (cp) { 932 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 933 934 rtm->rtm_version = RTM_VERSION; 935 rtm->rtm_type = type; 936 rtm->rtm_msglen = len; 937 rtm->rtm_hdrlen = hlen; 938 } 939 return (len); 940 } 941 942 /* 943 * This routine is called to generate a message from the routing 944 * socket indicating that a redirect has occurred, a routing lookup 945 * has failed, or that a protocol has detected timeouts to a particular 946 * destination. 947 */ 948 void 949 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, 950 struct ifnet *ifp, int error, u_int tableid) 951 { 952 struct rt_msghdr *rtm; 953 struct mbuf *m; 954 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 955 956 if (route_cb.any_count == 0) 957 return; 958 m = rt_msg1(type, rtinfo); 959 if (m == 0) 960 return; 961 rtm = mtod(m, struct rt_msghdr *); 962 rtm->rtm_flags = RTF_DONE | flags; 963 rtm->rtm_errno = error; 964 rtm->rtm_tableid = tableid; 965 rtm->rtm_addrs = rtinfo->rti_addrs; 966 if (ifp != NULL) 967 rtm->rtm_index = ifp->if_index; 968 if (sa == NULL) 969 route_proto.sp_protocol = 0; 970 else 971 route_proto.sp_protocol = sa->sa_family; 972 route_input(m, &route_proto, &route_src, &route_dst); 973 } 974 975 /* 976 * This routine is called to generate a message from the routing 977 * socket indicating that the status of a network interface has changed. 978 */ 979 void 980 rt_ifmsg(struct ifnet *ifp) 981 { 982 struct if_msghdr *ifm; 983 struct mbuf *m; 984 985 if (route_cb.any_count == 0) 986 return; 987 m = rt_msg1(RTM_IFINFO, NULL); 988 if (m == 0) 989 return; 990 ifm = mtod(m, struct if_msghdr *); 991 ifm->ifm_index = ifp->if_index; 992 ifm->ifm_flags = ifp->if_flags; 993 ifm->ifm_xflags = ifp->if_xflags; 994 ifm->ifm_data = ifp->if_data; 995 ifm->ifm_addrs = 0; 996 route_proto.sp_protocol = 0; 997 route_input(m, &route_proto, &route_src, &route_dst); 998 } 999 1000 /* 1001 * This is called to generate messages from the routing socket 1002 * indicating a network interface has had addresses associated with it. 1003 * if we ever reverse the logic and replace messages TO the routing 1004 * socket indicate a request to configure interfaces, then it will 1005 * be unnecessary as the routing socket will automatically generate 1006 * copies of it. 1007 */ 1008 void 1009 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 1010 { 1011 struct rt_addrinfo info; 1012 struct sockaddr *sa = NULL; 1013 int pass; 1014 struct mbuf *m = NULL; 1015 struct ifnet *ifp = ifa->ifa_ifp; 1016 1017 if (route_cb.any_count == 0) 1018 return; 1019 for (pass = 1; pass < 3; pass++) { 1020 bzero(&info, sizeof(info)); 1021 if ((cmd == RTM_ADD && pass == 1) || 1022 (cmd == RTM_DELETE && pass == 2)) { 1023 struct ifa_msghdr *ifam; 1024 int ncmd; 1025 1026 if (cmd == RTM_ADD) 1027 ncmd = RTM_NEWADDR; 1028 else 1029 ncmd = RTM_DELADDR; 1030 1031 ifaaddr = sa = ifa->ifa_addr; 1032 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 1033 netmask = ifa->ifa_netmask; 1034 brdaddr = ifa->ifa_dstaddr; 1035 if ((m = rt_msg1(ncmd, &info)) == NULL) 1036 continue; 1037 ifam = mtod(m, struct ifa_msghdr *); 1038 ifam->ifam_index = ifp->if_index; 1039 ifam->ifam_metric = ifa->ifa_metric; 1040 ifam->ifam_flags = ifa->ifa_flags; 1041 ifam->ifam_addrs = info.rti_addrs; 1042 ifam->ifam_tableid = ifp->if_rdomain; 1043 } 1044 if ((cmd == RTM_ADD && pass == 2) || 1045 (cmd == RTM_DELETE && pass == 1)) { 1046 struct rt_msghdr *rtm; 1047 1048 if (rt == 0) 1049 continue; 1050 netmask = rt_mask(rt); 1051 dst = sa = rt_key(rt); 1052 gate = rt->rt_gateway; 1053 if ((m = rt_msg1(cmd, &info)) == NULL) 1054 continue; 1055 rtm = mtod(m, struct rt_msghdr *); 1056 rtm->rtm_index = ifp->if_index; 1057 rtm->rtm_flags |= rt->rt_flags; 1058 rtm->rtm_errno = error; 1059 rtm->rtm_addrs = info.rti_addrs; 1060 rtm->rtm_tableid = ifp->if_rdomain; 1061 } 1062 if (sa == NULL) 1063 route_proto.sp_protocol = 0; 1064 else 1065 route_proto.sp_protocol = sa->sa_family; 1066 route_input(m, &route_proto, &route_src, &route_dst); 1067 } 1068 } 1069 1070 /* 1071 * This is called to generate routing socket messages indicating 1072 * network interface arrival and departure. 1073 */ 1074 void 1075 rt_ifannouncemsg(struct ifnet *ifp, int what) 1076 { 1077 struct if_announcemsghdr *ifan; 1078 struct mbuf *m; 1079 1080 if (route_cb.any_count == 0) 1081 return; 1082 m = rt_msg1(RTM_IFANNOUNCE, NULL); 1083 if (m == 0) 1084 return; 1085 ifan = mtod(m, struct if_announcemsghdr *); 1086 ifan->ifan_index = ifp->if_index; 1087 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name)); 1088 ifan->ifan_what = what; 1089 route_proto.sp_protocol = 0; 1090 route_input(m, &route_proto, &route_src, &route_dst); 1091 } 1092 1093 /* 1094 * This is used in dumping the kernel table via sysctl(). 1095 */ 1096 int 1097 sysctl_dumpentry(struct radix_node *rn, void *v) 1098 { 1099 struct walkarg *w = v; 1100 struct rtentry *rt = (struct rtentry *)rn; 1101 int error = 0, size; 1102 struct rt_addrinfo info; 1103 #ifdef MPLS 1104 struct sockaddr_mpls sa_mpls; 1105 #endif 1106 struct sockaddr_rtlabel sa_rt; 1107 const char *label; 1108 1109 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 1110 return 0; 1111 bzero(&info, sizeof(info)); 1112 dst = rt_key(rt); 1113 gate = rt->rt_gateway; 1114 netmask = rt_mask(rt); 1115 genmask = rt->rt_genmask; 1116 if (rt->rt_ifp) { 1117 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 1118 ifaaddr = rt->rt_ifa->ifa_addr; 1119 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 1120 brdaddr = rt->rt_ifa->ifa_dstaddr; 1121 } 1122 if (rt->rt_labelid) { 1123 bzero(&sa_rt, sizeof(sa_rt)); 1124 sa_rt.sr_len = sizeof(sa_rt); 1125 label = rtlabel_id2name(rt->rt_labelid); 1126 if (label != NULL) { 1127 strlcpy(sa_rt.sr_label, label, 1128 sizeof(sa_rt.sr_label)); 1129 info.rti_info[RTAX_LABEL] = 1130 (struct sockaddr *)&sa_rt; 1131 } 1132 } 1133 #ifdef MPLS 1134 if (rt->rt_flags & RTF_MPLS) { 1135 bzero(&sa_mpls, sizeof(sa_mpls)); 1136 sa_mpls.smpls_family = AF_MPLS; 1137 sa_mpls.smpls_len = sizeof(sa_mpls); 1138 sa_mpls.smpls_label = ((struct rt_mpls *) 1139 rt->rt_llinfo)->mpls_label; 1140 info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls; 1141 info.rti_mpls = ((struct rt_mpls *) 1142 rt->rt_llinfo)->mpls_operation; 1143 } 1144 #endif 1145 1146 size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w); 1147 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1148 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 1149 1150 rtm->rtm_flags = rt->rt_flags; 1151 rtm->rtm_priority = rt->rt_priority & RTP_MASK; 1152 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); 1153 rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt; 1154 rtm->rtm_index = rt->rt_ifp->if_index; 1155 rtm->rtm_addrs = info.rti_addrs; 1156 #ifdef MPLS 1157 rtm->rtm_mpls = info.rti_mpls; 1158 #endif 1159 if ((error = copyout(rtm, w->w_where, size)) != 0) 1160 w->w_where = NULL; 1161 else 1162 w->w_where += size; 1163 } 1164 return (error); 1165 } 1166 1167 int 1168 sysctl_iflist(int af, struct walkarg *w) 1169 { 1170 struct ifnet *ifp; 1171 struct ifaddr *ifa; 1172 struct rt_addrinfo info; 1173 int len, error = 0; 1174 1175 bzero(&info, sizeof(info)); 1176 TAILQ_FOREACH(ifp, &ifnet, if_list) { 1177 if (w->w_arg && w->w_arg != ifp->if_index) 1178 continue; 1179 ifa = TAILQ_FIRST(&ifp->if_addrlist); 1180 if (!ifa) 1181 continue; 1182 ifpaddr = ifa->ifa_addr; 1183 len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w); 1184 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1185 struct if_msghdr *ifm; 1186 1187 ifm = (struct if_msghdr *)w->w_tmem; 1188 ifm->ifm_index = ifp->if_index; 1189 ifm->ifm_flags = ifp->if_flags; 1190 ifm->ifm_data = ifp->if_data; 1191 ifm->ifm_addrs = info.rti_addrs; 1192 error = copyout(ifm, w->w_where, len); 1193 if (error) 1194 return (error); 1195 w->w_where += len; 1196 } 1197 ifpaddr = 0; 1198 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) != 1199 TAILQ_END(&ifp->if_addrlist)) { 1200 if (af && af != ifa->ifa_addr->sa_family) 1201 continue; 1202 ifaaddr = ifa->ifa_addr; 1203 netmask = ifa->ifa_netmask; 1204 brdaddr = ifa->ifa_dstaddr; 1205 len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w); 1206 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 1207 struct ifa_msghdr *ifam; 1208 1209 ifam = (struct ifa_msghdr *)w->w_tmem; 1210 ifam->ifam_index = ifa->ifa_ifp->if_index; 1211 ifam->ifam_flags = ifa->ifa_flags; 1212 ifam->ifam_metric = ifa->ifa_metric; 1213 ifam->ifam_addrs = info.rti_addrs; 1214 error = copyout(w->w_tmem, w->w_where, len); 1215 if (error) 1216 return (error); 1217 w->w_where += len; 1218 } 1219 } 1220 ifaaddr = netmask = brdaddr = 0; 1221 } 1222 return (0); 1223 } 1224 1225 int 1226 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, 1227 size_t newlen) 1228 { 1229 struct radix_node_head *rnh; 1230 int i, s, error = EINVAL; 1231 u_char af; 1232 struct walkarg w; 1233 u_int tableid = 0; 1234 1235 if (new) 1236 return (EPERM); 1237 if (namelen < 3 || namelen > 4) 1238 return (EINVAL); 1239 af = name[0]; 1240 bzero(&w, sizeof(w)); 1241 w.w_where = where; 1242 w.w_given = *given; 1243 w.w_needed = 0 - w.w_given; 1244 w.w_op = name[1]; 1245 w.w_arg = name[2]; 1246 1247 if (namelen == 4) { 1248 tableid = name[3]; 1249 if (!rtable_exists(tableid)) 1250 return (EINVAL); 1251 } 1252 1253 s = splsoftnet(); 1254 switch (w.w_op) { 1255 1256 case NET_RT_DUMP: 1257 case NET_RT_FLAGS: 1258 for (i = 1; i <= AF_MAX; i++) 1259 if ((rnh = rt_gettable(i, tableid)) != NULL && 1260 (af == 0 || af == i) && 1261 (error = (*rnh->rnh_walktree)(rnh, 1262 sysctl_dumpentry, &w))) 1263 break; 1264 break; 1265 1266 case NET_RT_IFLIST: 1267 error = sysctl_iflist(af, &w); 1268 break; 1269 1270 case NET_RT_STATS: 1271 error = sysctl_rdstruct(where, given, new, 1272 &rtstat, sizeof(rtstat)); 1273 splx(s); 1274 return (error); 1275 } 1276 splx(s); 1277 if (w.w_tmem) 1278 free(w.w_tmem, M_RTABLE); 1279 w.w_needed += w.w_given; 1280 if (where) { 1281 *given = w.w_where - (caddr_t)where; 1282 if (*given < w.w_needed) 1283 return (ENOMEM); 1284 } else 1285 *given = (11 * w.w_needed) / 10; 1286 1287 return (error); 1288 } 1289 1290 /* 1291 * Definitions of protocols supported in the ROUTE domain. 1292 */ 1293 1294 extern struct domain routedomain; /* or at least forward */ 1295 1296 struct protosw routesw[] = { 1297 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 1298 route_input, route_output, raw_ctlinput, route_ctloutput, 1299 route_usrreq, 1300 raw_init, 0, 0, 0, 1301 sysctl_rtable, 1302 } 1303 }; 1304 1305 struct domain routedomain = 1306 { PF_ROUTE, "route", route_init, 0, 0, 1307 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 1308