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.21 1995/09/27 15:00:49 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(dummy) 77 void *dummy; 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 (struct mbuf *)cmd, (struct mbuf *)data, 594 (struct mbuf *)ifp)); 595 #else 596 { 597 int ocmd = cmd; 598 599 switch (cmd) { 600 601 case SIOCSIFDSTADDR: 602 case SIOCSIFADDR: 603 case SIOCSIFBRDADDR: 604 case SIOCSIFNETMASK: 605 #if BYTE_ORDER != BIG_ENDIAN 606 if (ifr->ifr_addr.sa_family == 0 && 607 ifr->ifr_addr.sa_len < 16) { 608 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 609 ifr->ifr_addr.sa_len = 16; 610 } 611 #else 612 if (ifr->ifr_addr.sa_len == 0) 613 ifr->ifr_addr.sa_len = 16; 614 #endif 615 break; 616 617 case OSIOCGIFADDR: 618 cmd = SIOCGIFADDR; 619 break; 620 621 case OSIOCGIFDSTADDR: 622 cmd = SIOCGIFDSTADDR; 623 break; 624 625 case OSIOCGIFBRDADDR: 626 cmd = SIOCGIFBRDADDR; 627 break; 628 629 case OSIOCGIFNETMASK: 630 cmd = SIOCGIFNETMASK; 631 } 632 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 633 /* 634 * XXX callees reverse the following bogus casts, 635 * but it would be easier to use a separate 636 * interface that is guaranteed to work. 637 */ 638 (struct mbuf *)cmd, (struct mbuf *)data, 639 (struct mbuf *)ifp)); 640 switch (ocmd) { 641 642 case OSIOCGIFADDR: 643 case OSIOCGIFDSTADDR: 644 case OSIOCGIFBRDADDR: 645 case OSIOCGIFNETMASK: 646 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 647 } 648 return (error); 649 650 } 651 #endif 652 } 653 return (0); 654 } 655 656 /* 657 * Set/clear promiscuous mode on interface ifp based on the truth value 658 * of pswitch. The calls are reference counted so that only the first 659 * "on" request actually has an effect, as does the final "off" request. 660 * Results are undefined if the "off" and "on" requests are not matched. 661 */ 662 int 663 ifpromisc(ifp, pswitch) 664 struct ifnet *ifp; 665 int pswitch; 666 { 667 struct ifreq ifr; 668 669 if (pswitch) { 670 /* 671 * If the device is not configured up, we cannot put it in 672 * promiscuous mode. 673 */ 674 if ((ifp->if_flags & IFF_UP) == 0) 675 return (ENETDOWN); 676 if (ifp->if_pcount++ != 0) 677 return (0); 678 ifp->if_flags |= IFF_PROMISC; 679 log(LOG_INFO, "%s%d: promiscuous mode enabled\n", 680 ifp->if_name, ifp->if_unit); 681 } else { 682 if (--ifp->if_pcount > 0) 683 return (0); 684 ifp->if_flags &= ~IFF_PROMISC; 685 } 686 ifr.ifr_flags = ifp->if_flags; 687 return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 688 } 689 690 /* 691 * Return interface configuration 692 * of system. List may be used 693 * in later ioctl's (above) to get 694 * other information. 695 */ 696 /*ARGSUSED*/ 697 int 698 ifconf(cmd, data) 699 int cmd; 700 caddr_t data; 701 { 702 register struct ifconf *ifc = (struct ifconf *)data; 703 register struct ifnet *ifp = ifnet; 704 register struct ifaddr *ifa; 705 struct ifreq ifr, *ifrp; 706 int space = ifc->ifc_len, error = 0; 707 708 ifrp = ifc->ifc_req; 709 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 710 char workbuf[12], *unitname; 711 int unitlen, ifnlen; 712 713 unitname = sprint_d(ifp->if_unit, workbuf, sizeof workbuf); 714 unitlen = strlen(unitname); 715 ifnlen = strlen(ifp->if_name); 716 if(unitlen + ifnlen + 1 > sizeof ifr.ifr_name) { 717 error = ENAMETOOLONG; 718 } else { 719 strcpy(ifr.ifr_name, ifp->if_name); 720 strcpy(&ifr.ifr_name[ifnlen], unitname); 721 } 722 723 if ((ifa = ifp->if_addrlist) == 0) { 724 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 725 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 726 sizeof (ifr)); 727 if (error) 728 break; 729 space -= sizeof (ifr), ifrp++; 730 } else 731 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 732 register struct sockaddr *sa = ifa->ifa_addr; 733 #ifdef COMPAT_43 734 if (cmd == OSIOCGIFCONF) { 735 struct osockaddr *osa = 736 (struct osockaddr *)&ifr.ifr_addr; 737 ifr.ifr_addr = *sa; 738 osa->sa_family = sa->sa_family; 739 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 740 sizeof (ifr)); 741 ifrp++; 742 } else 743 #endif 744 if (sa->sa_len <= sizeof(*sa)) { 745 ifr.ifr_addr = *sa; 746 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 747 sizeof (ifr)); 748 ifrp++; 749 } else { 750 space -= sa->sa_len - sizeof(*sa); 751 if (space < sizeof (ifr)) 752 break; 753 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 754 sizeof (ifr.ifr_name)); 755 if (error == 0) 756 error = copyout((caddr_t)sa, 757 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 758 ifrp = (struct ifreq *) 759 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 760 } 761 if (error) 762 break; 763 space -= sizeof (ifr); 764 } 765 } 766 ifc->ifc_len -= space; 767 return (error); 768 } 769 770 static char * 771 sprint_d(n, buf, buflen) 772 u_int n; 773 char *buf; 774 int buflen; 775 { 776 register char *cp = buf + buflen - 1; 777 778 *cp = 0; 779 do { 780 cp--; 781 *cp = "0123456789"[n % 10]; 782 n /= 10; 783 } while (n != 0); 784 return (cp); 785 } 786