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