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