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