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