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