1 /* $OpenBSD: rtsock.c,v 1.16 2001/07/21 12:22:57 itojun 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. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)rtsock.c 8.6 (Berkeley) 2/11/95 66 */ 67 68 #include <sys/param.h> 69 #include <sys/systm.h> 70 #include <sys/proc.h> 71 #include <sys/mbuf.h> 72 #include <sys/socket.h> 73 #include <sys/socketvar.h> 74 #include <sys/domain.h> 75 #include <sys/protosw.h> 76 77 #include <vm/vm.h> 78 #include <sys/sysctl.h> 79 80 #include <net/if.h> 81 #include <net/route.h> 82 #include <net/raw_cb.h> 83 84 #include <machine/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 static struct mbuf * 96 rt_msg1 __P((int, struct rt_addrinfo *)); 97 static int rt_msg2 __P((int, 98 struct rt_addrinfo *, caddr_t, struct walkarg *)); 99 static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 100 101 /* Sleazy use of local variables throughout file, warning!!!! */ 102 #define dst info.rti_info[RTAX_DST] 103 #define gate info.rti_info[RTAX_GATEWAY] 104 #define netmask info.rti_info[RTAX_NETMASK] 105 #define genmask info.rti_info[RTAX_GENMASK] 106 #define ifpaddr info.rti_info[RTAX_IFP] 107 #define ifaaddr info.rti_info[RTAX_IFA] 108 #define brdaddr info.rti_info[RTAX_BRD] 109 110 /*ARGSUSED*/ 111 int 112 route_usrreq(so, req, m, nam, control) 113 register struct socket *so; 114 int req; 115 struct mbuf *m, *nam, *control; 116 { 117 register int error = 0; 118 register struct rawcb *rp = sotorawcb(so); 119 int s; 120 121 if (req == PRU_ATTACH) { 122 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 123 so->so_pcb = rp; 124 bzero(so->so_pcb, sizeof(*rp)); 125 } 126 if (req == PRU_DETACH && rp) { 127 int af = rp->rcb_proto.sp_protocol; 128 if (af == AF_INET) 129 route_cb.ip_count--; 130 else if (af == AF_INET6) 131 route_cb.ip6_count--; 132 else if (af == AF_NS) 133 route_cb.ns_count--; 134 else if (af == AF_ISO) 135 route_cb.iso_count--; 136 route_cb.any_count--; 137 } 138 s = splsoftnet(); 139 /* 140 * Don't call raw_usrreq() in the attach case, because 141 * we want to allow non-privileged processes to listen on 142 * and send "safe" commands to the routing socket. 143 */ 144 if (req == PRU_ATTACH) { 145 if (curproc == 0) 146 error = EACCES; 147 else 148 error = raw_attach(so, (int)(long)nam); 149 } else 150 error = raw_usrreq(so, req, m, nam, control); 151 152 rp = sotorawcb(so); 153 if (req == PRU_ATTACH && rp) { 154 int af = rp->rcb_proto.sp_protocol; 155 if (error) { 156 free((caddr_t)rp, M_PCB); 157 splx(s); 158 return (error); 159 } 160 if (af == AF_INET) 161 route_cb.ip_count++; 162 else if (af == AF_INET6) 163 route_cb.ip6_count++; 164 else if (af == AF_NS) 165 route_cb.ns_count++; 166 else if (af == AF_ISO) 167 route_cb.iso_count++; 168 rp->rcb_faddr = &route_src; 169 route_cb.any_count++; 170 soisconnected(so); 171 so->so_options |= SO_USELOOPBACK; 172 } 173 splx(s); 174 return (error); 175 } 176 177 /*ARGSUSED*/ 178 int 179 #if __STDC__ 180 route_output(struct mbuf *m, ...) 181 #else 182 route_output(m, va_alist) 183 struct mbuf *m; 184 va_dcl 185 #endif 186 { 187 register struct rt_msghdr *rtm = 0; 188 register struct radix_node *rn = 0; 189 register struct rtentry *rt = 0; 190 struct rtentry *saved_nrt = 0; 191 struct radix_node_head *rnh; 192 struct rt_addrinfo info; 193 int len, error = 0; 194 struct ifnet *ifp = 0; 195 struct ifaddr *ifa = 0; 196 struct socket *so; 197 va_list ap; 198 199 va_start(ap, m); 200 so = va_arg(ap, struct socket *); 201 va_end(ap); 202 203 #define senderr(e) do { error = e; goto flush;} while (0) 204 if (m == 0 || ((m->m_len < sizeof(int32_t)) && 205 (m = m_pullup(m, sizeof(int32_t))) == 0)) 206 return (ENOBUFS); 207 if ((m->m_flags & M_PKTHDR) == 0) 208 panic("route_output"); 209 len = m->m_pkthdr.len; 210 if (len < sizeof(*rtm) || 211 len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 212 dst = 0; 213 senderr(EINVAL); 214 } 215 R_Malloc(rtm, struct rt_msghdr *, len); 216 if (rtm == 0) { 217 dst = 0; 218 senderr(ENOBUFS); 219 } 220 m_copydata(m, 0, len, (caddr_t)rtm); 221 if (rtm->rtm_version != RTM_VERSION) { 222 dst = 0; 223 senderr(EPROTONOSUPPORT); 224 } 225 rtm->rtm_pid = curproc->p_pid; 226 bzero(&info, sizeof(info)); 227 info.rti_addrs = rtm->rtm_addrs; 228 rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 229 info.rti_flags = rtm->rtm_flags; 230 if (dst == 0 || (dst->sa_family >= AF_MAX)) 231 senderr(EINVAL); 232 if (gate != 0 && (gate->sa_family >= AF_MAX)) 233 senderr(EINVAL); 234 if (genmask) { 235 struct radix_node *t; 236 t = rn_addmask((caddr_t)genmask, 0, 1); 237 if (t && genmask->sa_len >= ((struct sockaddr *)t->rn_key)->sa_len && 238 Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1, 239 ((struct sockaddr *)t->rn_key)->sa_len) - 1) 240 genmask = (struct sockaddr *)(t->rn_key); 241 else 242 senderr(ENOBUFS); 243 } 244 245 /* 246 * Verify that the caller has the appropriate privilege; RTM_GET 247 * is the only operation the non-superuser is allowed. 248 */ 249 if (rtm->rtm_type != RTM_GET && 250 suser(curproc->p_ucred, &curproc->p_acflag) != 0) 251 senderr(EACCES); 252 switch (rtm->rtm_type) { 253 254 case RTM_DELETE: 255 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 256 if (error == 0) { 257 (rt = saved_nrt)->rt_refcnt++; 258 goto report; 259 } 260 break; 261 262 case RTM_ADD: 263 if (gate == 0) 264 senderr(EINVAL); 265 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); 266 if (error == 0 && saved_nrt) { 267 rt_setmetrics(rtm->rtm_inits, 268 &rtm->rtm_rmx, &saved_nrt->rt_rmx); 269 saved_nrt->rt_refcnt--; 270 saved_nrt->rt_genmask = genmask; 271 } 272 /* FALLTHROUGH */ 273 case RTM_GET: 274 case RTM_CHANGE: 275 case RTM_LOCK: 276 if ((rnh = rt_tables[dst->sa_family]) == 0) { 277 senderr(EAFNOSUPPORT); 278 } 279 rn = rnh->rnh_lookup(dst, netmask, rnh); 280 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) { 281 senderr(ESRCH); 282 } 283 rt = (struct rtentry *)rn; 284 rt->rt_refcnt++; 285 286 switch(rtm->rtm_type) { 287 288 case RTM_GET: 289 report: 290 dst = rt_key(rt); 291 gate = rt->rt_gateway; 292 netmask = rt_mask(rt); 293 genmask = rt->rt_genmask; 294 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 295 if ((ifp = rt->rt_ifp) != NULL) { 296 ifpaddr = ifp->if_addrlist.tqh_first->ifa_addr; 297 ifaaddr = rt->rt_ifa->ifa_addr; 298 if (ifp->if_flags & IFF_POINTOPOINT) 299 brdaddr = rt->rt_ifa->ifa_dstaddr; 300 else 301 brdaddr = 0; 302 rtm->rtm_index = ifp->if_index; 303 } else { 304 ifpaddr = 0; 305 ifaaddr = 0; 306 } 307 } 308 len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0, 309 (struct walkarg *)0); 310 if (len > rtm->rtm_msglen) { 311 struct rt_msghdr *new_rtm; 312 R_Malloc(new_rtm, struct rt_msghdr *, len); 313 if (new_rtm == 0) 314 senderr(ENOBUFS); 315 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 316 Free(rtm); rtm = new_rtm; 317 } 318 (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, 319 (struct walkarg *)0); 320 rtm->rtm_flags = rt->rt_flags; 321 rtm->rtm_rmx = rt->rt_rmx; 322 rtm->rtm_addrs = info.rti_addrs; 323 break; 324 325 case RTM_CHANGE: 326 /* 327 * new gateway could require new ifaddr, ifp; 328 * flags may also be different; ifp may be specified 329 * by ll sockaddr when protocol address is ambiguous 330 */ 331 if ((error = rt_getifa(&info)) != 0) 332 senderr(error); 333 if (gate && rt_setgate(rt, rt_key(rt), gate)) 334 senderr(EDQUOT); 335 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 336 (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) 337 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 338 ifp); 339 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 340 (gate && (ifa = ifa_ifwithroute(rt->rt_flags, 341 rt_key(rt), gate)))) 342 ifp = ifa->ifa_ifp; 343 if (ifa) { 344 register struct ifaddr *oifa = rt->rt_ifa; 345 if (oifa != ifa) { 346 if (oifa && oifa->ifa_rtrequest) 347 oifa->ifa_rtrequest(RTM_DELETE, rt, 348 &info); 349 IFAFREE(rt->rt_ifa); 350 rt->rt_ifa = ifa; 351 ifa->ifa_refcnt++; 352 rt->rt_ifp = ifp; 353 } 354 } 355 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 356 &rt->rt_rmx); 357 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 358 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 359 if (genmask) 360 rt->rt_genmask = genmask; 361 /* 362 * Fall into 363 */ 364 case RTM_ADD: 365 case RTM_LOCK: 366 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 367 rt->rt_rmx.rmx_locks |= 368 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 369 break; 370 } 371 break; 372 373 default: 374 senderr(EOPNOTSUPP); 375 } 376 377 flush: 378 if (rtm) { 379 if (error) 380 rtm->rtm_errno = error; 381 else 382 rtm->rtm_flags |= RTF_DONE; 383 } 384 if (rt) 385 rtfree(rt); 386 { 387 register struct rawcb *rp = 0; 388 /* 389 * Check to see if we don't want our own messages. 390 */ 391 if ((so->so_options & SO_USELOOPBACK) == 0) { 392 if (route_cb.any_count <= 1) { 393 if (rtm) 394 Free(rtm); 395 m_freem(m); 396 return (error); 397 } 398 /* There is another listener, so construct message */ 399 rp = sotorawcb(so); 400 } 401 if (rtm) { 402 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 403 if (m->m_pkthdr.len < rtm->rtm_msglen) { 404 m_freem(m); 405 m = NULL; 406 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 407 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 408 Free(rtm); 409 } 410 if (rp) 411 rp->rcb_proto.sp_family = 0; /* Avoid us */ 412 if (dst) 413 route_proto.sp_protocol = dst->sa_family; 414 if (m) 415 raw_input(m, &route_proto, &route_src, &route_dst); 416 if (rp) 417 rp->rcb_proto.sp_family = PF_ROUTE; 418 } 419 return (error); 420 } 421 422 void 423 rt_setmetrics(which, in, out) 424 u_long which; 425 register struct rt_metrics *in, *out; 426 { 427 #define metric(f, e) if (which & (f)) out->e = in->e; 428 metric(RTV_RPIPE, rmx_recvpipe); 429 metric(RTV_SPIPE, rmx_sendpipe); 430 metric(RTV_SSTHRESH, rmx_ssthresh); 431 metric(RTV_RTT, rmx_rtt); 432 metric(RTV_RTTVAR, rmx_rttvar); 433 metric(RTV_HOPCOUNT, rmx_hopcount); 434 metric(RTV_MTU, rmx_mtu); 435 metric(RTV_EXPIRE, rmx_expire); 436 #undef metric 437 } 438 439 #define ROUNDUP(a) \ 440 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 441 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 442 443 static void 444 rt_xaddrs(cp, cplim, rtinfo) 445 register caddr_t cp, cplim; 446 register struct rt_addrinfo *rtinfo; 447 { 448 register struct sockaddr *sa; 449 register int i; 450 451 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 452 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 453 if ((rtinfo->rti_addrs & (1 << i)) == 0) 454 continue; 455 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 456 ADVANCE(cp, sa); 457 } 458 } 459 460 /* 461 * Copy data from a buffer back into the indicated mbuf chain, 462 * starting "off" bytes from the beginning, extending the mbuf 463 * chain if necessary. The mbuf needs to be properly initalized 464 * including the setting of m_len. 465 */ 466 void 467 m_copyback(m0, off, len, cp) 468 struct mbuf *m0; 469 register int off; 470 register int len; 471 caddr_t cp; 472 { 473 register int mlen; 474 register struct mbuf *m = m0, *n; 475 int totlen = 0; 476 477 if (m0 == 0) 478 return; 479 while (off > (mlen = m->m_len)) { 480 off -= mlen; 481 totlen += mlen; 482 if (m->m_next == 0) { 483 n = m_getclr(M_DONTWAIT, m->m_type); 484 if (n == 0) 485 goto out; 486 n->m_len = min(MLEN, len + off); 487 m->m_next = n; 488 } 489 m = m->m_next; 490 } 491 while (len > 0) { 492 mlen = min (m->m_len - off, len); 493 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 494 cp += mlen; 495 len -= mlen; 496 mlen += off; 497 off = 0; 498 totlen += mlen; 499 if (len == 0) 500 break; 501 if (m->m_next == 0) { 502 n = m_get(M_DONTWAIT, m->m_type); 503 if (n == 0) 504 break; 505 n->m_len = min(MLEN, len); 506 m->m_next = n; 507 } 508 m = m->m_next; 509 } 510 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 511 m->m_pkthdr.len = totlen; 512 } 513 514 static struct mbuf * 515 rt_msg1(type, rtinfo) 516 int type; 517 register struct rt_addrinfo *rtinfo; 518 { 519 register struct rt_msghdr *rtm; 520 register struct mbuf *m; 521 register int i; 522 register struct sockaddr *sa; 523 int len, dlen; 524 525 switch (type) { 526 527 case RTM_DELADDR: 528 case RTM_NEWADDR: 529 len = sizeof(struct ifa_msghdr); 530 break; 531 532 case RTM_IFINFO: 533 len = sizeof(struct if_msghdr); 534 break; 535 536 default: 537 len = sizeof(struct rt_msghdr); 538 } 539 if (len > MCLBYTES) 540 panic("rt_msg1"); 541 m = m_gethdr(M_DONTWAIT, MT_DATA); 542 if (m && len > MHLEN) { 543 MCLGET(m, M_DONTWAIT); 544 if ((m->m_flags & M_EXT) == 0) { 545 m_free(m); 546 m = NULL; 547 } 548 } 549 if (m == 0) 550 return (m); 551 m->m_pkthdr.len = m->m_len = len; 552 m->m_pkthdr.rcvif = 0; 553 rtm = mtod(m, struct rt_msghdr *); 554 bzero((caddr_t)rtm, len); 555 for (i = 0; i < RTAX_MAX; i++) { 556 if ((sa = rtinfo->rti_info[i]) == NULL) 557 continue; 558 rtinfo->rti_addrs |= (1 << i); 559 dlen = ROUNDUP(sa->sa_len); 560 m_copyback(m, len, dlen, (caddr_t)sa); 561 len += dlen; 562 } 563 if (m->m_pkthdr.len != len) { 564 m_freem(m); 565 return (NULL); 566 } 567 rtm->rtm_msglen = len; 568 rtm->rtm_version = RTM_VERSION; 569 rtm->rtm_type = type; 570 return (m); 571 } 572 573 static int 574 rt_msg2(type, rtinfo, cp, w) 575 int type; 576 register struct rt_addrinfo *rtinfo; 577 caddr_t cp; 578 struct walkarg *w; 579 { 580 register int i; 581 int len, dlen, second_time = 0; 582 caddr_t cp0; 583 584 rtinfo->rti_addrs = 0; 585 again: 586 switch (type) { 587 588 case RTM_DELADDR: 589 case RTM_NEWADDR: 590 len = sizeof(struct ifa_msghdr); 591 break; 592 593 case RTM_IFINFO: 594 len = sizeof(struct if_msghdr); 595 break; 596 597 default: 598 len = sizeof(struct rt_msghdr); 599 } 600 if ((cp0 = cp) != NULL) 601 cp += len; 602 for (i = 0; i < RTAX_MAX; i++) { 603 register struct sockaddr *sa; 604 605 if ((sa = rtinfo->rti_info[i]) == 0) 606 continue; 607 rtinfo->rti_addrs |= (1 << i); 608 dlen = ROUNDUP(sa->sa_len); 609 if (cp) { 610 bcopy((caddr_t)sa, cp, (unsigned)dlen); 611 cp += dlen; 612 } 613 len += dlen; 614 } 615 if (cp == 0 && w != NULL && !second_time) { 616 register struct walkarg *rw = w; 617 618 rw->w_needed += len; 619 if (rw->w_needed <= 0 && rw->w_where) { 620 if (rw->w_tmemsize < len) { 621 if (rw->w_tmem) 622 free(rw->w_tmem, M_RTABLE); 623 rw->w_tmem = (caddr_t) malloc(len, M_RTABLE, 624 M_NOWAIT); 625 if (rw->w_tmem) 626 rw->w_tmemsize = len; 627 } 628 if (rw->w_tmem) { 629 cp = rw->w_tmem; 630 second_time = 1; 631 goto again; 632 } else 633 rw->w_where = 0; 634 } 635 } 636 if (cp) { 637 register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 638 639 rtm->rtm_version = RTM_VERSION; 640 rtm->rtm_type = type; 641 rtm->rtm_msglen = len; 642 } 643 return (len); 644 } 645 646 /* 647 * This routine is called to generate a message from the routing 648 * socket indicating that a redirect has occured, a routing lookup 649 * has failed, or that a protocol has detected timeouts to a particular 650 * destination. 651 */ 652 void 653 rt_missmsg(type, rtinfo, flags, error) 654 int type, flags, error; 655 register struct rt_addrinfo *rtinfo; 656 { 657 register struct rt_msghdr *rtm; 658 register struct mbuf *m; 659 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 660 661 if (route_cb.any_count == 0) 662 return; 663 m = rt_msg1(type, rtinfo); 664 if (m == 0) 665 return; 666 rtm = mtod(m, struct rt_msghdr *); 667 rtm->rtm_flags = RTF_DONE | flags; 668 rtm->rtm_errno = error; 669 rtm->rtm_addrs = rtinfo->rti_addrs; 670 route_proto.sp_protocol = sa ? sa->sa_family : 0; 671 raw_input(m, &route_proto, &route_src, &route_dst); 672 } 673 674 /* 675 * This routine is called to generate a message from the routing 676 * socket indicating that the status of a network interface has changed. 677 */ 678 void 679 rt_ifmsg(ifp) 680 register struct ifnet *ifp; 681 { 682 register struct if_msghdr *ifm; 683 struct mbuf *m; 684 struct rt_addrinfo info; 685 686 if (route_cb.any_count == 0) 687 return; 688 bzero((caddr_t)&info, sizeof(info)); 689 m = rt_msg1(RTM_IFINFO, &info); 690 if (m == 0) 691 return; 692 ifm = mtod(m, struct if_msghdr *); 693 ifm->ifm_index = ifp->if_index; 694 ifm->ifm_flags = ifp->if_flags; 695 ifm->ifm_data = ifp->if_data; 696 ifm->ifm_addrs = 0; 697 route_proto.sp_protocol = 0; 698 raw_input(m, &route_proto, &route_src, &route_dst); 699 } 700 701 /* 702 * This is called to generate messages from the routing socket 703 * indicating a network interface has had addresses associated with it. 704 * if we ever reverse the logic and replace messages TO the routing 705 * socket indicate a request to configure interfaces, then it will 706 * be unnecessary as the routing socket will automatically generate 707 * copies of it. 708 */ 709 void 710 rt_newaddrmsg(cmd, ifa, error, rt) 711 int cmd, error; 712 register struct ifaddr *ifa; 713 register struct rtentry *rt; 714 { 715 struct rt_addrinfo info; 716 struct sockaddr *sa = NULL; 717 int pass; 718 struct mbuf *m = NULL; 719 struct ifnet *ifp = ifa->ifa_ifp; 720 721 if (route_cb.any_count == 0) 722 return; 723 for (pass = 1; pass < 3; pass++) { 724 bzero((caddr_t)&info, sizeof(info)); 725 if ((cmd == RTM_ADD && pass == 1) || 726 (cmd == RTM_DELETE && pass == 2)) { 727 register struct ifa_msghdr *ifam; 728 int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 729 730 ifaaddr = sa = ifa->ifa_addr; 731 ifpaddr = ifp->if_addrlist.tqh_first->ifa_addr; 732 netmask = ifa->ifa_netmask; 733 brdaddr = ifa->ifa_dstaddr; 734 if ((m = rt_msg1(ncmd, &info)) == NULL) 735 continue; 736 ifam = mtod(m, struct ifa_msghdr *); 737 ifam->ifam_index = ifp->if_index; 738 ifam->ifam_metric = ifa->ifa_metric; 739 ifam->ifam_flags = ifa->ifa_flags; 740 ifam->ifam_addrs = info.rti_addrs; 741 } 742 if ((cmd == RTM_ADD && pass == 2) || 743 (cmd == RTM_DELETE && pass == 1)) { 744 register struct rt_msghdr *rtm; 745 746 if (rt == 0) 747 continue; 748 netmask = rt_mask(rt); 749 dst = sa = rt_key(rt); 750 gate = rt->rt_gateway; 751 if ((m = rt_msg1(cmd, &info)) == NULL) 752 continue; 753 rtm = mtod(m, struct rt_msghdr *); 754 rtm->rtm_index = ifp->if_index; 755 rtm->rtm_flags |= rt->rt_flags; 756 rtm->rtm_errno = error; 757 rtm->rtm_addrs = info.rti_addrs; 758 } 759 route_proto.sp_protocol = sa ? sa->sa_family : 0; 760 raw_input(m, &route_proto, &route_src, &route_dst); 761 } 762 } 763 764 /* 765 * This is used in dumping the kernel table via sysctl(). 766 */ 767 int 768 sysctl_dumpentry(rn, v) 769 struct radix_node *rn; 770 register void *v; 771 { 772 register struct walkarg *w = v; 773 register struct rtentry *rt = (struct rtentry *)rn; 774 int error = 0, size; 775 struct rt_addrinfo info; 776 777 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 778 return 0; 779 bzero((caddr_t)&info, sizeof(info)); 780 dst = rt_key(rt); 781 gate = rt->rt_gateway; 782 netmask = rt_mask(rt); 783 genmask = rt->rt_genmask; 784 if (rt->rt_ifp) { 785 ifpaddr = rt->rt_ifp->if_addrlist.tqh_first->ifa_addr; 786 ifaaddr = rt->rt_ifa->ifa_addr; 787 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 788 brdaddr = rt->rt_ifa->ifa_dstaddr; 789 } 790 size = rt_msg2(RTM_GET, &info, 0, w); 791 if (w->w_where && w->w_tmem) { 792 register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 793 794 rtm->rtm_flags = rt->rt_flags; 795 rtm->rtm_use = rt->rt_use; 796 rtm->rtm_rmx = rt->rt_rmx; 797 rtm->rtm_index = rt->rt_ifp->if_index; 798 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 799 rtm->rtm_addrs = info.rti_addrs; 800 if ((error = copyout((caddr_t)rtm, w->w_where, size)) != 0) 801 w->w_where = NULL; 802 else 803 w->w_where += size; 804 } 805 return (error); 806 } 807 808 int 809 sysctl_iflist(af, w) 810 int af; 811 register struct walkarg *w; 812 { 813 register struct ifnet *ifp; 814 register struct ifaddr *ifa; 815 struct rt_addrinfo info; 816 int len, error = 0; 817 818 bzero((caddr_t)&info, sizeof(info)); 819 for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) { 820 if (w->w_arg && w->w_arg != ifp->if_index) 821 continue; 822 ifa = ifp->if_addrlist.tqh_first; 823 ifpaddr = ifa->ifa_addr; 824 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 825 ifpaddr = 0; 826 if (w->w_where && w->w_tmem) { 827 register struct if_msghdr *ifm; 828 829 ifm = (struct if_msghdr *)w->w_tmem; 830 ifm->ifm_index = ifp->if_index; 831 ifm->ifm_flags = ifp->if_flags; 832 ifm->ifm_data = ifp->if_data; 833 ifm->ifm_addrs = info.rti_addrs; 834 error = copyout((caddr_t)ifm, w->w_where, len); 835 if (error) 836 return (error); 837 w->w_where += len; 838 } 839 while ((ifa = ifa->ifa_list.tqe_next) != NULL) { 840 if (af && af != ifa->ifa_addr->sa_family) 841 continue; 842 ifaaddr = ifa->ifa_addr; 843 netmask = ifa->ifa_netmask; 844 brdaddr = ifa->ifa_dstaddr; 845 len = rt_msg2(RTM_NEWADDR, &info, 0, w); 846 if (w->w_where && w->w_tmem) { 847 register struct ifa_msghdr *ifam; 848 849 ifam = (struct ifa_msghdr *)w->w_tmem; 850 ifam->ifam_index = ifa->ifa_ifp->if_index; 851 ifam->ifam_flags = ifa->ifa_flags; 852 ifam->ifam_metric = ifa->ifa_metric; 853 ifam->ifam_addrs = info.rti_addrs; 854 error = copyout(w->w_tmem, w->w_where, len); 855 if (error) 856 return (error); 857 w->w_where += len; 858 } 859 } 860 ifaaddr = netmask = brdaddr = 0; 861 } 862 return (0); 863 } 864 865 int 866 sysctl_rtable(name, namelen, where, given, new, newlen) 867 int *name; 868 u_int namelen; 869 void *where; 870 size_t *given; 871 void *new; 872 size_t newlen; 873 { 874 register struct radix_node_head *rnh; 875 int i, s, error = EINVAL; 876 u_char af; 877 struct walkarg w; 878 879 if (new) 880 return (EPERM); 881 if (namelen != 3) 882 return (EINVAL); 883 af = name[0]; 884 Bzero(&w, sizeof(w)); 885 w.w_where = where; 886 w.w_given = *given; 887 w.w_needed = 0 - w.w_given; 888 w.w_op = name[1]; 889 w.w_arg = name[2]; 890 891 s = splsoftnet(); 892 switch (w.w_op) { 893 894 case NET_RT_DUMP: 895 case NET_RT_FLAGS: 896 for (i = 1; i <= AF_MAX; i++) 897 if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 898 (error = (*rnh->rnh_walktree)(rnh, 899 sysctl_dumpentry, 900 &w))) 901 break; 902 break; 903 904 case NET_RT_IFLIST: 905 error = sysctl_iflist(af, &w); 906 } 907 splx(s); 908 if (w.w_tmem) 909 free(w.w_tmem, M_RTABLE); 910 w.w_needed += w.w_given; 911 if (where) { 912 *given = w.w_where - (caddr_t) where; 913 if (*given < w.w_needed) 914 return (ENOMEM); 915 } else { 916 *given = (11 * w.w_needed) / 10; 917 } 918 return (error); 919 } 920 921 /* 922 * Definitions of protocols supported in the ROUTE domain. 923 */ 924 925 extern struct domain routedomain; /* or at least forward */ 926 927 struct protosw routesw[] = { 928 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 929 raw_input, route_output, raw_ctlinput, 0, 930 route_usrreq, 931 raw_init, 0, 0, 0, 932 sysctl_rtable, 933 } 934 }; 935 936 struct domain routedomain = 937 { PF_ROUTE, "route", route_init, 0, 0, 938 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 939