1 /* 2 * Copyright (c) 1980 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 6.7 (Berkeley) 06/08/85 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_init) { 40 (*ifp->if_init)(ifp->if_unit); 41 if (ifp->if_snd.ifq_maxlen == 0) 42 ifp->if_snd.ifq_maxlen = ifqmaxlen; 43 } 44 if_slowtimo(); 45 } 46 47 #ifdef vax 48 /* 49 * Call each interface on a Unibus reset. 50 */ 51 ifubareset(uban) 52 int uban; 53 { 54 register struct ifnet *ifp; 55 56 for (ifp = ifnet; ifp; ifp = ifp->if_next) 57 if (ifp->if_reset) 58 (*ifp->if_reset)(ifp->if_unit, uban); 59 } 60 #endif 61 62 /* 63 * Attach an interface to the 64 * list of "active" interfaces. 65 */ 66 if_attach(ifp) 67 struct ifnet *ifp; 68 { 69 register struct ifnet **p = &ifnet; 70 71 while (*p) 72 p = &((*p)->if_next); 73 *p = ifp; 74 } 75 76 /* 77 * Locate an interface based on a complete address. 78 */ 79 /*ARGSUSED*/ 80 struct ifaddr * 81 ifa_ifwithaddr(addr) 82 struct sockaddr *addr; 83 { 84 register struct ifnet *ifp; 85 register struct ifaddr *ifa; 86 87 #define equal(a1, a2) \ 88 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 89 for (ifp = ifnet; ifp; ifp = ifp->if_next) 90 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 91 if (ifa->ifa_addr.sa_family != addr->sa_family) 92 continue; 93 if (equal(&ifa->ifa_addr, addr)) 94 return (ifa); 95 if ((ifp->if_flags & IFF_BROADCAST) && 96 equal(&ifa->ifa_broadaddr, addr)) 97 return (ifa); 98 } 99 return ((struct ifaddr *)0); 100 } 101 102 /* 103 * Find an interface on a specific network. If many, choice 104 * is first found. 105 */ 106 struct ifaddr * 107 ifa_ifwithnet(addr) 108 register struct sockaddr *addr; 109 { 110 register struct ifnet *ifp; 111 register struct ifaddr *ifa; 112 register u_int af = addr->sa_family; 113 register int (*netmatch)(); 114 115 if (af >= AF_MAX) 116 return (0); 117 netmatch = afswitch[af].af_netmatch; 118 for (ifp = ifnet; ifp; ifp = ifp->if_next) 119 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 120 if (ifa->ifa_addr.sa_family != addr->sa_family) 121 continue; 122 if ((*netmatch)(&ifa->ifa_addr, addr)) 123 return (ifa); 124 } 125 return ((struct ifaddr *)0); 126 } 127 128 /* 129 * Find an interface using a specific address family 130 */ 131 struct ifaddr * 132 ifa_ifwithaf(af) 133 register int af; 134 { 135 register struct ifnet *ifp; 136 register struct ifaddr *ifa; 137 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 == af) 141 return (ifa); 142 return ((struct ifaddr *)0); 143 } 144 145 /* 146 * Mark an interface down and notify protocols of 147 * the transition. 148 * NOTE: must be called at splnet or eqivalent. 149 */ 150 if_down(ifp) 151 register struct ifnet *ifp; 152 { 153 register struct ifaddr *ifa; 154 155 ifp->if_flags &= ~IFF_UP; 156 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 157 pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr); 158 } 159 160 /* 161 * Handle interface watchdog timer routines. Called 162 * from softclock, we decrement timers (if set) and 163 * call the appropriate interface routine on expiration. 164 */ 165 if_slowtimo() 166 { 167 register struct ifnet *ifp; 168 169 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 170 if (ifp->if_timer == 0 || --ifp->if_timer) 171 continue; 172 if (ifp->if_watchdog) 173 (*ifp->if_watchdog)(ifp->if_unit); 174 } 175 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 176 } 177 178 /* 179 * Map interface name to 180 * interface structure pointer. 181 */ 182 struct ifnet * 183 ifunit(name) 184 register char *name; 185 { 186 register char *cp; 187 register struct ifnet *ifp; 188 int unit; 189 190 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 191 if (*cp >= '0' && *cp <= '9') 192 break; 193 if (*cp == '\0' || cp == name + IFNAMSIZ) 194 return ((struct ifnet *)0); 195 unit = *cp - '0'; 196 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 197 if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 198 continue; 199 if (unit == ifp->if_unit) 200 break; 201 } 202 return (ifp); 203 } 204 205 /* 206 * Interface ioctls. 207 */ 208 ifioctl(so, cmd, data) 209 struct socket *so; 210 int cmd; 211 caddr_t data; 212 { 213 register struct ifnet *ifp; 214 register struct ifreq *ifr; 215 216 switch (cmd) { 217 218 case SIOCGIFCONF: 219 return (ifconf(cmd, data)); 220 221 #if defined(INET) && NETHER > 0 222 case SIOCSARP: 223 case SIOCDARP: 224 if (!suser()) 225 return (u.u_error); 226 /* FALL THROUGH */ 227 case SIOCGARP: 228 return (arpioctl(cmd, data)); 229 #endif 230 } 231 ifr = (struct ifreq *)data; 232 ifp = ifunit(ifr->ifr_name); 233 if (ifp == 0) 234 return (ENXIO); 235 switch (cmd) { 236 237 case SIOCGIFFLAGS: 238 ifr->ifr_flags = ifp->if_flags; 239 break; 240 241 case SIOCSIFFLAGS: 242 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 243 int s = splimp(); 244 if_down(ifp); 245 splx(s); 246 } 247 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 248 (ifr->ifr_flags &~ IFF_CANTCHANGE); 249 break; 250 251 default: 252 if (so->so_proto == 0) 253 return (EOPNOTSUPP); 254 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 255 cmd, data, ifp)); 256 } 257 return (0); 258 } 259 260 /* 261 * Return interface configuration 262 * of system. List may be used 263 * in later ioctl's (above) to get 264 * other information. 265 */ 266 /*ARGSUSED*/ 267 ifconf(cmd, data) 268 int cmd; 269 caddr_t data; 270 { 271 register struct ifconf *ifc = (struct ifconf *)data; 272 register struct ifnet *ifp = ifnet; 273 register struct ifaddr *ifa; 274 register char *cp, *ep; 275 struct ifreq ifr, *ifrp; 276 int space = ifc->ifc_len, error = 0; 277 278 ifrp = ifc->ifc_req; 279 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 280 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 281 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 282 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 283 ; 284 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 285 if ((ifa = ifp->if_addrlist) == 0) { 286 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 287 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 288 if (error) 289 break; 290 space -= sizeof (ifr), ifrp++; 291 } else 292 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 293 ifr.ifr_addr = ifa->ifa_addr; 294 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 295 if (error) 296 break; 297 space -= sizeof (ifr), ifrp++; 298 } 299 } 300 ifc->ifc_len -= space; 301 return (error); 302 } 303