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