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.7 (Berkeley) 04/26/89 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 "dir.h" 27 #include "user.h" 28 #include "kernel.h" 29 #include "ioctl.h" 30 #include "errno.h" 31 32 #include "if.h" 33 #include "af.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 /* 72 * Attach an interface to the 73 * list of "active" interfaces. 74 */ 75 if_attach(ifp) 76 struct ifnet *ifp; 77 { 78 register struct ifnet **p = &ifnet; 79 80 while (*p) 81 p = &((*p)->if_next); 82 *p = ifp; 83 } 84 85 /* 86 * Locate an interface based on a complete address. 87 */ 88 /*ARGSUSED*/ 89 struct ifaddr * 90 ifa_ifwithaddr(addr) 91 register struct sockaddr *addr; 92 { 93 register struct ifnet *ifp; 94 register struct ifaddr *ifa; 95 96 #define equal(a1, a2) \ 97 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 98 for (ifp = ifnet; ifp; ifp = ifp->if_next) 99 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 100 if (ifa->ifa_addr->sa_family != addr->sa_family) 101 continue; 102 if (equal(addr, ifa->ifa_addr)) 103 return (ifa); 104 if ((ifp->if_flags & IFF_BROADCAST) && 105 equal(&ifa->ifa_broadaddr, addr)) 106 return (ifa); 107 } 108 return ((struct ifaddr *)0); 109 } 110 /* 111 * Locate the point to point interface with a given destination address. 112 */ 113 /*ARGSUSED*/ 114 struct ifaddr * 115 ifa_ifwithdstaddr(addr) 116 register struct sockaddr *addr; 117 { 118 register struct ifnet *ifp; 119 register struct ifaddr *ifa; 120 121 for (ifp = ifnet; ifp; ifp = ifp->if_next) 122 if (ifp->if_flags & IFF_POINTOPOINT) 123 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 124 if (ifa->ifa_addr->sa_family != addr->sa_family) 125 continue; 126 if (equal(addr, ifa->ifa_dstaddr)) 127 return (ifa); 128 } 129 return ((struct ifaddr *)0); 130 } 131 132 /* 133 * Find an interface on a specific network. If many, choice 134 * is first found. 135 */ 136 struct ifaddr * 137 ifa_ifwithnet(addr) 138 struct sockaddr *addr; 139 { 140 register struct ifnet *ifp; 141 register struct ifaddr *ifa; 142 register char *cp, *cp2, *cp3; 143 register char *cplim; 144 u_int af = addr->sa_family; 145 146 if (af >= AF_MAX) 147 return (0); 148 for (ifp = ifnet; ifp; ifp = ifp->if_next) 149 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 150 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0) 151 continue; 152 cp = addr->sa_data; 153 cp2 = ifa->ifa_addr->sa_data; 154 cp3 = ifa->ifa_netmask->sa_data; 155 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 156 for (; cp3 < cplim; cp3++) 157 if ((*cp++ ^ *cp2++) & *cp3) 158 break; 159 if (cp3 == cplim) 160 return (ifa); 161 } 162 return ((struct ifaddr *)0); 163 } 164 165 #ifdef notdef 166 /* 167 * Find an interface using a specific address family 168 */ 169 struct ifaddr * 170 ifa_ifwithaf(af) 171 register int af; 172 { 173 register struct ifnet *ifp; 174 register struct ifaddr *ifa; 175 176 for (ifp = ifnet; ifp; ifp = ifp->if_next) 177 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 178 if (ifa->ifa_addr->sa_family == af) 179 return (ifa); 180 return ((struct ifaddr *)0); 181 } 182 #endif 183 184 /* 185 * Mark an interface down and notify protocols of 186 * the transition. 187 * NOTE: must be called at splnet or eqivalent. 188 */ 189 if_down(ifp) 190 register struct ifnet *ifp; 191 { 192 register struct ifaddr *ifa; 193 194 ifp->if_flags &= ~IFF_UP; 195 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 196 pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 197 if_qflush(&ifp->if_snd); 198 } 199 200 /* 201 * Flush an interface queue. 202 */ 203 if_qflush(ifq) 204 register struct ifqueue *ifq; 205 { 206 register struct mbuf *m, *n; 207 208 n = ifq->ifq_head; 209 while (m = n) { 210 n = m->m_act; 211 m_freem(m); 212 } 213 ifq->ifq_head = 0; 214 ifq->ifq_tail = 0; 215 ifq->ifq_len = 0; 216 } 217 218 /* 219 * Handle interface watchdog timer routines. Called 220 * from softclock, we decrement timers (if set) and 221 * call the appropriate interface routine on expiration. 222 */ 223 if_slowtimo() 224 { 225 register struct ifnet *ifp; 226 int s = splimp(); 227 228 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 229 if (ifp->if_timer == 0 || --ifp->if_timer) 230 continue; 231 if (ifp->if_watchdog) 232 (*ifp->if_watchdog)(ifp->if_unit); 233 } 234 splx(s); 235 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 236 } 237 238 /* 239 * Map interface name to 240 * interface structure pointer. 241 */ 242 struct ifnet * 243 ifunit(name) 244 register char *name; 245 { 246 register char *cp; 247 register struct ifnet *ifp; 248 int unit; 249 unsigned len; 250 char *ep, c; 251 252 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 253 if (*cp >= '0' && *cp <= '9') 254 break; 255 if (*cp == '\0' || cp == name + IFNAMSIZ) 256 return ((struct ifnet *)0); 257 /* 258 * Save first char of unit, and pointer to it, 259 * so we can put a null there to avoid matching 260 * initial substrings of interface names. 261 */ 262 len = cp - name + 1; 263 c = *cp; 264 ep = cp; 265 for (unit = 0; *cp >= '0' && *cp <= '9'; ) 266 unit = unit * 10 + *cp++ - '0'; 267 *ep = 0; 268 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 269 if (bcmp(ifp->if_name, name, len)) 270 continue; 271 if (unit == ifp->if_unit) 272 break; 273 } 274 *ep = c; 275 return (ifp); 276 } 277 278 /* 279 * Interface ioctls. 280 */ 281 ifioctl(so, cmd, data) 282 struct socket *so; 283 int cmd; 284 caddr_t data; 285 { 286 register struct ifnet *ifp; 287 register struct ifreq *ifr; 288 int error; 289 290 switch (cmd) { 291 292 case SIOCGIFCONF: 293 case OSIOCGIFCONF: 294 return (ifconf(cmd, data)); 295 296 #if defined(INET) && NETHER > 0 297 case SIOCSARP: 298 case SIOCDARP: 299 if (error = suser(u.u_cred, &u.u_acflag)) 300 return (error); 301 /* FALL THROUGH */ 302 case SIOCGARP: 303 case OSIOCGARP: 304 return (arpioctl(cmd, data)); 305 #endif 306 } 307 ifr = (struct ifreq *)data; 308 ifp = ifunit(ifr->ifr_name); 309 if (ifp == 0) 310 return (ENXIO); 311 switch (cmd) { 312 313 case SIOCGIFFLAGS: 314 ifr->ifr_flags = ifp->if_flags; 315 break; 316 317 case SIOCGIFMETRIC: 318 ifr->ifr_metric = ifp->if_metric; 319 break; 320 321 case SIOCSIFFLAGS: 322 if (error = suser(u.u_cred, &u.u_acflag)) 323 return (error); 324 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 325 int s = splimp(); 326 if_down(ifp); 327 splx(s); 328 } 329 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 330 (ifr->ifr_flags &~ IFF_CANTCHANGE); 331 if (ifp->if_ioctl) 332 (void) (*ifp->if_ioctl)(ifp, cmd, data); 333 break; 334 335 case SIOCSIFMETRIC: 336 if (error = suser(u.u_cred, &u.u_acflag)) 337 return (error); 338 ifp->if_metric = ifr->ifr_metric; 339 break; 340 341 default: 342 if (so->so_proto == 0) 343 return (EOPNOTSUPP); 344 #ifndef COMPAT_43 345 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 346 cmd, data, ifp)); 347 #else 348 { 349 int error, ocmd = cmd; 350 351 switch (cmd) { 352 353 case SIOCSIFDSTADDR: 354 case SIOCSIFADDR: 355 case SIOCSIFBRDADDR: 356 case SIOCSIFNETMASK: 357 #if BYTE_ORDER != BIG_ENDIAN 358 if (ifr->ifr_addr.sa_family == 0 && 359 ifr->ifr_addr.sa_len < 16) { 360 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 361 ifr->ifr_addr.sa_len = 16; 362 } 363 #else 364 if (ifr->ifr_addr.sa_len == 0) 365 ifr->ifr_addr.sa_len = 16; 366 #endif 367 break; 368 369 case OSIOCGIFADDR: 370 cmd = SIOCGIFADDR; 371 break; 372 373 case OSIOCGIFDSTADDR: 374 cmd = SIOCGIFDSTADDR; 375 break; 376 377 case OSIOCGIFBRDADDR: 378 cmd = SIOCGIFBRDADDR; 379 break; 380 381 case OSIOCGIFNETMASK: 382 cmd = SIOCGIFNETMASK; 383 } 384 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 385 cmd, data, ifp)); 386 switch (ocmd) { 387 388 case OSIOCGIFADDR: 389 case OSIOCGIFDSTADDR: 390 case OSIOCGIFBRDADDR: 391 case OSIOCGIFNETMASK: 392 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 393 } 394 return (error); 395 396 } 397 #endif 398 } 399 return (0); 400 } 401 402 /* 403 * Return interface configuration 404 * of system. List may be used 405 * in later ioctl's (above) to get 406 * other information. 407 */ 408 /*ARGSUSED*/ 409 ifconf(cmd, data) 410 int cmd; 411 caddr_t data; 412 { 413 register struct ifconf *ifc = (struct ifconf *)data; 414 register struct ifnet *ifp = ifnet; 415 register struct ifaddr *ifa; 416 register char *cp, *ep; 417 struct ifreq ifr, *ifrp; 418 int space = ifc->ifc_len, error = 0; 419 420 ifrp = ifc->ifc_req; 421 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 422 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 423 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 424 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 425 ; 426 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 427 if ((ifa = ifp->if_addrlist) == 0) { 428 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 429 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 430 if (error) 431 break; 432 space -= sizeof (ifr), ifrp++; 433 } else 434 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 435 register struct sockaddr *sa = ifa->ifa_addr; 436 #ifdef COMPAT_43 437 if (cmd == OSIOCGIFCONF) { 438 struct osockaddr *osa = 439 (struct osockaddr *)&ifr.ifr_addr; 440 ifr.ifr_addr = *sa; 441 osa->sa_family = sa->sa_family; 442 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 443 sizeof (ifr)); 444 ifrp++; 445 } else 446 #endif 447 if (sa->sa_len <= sizeof(*sa)) { 448 ifr.ifr_addr = *sa; 449 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 450 sizeof (ifr)); 451 ifrp++; 452 } else { 453 space -= sa->sa_len - sizeof(*sa); 454 if (space < sizeof (ifr)) 455 break; 456 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 457 sizeof (ifr.ifr_name)); 458 if (error == 0) 459 error = copyout((caddr_t)sa, 460 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 461 ifrp = (struct ifreq *) 462 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 463 } 464 if (error) 465 break; 466 space -= sizeof (ifr); 467 } 468 } 469 ifc->ifc_len -= space; 470 return (error); 471 } 472