1 /* 2 * Copyright (c) 1980, 1986, 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 * @(#)if.c 8.3 (Berkeley) 1/4/94 34 * $Id: if.c,v 1.20 1995/09/22 17:57:46 wollman Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/mbuf.h> 39 #include <sys/systm.h> 40 #include <sys/proc.h> 41 #include <sys/socket.h> 42 #include <sys/socketvar.h> 43 #include <sys/protosw.h> 44 #include <sys/kernel.h> 45 #include <sys/ioctl.h> 46 #include <sys/errno.h> 47 #include <sys/syslog.h> 48 49 #include <net/if.h> 50 #include <net/if_dl.h> 51 #include <net/if_types.h> 52 #include <net/radix.h> 53 #include <ether.h> 54 55 /* 56 * System initialization 57 */ 58 59 static void ifinit __P((void *)); 60 SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) 61 62 63 int ifqmaxlen = IFQ_MAXLEN; 64 struct ifnet *ifnet; 65 66 /* 67 * Network interface utility routines. 68 * 69 * Routines with ifa_ifwith* names take sockaddr *'s as 70 * parameters. 71 * 72 * This routine assumes that it will be called at splimp() or higher. 73 */ 74 /* ARGSUSED*/ 75 void 76 ifinit(udata) 77 void *udata; /* not used*/ 78 { 79 register struct ifnet *ifp; 80 81 for (ifp = ifnet; ifp; ifp = ifp->if_next) 82 if (ifp->if_snd.ifq_maxlen == 0) 83 ifp->if_snd.ifq_maxlen = ifqmaxlen; 84 if_slowtimo(0); 85 } 86 87 #ifdef vax 88 /* 89 * Call each interface on a Unibus reset. 90 */ 91 void 92 ifubareset(uban) 93 int uban; 94 { 95 register struct ifnet *ifp; 96 97 for (ifp = ifnet; ifp; ifp = ifp->if_next) 98 if (ifp->if_reset) 99 (*ifp->if_reset)(ifp->if_unit, uban); 100 } 101 #endif 102 103 int if_index = 0; 104 struct ifaddr **ifnet_addrs; 105 static char *sprint_d __P((u_int, char *, int)); 106 107 /* 108 * Attach an interface to the 109 * list of "active" interfaces. 110 */ 111 void 112 if_attach(ifp) 113 struct ifnet *ifp; 114 { 115 unsigned socksize, ifasize; 116 int namelen, unitlen, masklen; 117 char workbuf[12], *unitname; 118 register struct ifnet **p = &ifnet; 119 register struct sockaddr_dl *sdl; 120 register struct ifaddr *ifa; 121 static int if_indexlim = 8; 122 123 124 while (*p) 125 p = &((*p)->if_next); 126 *p = ifp; 127 ifp->if_index = ++if_index; 128 if (ifnet_addrs == 0 || if_index >= if_indexlim) { 129 unsigned n = (if_indexlim <<= 1) * sizeof(ifa); 130 struct ifaddr **q = (struct ifaddr **) 131 malloc(n, M_IFADDR, M_WAITOK); 132 bzero((caddr_t)q, n); 133 if (ifnet_addrs) { 134 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); 135 free((caddr_t)ifnet_addrs, M_IFADDR); 136 } 137 ifnet_addrs = q; 138 } 139 /* 140 * create a Link Level name for this device 141 */ 142 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf)); 143 namelen = strlen(ifp->if_name); 144 unitlen = strlen(unitname); 145 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 146 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + 147 unitlen + namelen; 148 socksize = masklen + ifp->if_addrlen; 149 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 150 socksize = ROUNDUP(socksize); 151 if (socksize < sizeof(*sdl)) 152 socksize = sizeof(*sdl); 153 ifasize = sizeof(*ifa) + 2 * socksize; 154 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); 155 if (ifa) { 156 bzero((caddr_t)ifa, ifasize); 157 sdl = (struct sockaddr_dl *)(ifa + 1); 158 sdl->sdl_len = socksize; 159 sdl->sdl_family = AF_LINK; 160 bcopy(ifp->if_name, sdl->sdl_data, namelen); 161 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen); 162 sdl->sdl_nlen = (namelen += unitlen); 163 sdl->sdl_index = ifp->if_index; 164 sdl->sdl_type = ifp->if_type; 165 ifnet_addrs[if_index - 1] = ifa; 166 ifa->ifa_ifp = ifp; 167 ifa->ifa_next = ifp->if_addrlist; 168 ifa->ifa_rtrequest = link_rtrequest; 169 ifp->if_addrlist = ifa; 170 ifa->ifa_addr = (struct sockaddr *)sdl; 171 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 172 ifa->ifa_netmask = (struct sockaddr *)sdl; 173 sdl->sdl_len = masklen; 174 while (namelen != 0) 175 sdl->sdl_data[--namelen] = 0xff; 176 } 177 /* XXX -- Temporary fix before changing 10 ethernet drivers */ 178 #if NETHER > 0 179 if (ifp->if_output == ether_output) 180 ether_ifattach(ifp); 181 #endif 182 } 183 /* 184 * Locate an interface based on a complete address. 185 */ 186 /*ARGSUSED*/ 187 struct ifaddr * 188 ifa_ifwithaddr(addr) 189 register struct sockaddr *addr; 190 { 191 register struct ifnet *ifp; 192 register struct ifaddr *ifa; 193 194 #define equal(a1, a2) \ 195 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 196 for (ifp = ifnet; ifp; ifp = ifp->if_next) 197 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 198 if (ifa->ifa_addr->sa_family != addr->sa_family) 199 continue; 200 if (equal(addr, ifa->ifa_addr)) 201 return (ifa); 202 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && 203 equal(ifa->ifa_broadaddr, addr)) 204 return (ifa); 205 } 206 return ((struct ifaddr *)0); 207 } 208 /* 209 * Locate the point to point interface with a given destination address. 210 */ 211 /*ARGSUSED*/ 212 struct ifaddr * 213 ifa_ifwithdstaddr(addr) 214 register struct sockaddr *addr; 215 { 216 register struct ifnet *ifp; 217 register struct ifaddr *ifa; 218 219 for (ifp = ifnet; ifp; ifp = ifp->if_next) 220 if (ifp->if_flags & IFF_POINTOPOINT) 221 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 222 if (ifa->ifa_addr->sa_family != addr->sa_family) 223 continue; 224 if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 225 return (ifa); 226 } 227 return ((struct ifaddr *)0); 228 } 229 230 /* 231 * Find an interface on a specific network. If many, choice 232 * is most specific found. 233 */ 234 struct ifaddr * 235 ifa_ifwithnet(addr) 236 struct sockaddr *addr; 237 { 238 register struct ifnet *ifp; 239 register struct ifaddr *ifa; 240 struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 241 u_int af = addr->sa_family; 242 char *addr_data = addr->sa_data, *cplim; 243 244 if (af == AF_LINK) { 245 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 246 if (sdl->sdl_index && sdl->sdl_index <= if_index) 247 return (ifnet_addrs[sdl->sdl_index - 1]); 248 } 249 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 250 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 251 register char *cp, *cp2, *cp3; 252 253 if (ifa->ifa_addr->sa_family != af) 254 next: continue; 255 if (ifp->if_flags & IFF_POINTOPOINT) { 256 if (equal(addr, ifa->ifa_dstaddr)) 257 return (ifa); 258 } else { 259 if (ifa->ifa_netmask == 0) 260 continue; 261 cp = addr_data; 262 cp2 = ifa->ifa_addr->sa_data; 263 cp3 = ifa->ifa_netmask->sa_data; 264 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 265 while (cp3 < cplim) 266 if ((*cp++ ^ *cp2++) & *cp3++) 267 goto next; 268 if (ifa_maybe == 0 || 269 rn_refines((caddr_t)ifa->ifa_netmask, 270 (caddr_t)ifa_maybe->ifa_netmask)) 271 ifa_maybe = ifa; 272 } 273 } 274 } 275 return (ifa_maybe); 276 } 277 278 /* 279 * Find an interface using a specific address family 280 */ 281 struct ifaddr * 282 ifa_ifwithaf(af) 283 register int af; 284 { 285 register struct ifnet *ifp; 286 register struct ifaddr *ifa; 287 288 for (ifp = ifnet; ifp; ifp = ifp->if_next) 289 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 290 if (ifa->ifa_addr->sa_family == af) 291 return (ifa); 292 return ((struct ifaddr *)0); 293 } 294 295 /* 296 * Find an interface address specific to an interface best matching 297 * a given address. 298 */ 299 struct ifaddr * 300 ifaof_ifpforaddr(addr, ifp) 301 struct sockaddr *addr; 302 register struct ifnet *ifp; 303 { 304 register struct ifaddr *ifa; 305 register char *cp, *cp2, *cp3; 306 register char *cplim; 307 struct ifaddr *ifa_maybe = 0; 308 u_int af = addr->sa_family; 309 310 if (af >= AF_MAX) 311 return (0); 312 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 313 if (ifa->ifa_addr->sa_family != af) 314 continue; 315 ifa_maybe = ifa; 316 if (ifa->ifa_netmask == 0) { 317 if (equal(addr, ifa->ifa_addr) || 318 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 319 return (ifa); 320 continue; 321 } 322 if (ifp->if_flags & IFF_POINTOPOINT) { 323 if (equal(addr, ifa->ifa_dstaddr)) 324 return (ifa); 325 } else { 326 cp = addr->sa_data; 327 cp2 = ifa->ifa_addr->sa_data; 328 cp3 = ifa->ifa_netmask->sa_data; 329 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 330 for (; cp3 < cplim; cp3++) 331 if ((*cp++ ^ *cp2++) & *cp3) 332 break; 333 if (cp3 == cplim) 334 return (ifa); 335 } 336 } 337 return (ifa_maybe); 338 } 339 340 #include <net/route.h> 341 342 /* 343 * Default action when installing a route with a Link Level gateway. 344 * Lookup an appropriate real ifa to point to. 345 * This should be moved to /sys/net/link.c eventually. 346 */ 347 void 348 link_rtrequest(cmd, rt, sa) 349 int cmd; 350 register struct rtentry *rt; 351 struct sockaddr *sa; 352 { 353 register struct ifaddr *ifa; 354 struct sockaddr *dst; 355 struct ifnet *ifp; 356 357 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 358 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 359 return; 360 ifa = ifaof_ifpforaddr(dst, ifp); 361 if (ifa) { 362 IFAFREE(rt->rt_ifa); 363 rt->rt_ifa = ifa; 364 ifa->ifa_refcnt++; 365 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 366 ifa->ifa_rtrequest(cmd, rt, sa); 367 } 368 } 369 370 /* 371 * Mark an interface down and notify protocols of 372 * the transition. 373 * NOTE: must be called at splnet or eqivalent. 374 */ 375 void 376 if_down(ifp) 377 register struct ifnet *ifp; 378 { 379 register struct ifaddr *ifa; 380 381 ifp->if_flags &= ~IFF_UP; 382 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 383 pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 384 if_qflush(&ifp->if_snd); 385 rt_ifmsg(ifp); 386 } 387 388 /* 389 * Mark an interface up and notify protocols of 390 * the transition. 391 * NOTE: must be called at splnet or eqivalent. 392 */ 393 void 394 if_up(ifp) 395 register struct ifnet *ifp; 396 { 397 398 ifp->if_flags |= IFF_UP; 399 #ifdef notyet 400 register struct ifaddr *ifa; 401 /* this has no effect on IP, and will kill all iso connections XXX */ 402 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 403 pfctlinput(PRC_IFUP, ifa->ifa_addr); 404 #endif 405 rt_ifmsg(ifp); 406 } 407 408 /* 409 * Flush an interface queue. 410 */ 411 void 412 if_qflush(ifq) 413 register struct ifqueue *ifq; 414 { 415 register struct mbuf *m, *n; 416 417 n = ifq->ifq_head; 418 while ((m = n) != 0) { 419 n = m->m_act; 420 m_freem(m); 421 } 422 ifq->ifq_head = 0; 423 ifq->ifq_tail = 0; 424 ifq->ifq_len = 0; 425 } 426 427 /* 428 * Handle interface watchdog timer routines. Called 429 * from softclock, we decrement timers (if set) and 430 * call the appropriate interface routine on expiration. 431 */ 432 void 433 if_slowtimo(arg) 434 void *arg; 435 { 436 register struct ifnet *ifp; 437 int s = splimp(); 438 439 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 440 if (ifp->if_timer == 0 || --ifp->if_timer) 441 continue; 442 if (ifp->if_watchdog) 443 (*ifp->if_watchdog)(ifp->if_unit); 444 } 445 splx(s); 446 timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 447 } 448 449 /* 450 * Map interface name to 451 * interface structure pointer. 452 */ 453 struct ifnet * 454 ifunit(name) 455 register char *name; 456 { 457 register char *cp; 458 register struct ifnet *ifp; 459 int unit; 460 unsigned len; 461 char *ep, c; 462 463 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 464 if (*cp >= '0' && *cp <= '9') 465 break; 466 if (*cp == '\0' || cp == name + IFNAMSIZ) 467 return ((struct ifnet *)0); 468 /* 469 * Save first char of unit, and pointer to it, 470 * so we can put a null there to avoid matching 471 * initial substrings of interface names. 472 */ 473 len = cp - name + 1; 474 c = *cp; 475 ep = cp; 476 for (unit = 0; *cp >= '0' && *cp <= '9'; ) 477 unit = unit * 10 + *cp++ - '0'; 478 *ep = 0; 479 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 480 if (bcmp(ifp->if_name, name, len)) 481 continue; 482 if (unit == ifp->if_unit) 483 break; 484 } 485 *ep = c; 486 return (ifp); 487 } 488 489 /* 490 * Interface ioctls. 491 */ 492 int 493 ifioctl(so, cmd, data, p) 494 struct socket *so; 495 int cmd; 496 caddr_t data; 497 struct proc *p; 498 { 499 register struct ifnet *ifp; 500 register struct ifreq *ifr; 501 int error; 502 503 switch (cmd) { 504 505 case SIOCGIFCONF: 506 case OSIOCGIFCONF: 507 return (ifconf(cmd, data)); 508 } 509 ifr = (struct ifreq *)data; 510 ifp = ifunit(ifr->ifr_name); 511 if (ifp == 0) 512 return (ENXIO); 513 switch (cmd) { 514 515 case SIOCGIFFLAGS: 516 ifr->ifr_flags = ifp->if_flags; 517 break; 518 519 case SIOCGIFMETRIC: 520 ifr->ifr_metric = ifp->if_metric; 521 break; 522 523 case SIOCGIFMTU: 524 ifr->ifr_mtu = ifp->if_mtu; 525 break; 526 527 case SIOCGIFPHYS: 528 ifr->ifr_phys = ifp->if_physical; 529 break; 530 531 case SIOCSIFFLAGS: 532 error = suser(p->p_ucred, &p->p_acflag); 533 if (error) 534 return (error); 535 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 536 int s = splimp(); 537 if_down(ifp); 538 splx(s); 539 } 540 if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { 541 int s = splimp(); 542 if_up(ifp); 543 splx(s); 544 } 545 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 546 (ifr->ifr_flags &~ IFF_CANTCHANGE); 547 if (ifp->if_ioctl) 548 (void) (*ifp->if_ioctl)(ifp, cmd, data); 549 break; 550 551 case SIOCSIFMETRIC: 552 error = suser(p->p_ucred, &p->p_acflag); 553 if (error) 554 return (error); 555 ifp->if_metric = ifr->ifr_metric; 556 break; 557 558 case SIOCSIFPHYS: 559 error = suser(p->p_ucred, &p->p_acflag); 560 if (error) return error; 561 562 if (!ifp->if_ioctl) return EOPNOTSUPP; 563 return ifp->if_ioctl(ifp, cmd, data); 564 565 case SIOCSIFMTU: 566 error = suser(p->p_ucred, &p->p_acflag); 567 if (error) 568 return (error); 569 if (ifp->if_ioctl == NULL) 570 return (EOPNOTSUPP); 571 /* 572 * 72 was chosen below because it is the size of a TCP/IP 573 * header (40) + the minimum mss (32). 574 */ 575 if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) 576 return (EINVAL); 577 return ((*ifp->if_ioctl)(ifp, cmd, data)); 578 579 case SIOCADDMULTI: 580 case SIOCDELMULTI: 581 error = suser(p->p_ucred, &p->p_acflag); 582 if (error) 583 return (error); 584 if (ifp->if_ioctl == NULL) 585 return (EOPNOTSUPP); 586 return ((*ifp->if_ioctl)(ifp, cmd, data)); 587 588 default: 589 if (so->so_proto == 0) 590 return (EOPNOTSUPP); 591 #ifndef COMPAT_43 592 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 593 cmd, data, ifp)); 594 #else 595 { 596 int ocmd = cmd; 597 598 switch (cmd) { 599 600 case SIOCSIFDSTADDR: 601 case SIOCSIFADDR: 602 case SIOCSIFBRDADDR: 603 case SIOCSIFNETMASK: 604 #if BYTE_ORDER != BIG_ENDIAN 605 if (ifr->ifr_addr.sa_family == 0 && 606 ifr->ifr_addr.sa_len < 16) { 607 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 608 ifr->ifr_addr.sa_len = 16; 609 } 610 #else 611 if (ifr->ifr_addr.sa_len == 0) 612 ifr->ifr_addr.sa_len = 16; 613 #endif 614 break; 615 616 case OSIOCGIFADDR: 617 cmd = SIOCGIFADDR; 618 break; 619 620 case OSIOCGIFDSTADDR: 621 cmd = SIOCGIFDSTADDR; 622 break; 623 624 case OSIOCGIFBRDADDR: 625 cmd = SIOCGIFBRDADDR; 626 break; 627 628 case OSIOCGIFNETMASK: 629 cmd = SIOCGIFNETMASK; 630 } 631 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 632 cmd, data, ifp)); 633 switch (ocmd) { 634 635 case OSIOCGIFADDR: 636 case OSIOCGIFDSTADDR: 637 case OSIOCGIFBRDADDR: 638 case OSIOCGIFNETMASK: 639 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 640 } 641 return (error); 642 643 } 644 #endif 645 } 646 return (0); 647 } 648 649 /* 650 * Set/clear promiscuous mode on interface ifp based on the truth value 651 * of pswitch. The calls are reference counted so that only the first 652 * "on" request actually has an effect, as does the final "off" request. 653 * Results are undefined if the "off" and "on" requests are not matched. 654 */ 655 int 656 ifpromisc(ifp, pswitch) 657 struct ifnet *ifp; 658 int pswitch; 659 { 660 struct ifreq ifr; 661 662 if (pswitch) { 663 /* 664 * If the device is not configured up, we cannot put it in 665 * promiscuous mode. 666 */ 667 if ((ifp->if_flags & IFF_UP) == 0) 668 return (ENETDOWN); 669 if (ifp->if_pcount++ != 0) 670 return (0); 671 ifp->if_flags |= IFF_PROMISC; 672 log(LOG_INFO, "%s%d: promiscuous mode enabled\n", 673 ifp->if_name, ifp->if_unit); 674 } else { 675 if (--ifp->if_pcount > 0) 676 return (0); 677 ifp->if_flags &= ~IFF_PROMISC; 678 } 679 ifr.ifr_flags = ifp->if_flags; 680 return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 681 } 682 683 /* 684 * Return interface configuration 685 * of system. List may be used 686 * in later ioctl's (above) to get 687 * other information. 688 */ 689 /*ARGSUSED*/ 690 int 691 ifconf(cmd, data) 692 int cmd; 693 caddr_t data; 694 { 695 register struct ifconf *ifc = (struct ifconf *)data; 696 register struct ifnet *ifp = ifnet; 697 register struct ifaddr *ifa; 698 struct ifreq ifr, *ifrp; 699 int space = ifc->ifc_len, error = 0; 700 701 ifrp = ifc->ifc_req; 702 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 703 char workbuf[12], *unitname; 704 int unitlen, ifnlen; 705 706 unitname = sprint_d(ifp->if_unit, workbuf, sizeof workbuf); 707 unitlen = strlen(unitname); 708 ifnlen = strlen(ifp->if_name); 709 if(unitlen + ifnlen + 1 > sizeof ifr.ifr_name) { 710 error = ENAMETOOLONG; 711 } else { 712 strcpy(ifr.ifr_name, ifp->if_name); 713 strcpy(&ifr.ifr_name[ifnlen], unitname); 714 } 715 716 if ((ifa = ifp->if_addrlist) == 0) { 717 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 718 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 719 sizeof (ifr)); 720 if (error) 721 break; 722 space -= sizeof (ifr), ifrp++; 723 } else 724 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 725 register struct sockaddr *sa = ifa->ifa_addr; 726 #ifdef COMPAT_43 727 if (cmd == OSIOCGIFCONF) { 728 struct osockaddr *osa = 729 (struct osockaddr *)&ifr.ifr_addr; 730 ifr.ifr_addr = *sa; 731 osa->sa_family = sa->sa_family; 732 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 733 sizeof (ifr)); 734 ifrp++; 735 } else 736 #endif 737 if (sa->sa_len <= sizeof(*sa)) { 738 ifr.ifr_addr = *sa; 739 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 740 sizeof (ifr)); 741 ifrp++; 742 } else { 743 space -= sa->sa_len - sizeof(*sa); 744 if (space < sizeof (ifr)) 745 break; 746 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 747 sizeof (ifr.ifr_name)); 748 if (error == 0) 749 error = copyout((caddr_t)sa, 750 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 751 ifrp = (struct ifreq *) 752 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 753 } 754 if (error) 755 break; 756 space -= sizeof (ifr); 757 } 758 } 759 ifc->ifc_len -= space; 760 return (error); 761 } 762 763 static char * 764 sprint_d(n, buf, buflen) 765 u_int n; 766 char *buf; 767 int buflen; 768 { 769 register char *cp = buf + buflen - 1; 770 771 *cp = 0; 772 do { 773 cp--; 774 *cp = "0123456789"[n % 10]; 775 n /= 10; 776 } while (n != 0); 777 return (cp); 778 } 779