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) 06/04/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 } 337