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.8 (Berkeley) 07/18/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 * Locate the point to point interface with a given destination address. 103 */ 104 /*ARGSUSED*/ 105 struct ifaddr * 106 ifa_ifwithdstaddr(addr) 107 struct sockaddr *addr; 108 { 109 register struct ifnet *ifp; 110 register struct ifaddr *ifa; 111 112 for (ifp = ifnet; ifp; ifp = ifp->if_next) 113 if (ifp->if_flags & IFF_POINTOPOINT) 114 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 115 if (ifa->ifa_addr.sa_family != addr->sa_family) 116 continue; 117 if (equal(&ifa->ifa_dstaddr, addr)) 118 return (ifa); 119 } 120 return ((struct ifaddr *)0); 121 } 122 123 /* 124 * Find an interface on a specific network. If many, choice 125 * is first found. 126 */ 127 struct ifaddr * 128 ifa_ifwithnet(addr) 129 register struct sockaddr *addr; 130 { 131 register struct ifnet *ifp; 132 register struct ifaddr *ifa; 133 register u_int af = addr->sa_family; 134 register int (*netmatch)(); 135 136 if (af >= AF_MAX) 137 return (0); 138 netmatch = afswitch[af].af_netmatch; 139 for (ifp = ifnet; ifp; ifp = ifp->if_next) 140 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 141 if (ifa->ifa_addr.sa_family != addr->sa_family) 142 continue; 143 if ((*netmatch)(&ifa->ifa_addr, addr)) 144 return (ifa); 145 } 146 return ((struct ifaddr *)0); 147 } 148 149 /* 150 * Find an interface using a specific address family 151 */ 152 struct ifaddr * 153 ifa_ifwithaf(af) 154 register int af; 155 { 156 register struct ifnet *ifp; 157 register struct ifaddr *ifa; 158 159 for (ifp = ifnet; ifp; ifp = ifp->if_next) 160 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 161 if (ifa->ifa_addr.sa_family == af) 162 return (ifa); 163 return ((struct ifaddr *)0); 164 } 165 166 /* 167 * Mark an interface down and notify protocols of 168 * the transition. 169 * NOTE: must be called at splnet or eqivalent. 170 */ 171 if_down(ifp) 172 register struct ifnet *ifp; 173 { 174 register struct ifaddr *ifa; 175 176 ifp->if_flags &= ~IFF_UP; 177 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 178 pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr); 179 } 180 181 /* 182 * Handle interface watchdog timer routines. Called 183 * from softclock, we decrement timers (if set) and 184 * call the appropriate interface routine on expiration. 185 */ 186 if_slowtimo() 187 { 188 register struct ifnet *ifp; 189 190 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 191 if (ifp->if_timer == 0 || --ifp->if_timer) 192 continue; 193 if (ifp->if_watchdog) 194 (*ifp->if_watchdog)(ifp->if_unit); 195 } 196 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 197 } 198 199 /* 200 * Map interface name to 201 * interface structure pointer. 202 */ 203 struct ifnet * 204 ifunit(name) 205 register char *name; 206 { 207 register char *cp; 208 register struct ifnet *ifp; 209 int unit; 210 211 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 212 if (*cp >= '0' && *cp <= '9') 213 break; 214 if (*cp == '\0' || cp == name + IFNAMSIZ) 215 return ((struct ifnet *)0); 216 unit = *cp - '0'; 217 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 218 if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 219 continue; 220 if (unit == ifp->if_unit) 221 break; 222 } 223 return (ifp); 224 } 225 226 /* 227 * Interface ioctls. 228 */ 229 ifioctl(so, cmd, data) 230 struct socket *so; 231 int cmd; 232 caddr_t data; 233 { 234 register struct ifnet *ifp; 235 register struct ifreq *ifr; 236 237 switch (cmd) { 238 239 case SIOCGIFCONF: 240 return (ifconf(cmd, data)); 241 242 #if defined(INET) && NETHER > 0 243 case SIOCSARP: 244 case SIOCDARP: 245 if (!suser()) 246 return (u.u_error); 247 /* FALL THROUGH */ 248 case SIOCGARP: 249 return (arpioctl(cmd, data)); 250 #endif 251 } 252 ifr = (struct ifreq *)data; 253 ifp = ifunit(ifr->ifr_name); 254 if (ifp == 0) 255 return (ENXIO); 256 switch (cmd) { 257 258 case SIOCGIFFLAGS: 259 ifr->ifr_flags = ifp->if_flags; 260 break; 261 262 case SIOCSIFFLAGS: 263 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 264 int s = splimp(); 265 if_down(ifp); 266 splx(s); 267 } 268 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 269 (ifr->ifr_flags &~ IFF_CANTCHANGE); 270 break; 271 272 default: 273 if (so->so_proto == 0) 274 return (EOPNOTSUPP); 275 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 276 cmd, data, ifp)); 277 } 278 return (0); 279 } 280 281 /* 282 * Return interface configuration 283 * of system. List may be used 284 * in later ioctl's (above) to get 285 * other information. 286 */ 287 /*ARGSUSED*/ 288 ifconf(cmd, data) 289 int cmd; 290 caddr_t data; 291 { 292 register struct ifconf *ifc = (struct ifconf *)data; 293 register struct ifnet *ifp = ifnet; 294 register struct ifaddr *ifa; 295 register char *cp, *ep; 296 struct ifreq ifr, *ifrp; 297 int space = ifc->ifc_len, error = 0; 298 299 ifrp = ifc->ifc_req; 300 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 301 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 302 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 303 for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 304 ; 305 *cp++ = '0' + ifp->if_unit; *cp = '\0'; 306 if ((ifa = ifp->if_addrlist) == 0) { 307 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 308 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 309 if (error) 310 break; 311 space -= sizeof (ifr), ifrp++; 312 } else 313 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 314 ifr.ifr_addr = ifa->ifa_addr; 315 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 316 if (error) 317 break; 318 space -= sizeof (ifr), ifrp++; 319 } 320 } 321 ifc->ifc_len -= space; 322 return (error); 323 } 324