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