1 /* $OpenBSD: rtsock.c,v 1.19 2001/12/10 06:10:53 jason 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 <uvm/uvm_extern.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 = 297 TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 298 ifaaddr = rt->rt_ifa->ifa_addr; 299 if (ifp->if_flags & IFF_POINTOPOINT) 300 brdaddr = rt->rt_ifa->ifa_dstaddr; 301 else 302 brdaddr = 0; 303 rtm->rtm_index = ifp->if_index; 304 } else { 305 ifpaddr = 0; 306 ifaaddr = 0; 307 } 308 } 309 len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0, 310 (struct walkarg *)0); 311 if (len > rtm->rtm_msglen) { 312 struct rt_msghdr *new_rtm; 313 R_Malloc(new_rtm, struct rt_msghdr *, len); 314 if (new_rtm == 0) 315 senderr(ENOBUFS); 316 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 317 Free(rtm); rtm = new_rtm; 318 } 319 (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, 320 (struct walkarg *)0); 321 rtm->rtm_flags = rt->rt_flags; 322 rtm->rtm_rmx = rt->rt_rmx; 323 rtm->rtm_addrs = info.rti_addrs; 324 break; 325 326 case RTM_CHANGE: 327 /* 328 * new gateway could require new ifaddr, ifp; 329 * flags may also be different; ifp may be specified 330 * by ll sockaddr when protocol address is ambiguous 331 */ 332 if ((error = rt_getifa(&info)) != 0) 333 senderr(error); 334 if (gate && rt_setgate(rt, rt_key(rt), gate)) 335 senderr(EDQUOT); 336 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 337 (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) 338 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 339 ifp); 340 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 341 (gate && (ifa = ifa_ifwithroute(rt->rt_flags, 342 rt_key(rt), gate)))) 343 ifp = ifa->ifa_ifp; 344 if (ifa) { 345 register struct ifaddr *oifa = rt->rt_ifa; 346 if (oifa != ifa) { 347 if (oifa && oifa->ifa_rtrequest) 348 oifa->ifa_rtrequest(RTM_DELETE, rt, 349 &info); 350 IFAFREE(rt->rt_ifa); 351 rt->rt_ifa = ifa; 352 ifa->ifa_refcnt++; 353 rt->rt_ifp = ifp; 354 } 355 } 356 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 357 &rt->rt_rmx); 358 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 359 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); 360 if (genmask) 361 rt->rt_genmask = genmask; 362 /* 363 * Fall into 364 */ 365 case RTM_ADD: 366 case RTM_LOCK: 367 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 368 rt->rt_rmx.rmx_locks |= 369 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 370 break; 371 } 372 break; 373 374 default: 375 senderr(EOPNOTSUPP); 376 } 377 378 flush: 379 if (rtm) { 380 if (error) 381 rtm->rtm_errno = error; 382 else 383 rtm->rtm_flags |= RTF_DONE; 384 } 385 if (rt) 386 rtfree(rt); 387 { 388 register struct rawcb *rp = 0; 389 /* 390 * Check to see if we don't want our own messages. 391 */ 392 if ((so->so_options & SO_USELOOPBACK) == 0) { 393 if (route_cb.any_count <= 1) { 394 if (rtm) 395 Free(rtm); 396 m_freem(m); 397 return (error); 398 } 399 /* There is another listener, so construct message */ 400 rp = sotorawcb(so); 401 } 402 if (rtm) { 403 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 404 if (m->m_pkthdr.len < rtm->rtm_msglen) { 405 m_freem(m); 406 m = NULL; 407 } else if (m->m_pkthdr.len > rtm->rtm_msglen) 408 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 409 Free(rtm); 410 } 411 if (rp) 412 rp->rcb_proto.sp_family = 0; /* Avoid us */ 413 if (dst) 414 route_proto.sp_protocol = dst->sa_family; 415 if (m) 416 raw_input(m, &route_proto, &route_src, &route_dst); 417 if (rp) 418 rp->rcb_proto.sp_family = PF_ROUTE; 419 } 420 return (error); 421 } 422 423 void 424 rt_setmetrics(which, in, out) 425 u_long which; 426 register struct rt_metrics *in, *out; 427 { 428 #define metric(f, e) if (which & (f)) out->e = in->e; 429 metric(RTV_RPIPE, rmx_recvpipe); 430 metric(RTV_SPIPE, rmx_sendpipe); 431 metric(RTV_SSTHRESH, rmx_ssthresh); 432 metric(RTV_RTT, rmx_rtt); 433 metric(RTV_RTTVAR, rmx_rttvar); 434 metric(RTV_HOPCOUNT, rmx_hopcount); 435 metric(RTV_MTU, rmx_mtu); 436 metric(RTV_EXPIRE, rmx_expire); 437 #undef metric 438 } 439 440 #define ROUNDUP(a) \ 441 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 442 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 443 444 static void 445 rt_xaddrs(cp, cplim, rtinfo) 446 register caddr_t cp, cplim; 447 register struct rt_addrinfo *rtinfo; 448 { 449 register struct sockaddr *sa; 450 register int i; 451 452 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 453 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 454 if ((rtinfo->rti_addrs & (1 << i)) == 0) 455 continue; 456 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 457 ADVANCE(cp, sa); 458 } 459 } 460 461 /* 462 * Copy data from a buffer back into the indicated mbuf chain, 463 * starting "off" bytes from the beginning, extending the mbuf 464 * chain if necessary. The mbuf needs to be properly initalized 465 * including the setting of m_len. 466 */ 467 void 468 m_copyback(m0, off, len, cp) 469 struct mbuf *m0; 470 register int off; 471 register int len; 472 caddr_t cp; 473 { 474 register int mlen; 475 register struct mbuf *m = m0, *n; 476 int totlen = 0; 477 478 if (m0 == 0) 479 return; 480 while (off > (mlen = m->m_len)) { 481 off -= mlen; 482 totlen += mlen; 483 if (m->m_next == 0) { 484 n = m_getclr(M_DONTWAIT, m->m_type); 485 if (n == 0) 486 goto out; 487 n->m_len = min(MLEN, len + off); 488 m->m_next = n; 489 } 490 m = m->m_next; 491 } 492 while (len > 0) { 493 mlen = min (m->m_len - off, len); 494 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 495 cp += mlen; 496 len -= mlen; 497 mlen += off; 498 off = 0; 499 totlen += mlen; 500 if (len == 0) 501 break; 502 if (m->m_next == 0) { 503 n = m_get(M_DONTWAIT, m->m_type); 504 if (n == 0) 505 break; 506 n->m_len = min(MLEN, len); 507 m->m_next = n; 508 } 509 m = m->m_next; 510 } 511 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 512 m->m_pkthdr.len = totlen; 513 } 514 515 static struct mbuf * 516 rt_msg1(type, rtinfo) 517 int type; 518 register struct rt_addrinfo *rtinfo; 519 { 520 register struct rt_msghdr *rtm; 521 register struct mbuf *m; 522 register int i; 523 register struct sockaddr *sa; 524 int len, dlen; 525 526 switch (type) { 527 528 case RTM_DELADDR: 529 case RTM_NEWADDR: 530 len = sizeof(struct ifa_msghdr); 531 break; 532 533 case RTM_IFINFO: 534 len = sizeof(struct if_msghdr); 535 break; 536 537 default: 538 len = sizeof(struct rt_msghdr); 539 } 540 if (len > MCLBYTES) 541 panic("rt_msg1"); 542 m = m_gethdr(M_DONTWAIT, MT_DATA); 543 if (m && len > MHLEN) { 544 MCLGET(m, M_DONTWAIT); 545 if ((m->m_flags & M_EXT) == 0) { 546 m_free(m); 547 m = NULL; 548 } 549 } 550 if (m == 0) 551 return (m); 552 m->m_pkthdr.len = m->m_len = len; 553 m->m_pkthdr.rcvif = 0; 554 rtm = mtod(m, struct rt_msghdr *); 555 bzero((caddr_t)rtm, len); 556 for (i = 0; i < RTAX_MAX; i++) { 557 if ((sa = rtinfo->rti_info[i]) == NULL) 558 continue; 559 rtinfo->rti_addrs |= (1 << i); 560 dlen = ROUNDUP(sa->sa_len); 561 m_copyback(m, len, dlen, (caddr_t)sa); 562 len += dlen; 563 } 564 if (m->m_pkthdr.len != len) { 565 m_freem(m); 566 return (NULL); 567 } 568 rtm->rtm_msglen = len; 569 rtm->rtm_version = RTM_VERSION; 570 rtm->rtm_type = type; 571 return (m); 572 } 573 574 static int 575 rt_msg2(type, rtinfo, cp, w) 576 int type; 577 register struct rt_addrinfo *rtinfo; 578 caddr_t cp; 579 struct walkarg *w; 580 { 581 register int i; 582 int len, dlen, second_time = 0; 583 caddr_t cp0; 584 585 rtinfo->rti_addrs = 0; 586 again: 587 switch (type) { 588 589 case RTM_DELADDR: 590 case RTM_NEWADDR: 591 len = sizeof(struct ifa_msghdr); 592 break; 593 594 case RTM_IFINFO: 595 len = sizeof(struct if_msghdr); 596 break; 597 598 default: 599 len = sizeof(struct rt_msghdr); 600 } 601 if ((cp0 = cp) != NULL) 602 cp += len; 603 for (i = 0; i < RTAX_MAX; i++) { 604 register struct sockaddr *sa; 605 606 if ((sa = rtinfo->rti_info[i]) == 0) 607 continue; 608 rtinfo->rti_addrs |= (1 << i); 609 dlen = ROUNDUP(sa->sa_len); 610 if (cp) { 611 bcopy((caddr_t)sa, cp, (unsigned)dlen); 612 cp += dlen; 613 } 614 len += dlen; 615 } 616 if (cp == 0 && w != NULL && !second_time) { 617 register struct walkarg *rw = w; 618 619 rw->w_needed += len; 620 if (rw->w_needed <= 0 && rw->w_where) { 621 if (rw->w_tmemsize < len) { 622 if (rw->w_tmem) 623 free(rw->w_tmem, M_RTABLE); 624 rw->w_tmem = (caddr_t) malloc(len, M_RTABLE, 625 M_NOWAIT); 626 if (rw->w_tmem) 627 rw->w_tmemsize = len; 628 } 629 if (rw->w_tmem) { 630 cp = rw->w_tmem; 631 second_time = 1; 632 goto again; 633 } else 634 rw->w_where = 0; 635 } 636 } 637 if (cp) { 638 register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 639 640 rtm->rtm_version = RTM_VERSION; 641 rtm->rtm_type = type; 642 rtm->rtm_msglen = len; 643 } 644 return (len); 645 } 646 647 /* 648 * This routine is called to generate a message from the routing 649 * socket indicating that a redirect has occurred, a routing lookup 650 * has failed, or that a protocol has detected timeouts to a particular 651 * destination. 652 */ 653 void 654 rt_missmsg(type, rtinfo, flags, error) 655 int type, flags, error; 656 register struct rt_addrinfo *rtinfo; 657 { 658 register struct rt_msghdr *rtm; 659 register struct mbuf *m; 660 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 661 662 if (route_cb.any_count == 0) 663 return; 664 m = rt_msg1(type, rtinfo); 665 if (m == 0) 666 return; 667 rtm = mtod(m, struct rt_msghdr *); 668 rtm->rtm_flags = RTF_DONE | flags; 669 rtm->rtm_errno = error; 670 rtm->rtm_addrs = rtinfo->rti_addrs; 671 route_proto.sp_protocol = sa ? sa->sa_family : 0; 672 raw_input(m, &route_proto, &route_src, &route_dst); 673 } 674 675 /* 676 * This routine is called to generate a message from the routing 677 * socket indicating that the status of a network interface has changed. 678 */ 679 void 680 rt_ifmsg(ifp) 681 register struct ifnet *ifp; 682 { 683 register struct if_msghdr *ifm; 684 struct mbuf *m; 685 struct rt_addrinfo info; 686 687 if (route_cb.any_count == 0) 688 return; 689 bzero((caddr_t)&info, sizeof(info)); 690 m = rt_msg1(RTM_IFINFO, &info); 691 if (m == 0) 692 return; 693 ifm = mtod(m, struct if_msghdr *); 694 ifm->ifm_index = ifp->if_index; 695 ifm->ifm_flags = ifp->if_flags; 696 ifm->ifm_data = ifp->if_data; 697 ifm->ifm_addrs = 0; 698 route_proto.sp_protocol = 0; 699 raw_input(m, &route_proto, &route_src, &route_dst); 700 } 701 702 /* 703 * This is called to generate messages from the routing socket 704 * indicating a network interface has had addresses associated with it. 705 * if we ever reverse the logic and replace messages TO the routing 706 * socket indicate a request to configure interfaces, then it will 707 * be unnecessary as the routing socket will automatically generate 708 * copies of it. 709 */ 710 void 711 rt_newaddrmsg(cmd, ifa, error, rt) 712 int cmd, error; 713 register struct ifaddr *ifa; 714 register struct rtentry *rt; 715 { 716 struct rt_addrinfo info; 717 struct sockaddr *sa = NULL; 718 int pass; 719 struct mbuf *m = NULL; 720 struct ifnet *ifp = ifa->ifa_ifp; 721 722 if (route_cb.any_count == 0) 723 return; 724 for (pass = 1; pass < 3; pass++) { 725 bzero((caddr_t)&info, sizeof(info)); 726 if ((cmd == RTM_ADD && pass == 1) || 727 (cmd == RTM_DELETE && pass == 2)) { 728 register struct ifa_msghdr *ifam; 729 int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 730 731 ifaaddr = sa = ifa->ifa_addr; 732 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr; 733 netmask = ifa->ifa_netmask; 734 brdaddr = ifa->ifa_dstaddr; 735 if ((m = rt_msg1(ncmd, &info)) == NULL) 736 continue; 737 ifam = mtod(m, struct ifa_msghdr *); 738 ifam->ifam_index = ifp->if_index; 739 ifam->ifam_metric = ifa->ifa_metric; 740 ifam->ifam_flags = ifa->ifa_flags; 741 ifam->ifam_addrs = info.rti_addrs; 742 } 743 if ((cmd == RTM_ADD && pass == 2) || 744 (cmd == RTM_DELETE && pass == 1)) { 745 register struct rt_msghdr *rtm; 746 747 if (rt == 0) 748 continue; 749 netmask = rt_mask(rt); 750 dst = sa = rt_key(rt); 751 gate = rt->rt_gateway; 752 if ((m = rt_msg1(cmd, &info)) == NULL) 753 continue; 754 rtm = mtod(m, struct rt_msghdr *); 755 rtm->rtm_index = ifp->if_index; 756 rtm->rtm_flags |= rt->rt_flags; 757 rtm->rtm_errno = error; 758 rtm->rtm_addrs = info.rti_addrs; 759 } 760 route_proto.sp_protocol = sa ? sa->sa_family : 0; 761 raw_input(m, &route_proto, &route_src, &route_dst); 762 } 763 } 764 765 /* 766 * This is used in dumping the kernel table via sysctl(). 767 */ 768 int 769 sysctl_dumpentry(rn, v) 770 struct radix_node *rn; 771 register void *v; 772 { 773 register struct walkarg *w = v; 774 register struct rtentry *rt = (struct rtentry *)rn; 775 int error = 0, size; 776 struct rt_addrinfo info; 777 778 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 779 return 0; 780 bzero((caddr_t)&info, sizeof(info)); 781 dst = rt_key(rt); 782 gate = rt->rt_gateway; 783 netmask = rt_mask(rt); 784 genmask = rt->rt_genmask; 785 if (rt->rt_ifp) { 786 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 787 ifaaddr = rt->rt_ifa->ifa_addr; 788 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 789 brdaddr = rt->rt_ifa->ifa_dstaddr; 790 } 791 size = rt_msg2(RTM_GET, &info, 0, w); 792 if (w->w_where && w->w_tmem) { 793 register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 794 795 rtm->rtm_flags = rt->rt_flags; 796 rtm->rtm_use = rt->rt_use; 797 rtm->rtm_rmx = rt->rt_rmx; 798 rtm->rtm_index = rt->rt_ifp->if_index; 799 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 800 rtm->rtm_addrs = info.rti_addrs; 801 if ((error = copyout((caddr_t)rtm, w->w_where, size)) != 0) 802 w->w_where = NULL; 803 else 804 w->w_where += size; 805 } 806 return (error); 807 } 808 809 int 810 sysctl_iflist(af, w) 811 int af; 812 register struct walkarg *w; 813 { 814 register struct ifnet *ifp; 815 register struct ifaddr *ifa; 816 struct rt_addrinfo info; 817 int len, error = 0; 818 819 bzero((caddr_t)&info, sizeof(info)); 820 TAILQ_FOREACH(ifp, &ifnet, if_list) { 821 if (w->w_arg && w->w_arg != ifp->if_index) 822 continue; 823 ifa = TAILQ_FIRST(&ifp->if_addrlist); 824 ifpaddr = ifa->ifa_addr; 825 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 826 ifpaddr = 0; 827 if (w->w_where && w->w_tmem) { 828 register struct if_msghdr *ifm; 829 830 ifm = (struct if_msghdr *)w->w_tmem; 831 ifm->ifm_index = ifp->if_index; 832 ifm->ifm_flags = ifp->if_flags; 833 ifm->ifm_data = ifp->if_data; 834 ifm->ifm_addrs = info.rti_addrs; 835 error = copyout((caddr_t)ifm, w->w_where, len); 836 if (error) 837 return (error); 838 w->w_where += len; 839 } 840 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) != 841 TAILQ_END(&ifp->if_addrlist)) { 842 if (af && af != ifa->ifa_addr->sa_family) 843 continue; 844 ifaaddr = ifa->ifa_addr; 845 netmask = ifa->ifa_netmask; 846 brdaddr = ifa->ifa_dstaddr; 847 len = rt_msg2(RTM_NEWADDR, &info, 0, w); 848 if (w->w_where && w->w_tmem) { 849 register struct ifa_msghdr *ifam; 850 851 ifam = (struct ifa_msghdr *)w->w_tmem; 852 ifam->ifam_index = ifa->ifa_ifp->if_index; 853 ifam->ifam_flags = ifa->ifa_flags; 854 ifam->ifam_metric = ifa->ifa_metric; 855 ifam->ifam_addrs = info.rti_addrs; 856 error = copyout(w->w_tmem, w->w_where, len); 857 if (error) 858 return (error); 859 w->w_where += len; 860 } 861 } 862 ifaaddr = netmask = brdaddr = 0; 863 } 864 return (0); 865 } 866 867 int 868 sysctl_rtable(name, namelen, where, given, new, newlen) 869 int *name; 870 u_int namelen; 871 void *where; 872 size_t *given; 873 void *new; 874 size_t newlen; 875 { 876 register struct radix_node_head *rnh; 877 int i, s, error = EINVAL; 878 u_char af; 879 struct walkarg w; 880 881 if (new) 882 return (EPERM); 883 if (namelen != 3) 884 return (EINVAL); 885 af = name[0]; 886 Bzero(&w, sizeof(w)); 887 w.w_where = where; 888 w.w_given = *given; 889 w.w_needed = 0 - w.w_given; 890 w.w_op = name[1]; 891 w.w_arg = name[2]; 892 893 s = splsoftnet(); 894 switch (w.w_op) { 895 896 case NET_RT_DUMP: 897 case NET_RT_FLAGS: 898 for (i = 1; i <= AF_MAX; i++) 899 if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 900 (error = (*rnh->rnh_walktree)(rnh, 901 sysctl_dumpentry, 902 &w))) 903 break; 904 break; 905 906 case NET_RT_IFLIST: 907 error = sysctl_iflist(af, &w); 908 } 909 splx(s); 910 if (w.w_tmem) 911 free(w.w_tmem, M_RTABLE); 912 w.w_needed += w.w_given; 913 if (where) { 914 *given = w.w_where - (caddr_t) where; 915 if (*given < w.w_needed) 916 return (ENOMEM); 917 } else { 918 *given = (11 * w.w_needed) / 10; 919 } 920 return (error); 921 } 922 923 /* 924 * Definitions of protocols supported in the ROUTE domain. 925 */ 926 927 extern struct domain routedomain; /* or at least forward */ 928 929 struct protosw routesw[] = { 930 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 931 raw_input, route_output, raw_ctlinput, 0, 932 route_usrreq, 933 raw_init, 0, 0, 0, 934 sysctl_rtable, 935 } 936 }; 937 938 struct domain routedomain = 939 { PF_ROUTE, "route", route_init, 0, 0, 940 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 941