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