1 /* if.c 4.26 83/03/15 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/socket.h" 6 #include "../h/protosw.h" 7 #include "../h/time.h" 8 #include "../h/kernel.h" 9 #include "../h/ioctl.h" 10 #include "../h/errno.h" 11 12 #include "../net/if.h" 13 #include "../net/af.h" 14 15 int ifqmaxlen = IFQ_MAXLEN; 16 17 /* 18 * Network interface utility routines. 19 * 20 * Routines with if_ifwith* names take sockaddr *'s as 21 * parameters. Other routines take value parameters, 22 * e.g. if_ifwithnet takes the network number. 23 */ 24 25 ifinit() 26 { 27 register struct ifnet *ifp; 28 29 for (ifp = ifnet; ifp; ifp = ifp->if_next) 30 if (ifp->if_init) { 31 (*ifp->if_init)(ifp->if_unit); 32 if (ifp->if_snd.ifq_maxlen == 0) 33 ifp->if_snd.ifq_maxlen = ifqmaxlen; 34 } 35 if_slowtimo(); 36 } 37 38 #if vax 39 /* 40 * Call each interface on a Unibus reset. 41 */ 42 ifubareset(uban) 43 int uban; 44 { 45 register struct ifnet *ifp; 46 47 for (ifp = ifnet; ifp; ifp = ifp->if_next) 48 if (ifp->if_reset) 49 (*ifp->if_reset)(uban); 50 } 51 #endif 52 53 /* 54 * Attach an interface to the 55 * list of "active" interfaces. 56 */ 57 if_attach(ifp) 58 struct ifnet *ifp; 59 { 60 register struct ifnet **p = &ifnet; 61 62 while (*p) 63 p = &((*p)->if_next); 64 *p = ifp; 65 } 66 67 /* 68 * Locate an interface based on a complete address. 69 */ 70 /*ARGSUSED*/ 71 struct ifnet * 72 if_ifwithaddr(addr) 73 struct sockaddr *addr; 74 { 75 register struct ifnet *ifp; 76 77 #define equal(a1, a2) \ 78 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 79 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 80 if (ifp->if_addr.sa_family != addr->sa_family) 81 continue; 82 if (equal(&ifp->if_addr, addr)) 83 break; 84 if ((ifp->if_flags & IFF_BROADCAST) && 85 equal(&ifp->if_broadaddr, addr)) 86 break; 87 } 88 return (ifp); 89 } 90 91 /* 92 * Find an interface on a specific network. If many, choice 93 * is first found. 94 */ 95 struct ifnet * 96 if_ifwithnet(addr) 97 register struct sockaddr *addr; 98 { 99 register struct ifnet *ifp; 100 register u_int af = addr->sa_family; 101 register int (*netmatch)(); 102 103 if (af >= AF_MAX) 104 return (0); 105 netmatch = afswitch[af].af_netmatch; 106 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 107 if (af != ifp->if_addr.sa_family) 108 continue; 109 if ((*netmatch)(addr, &ifp->if_addr)) 110 break; 111 } 112 return (ifp); 113 } 114 115 /* 116 * As above, but parameter is network number. 117 */ 118 struct ifnet * 119 if_ifonnetof(net) 120 register int net; 121 { 122 register struct ifnet *ifp; 123 124 for (ifp = ifnet; ifp; ifp = ifp->if_next) 125 if (ifp->if_net == net) 126 break; 127 return (ifp); 128 } 129 130 /* 131 * Find an interface using a specific address family 132 */ 133 struct ifnet * 134 if_ifwithaf(af) 135 register int af; 136 { 137 register struct ifnet *ifp; 138 139 for (ifp = ifnet; ifp; ifp = ifp->if_next) 140 if (ifp->if_addr.sa_family == af) 141 break; 142 return (ifp); 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 154 ifp->if_flags &= ~IFF_UP; 155 pfctlinput(PRC_IFDOWN, (caddr_t)&ifp->if_addr); 156 } 157 158 /* 159 * Handle interface watchdog timer routines. Called 160 * from softclock, we decrement timers (if set) and 161 * call the appropriate interface routine on expiration. 162 */ 163 if_slowtimo() 164 { 165 register struct ifnet *ifp; 166 167 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 168 if (ifp->if_timer == 0 || --ifp->if_timer) 169 continue; 170 if (ifp->if_watchdog) 171 (*ifp->if_watchdog)(ifp->if_unit); 172 } 173 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 174 } 175 176 /* 177 * Service a socket ioctl request directed 178 * to an interface. 179 */ 180 ifrequest(cmd, data) 181 int cmd; 182 caddr_t data; 183 { 184 register struct ifnet *ifp; 185 register struct ifreq *ifr; 186 register char *cp; 187 int unit, s; 188 189 ifr = (struct ifreq *)data; 190 for (cp = ifr->ifr_name; *cp; cp++) 191 if (*cp >= '0' && *cp <= '9') 192 break; 193 if (*cp == 0) 194 return (ENXIO); /* couldn't find unit */ 195 unit = *cp - '0', *cp = 0; 196 for (ifp = ifnet; ifp; ifp = ifp->if_next) { 197 if (bcmp(ifp->if_name, ifr->ifr_name, cp - ifr->ifr_name)) 198 continue; 199 if (unit == ifp->if_unit) 200 goto found; 201 } 202 return (ENXIO); 203 204 found: 205 switch (cmd) { 206 207 case SIOCGIFADDR: 208 ifr->ifr_addr = ifp->if_addr; 209 break; 210 211 case SIOCSIFADDR: 212 if_rtinit(ifp, -1); /* delete previous route */ 213 s = splimp(); 214 ifp->if_addr = ifr->ifr_addr; 215 (*ifp->if_init)(unit); 216 splx(s); 217 break; 218 219 case SIOCGIFDSTADDR: 220 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 221 return (EINVAL); 222 ifr->ifr_dstaddr = ifp->if_dstaddr; 223 break; 224 225 case SIOCSIFDSTADDR: 226 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 227 return (EINVAL); 228 s = splimp(); 229 ifp->if_dstaddr = ifr->ifr_dstaddr; 230 splx(s); 231 break; 232 233 case SIOCGIFFLAGS: 234 ifr->ifr_flags = ifp->if_flags; 235 break; 236 237 case SIOCSIFFLAGS: 238 if ((ifr->ifr_flags & IFF_UP) == 0 && 239 (ifp->if_flags & IFF_UP)) { 240 s = splimp(); 241 if_down(ifp); 242 splx(s); 243 } 244 ifp->if_flags = ifr->ifr_flags; 245 break; 246 247 default: 248 return (EINVAL); 249 } 250 return (0); 251 } 252 253 /* 254 * Return interface configuration 255 * of system. List may be used 256 * in later ioctl's (above) to get 257 * other information. 258 */ 259 ifconf(cmd, data) 260 int cmd; 261 caddr_t data; 262 { 263 register struct ifconf *ifc = (struct ifconf *)data; 264 register struct ifnet *ifp = ifnet; 265 register char *cp; 266 struct ifreq ifr; 267 int space = ifc->ifc_len, error = 0; 268 269 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 270 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name)); 271 for (cp = ifr.ifr_name; *cp; cp++) 272 ; 273 *cp = '0' + ifp->if_unit; 274 ifr.ifr_addr = ifp->if_addr; 275 error = copyout((caddr_t)&ifr, ifc->ifc_buf, sizeof (ifr)); 276 if (error) 277 break; 278 space -= sizeof (ifr); 279 ifc->ifc_req++; 280 } 281 ifc->ifc_len -= space; 282 return (error); 283 } 284