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