1 /* $NetBSD: if.c,v 1.19 1995/03/09 09:47:25 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)if.c 8.3 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.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 48 #include <net/if.h> 49 #include <net/if_dl.h> 50 #include <net/if_types.h> 51 52 int ifqmaxlen = IFQ_MAXLEN; 53 void if_slowtimo __P((void *arg)); 54 55 /* 56 * Network interface utility routines. 57 * 58 * Routines with ifa_ifwith* names take sockaddr *'s as 59 * parameters. 60 */ 61 void 62 ifinit() 63 { 64 register struct ifnet *ifp; 65 66 for (ifp = ifnet; ifp; ifp = ifp->if_next) 67 if (ifp->if_snd.ifq_maxlen == 0) 68 ifp->if_snd.ifq_maxlen = ifqmaxlen; 69 if_slowtimo(NULL); 70 } 71 72 int if_index = 0; 73 struct ifaddr **ifnet_addrs; 74 static char *sprint_d __P((u_int, char *, int)); 75 76 /* 77 * Attach an interface to the 78 * list of "active" interfaces. 79 */ 80 void 81 if_attach(ifp) 82 struct ifnet *ifp; 83 { 84 unsigned socksize, ifasize; 85 int namelen, unitlen, masklen; 86 char workbuf[12], *unitname; 87 register struct ifnet **p = &ifnet; 88 register struct sockaddr_dl *sdl; 89 register struct ifaddr *ifa; 90 static int if_indexlim = 8; 91 extern void link_rtrequest(); 92 93 while (*p) 94 p = &((*p)->if_next); 95 *p = ifp; 96 ifp->if_index = ++if_index; 97 if (ifnet_addrs == 0 || if_index >= if_indexlim) { 98 unsigned n = (if_indexlim <<= 1) * sizeof(ifa); 99 struct ifaddr **q = (struct ifaddr **) 100 malloc(n, M_IFADDR, M_WAITOK); 101 if (ifnet_addrs) { 102 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); 103 free((caddr_t)ifnet_addrs, M_IFADDR); 104 } 105 ifnet_addrs = q; 106 } 107 /* 108 * create a Link Level name for this device 109 */ 110 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf)); 111 namelen = strlen(ifp->if_name); 112 unitlen = strlen(unitname); 113 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 114 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + 115 unitlen + namelen; 116 socksize = masklen + ifp->if_addrlen; 117 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 118 socksize = ROUNDUP(socksize); 119 if (socksize < sizeof(*sdl)) 120 socksize = sizeof(*sdl); 121 ifasize = sizeof(*ifa) + 2 * socksize; 122 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); 123 if (ifa == 0) 124 return; 125 bzero((caddr_t)ifa, ifasize); 126 sdl = (struct sockaddr_dl *)(ifa + 1); 127 sdl->sdl_len = socksize; 128 sdl->sdl_family = AF_LINK; 129 bcopy(ifp->if_name, sdl->sdl_data, namelen); 130 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen); 131 sdl->sdl_nlen = (namelen += unitlen); 132 sdl->sdl_index = ifp->if_index; 133 sdl->sdl_type = ifp->if_type; 134 ifnet_addrs[if_index - 1] = ifa; 135 ifa->ifa_ifp = ifp; 136 ifa->ifa_next = ifp->if_addrlist; 137 ifa->ifa_rtrequest = link_rtrequest; 138 ifp->if_addrlist = ifa; 139 ifa->ifa_addr = (struct sockaddr *)sdl; 140 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 141 ifa->ifa_netmask = (struct sockaddr *)sdl; 142 sdl->sdl_len = masklen; 143 while (namelen != 0) 144 sdl->sdl_data[--namelen] = 0xff; 145 } 146 /* 147 * Locate an interface based on a complete address. 148 */ 149 /*ARGSUSED*/ 150 struct ifaddr * 151 ifa_ifwithaddr(addr) 152 register struct sockaddr *addr; 153 { 154 register struct ifnet *ifp; 155 register struct ifaddr *ifa; 156 157 #define equal(a1, a2) \ 158 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 159 for (ifp = ifnet; ifp; ifp = ifp->if_next) 160 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 161 if (ifa->ifa_addr->sa_family != addr->sa_family) 162 continue; 163 if (equal(addr, ifa->ifa_addr)) 164 return (ifa); 165 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && 166 equal(ifa->ifa_broadaddr, addr)) 167 return (ifa); 168 } 169 return ((struct ifaddr *)0); 170 } 171 /* 172 * Locate the point to point interface with a given destination address. 173 */ 174 /*ARGSUSED*/ 175 struct ifaddr * 176 ifa_ifwithdstaddr(addr) 177 register struct sockaddr *addr; 178 { 179 register struct ifnet *ifp; 180 register struct ifaddr *ifa; 181 182 for (ifp = ifnet; ifp; ifp = ifp->if_next) 183 if (ifp->if_flags & IFF_POINTOPOINT) 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_dstaddr)) 188 return (ifa); 189 } 190 return ((struct ifaddr *)0); 191 } 192 193 /* 194 * Find an interface on a specific network. If many, choice 195 * is most specific found. 196 */ 197 struct ifaddr * 198 ifa_ifwithnet(addr) 199 struct sockaddr *addr; 200 { 201 register struct ifnet *ifp; 202 register struct ifaddr *ifa; 203 struct ifaddr *ifa_maybe = 0; 204 u_int af = addr->sa_family; 205 char *addr_data = addr->sa_data, *cplim; 206 207 if (af == AF_LINK) { 208 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 209 if (sdl->sdl_index && sdl->sdl_index <= if_index) 210 return (ifnet_addrs[sdl->sdl_index - 1]); 211 } 212 for (ifp = ifnet; ifp; ifp = ifp->if_next) 213 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 214 register char *cp, *cp2, *cp3; 215 216 if (ifa->ifa_addr->sa_family != af || 217 ifa->ifa_netmask == 0) 218 next: continue; 219 cp = addr_data; 220 cp2 = ifa->ifa_addr->sa_data; 221 cp3 = ifa->ifa_netmask->sa_data; 222 cplim = (char *)ifa->ifa_netmask + 223 ifa->ifa_netmask->sa_len; 224 while (cp3 < cplim) 225 if ((*cp++ ^ *cp2++) & *cp3++) 226 goto next; 227 if (ifa_maybe == 0 || 228 rn_refines((caddr_t)ifa->ifa_netmask, 229 (caddr_t)ifa_maybe->ifa_netmask)) 230 ifa_maybe = ifa; 231 } 232 return (ifa_maybe); 233 } 234 235 /* 236 * Find an interface using a specific address family 237 */ 238 struct ifaddr * 239 ifa_ifwithaf(af) 240 register int af; 241 { 242 register struct ifnet *ifp; 243 register struct ifaddr *ifa; 244 245 for (ifp = ifnet; ifp; ifp = ifp->if_next) 246 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 247 if (ifa->ifa_addr->sa_family == af) 248 return (ifa); 249 return ((struct ifaddr *)0); 250 } 251 252 /* 253 * Find an interface address specific to an interface best matching 254 * a given address. 255 */ 256 struct ifaddr * 257 ifaof_ifpforaddr(addr, ifp) 258 struct sockaddr *addr; 259 register struct ifnet *ifp; 260 { 261 register struct ifaddr *ifa; 262 register char *cp, *cp2, *cp3; 263 register char *cplim; 264 struct ifaddr *ifa_maybe = 0; 265 u_int af = addr->sa_family; 266 267 if (af >= AF_MAX) 268 return (0); 269 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 270 if (ifa->ifa_addr->sa_family != af) 271 continue; 272 ifa_maybe = ifa; 273 if (ifa->ifa_netmask == 0) { 274 if (equal(addr, ifa->ifa_addr) || 275 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 276 return (ifa); 277 continue; 278 } 279 cp = addr->sa_data; 280 cp2 = ifa->ifa_addr->sa_data; 281 cp3 = ifa->ifa_netmask->sa_data; 282 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 283 for (; cp3 < cplim; cp3++) 284 if ((*cp++ ^ *cp2++) & *cp3) 285 break; 286 if (cp3 == cplim) 287 return (ifa); 288 } 289 return (ifa_maybe); 290 } 291 292 #include <net/route.h> 293 294 /* 295 * Default action when installing a route with a Link Level gateway. 296 * Lookup an appropriate real ifa to point to. 297 * This should be moved to /sys/net/link.c eventually. 298 */ 299 void 300 link_rtrequest(cmd, rt, sa) 301 int cmd; 302 register struct rtentry *rt; 303 struct sockaddr *sa; 304 { 305 register struct ifaddr *ifa; 306 struct sockaddr *dst; 307 struct ifnet *ifp; 308 309 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 310 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 311 return; 312 if (ifa = ifaof_ifpforaddr(dst, ifp)) { 313 IFAFREE(rt->rt_ifa); 314 rt->rt_ifa = ifa; 315 ifa->ifa_refcnt++; 316 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 317 ifa->ifa_rtrequest(cmd, rt, sa); 318 } 319 } 320 321 /* 322 * Mark an interface down and notify protocols of 323 * the transition. 324 * NOTE: must be called at splnet or eqivalent. 325 */ 326 void 327 if_down(ifp) 328 register struct ifnet *ifp; 329 { 330 register struct ifaddr *ifa; 331 332 ifp->if_flags &= ~IFF_UP; 333 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 334 pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 335 if_qflush(&ifp->if_snd); 336 rt_ifmsg(ifp); 337 } 338 339 /* 340 * Mark an interface up and notify protocols of 341 * the transition. 342 * NOTE: must be called at splnet or equivalent. 343 */ 344 void 345 if_up(ifp) 346 register struct ifnet *ifp; 347 { 348 register struct ifaddr *ifa; 349 350 ifp->if_flags |= IFF_UP; 351 #ifdef notyet 352 /* this has no effect on IP, and will kill all ISO connections XXX */ 353 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 354 pfctlinput(PRC_IFUP, ifa->ifa_addr); 355 #endif 356 rt_ifmsg(ifp); 357 } 358 359 /* 360 * Flush an interface queue. 361 */ 362 void 363 if_qflush(ifq) 364 register struct ifqueue *ifq; 365 { 366 register struct mbuf *m, *n; 367 368 n = ifq->ifq_head; 369 while (m = n) { 370 n = m->m_act; 371 m_freem(m); 372 } 373 ifq->ifq_head = 0; 374 ifq->ifq_tail = 0; 375 ifq->ifq_len = 0; 376 } 377 378 /* 379 * Handle interface watchdog timer routines. Called 380 * from softclock, we decrement timers (if set) and 381 * call the appropriate interface routine on expiration. 382 */ 383 void 384 if_slowtimo(arg) 385 void *arg; 386 { 387 register struct ifnet *ifp; 388 int s = splimp(); 389 390 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 391 if (ifp->if_timer == 0 || --ifp->if_timer) 392 continue; 393 if (ifp->if_watchdog) 394 (*ifp->if_watchdog)(ifp->if_unit); 395 } 396 splx(s); 397 timeout(if_slowtimo, NULL, hz / IFNET_SLOWHZ); 398 } 399 400 /* 401 * Map interface name to 402 * interface structure pointer. 403 */ 404 struct ifnet * 405 ifunit(name) 406 register char *name; 407 { 408 register char *cp; 409 register struct ifnet *ifp; 410 int unit; 411 unsigned len; 412 char *ep, c; 413 414 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 415 if (*cp >= '0' && *cp <= '9') 416 break; 417 if (*cp == '\0' || cp == name + IFNAMSIZ) 418 return ((struct ifnet *)0); 419 /* 420 * Save first char of unit, and pointer to it, 421 * so we can put a null there to avoid matching 422 * initial substrings of interface names. 423 */ 424 len = cp - name + 1; 425 c = *cp; 426 ep = cp; 427 for (unit = 0; *cp >= '0' && *cp <= '9'; ) 428 unit = unit * 10 + *cp++ - '0'; 429 *ep = 0; 430 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 431 if (bcmp(ifp->if_name, name, len)) 432 continue; 433 if (unit == ifp->if_unit) 434 break; 435 } 436 *ep = c; 437 return (ifp); 438 } 439 440 /* 441 * Interface ioctls. 442 */ 443 int 444 ifioctl(so, cmd, data, p) 445 struct socket *so; 446 u_long cmd; 447 caddr_t data; 448 struct proc *p; 449 { 450 register struct ifnet *ifp; 451 register struct ifreq *ifr; 452 int error; 453 454 switch (cmd) { 455 456 case SIOCGIFCONF: 457 case OSIOCGIFCONF: 458 return (ifconf(cmd, data)); 459 } 460 ifr = (struct ifreq *)data; 461 ifp = ifunit(ifr->ifr_name); 462 if (ifp == 0) 463 return (ENXIO); 464 switch (cmd) { 465 466 case SIOCGIFFLAGS: 467 ifr->ifr_flags = ifp->if_flags; 468 break; 469 470 case SIOCGIFMETRIC: 471 ifr->ifr_metric = ifp->if_metric; 472 break; 473 474 case SIOCSIFFLAGS: 475 if (error = suser(p->p_ucred, &p->p_acflag)) 476 return (error); 477 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 478 int s = splimp(); 479 if_down(ifp); 480 splx(s); 481 } 482 if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { 483 int s = splimp(); 484 if_up(ifp); 485 splx(s); 486 } 487 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 488 (ifr->ifr_flags &~ IFF_CANTCHANGE); 489 if (ifp->if_ioctl) 490 (void) (*ifp->if_ioctl)(ifp, cmd, data); 491 break; 492 493 case SIOCSIFMETRIC: 494 if (error = suser(p->p_ucred, &p->p_acflag)) 495 return (error); 496 ifp->if_metric = ifr->ifr_metric; 497 break; 498 499 case SIOCADDMULTI: 500 case SIOCDELMULTI: 501 if (error = suser(p->p_ucred, &p->p_acflag)) 502 return (error); 503 if (ifp->if_ioctl == 0) 504 return (EOPNOTSUPP); 505 return ((*ifp->if_ioctl)(ifp, cmd, data)); 506 507 default: 508 if (so->so_proto == 0) 509 return (EOPNOTSUPP); 510 #ifndef COMPAT_43 511 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 512 cmd, data, ifp)); 513 #else 514 { 515 int ocmd = cmd; 516 517 switch (cmd) { 518 519 case SIOCSIFDSTADDR: 520 case SIOCSIFADDR: 521 case SIOCSIFBRDADDR: 522 case SIOCSIFNETMASK: 523 #if BYTE_ORDER != BIG_ENDIAN 524 if (ifr->ifr_addr.sa_family == 0 && 525 ifr->ifr_addr.sa_len < 16) { 526 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 527 ifr->ifr_addr.sa_len = 16; 528 } 529 #else 530 if (ifr->ifr_addr.sa_len == 0) 531 ifr->ifr_addr.sa_len = 16; 532 #endif 533 break; 534 535 case OSIOCGIFADDR: 536 cmd = SIOCGIFADDR; 537 break; 538 539 case OSIOCGIFDSTADDR: 540 cmd = SIOCGIFDSTADDR; 541 break; 542 543 case OSIOCGIFBRDADDR: 544 cmd = SIOCGIFBRDADDR; 545 break; 546 547 case OSIOCGIFNETMASK: 548 cmd = SIOCGIFNETMASK; 549 } 550 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 551 cmd, data, ifp)); 552 switch (ocmd) { 553 554 case OSIOCGIFADDR: 555 case OSIOCGIFDSTADDR: 556 case OSIOCGIFBRDADDR: 557 case OSIOCGIFNETMASK: 558 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 559 } 560 return (error); 561 562 } 563 #endif 564 } 565 return (0); 566 } 567 568 /* 569 * Return interface configuration 570 * of system. List may be used 571 * in later ioctl's (above) to get 572 * other information. 573 */ 574 /*ARGSUSED*/ 575 int 576 ifconf(cmd, data) 577 u_long cmd; 578 caddr_t data; 579 { 580 register struct ifconf *ifc = (struct ifconf *)data; 581 register struct ifnet *ifp = ifnet; 582 register struct ifaddr *ifa; 583 register char *cp, *ep; 584 struct ifreq ifr, *ifrp; 585 int space = ifc->ifc_len, error = 0; 586 587 ifrp = ifc->ifc_req; 588 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 589 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 590 strncpy(ifr.ifr_name, ifp->if_name, sizeof(ifr.ifr_name) - 2); 591 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 592 continue; 593 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 594 if ((ifa = ifp->if_addrlist) == 0) { 595 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 596 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 597 sizeof(ifr)); 598 if (error) 599 break; 600 space -= sizeof (ifr), ifrp++; 601 } else 602 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 603 register struct sockaddr *sa = ifa->ifa_addr; 604 #ifdef COMPAT_43 605 if (cmd == OSIOCGIFCONF) { 606 struct osockaddr *osa = 607 (struct osockaddr *)&ifr.ifr_addr; 608 ifr.ifr_addr = *sa; 609 osa->sa_family = sa->sa_family; 610 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 611 sizeof (ifr)); 612 ifrp++; 613 } else 614 #endif 615 if (sa->sa_len <= sizeof(*sa)) { 616 ifr.ifr_addr = *sa; 617 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 618 sizeof (ifr)); 619 ifrp++; 620 } else { 621 space -= sa->sa_len - sizeof(*sa); 622 if (space < sizeof (ifr)) 623 break; 624 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 625 sizeof (ifr.ifr_name)); 626 if (error == 0) 627 error = copyout((caddr_t)sa, 628 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 629 ifrp = (struct ifreq *) 630 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 631 } 632 if (error) 633 break; 634 space -= sizeof (ifr); 635 } 636 } 637 ifc->ifc_len -= space; 638 return (error); 639 } 640 641 static char * 642 sprint_d(n, buf, buflen) 643 u_int n; 644 char *buf; 645 int buflen; 646 { 647 register char *cp = buf + buflen - 1; 648 649 *cp = 0; 650 do { 651 cp--; 652 *cp = "0123456789"[n % 10]; 653 n /= 10; 654 } while (n != 0); 655 return (cp); 656 } 657