1 /* 2 * Copyright (c) 1980, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)if.c 7.11 (Berkeley) 05/14/90 18 */ 19 20 #include "param.h" 21 #include "mbuf.h" 22 #include "systm.h" 23 #include "socket.h" 24 #include "socketvar.h" 25 #include "protosw.h" 26 #include "user.h" 27 #include "kernel.h" 28 #include "ioctl.h" 29 #include "errno.h" 30 31 #include "if.h" 32 #include "af.h" 33 #include "if_dl.h" 34 35 #include "ether.h" 36 37 int ifqmaxlen = IFQ_MAXLEN; 38 39 /* 40 * Network interface utility routines. 41 * 42 * Routines with ifa_ifwith* names take sockaddr *'s as 43 * parameters. 44 */ 45 46 ifinit() 47 { 48 register struct ifnet *ifp; 49 50 for (ifp = ifnet; ifp; ifp = ifp->if_next) 51 if (ifp->if_snd.ifq_maxlen == 0) 52 ifp->if_snd.ifq_maxlen = ifqmaxlen; 53 if_slowtimo(); 54 } 55 56 #ifdef vax 57 /* 58 * Call each interface on a Unibus reset. 59 */ 60 ifubareset(uban) 61 int uban; 62 { 63 register struct ifnet *ifp; 64 65 for (ifp = ifnet; ifp; ifp = ifp->if_next) 66 if (ifp->if_reset) 67 (*ifp->if_reset)(ifp->if_unit, uban); 68 } 69 #endif 70 71 int if_index = 0; 72 /* 73 * Attach an interface to the 74 * list of "active" interfaces. 75 */ 76 if_attach(ifp) 77 struct ifnet *ifp; 78 { 79 register struct ifnet **p = &ifnet; 80 unsigned socksize, ifasize; 81 int namelen, unitlen; 82 char workbuf[16]; 83 register struct sockaddr_dl *sdl; 84 register struct ifaddr *ifa; 85 extern link_rtrequest(); 86 87 while (*p) 88 p = &((*p)->if_next); 89 *p = ifp; 90 ifp->if_index = ++if_index; 91 /* 92 * create a Link Level name for this device 93 */ 94 sprint_d(workbuf, ifp->if_unit); 95 namelen = strlen(ifp->if_name); 96 unitlen = strlen(workbuf); 97 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 98 socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) + 99 unitlen + namelen + ifp->if_addrlen; 100 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 101 socksize = ROUNDUP(socksize); 102 ifasize = sizeof(*ifa) + 2 * socksize; 103 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); 104 if (ifa == 0) 105 return; 106 bzero((caddr_t)ifa, ifasize); 107 sdl = (struct sockaddr_dl *)(ifa + 1); 108 ifa->ifa_addr = (struct sockaddr *)sdl; 109 ifa->ifa_ifp = ifp; 110 sdl->sdl_len = socksize; 111 sdl->sdl_family = AF_LINK; 112 bcopy(ifp->if_name, sdl->sdl_data, namelen); 113 bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen); 114 sdl->sdl_nlen = (namelen += unitlen); 115 sdl->sdl_index = ifp->if_index; 116 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 117 ifa->ifa_netmask = (struct sockaddr *)sdl; 118 sdl->sdl_len = socksize - ifp->if_addrlen; 119 while (namelen != 0) 120 sdl->sdl_data[--namelen] = 0xff; 121 ifa->ifa_next = ifp->if_addrlist; 122 ifa->ifa_rtrequest = link_rtrequest; 123 ifp->if_addrlist = ifa; 124 } 125 /* 126 * Locate an interface based on a complete address. 127 */ 128 /*ARGSUSED*/ 129 struct ifaddr * 130 ifa_ifwithaddr(addr) 131 register struct sockaddr *addr; 132 { 133 register struct ifnet *ifp; 134 register struct ifaddr *ifa; 135 136 #define equal(a1, a2) \ 137 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 138 for (ifp = ifnet; ifp; ifp = ifp->if_next) 139 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 140 if (ifa->ifa_addr->sa_family != addr->sa_family) 141 continue; 142 if (equal(addr, ifa->ifa_addr)) 143 return (ifa); 144 if ((ifp->if_flags & IFF_BROADCAST) && 145 equal(&ifa->ifa_broadaddr, addr)) 146 return (ifa); 147 } 148 return ((struct ifaddr *)0); 149 } 150 /* 151 * Locate the point to point interface with a given destination address. 152 */ 153 /*ARGSUSED*/ 154 struct ifaddr * 155 ifa_ifwithdstaddr(addr) 156 register struct sockaddr *addr; 157 { 158 register struct ifnet *ifp; 159 register struct ifaddr *ifa; 160 161 for (ifp = ifnet; ifp; ifp = ifp->if_next) 162 if (ifp->if_flags & IFF_POINTOPOINT) 163 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 164 if (ifa->ifa_addr->sa_family != addr->sa_family) 165 continue; 166 if (equal(addr, ifa->ifa_dstaddr)) 167 return (ifa); 168 } 169 return ((struct ifaddr *)0); 170 } 171 172 /* 173 * Find an interface on a specific network. If many, choice 174 * is first found. 175 */ 176 struct ifaddr * 177 ifa_ifwithnet(addr) 178 struct sockaddr *addr; 179 { 180 register struct ifnet *ifp; 181 register struct ifaddr *ifa; 182 register char *cp, *cp2, *cp3; 183 register char *cplim; 184 u_int af = addr->sa_family; 185 186 if (af >= AF_MAX) 187 return (0); 188 for (ifp = ifnet; ifp; ifp = ifp->if_next) 189 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 190 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0) 191 continue; 192 cp = addr->sa_data; 193 cp2 = ifa->ifa_addr->sa_data; 194 cp3 = ifa->ifa_netmask->sa_data; 195 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 196 for (; cp3 < cplim; cp3++) 197 if ((*cp++ ^ *cp2++) & *cp3) 198 break; 199 if (cp3 == cplim) 200 return (ifa); 201 } 202 return ((struct ifaddr *)0); 203 } 204 205 /* 206 * Find an interface using a specific address family 207 */ 208 struct ifaddr * 209 ifa_ifwithaf(af) 210 register int af; 211 { 212 register struct ifnet *ifp; 213 register struct ifaddr *ifa; 214 215 for (ifp = ifnet; ifp; ifp = ifp->if_next) 216 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 217 if (ifa->ifa_addr->sa_family == af) 218 return (ifa); 219 return ((struct ifaddr *)0); 220 } 221 222 #include "route.h" 223 /* 224 * Default action when installing a route with a Link Level gateway. 225 * Lookup an appropriate real ifa to point to. 226 * This should be moved to /sys/net/link.c eventually. 227 */ 228 link_rtrequest(cmd, rt, sa) 229 register struct rtentry *rt; 230 struct sockaddr *sa; 231 { 232 register struct ifaddr *ifa; 233 struct sockaddr *dst; 234 struct ifnet *ifp, *oldifnet = ifnet; 235 236 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 237 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 238 return; 239 ifnet = ifp; 240 if (((ifa = ifa_ifwithnet(dst)) && ifa->ifa_ifp == ifp) || 241 ((ifa = ifa_ifwithaf(dst->sa_family)) && ifa->ifa_ifp == ifp)) { 242 ifnet = oldifnet; 243 rt->rt_ifa = ifa; 244 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 245 ifa->ifa_rtrequest(cmd, rt, sa); 246 } else 247 ifnet = oldifnet; 248 } 249 250 /* 251 * Mark an interface down and notify protocols of 252 * the transition. 253 * NOTE: must be called at splnet or eqivalent. 254 */ 255 if_down(ifp) 256 register struct ifnet *ifp; 257 { 258 register struct ifaddr *ifa; 259 260 ifp->if_flags &= ~IFF_UP; 261 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 262 pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 263 if_qflush(&ifp->if_snd); 264 } 265 266 /* 267 * Flush an interface queue. 268 */ 269 if_qflush(ifq) 270 register struct ifqueue *ifq; 271 { 272 register struct mbuf *m, *n; 273 274 n = ifq->ifq_head; 275 while (m = n) { 276 n = m->m_act; 277 m_freem(m); 278 } 279 ifq->ifq_head = 0; 280 ifq->ifq_tail = 0; 281 ifq->ifq_len = 0; 282 } 283 284 /* 285 * Handle interface watchdog timer routines. Called 286 * from softclock, we decrement timers (if set) and 287 * call the appropriate interface routine on expiration. 288 */ 289 if_slowtimo() 290 { 291 register struct ifnet *ifp; 292 int s = splimp(); 293 294 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 295 if (ifp->if_timer == 0 || --ifp->if_timer) 296 continue; 297 if (ifp->if_watchdog) 298 (*ifp->if_watchdog)(ifp->if_unit); 299 } 300 splx(s); 301 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 302 } 303 304 /* 305 * Map interface name to 306 * interface structure pointer. 307 */ 308 struct ifnet * 309 ifunit(name) 310 register char *name; 311 { 312 register char *cp; 313 register struct ifnet *ifp; 314 int unit; 315 unsigned len; 316 char *ep, c; 317 318 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 319 if (*cp >= '0' && *cp <= '9') 320 break; 321 if (*cp == '\0' || cp == name + IFNAMSIZ) 322 return ((struct ifnet *)0); 323 /* 324 * Save first char of unit, and pointer to it, 325 * so we can put a null there to avoid matching 326 * initial substrings of interface names. 327 */ 328 len = cp - name + 1; 329 c = *cp; 330 ep = cp; 331 for (unit = 0; *cp >= '0' && *cp <= '9'; ) 332 unit = unit * 10 + *cp++ - '0'; 333 *ep = 0; 334 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 335 if (bcmp(ifp->if_name, name, len)) 336 continue; 337 if (unit == ifp->if_unit) 338 break; 339 } 340 *ep = c; 341 return (ifp); 342 } 343 344 /* 345 * Interface ioctls. 346 */ 347 ifioctl(so, cmd, data) 348 struct socket *so; 349 int cmd; 350 caddr_t data; 351 { 352 register struct ifnet *ifp; 353 register struct ifreq *ifr; 354 int error; 355 356 switch (cmd) { 357 358 case SIOCGIFCONF: 359 case OSIOCGIFCONF: 360 return (ifconf(cmd, data)); 361 362 #if defined(INET) && NETHER > 0 363 case SIOCSARP: 364 case SIOCDARP: 365 if (error = suser(u.u_cred, &u.u_acflag)) 366 return (error); 367 /* FALL THROUGH */ 368 case SIOCGARP: 369 case OSIOCGARP: 370 return (arpioctl(cmd, data)); 371 #endif 372 } 373 ifr = (struct ifreq *)data; 374 ifp = ifunit(ifr->ifr_name); 375 if (ifp == 0) 376 return (ENXIO); 377 switch (cmd) { 378 379 case SIOCGIFFLAGS: 380 ifr->ifr_flags = ifp->if_flags; 381 break; 382 383 case SIOCGIFMETRIC: 384 ifr->ifr_metric = ifp->if_metric; 385 break; 386 387 case SIOCSIFFLAGS: 388 if (error = suser(u.u_cred, &u.u_acflag)) 389 return (error); 390 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 391 int s = splimp(); 392 if_down(ifp); 393 splx(s); 394 } 395 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 396 (ifr->ifr_flags &~ IFF_CANTCHANGE); 397 if (ifp->if_ioctl) 398 (void) (*ifp->if_ioctl)(ifp, cmd, data); 399 break; 400 401 case SIOCSIFMETRIC: 402 if (error = suser(u.u_cred, &u.u_acflag)) 403 return (error); 404 ifp->if_metric = ifr->ifr_metric; 405 break; 406 407 default: 408 if (so->so_proto == 0) 409 return (EOPNOTSUPP); 410 #ifndef COMPAT_43 411 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 412 cmd, data, ifp)); 413 #else 414 { 415 int ocmd = cmd; 416 417 switch (cmd) { 418 419 case SIOCSIFDSTADDR: 420 case SIOCSIFADDR: 421 case SIOCSIFBRDADDR: 422 case SIOCSIFNETMASK: 423 #if BYTE_ORDER != BIG_ENDIAN 424 if (ifr->ifr_addr.sa_family == 0 && 425 ifr->ifr_addr.sa_len < 16) { 426 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 427 ifr->ifr_addr.sa_len = 16; 428 } 429 #else 430 if (ifr->ifr_addr.sa_len == 0) 431 ifr->ifr_addr.sa_len = 16; 432 #endif 433 break; 434 435 case OSIOCGIFADDR: 436 cmd = SIOCGIFADDR; 437 break; 438 439 case OSIOCGIFDSTADDR: 440 cmd = SIOCGIFDSTADDR; 441 break; 442 443 case OSIOCGIFBRDADDR: 444 cmd = SIOCGIFBRDADDR; 445 break; 446 447 case OSIOCGIFNETMASK: 448 cmd = SIOCGIFNETMASK; 449 } 450 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 451 cmd, data, ifp)); 452 switch (ocmd) { 453 454 case OSIOCGIFADDR: 455 case OSIOCGIFDSTADDR: 456 case OSIOCGIFBRDADDR: 457 case OSIOCGIFNETMASK: 458 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 459 } 460 return (error); 461 462 } 463 #endif 464 } 465 return (0); 466 } 467 468 /* 469 * Return interface configuration 470 * of system. List may be used 471 * in later ioctl's (above) to get 472 * other information. 473 */ 474 /*ARGSUSED*/ 475 ifconf(cmd, data) 476 int cmd; 477 caddr_t data; 478 { 479 register struct ifconf *ifc = (struct ifconf *)data; 480 register struct ifnet *ifp = ifnet; 481 register struct ifaddr *ifa; 482 register char *cp, *ep; 483 struct ifreq ifr, *ifrp; 484 int space = ifc->ifc_len, error = 0; 485 486 ifrp = ifc->ifc_req; 487 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 488 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 489 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 490 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 491 ; 492 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 493 if ((ifa = ifp->if_addrlist) == 0) { 494 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 495 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 496 if (error) 497 break; 498 space -= sizeof (ifr), ifrp++; 499 } else 500 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 501 register struct sockaddr *sa = ifa->ifa_addr; 502 #ifdef COMPAT_43 503 if (cmd == OSIOCGIFCONF) { 504 struct osockaddr *osa = 505 (struct osockaddr *)&ifr.ifr_addr; 506 ifr.ifr_addr = *sa; 507 osa->sa_family = sa->sa_family; 508 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 509 sizeof (ifr)); 510 ifrp++; 511 } else 512 #endif 513 if (sa->sa_len <= sizeof(*sa)) { 514 ifr.ifr_addr = *sa; 515 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 516 sizeof (ifr)); 517 ifrp++; 518 } else { 519 space -= sa->sa_len - sizeof(*sa); 520 if (space < sizeof (ifr)) 521 break; 522 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 523 sizeof (ifr.ifr_name)); 524 if (error == 0) 525 error = copyout((caddr_t)sa, 526 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 527 ifrp = (struct ifreq *) 528 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 529 } 530 if (error) 531 break; 532 space -= sizeof (ifr); 533 } 534 } 535 ifc->ifc_len -= space; 536 return (error); 537 } 538 539 static sprint_d(cp, n) 540 register char *cp; 541 u_short n; 542 { 543 register int q, m; 544 do { 545 if (n >= 10000) m = 10000; 546 else if (n >= 1000) m = 1000; 547 else if (n >= 100) m = 100; 548 else if (n >= 10) m = 10; 549 else m = 1; 550 q = n / m; 551 n -= m * q; 552 if (q > 9) q = 10; /* For crays with more than 100K interfaces */ 553 *cp++ = "0123456789Z"[q]; 554 } while (n > 0); 555 *cp++ = 0; 556 } 557