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