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