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.6 (Berkeley) 02/17/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 289 switch (cmd) { 290 291 case SIOCGIFCONF: 292 case OSIOCGIFCONF: 293 return (ifconf(cmd, data)); 294 295 #if defined(INET) && NETHER > 0 296 case SIOCSARP: 297 case SIOCDARP: 298 if (!suser()) 299 return (u.u_error); 300 /* FALL THROUGH */ 301 case SIOCGARP: 302 case OSIOCGARP: 303 return (arpioctl(cmd, data)); 304 #endif 305 } 306 ifr = (struct ifreq *)data; 307 ifp = ifunit(ifr->ifr_name); 308 if (ifp == 0) 309 return (ENXIO); 310 switch (cmd) { 311 312 case SIOCGIFFLAGS: 313 ifr->ifr_flags = ifp->if_flags; 314 break; 315 316 case SIOCGIFMETRIC: 317 ifr->ifr_metric = ifp->if_metric; 318 break; 319 320 case SIOCSIFFLAGS: 321 if (!suser()) 322 return (u.u_error); 323 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 324 int s = splimp(); 325 if_down(ifp); 326 splx(s); 327 } 328 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 329 (ifr->ifr_flags &~ IFF_CANTCHANGE); 330 if (ifp->if_ioctl) 331 (void) (*ifp->if_ioctl)(ifp, cmd, data); 332 break; 333 334 case SIOCSIFMETRIC: 335 if (!suser()) 336 return (u.u_error); 337 ifp->if_metric = ifr->ifr_metric; 338 break; 339 340 default: 341 if (so->so_proto == 0) 342 return (EOPNOTSUPP); 343 #ifndef COMPAT_43 344 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 345 cmd, data, ifp)); 346 #else 347 { 348 int error, ocmd = cmd; 349 350 switch (cmd) { 351 352 case SIOCSIFDSTADDR: 353 case SIOCSIFADDR: 354 case SIOCSIFBRDADDR: 355 case SIOCSIFNETMASK: 356 #if BYTE_ORDER != BIG_ENDIAN 357 if (ifr->ifr_addr.sa_family == 0 && 358 ifr->ifr_addr.sa_len < 16) { 359 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 360 ifr->ifr_addr.sa_len = 16; 361 } 362 #else 363 if (ifr->ifr_addr.sa_len == 0) 364 ifr->ifr_addr.sa_len = 16; 365 #endif 366 break; 367 368 case OSIOCGIFADDR: 369 cmd = SIOCGIFADDR; 370 break; 371 372 case OSIOCGIFDSTADDR: 373 cmd = SIOCGIFDSTADDR; 374 break; 375 376 case OSIOCGIFBRDADDR: 377 cmd = SIOCGIFBRDADDR; 378 break; 379 380 case OSIOCGIFNETMASK: 381 cmd = SIOCGIFNETMASK; 382 } 383 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 384 cmd, data, ifp)); 385 switch (ocmd) { 386 387 case OSIOCGIFADDR: 388 case OSIOCGIFDSTADDR: 389 case OSIOCGIFBRDADDR: 390 case OSIOCGIFNETMASK: 391 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 392 } 393 return (error); 394 395 } 396 #endif 397 } 398 return (0); 399 } 400 401 /* 402 * Return interface configuration 403 * of system. List may be used 404 * in later ioctl's (above) to get 405 * other information. 406 */ 407 /*ARGSUSED*/ 408 ifconf(cmd, data) 409 int cmd; 410 caddr_t data; 411 { 412 register struct ifconf *ifc = (struct ifconf *)data; 413 register struct ifnet *ifp = ifnet; 414 register struct ifaddr *ifa; 415 register char *cp, *ep; 416 struct ifreq ifr, *ifrp; 417 int space = ifc->ifc_len, error = 0; 418 419 ifrp = ifc->ifc_req; 420 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 421 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 422 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 423 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 424 ; 425 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 426 if ((ifa = ifp->if_addrlist) == 0) { 427 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 428 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 429 if (error) 430 break; 431 space -= sizeof (ifr), ifrp++; 432 } else 433 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 434 register struct sockaddr *sa = ifa->ifa_addr; 435 #ifdef COMPAT_43 436 if (cmd == OSIOCGIFCONF) { 437 struct osockaddr *osa = 438 (struct osockaddr *)&ifr.ifr_addr; 439 ifr.ifr_addr = *sa; 440 osa->sa_family = sa->sa_family; 441 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 442 sizeof (ifr)); 443 ifrp++; 444 } else 445 #endif 446 if (sa->sa_len <= sizeof(*sa)) { 447 ifr.ifr_addr = *sa; 448 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 449 sizeof (ifr)); 450 ifrp++; 451 } else { 452 space -= sa->sa_len - sizeof(*sa); 453 if (space < sizeof (ifr)) 454 break; 455 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 456 sizeof (ifr.ifr_name)); 457 if (error == 0) 458 error = copyout((caddr_t)sa, 459 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 460 ifrp = (struct ifreq *) 461 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 462 } 463 if (error) 464 break; 465 space -= sizeof (ifr); 466 } 467 } 468 ifc->ifc_len -= space; 469 return (error); 470 } 471