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