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: rtsock.c,v 1.7 1994/10/11 23:16:29 wollman Exp $ 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 so->so_pcb = (caddr_t)rp; 88 if (so->so_pcb) 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(long)) && 143 (m = m_pullup(m, sizeof(long))) == 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, 0UL); 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 ifp = rt->rt_ifp; 227 if (ifp) { 228 ifpaddr = ifp->if_addrlist->ifa_addr; 229 ifaaddr = rt->rt_ifa->ifa_addr; 230 rtm->rtm_index = ifp->if_index; 231 } else { 232 ifpaddr = 0; 233 ifaaddr = 0; 234 } 235 } 236 len = rt_msg2(RTM_GET, &info, (caddr_t)0, 237 (struct walkarg *)0); 238 if (len > rtm->rtm_msglen) { 239 struct rt_msghdr *new_rtm; 240 R_Malloc(new_rtm, struct rt_msghdr *, len); 241 if (new_rtm == 0) 242 senderr(ENOBUFS); 243 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 244 Free(rtm); rtm = new_rtm; 245 } 246 (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 247 (struct walkarg *)0); 248 rtm->rtm_flags = rt->rt_flags; 249 rtm->rtm_rmx = rt->rt_rmx; 250 rtm->rtm_addrs = info.rti_addrs; 251 break; 252 253 case RTM_CHANGE: 254 if (gate && rt_setgate(rt, rt_key(rt), gate)) 255 senderr(EDQUOT); 256 257 /* 258 * If they tried to change things but didn't specify 259 * the required gateway, then just use the old one. 260 * This can happen if the user tries to change the 261 * flags on the default route without changing the 262 * default gateway. Changing flags still doesn't work. 263 */ 264 if ((rt->rt_flags & RTF_GATEWAY) && !gate) 265 gate = rt->rt_gateway; 266 267 /* new gateway could require new ifaddr, ifp; 268 flags may also be different; ifp may be specified 269 by ll sockaddr when protocol address is ambiguous */ 270 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 271 (ifp = ifa->ifa_ifp)) 272 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 273 ifp); 274 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 275 (ifa = ifa_ifwithroute(rt->rt_flags, 276 rt_key(rt), gate))) 277 ifp = ifa->ifa_ifp; 278 if (ifa) { 279 register struct ifaddr *oifa = rt->rt_ifa; 280 if (oifa != ifa) { 281 if (oifa && oifa->ifa_rtrequest) 282 oifa->ifa_rtrequest(RTM_DELETE, 283 rt, gate); 284 IFAFREE(rt->rt_ifa); 285 rt->rt_ifa = ifa; 286 ifa->ifa_refcnt++; 287 rt->rt_ifp = ifp; 288 } 289 } 290 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 291 &rt->rt_rmx); 292 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 293 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 294 if (genmask) 295 rt->rt_genmask = genmask; 296 /* 297 * Fall into 298 */ 299 case RTM_LOCK: 300 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 301 rt->rt_rmx.rmx_locks |= 302 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 303 break; 304 } 305 break; 306 307 default: 308 senderr(EOPNOTSUPP); 309 } 310 311 flush: 312 if (rtm) { 313 if (error) 314 rtm->rtm_errno = error; 315 else 316 rtm->rtm_flags |= RTF_DONE; 317 } 318 if (rt) 319 rtfree(rt); 320 { 321 register struct rawcb *rp = 0; 322 /* 323 * Check to see if we don't want our own messages. 324 */ 325 if ((so->so_options & SO_USELOOPBACK) == 0) { 326 if (route_cb.any_count <= 1) { 327 if (rtm) 328 Free(rtm); 329 m_freem(m); 330 return (error); 331 } 332 /* There is another listener, so construct message */ 333 rp = sotorawcb(so); 334 } 335 if (rtm) { 336 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 337 Free(rtm); 338 } 339 if (rp) 340 rp->rcb_proto.sp_family = 0; /* Avoid us */ 341 if (dst) 342 route_proto.sp_protocol = dst->sa_family; 343 raw_input(m, &route_proto, &route_src, &route_dst); 344 if (rp) 345 rp->rcb_proto.sp_family = PF_ROUTE; 346 } 347 return (error); 348 } 349 350 void 351 rt_setmetrics(which, in, out) 352 u_long which; 353 register struct rt_metrics *in, *out; 354 { 355 #define metric(f, e) if (which & (f)) out->e = in->e; 356 metric(RTV_RPIPE, rmx_recvpipe); 357 metric(RTV_SPIPE, rmx_sendpipe); 358 metric(RTV_SSTHRESH, rmx_ssthresh); 359 metric(RTV_RTT, rmx_rtt); 360 metric(RTV_RTTVAR, rmx_rttvar); 361 metric(RTV_HOPCOUNT, rmx_hopcount); 362 metric(RTV_MTU, rmx_mtu); 363 metric(RTV_EXPIRE, rmx_expire); 364 #undef metric 365 } 366 367 #define ROUNDUP(a) \ 368 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 369 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 370 371 static void 372 rt_xaddrs(cp, cplim, rtinfo) 373 register caddr_t cp, cplim; 374 register struct rt_addrinfo *rtinfo; 375 { 376 register struct sockaddr *sa; 377 register int i; 378 379 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 380 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 381 if ((rtinfo->rti_addrs & (1 << i)) == 0) 382 continue; 383 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 384 ADVANCE(cp, sa); 385 } 386 } 387 388 static struct mbuf * 389 rt_msg1(type, rtinfo) 390 int type; 391 register struct rt_addrinfo *rtinfo; 392 { 393 register struct rt_msghdr *rtm; 394 register struct mbuf *m; 395 register int i; 396 register struct sockaddr *sa; 397 int len, dlen; 398 399 m = m_gethdr(M_DONTWAIT, MT_DATA); 400 if (m == 0) 401 return (m); 402 switch (type) { 403 404 case RTM_DELADDR: 405 case RTM_NEWADDR: 406 len = sizeof(struct ifa_msghdr); 407 break; 408 409 case RTM_IFINFO: 410 len = sizeof(struct if_msghdr); 411 break; 412 413 default: 414 len = sizeof(struct rt_msghdr); 415 } 416 if (len > MHLEN) 417 panic("rt_msg1"); 418 m->m_pkthdr.len = m->m_len = len; 419 m->m_pkthdr.rcvif = 0; 420 rtm = mtod(m, struct rt_msghdr *); 421 bzero((caddr_t)rtm, len); 422 for (i = 0; i < RTAX_MAX; i++) { 423 if ((sa = rtinfo->rti_info[i]) == NULL) 424 continue; 425 rtinfo->rti_addrs |= (1 << i); 426 dlen = ROUNDUP(sa->sa_len); 427 m_copyback(m, len, dlen, (caddr_t)sa); 428 len += dlen; 429 } 430 if (m->m_pkthdr.len != len) { 431 m_freem(m); 432 return (NULL); 433 } 434 rtm->rtm_msglen = len; 435 rtm->rtm_version = RTM_VERSION; 436 rtm->rtm_type = type; 437 return (m); 438 } 439 440 static int 441 rt_msg2(type, rtinfo, cp, w) 442 int type; 443 register struct rt_addrinfo *rtinfo; 444 caddr_t cp; 445 struct walkarg *w; 446 { 447 register int i; 448 int len, dlen, second_time = 0; 449 caddr_t cp0; 450 451 rtinfo->rti_addrs = 0; 452 again: 453 switch (type) { 454 455 case RTM_DELADDR: 456 case RTM_NEWADDR: 457 len = sizeof(struct ifa_msghdr); 458 break; 459 460 case RTM_IFINFO: 461 len = sizeof(struct if_msghdr); 462 break; 463 464 default: 465 len = sizeof(struct rt_msghdr); 466 } 467 cp0 = cp; 468 if (cp0) 469 cp += len; 470 for (i = 0; i < RTAX_MAX; i++) { 471 register struct sockaddr *sa; 472 473 if ((sa = rtinfo->rti_info[i]) == 0) 474 continue; 475 rtinfo->rti_addrs |= (1 << i); 476 dlen = ROUNDUP(sa->sa_len); 477 if (cp) { 478 bcopy((caddr_t)sa, cp, (unsigned)dlen); 479 cp += dlen; 480 } 481 len += dlen; 482 } 483 if (cp == 0 && w != NULL && !second_time) { 484 register struct walkarg *rw = w; 485 486 rw->w_needed += len; 487 if (rw->w_needed <= 0 && rw->w_where) { 488 if (rw->w_tmemsize < len) { 489 if (rw->w_tmem) 490 free(rw->w_tmem, M_RTABLE); 491 rw->w_tmem = (caddr_t) 492 malloc(len, M_RTABLE, M_NOWAIT); 493 if (rw->w_tmem) 494 rw->w_tmemsize = len; 495 } 496 if (rw->w_tmem) { 497 cp = rw->w_tmem; 498 second_time = 1; 499 goto again; 500 } else 501 rw->w_where = 0; 502 } 503 } 504 if (cp) { 505 register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 506 507 rtm->rtm_version = RTM_VERSION; 508 rtm->rtm_type = type; 509 rtm->rtm_msglen = len; 510 } 511 return (len); 512 } 513 514 /* 515 * This routine is called to generate a message from the routing 516 * socket indicating that a redirect has occured, a routing lookup 517 * has failed, or that a protocol has detected timeouts to a particular 518 * destination. 519 */ 520 void 521 rt_missmsg(type, rtinfo, flags, error) 522 int type, flags, error; 523 register struct rt_addrinfo *rtinfo; 524 { 525 register struct rt_msghdr *rtm; 526 register struct mbuf *m; 527 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 528 529 if (route_cb.any_count == 0) 530 return; 531 m = rt_msg1(type, rtinfo); 532 if (m == 0) 533 return; 534 rtm = mtod(m, struct rt_msghdr *); 535 rtm->rtm_flags = RTF_DONE | flags; 536 rtm->rtm_errno = error; 537 rtm->rtm_addrs = rtinfo->rti_addrs; 538 route_proto.sp_protocol = sa ? sa->sa_family : 0; 539 raw_input(m, &route_proto, &route_src, &route_dst); 540 } 541 542 /* 543 * This routine is called to generate a message from the routing 544 * socket indicating that the status of a network interface has changed. 545 */ 546 void 547 rt_ifmsg(ifp) 548 register struct ifnet *ifp; 549 { 550 register struct if_msghdr *ifm; 551 struct mbuf *m; 552 struct rt_addrinfo info; 553 554 if (route_cb.any_count == 0) 555 return; 556 bzero((caddr_t)&info, sizeof(info)); 557 m = rt_msg1(RTM_IFINFO, &info); 558 if (m == 0) 559 return; 560 ifm = mtod(m, struct if_msghdr *); 561 ifm->ifm_index = ifp->if_index; 562 ifm->ifm_flags = (u_short)ifp->if_flags; 563 ifm->ifm_data = ifp->if_data; 564 ifm->ifm_addrs = 0; 565 route_proto.sp_protocol = 0; 566 raw_input(m, &route_proto, &route_src, &route_dst); 567 } 568 569 /* 570 * This is called to generate messages from the routing socket 571 * indicating a network interface has had addresses associated with it. 572 * if we ever reverse the logic and replace messages TO the routing 573 * socket indicate a request to configure interfaces, then it will 574 * be unnecessary as the routing socket will automatically generate 575 * copies of it. 576 */ 577 void 578 rt_newaddrmsg(cmd, ifa, error, rt) 579 int cmd, error; 580 register struct ifaddr *ifa; 581 register struct rtentry *rt; 582 { 583 struct rt_addrinfo info; 584 struct sockaddr *sa = 0; 585 int pass; 586 struct mbuf *m = 0; 587 struct ifnet *ifp = ifa->ifa_ifp; 588 589 if (route_cb.any_count == 0) 590 return; 591 for (pass = 1; pass < 3; pass++) { 592 bzero((caddr_t)&info, sizeof(info)); 593 if ((cmd == RTM_ADD && pass == 1) || 594 (cmd == RTM_DELETE && pass == 2)) { 595 register struct ifa_msghdr *ifam; 596 int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 597 598 ifaaddr = sa = ifa->ifa_addr; 599 ifpaddr = ifp->if_addrlist->ifa_addr; 600 netmask = ifa->ifa_netmask; 601 brdaddr = ifa->ifa_dstaddr; 602 if ((m = rt_msg1(ncmd, &info)) == NULL) 603 continue; 604 ifam = mtod(m, struct ifa_msghdr *); 605 ifam->ifam_index = ifp->if_index; 606 ifam->ifam_metric = ifa->ifa_metric; 607 ifam->ifam_flags = ifa->ifa_flags; 608 ifam->ifam_addrs = info.rti_addrs; 609 } 610 if ((cmd == RTM_ADD && pass == 2) || 611 (cmd == RTM_DELETE && pass == 1)) { 612 register struct rt_msghdr *rtm; 613 614 if (rt == 0) 615 continue; 616 netmask = rt_mask(rt); 617 dst = sa = rt_key(rt); 618 gate = rt->rt_gateway; 619 if ((m = rt_msg1(cmd, &info)) == NULL) 620 continue; 621 rtm = mtod(m, struct rt_msghdr *); 622 rtm->rtm_index = ifp->if_index; 623 rtm->rtm_flags |= rt->rt_flags; 624 rtm->rtm_errno = error; 625 rtm->rtm_addrs = info.rti_addrs; 626 } 627 route_proto.sp_protocol = sa ? sa->sa_family : 0; 628 raw_input(m, &route_proto, &route_src, &route_dst); 629 } 630 } 631 632 /* 633 * This is used in dumping the kernel table via sysctl(). 634 */ 635 int 636 sysctl_dumpentry(rn, w) 637 struct radix_node *rn; 638 register struct walkarg *w; 639 { 640 register struct rtentry *rt = (struct rtentry *)rn; 641 int error = 0, size; 642 struct rt_addrinfo info; 643 644 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 645 return 0; 646 bzero((caddr_t)&info, sizeof(info)); 647 dst = rt_key(rt); 648 gate = rt->rt_gateway; 649 netmask = rt_mask(rt); 650 genmask = rt->rt_genmask; 651 size = rt_msg2(RTM_GET, &info, 0, w); 652 if (w->w_where && w->w_tmem) { 653 register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 654 655 rtm->rtm_flags = rt->rt_flags; 656 rtm->rtm_use = rt->rt_use; 657 rtm->rtm_rmx = rt->rt_rmx; 658 rtm->rtm_index = rt->rt_ifp->if_index; 659 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 660 rtm->rtm_addrs = info.rti_addrs; 661 error = copyout((caddr_t)rtm, w->w_where, size); 662 if (error) 663 w->w_where = NULL; 664 else 665 w->w_where += size; 666 } 667 return (error); 668 } 669 670 int 671 sysctl_iflist(af, w) 672 int af; 673 register struct walkarg *w; 674 { 675 register struct ifnet *ifp; 676 register struct ifaddr *ifa; 677 struct rt_addrinfo info; 678 int len, error = 0; 679 680 bzero((caddr_t)&info, sizeof(info)); 681 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 682 if (w->w_arg && w->w_arg != ifp->if_index) 683 continue; 684 ifa = ifp->if_addrlist; 685 ifpaddr = ifa->ifa_addr; 686 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 687 ifpaddr = 0; 688 if (w->w_where && w->w_tmem) { 689 register struct if_msghdr *ifm; 690 691 ifm = (struct if_msghdr *)w->w_tmem; 692 ifm->ifm_index = ifp->if_index; 693 ifm->ifm_flags = (u_short)ifp->if_flags; 694 ifm->ifm_data = ifp->if_data; 695 ifm->ifm_addrs = info.rti_addrs; 696 error = copyout((caddr_t)ifm, w->w_where, len); 697 if (error) 698 return (error); 699 w->w_where += len; 700 } 701 while ((ifa = ifa->ifa_next) != 0) { 702 if (af && af != ifa->ifa_addr->sa_family) 703 continue; 704 ifaaddr = ifa->ifa_addr; 705 netmask = ifa->ifa_netmask; 706 brdaddr = ifa->ifa_dstaddr; 707 len = rt_msg2(RTM_NEWADDR, &info, 0, w); 708 if (w->w_where && w->w_tmem) { 709 register struct ifa_msghdr *ifam; 710 711 ifam = (struct ifa_msghdr *)w->w_tmem; 712 ifam->ifam_index = ifa->ifa_ifp->if_index; 713 ifam->ifam_flags = ifa->ifa_flags; 714 ifam->ifam_metric = ifa->ifa_metric; 715 ifam->ifam_addrs = info.rti_addrs; 716 error = copyout(w->w_tmem, w->w_where, len); 717 if (error) 718 return (error); 719 w->w_where += len; 720 } 721 } 722 ifaaddr = netmask = brdaddr = 0; 723 } 724 return (0); 725 } 726 727 int 728 sysctl_rtable(name, namelen, where, given, new, newlen) 729 int *name; 730 int namelen; 731 caddr_t where; 732 size_t *given; 733 caddr_t *new; 734 size_t newlen; 735 { 736 register struct radix_node_head *rnh; 737 int i, s, error = EINVAL; 738 u_char af; 739 struct walkarg w; 740 741 if (new) 742 return (EPERM); 743 if (namelen != 3) 744 return (EINVAL); 745 af = name[0]; 746 Bzero(&w, sizeof(w)); 747 w.w_where = where; 748 w.w_given = *given; 749 w.w_needed = 0 - w.w_given; 750 w.w_op = name[1]; 751 w.w_arg = name[2]; 752 753 s = splnet(); 754 switch (w.w_op) { 755 756 case NET_RT_DUMP: 757 case NET_RT_FLAGS: 758 for (i = 1; i <= AF_MAX; i++) 759 if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 760 (error = rnh->rnh_walktree(rnh, 761 sysctl_dumpentry, &w))) 762 break; 763 break; 764 765 case NET_RT_IFLIST: 766 error = sysctl_iflist(af, &w); 767 } 768 splx(s); 769 if (w.w_tmem) 770 free(w.w_tmem, M_RTABLE); 771 w.w_needed += w.w_given; 772 if (where) { 773 *given = w.w_where - where; 774 if (*given < w.w_needed) 775 return (ENOMEM); 776 } else { 777 *given = (11 * w.w_needed) / 10; 778 } 779 return (error); 780 } 781 782 /* 783 * Definitions of protocols supported in the ROUTE domain. 784 */ 785 786 extern struct domain routedomain; /* or at least forward */ 787 788 struct protosw routesw[] = { 789 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 790 raw_input, route_output, raw_ctlinput, 0, 791 route_usrreq, 792 raw_init, 0, 0, 0, 793 sysctl_rtable, 794 } 795 }; 796 797 struct domain routedomain = 798 { PF_ROUTE, "route", route_init, 0, 0, 799 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 800