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