1: /* 2: * Copyright (c) 1980, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)if.c 7.1 (Berkeley) 6/4/86 7: */ 8: 9: #include "param.h" 10: #include "systm.h" 11: #include "socket.h" 12: #include "socketvar.h" 13: #include "protosw.h" 14: #include "dir.h" 15: #include "user.h" 16: #include "kernel.h" 17: #include "ioctl.h" 18: #include "errno.h" 19: 20: #include "if.h" 21: #include "af.h" 22: 23: #include "ether.h" 24: 25: int ifqmaxlen = IFQ_MAXLEN; 26: 27: /* 28: * Network interface utility routines. 29: * 30: * Routines with ifa_ifwith* names take sockaddr *'s as 31: * parameters. 32: */ 33: 34: ifinit() 35: { 36: register struct ifnet *ifp; 37: 38: for (ifp = ifnet; ifp; ifp = ifp->if_next) 39: if (ifp->if_snd.ifq_maxlen == 0) 40: ifp->if_snd.ifq_maxlen = ifqmaxlen; 41: if_slowtimo(); 42: } 43: 44: #ifdef vax 45: /* 46: * Call each interface on a Unibus reset. 47: */ 48: ifubareset(uban) 49: int uban; 50: { 51: register struct ifnet *ifp; 52: 53: for (ifp = ifnet; ifp; ifp = ifp->if_next) 54: if (ifp->if_reset) 55: (*ifp->if_reset)(ifp->if_unit, uban); 56: } 57: #endif 58: 59: /* 60: * Attach an interface to the 61: * list of "active" interfaces. 62: */ 63: if_attach(ifp) 64: struct ifnet *ifp; 65: { 66: register struct ifnet **p = &ifnet; 67: 68: while (*p) 69: p = &((*p)->if_next); 70: *p = ifp; 71: } 72: 73: /* 74: * Locate an interface based on a complete address. 75: */ 76: /*ARGSUSED*/ 77: struct ifaddr * 78: ifa_ifwithaddr(addr) 79: struct sockaddr *addr; 80: { 81: register struct ifnet *ifp; 82: register struct ifaddr *ifa; 83: 84: #define equal(a1, a2) \ 85: (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 86: for (ifp = ifnet; ifp; ifp = ifp->if_next) 87: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 88: if (ifa->ifa_addr.sa_family != addr->sa_family) 89: continue; 90: if (equal(&ifa->ifa_addr, addr)) 91: return (ifa); 92: if ((ifp->if_flags & IFF_BROADCAST) && 93: equal(&ifa->ifa_broadaddr, addr)) 94: return (ifa); 95: } 96: return ((struct ifaddr *)0); 97: } 98: /* 99: * Locate the point to point interface with a given destination address. 100: */ 101: /*ARGSUSED*/ 102: struct ifaddr * 103: ifa_ifwithdstaddr(addr) 104: struct sockaddr *addr; 105: { 106: register struct ifnet *ifp; 107: register struct ifaddr *ifa; 108: 109: for (ifp = ifnet; ifp; ifp = ifp->if_next) 110: if (ifp->if_flags & IFF_POINTOPOINT) 111: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 112: if (ifa->ifa_addr.sa_family != addr->sa_family) 113: continue; 114: if (equal(&ifa->ifa_dstaddr, addr)) 115: return (ifa); 116: } 117: return ((struct ifaddr *)0); 118: } 119: 120: /* 121: * Find an interface on a specific network. If many, choice 122: * is first found. 123: */ 124: struct ifaddr * 125: ifa_ifwithnet(addr) 126: register struct sockaddr *addr; 127: { 128: register struct ifnet *ifp; 129: register struct ifaddr *ifa; 130: register u_int af = addr->sa_family; 131: register int (*netmatch)(); 132: 133: if (af >= AF_MAX) 134: return (0); 135: netmatch = afswitch[af].af_netmatch; 136: for (ifp = ifnet; ifp; ifp = ifp->if_next) 137: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 138: if (ifa->ifa_addr.sa_family != addr->sa_family) 139: continue; 140: if ((*netmatch)(&ifa->ifa_addr, addr)) 141: return (ifa); 142: } 143: return ((struct ifaddr *)0); 144: } 145: 146: #ifdef notdef 147: /* 148: * Find an interface using a specific address family 149: */ 150: struct ifaddr * 151: ifa_ifwithaf(af) 152: register int af; 153: { 154: register struct ifnet *ifp; 155: register struct ifaddr *ifa; 156: 157: for (ifp = ifnet; ifp; ifp = ifp->if_next) 158: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 159: if (ifa->ifa_addr.sa_family == af) 160: return (ifa); 161: return ((struct ifaddr *)0); 162: } 163: #endif 164: 165: /* 166: * Mark an interface down and notify protocols of 167: * the transition. 168: * NOTE: must be called at splnet or eqivalent. 169: */ 170: if_down(ifp) 171: register struct ifnet *ifp; 172: { 173: register struct ifaddr *ifa; 174: 175: ifp->if_flags &= ~IFF_UP; 176: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 177: pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 178: } 179: 180: /* 181: * Handle interface watchdog timer routines. Called 182: * from softclock, we decrement timers (if set) and 183: * call the appropriate interface routine on expiration. 184: */ 185: if_slowtimo() 186: { 187: register struct ifnet *ifp; 188: 189: for (ifp = ifnet; ifp; ifp = ifp->if_next) { 190: if (ifp->if_timer == 0 || --ifp->if_timer) 191: continue; 192: if (ifp->if_watchdog) 193: (*ifp->if_watchdog)(ifp->if_unit); 194: } 195: timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 196: } 197: 198: /* 199: * Map interface name to 200: * interface structure pointer. 201: */ 202: struct ifnet * 203: ifunit(name) 204: register char *name; 205: { 206: register char *cp; 207: register struct ifnet *ifp; 208: int unit; 209: 210: for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 211: if (*cp >= '0' && *cp <= '9') 212: break; 213: if (*cp == '\0' || cp == name + IFNAMSIZ) 214: return ((struct ifnet *)0); 215: unit = *cp - '0'; 216: for (ifp = ifnet; ifp; ifp = ifp->if_next) { 217: if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 218: continue; 219: if (unit == ifp->if_unit) 220: break; 221: } 222: return (ifp); 223: } 224: 225: /* 226: * Interface ioctls. 227: */ 228: ifioctl(so, cmd, data) 229: struct socket *so; 230: int cmd; 231: caddr_t data; 232: { 233: register struct ifnet *ifp; 234: register struct ifreq *ifr; 235: 236: switch (cmd) { 237: 238: case SIOCGIFCONF: 239: return (ifconf(cmd, data)); 240: 241: #if defined(INET) && NETHER > 0 242: case SIOCSARP: 243: case SIOCDARP: 244: if (!suser()) 245: return (u.u_error); 246: /* FALL THROUGH */ 247: case SIOCGARP: 248: return (arpioctl(cmd, data)); 249: #endif 250: } 251: ifr = (struct ifreq *)data; 252: ifp = ifunit(ifr->ifr_name); 253: if (ifp == 0) 254: return (ENXIO); 255: switch (cmd) { 256: 257: case SIOCGIFFLAGS: 258: ifr->ifr_flags = ifp->if_flags; 259: break; 260: 261: case SIOCGIFMETRIC: 262: ifr->ifr_metric = ifp->if_metric; 263: break; 264: 265: case SIOCSIFFLAGS: 266: if (!suser()) 267: return (u.u_error); 268: if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 269: int s = splimp(); 270: if_down(ifp); 271: splx(s); 272: } 273: ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 274: (ifr->ifr_flags &~ IFF_CANTCHANGE); 275: if (ifp->if_ioctl) 276: (void) (*ifp->if_ioctl)(ifp, cmd, data); 277: break; 278: 279: case SIOCSIFMETRIC: 280: if (!suser()) 281: return (u.u_error); 282: ifp->if_metric = ifr->ifr_metric; 283: break; 284: 285: default: 286: if (so->so_proto == 0) 287: return (EOPNOTSUPP); 288: return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 289: cmd, data, ifp)); 290: } 291: return (0); 292: } 293: 294: /* 295: * Return interface configuration 296: * of system. List may be used 297: * in later ioctl's (above) to get 298: * other information. 299: */ 300: /*ARGSUSED*/ 301: ifconf(cmd, data) 302: int cmd; 303: caddr_t data; 304: { 305: register struct ifconf *ifc = (struct ifconf *)data; 306: register struct ifnet *ifp = ifnet; 307: register struct ifaddr *ifa; 308: register char *cp, *ep; 309: struct ifreq ifr, *ifrp; 310: int space = ifc->ifc_len, error = 0; 311: 312: ifrp = ifc->ifc_req; 313: ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 314: for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 315: bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 316: for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 317: ; 318: *cp++ = '0' + ifp->if_unit; *cp = '\0'; 319: if ((ifa = ifp->if_addrlist) == 0) { 320: bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 321: error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 322: if (error) 323: break; 324: space -= sizeof (ifr), ifrp++; 325: } else 326: for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 327: ifr.ifr_addr = ifa->ifa_addr; 328: error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 329: if (error) 330: break; 331: space -= sizeof (ifr), ifrp++; 332: } 333: } 334: ifc->ifc_len -= space; 335: return (error); 336: }