Commit | Line | Data |
---|---|---|
cb1c44c2 KM |
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 | * | |
aad26eac | 6 | * @(#)if.c 6.9 (Berkeley) %G% |
cb1c44c2 | 7 | */ |
1bfd8df7 | 8 | |
a0369dcf JB |
9 | #include "param.h" |
10 | #include "systm.h" | |
11 | #include "socket.h" | |
f211a0b7 | 12 | #include "socketvar.h" |
a0369dcf JB |
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" | |
1bfd8df7 | 22 | |
17fcfec5 MK |
23 | #include "ether.h" |
24 | ||
1e977657 BJ |
25 | int ifqmaxlen = IFQ_MAXLEN; |
26 | ||
ee787340 SL |
27 | /* |
28 | * Network interface utility routines. | |
29 | * | |
f211a0b7 MK |
30 | * Routines with ifa_ifwith* names take sockaddr *'s as |
31 | * parameters. | |
ee787340 SL |
32 | */ |
33 | ||
85ce71f2 BJ |
34 | ifinit() |
35 | { | |
36 | register struct ifnet *ifp; | |
37 | ||
38 | for (ifp = ifnet; ifp; ifp = ifp->if_next) | |
aad26eac MK |
39 | if (ifp->if_snd.ifq_maxlen == 0) |
40 | ifp->if_snd.ifq_maxlen = ifqmaxlen; | |
5248a70b | 41 | if_slowtimo(); |
85ce71f2 BJ |
42 | } |
43 | ||
a62dd253 | 44 | #ifdef vax |
ee787340 SL |
45 | /* |
46 | * Call each interface on a Unibus reset. | |
47 | */ | |
85ce71f2 BJ |
48 | ifubareset(uban) |
49 | int uban; | |
50 | { | |
51 | register struct ifnet *ifp; | |
52 | ||
53 | for (ifp = ifnet; ifp; ifp = ifp->if_next) | |
8af3ca7c | 54 | if (ifp->if_reset) |
9d6a72e7 | 55 | (*ifp->if_reset)(ifp->if_unit, uban); |
85ce71f2 | 56 | } |
14fa60f2 | 57 | #endif |
85ce71f2 | 58 | |
ee787340 SL |
59 | /* |
60 | * Attach an interface to the | |
61 | * list of "active" interfaces. | |
62 | */ | |
405c9168 BJ |
63 | if_attach(ifp) |
64 | struct ifnet *ifp; | |
65 | { | |
c4af8b24 | 66 | register struct ifnet **p = &ifnet; |
405c9168 | 67 | |
c4af8b24 BJ |
68 | while (*p) |
69 | p = &((*p)->if_next); | |
70 | *p = ifp; | |
405c9168 BJ |
71 | } |
72 | ||
ee787340 SL |
73 | /* |
74 | * Locate an interface based on a complete address. | |
75 | */ | |
4ad99bae | 76 | /*ARGSUSED*/ |
f211a0b7 MK |
77 | struct ifaddr * |
78 | ifa_ifwithaddr(addr) | |
ee787340 | 79 | struct sockaddr *addr; |
1bfd8df7 BJ |
80 | { |
81 | register struct ifnet *ifp; | |
f211a0b7 | 82 | register struct ifaddr *ifa; |
1bfd8df7 | 83 | |
ee787340 SL |
84 | #define equal(a1, a2) \ |
85 | (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) | |
f211a0b7 MK |
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) | |
ee787340 | 89 | continue; |
f211a0b7 MK |
90 | if (equal(&ifa->ifa_addr, addr)) |
91 | return (ifa); | |
ee787340 | 92 | if ((ifp->if_flags & IFF_BROADCAST) && |
f211a0b7 MK |
93 | equal(&ifa->ifa_broadaddr, addr)) |
94 | return (ifa); | |
ee787340 | 95 | } |
f211a0b7 | 96 | return ((struct ifaddr *)0); |
1bfd8df7 | 97 | } |
ae674e00 KS |
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 | } | |
1bfd8df7 | 119 | |
ee787340 SL |
120 | /* |
121 | * Find an interface on a specific network. If many, choice | |
122 | * is first found. | |
123 | */ | |
f211a0b7 MK |
124 | struct ifaddr * |
125 | ifa_ifwithnet(addr) | |
ee787340 SL |
126 | register struct sockaddr *addr; |
127 | { | |
128 | register struct ifnet *ifp; | |
f211a0b7 | 129 | register struct ifaddr *ifa; |
14fa60f2 | 130 | register u_int af = addr->sa_family; |
e65dcd4c | 131 | register int (*netmatch)(); |
ee787340 | 132 | |
e65dcd4c SL |
133 | if (af >= AF_MAX) |
134 | return (0); | |
135 | netmatch = afswitch[af].af_netmatch; | |
f211a0b7 MK |
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) | |
ee787340 | 139 | continue; |
f211a0b7 MK |
140 | if ((*netmatch)(&ifa->ifa_addr, addr)) |
141 | return (ifa); | |
ee787340 | 142 | } |
f211a0b7 | 143 | return ((struct ifaddr *)0); |
1bfd8df7 BJ |
144 | } |
145 | ||
ee787340 SL |
146 | /* |
147 | * Find an interface using a specific address family | |
148 | */ | |
f211a0b7 MK |
149 | struct ifaddr * |
150 | ifa_ifwithaf(af) | |
ee787340 | 151 | register int af; |
8a13b737 | 152 | { |
ee787340 | 153 | register struct ifnet *ifp; |
f211a0b7 | 154 | register struct ifaddr *ifa; |
8a13b737 | 155 | |
ee787340 | 156 | for (ifp = ifnet; ifp; ifp = ifp->if_next) |
f211a0b7 MK |
157 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) |
158 | if (ifa->ifa_addr.sa_family == af) | |
159 | return (ifa); | |
160 | return ((struct ifaddr *)0); | |
8a13b737 | 161 | } |
f1b2fa5b | 162 | |
72e4f44e SL |
163 | /* |
164 | * Mark an interface down and notify protocols of | |
165 | * the transition. | |
af0b24db | 166 | * NOTE: must be called at splnet or eqivalent. |
72e4f44e SL |
167 | */ |
168 | if_down(ifp) | |
169 | register struct ifnet *ifp; | |
170 | { | |
f211a0b7 | 171 | register struct ifaddr *ifa; |
5248a70b | 172 | |
72e4f44e | 173 | ifp->if_flags &= ~IFF_UP; |
f211a0b7 | 174 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) |
aad26eac | 175 | pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); |
72e4f44e | 176 | } |
de602274 SL |
177 | |
178 | /* | |
179 | * Handle interface watchdog timer routines. Called | |
180 | * from softclock, we decrement timers (if set) and | |
181 | * call the appropriate interface routine on expiration. | |
182 | */ | |
183 | if_slowtimo() | |
184 | { | |
185 | register struct ifnet *ifp; | |
186 | ||
af0b24db SL |
187 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
188 | if (ifp->if_timer == 0 || --ifp->if_timer) | |
189 | continue; | |
190 | if (ifp->if_watchdog) | |
de602274 | 191 | (*ifp->if_watchdog)(ifp->if_unit); |
af0b24db | 192 | } |
6e7edb25 | 193 | timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); |
de602274 | 194 | } |
0c33c832 SL |
195 | |
196 | /* | |
a62dd253 SL |
197 | * Map interface name to |
198 | * interface structure pointer. | |
0c33c832 | 199 | */ |
a62dd253 SL |
200 | struct ifnet * |
201 | ifunit(name) | |
202 | register char *name; | |
0c33c832 | 203 | { |
0c33c832 | 204 | register char *cp; |
a62dd253 SL |
205 | register struct ifnet *ifp; |
206 | int unit; | |
0c33c832 | 207 | |
a62dd253 | 208 | for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) |
0c33c832 SL |
209 | if (*cp >= '0' && *cp <= '9') |
210 | break; | |
a62dd253 SL |
211 | if (*cp == '\0' || cp == name + IFNAMSIZ) |
212 | return ((struct ifnet *)0); | |
ff50f144 | 213 | unit = *cp - '0'; |
0c33c832 | 214 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
a62dd253 | 215 | if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) |
0c33c832 SL |
216 | continue; |
217 | if (unit == ifp->if_unit) | |
a62dd253 | 218 | break; |
0c33c832 | 219 | } |
a62dd253 SL |
220 | return (ifp); |
221 | } | |
222 | ||
223 | /* | |
224 | * Interface ioctls. | |
225 | */ | |
f211a0b7 MK |
226 | ifioctl(so, cmd, data) |
227 | struct socket *so; | |
a62dd253 SL |
228 | int cmd; |
229 | caddr_t data; | |
230 | { | |
231 | register struct ifnet *ifp; | |
232 | register struct ifreq *ifr; | |
0c33c832 | 233 | |
0c33c832 SL |
234 | switch (cmd) { |
235 | ||
a62dd253 SL |
236 | case SIOCGIFCONF: |
237 | return (ifconf(cmd, data)); | |
0c33c832 | 238 | |
aad26eac | 239 | #if (defined(INET) || defined(BBNNET)) && NETHER > 0 |
17fcfec5 MK |
240 | case SIOCSARP: |
241 | case SIOCDARP: | |
242 | if (!suser()) | |
243 | return (u.u_error); | |
244 | /* FALL THROUGH */ | |
245 | case SIOCGARP: | |
246 | return (arpioctl(cmd, data)); | |
247 | #endif | |
a62dd253 SL |
248 | } |
249 | ifr = (struct ifreq *)data; | |
250 | ifp = ifunit(ifr->ifr_name); | |
251 | if (ifp == 0) | |
252 | return (ENXIO); | |
253 | switch (cmd) { | |
0c33c832 | 254 | |
0c33c832 SL |
255 | case SIOCGIFFLAGS: |
256 | ifr->ifr_flags = ifp->if_flags; | |
257 | break; | |
258 | ||
81889e84 SL |
259 | case SIOCSIFFLAGS: |
260 | if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { | |
261 | int s = splimp(); | |
262 | if_down(ifp); | |
263 | splx(s); | |
264 | } | |
f211a0b7 MK |
265 | ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
266 | (ifr->ifr_flags &~ IFF_CANTCHANGE); | |
aad26eac MK |
267 | if (ifp->if_ioctl) |
268 | (void) (*ifp->if_ioctl)(ifp, cmd, data); | |
81889e84 SL |
269 | break; |
270 | ||
0c33c832 | 271 | default: |
f211a0b7 | 272 | if (so->so_proto == 0) |
a62dd253 | 273 | return (EOPNOTSUPP); |
f211a0b7 MK |
274 | return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, |
275 | cmd, data, ifp)); | |
0c33c832 SL |
276 | } |
277 | return (0); | |
278 | } | |
279 | ||
280 | /* | |
281 | * Return interface configuration | |
282 | * of system. List may be used | |
283 | * in later ioctl's (above) to get | |
284 | * other information. | |
285 | */ | |
9e9695c7 | 286 | /*ARGSUSED*/ |
0c33c832 SL |
287 | ifconf(cmd, data) |
288 | int cmd; | |
289 | caddr_t data; | |
290 | { | |
291 | register struct ifconf *ifc = (struct ifconf *)data; | |
292 | register struct ifnet *ifp = ifnet; | |
f211a0b7 | 293 | register struct ifaddr *ifa; |
9b956fa5 SL |
294 | register char *cp, *ep; |
295 | struct ifreq ifr, *ifrp; | |
0c33c832 SL |
296 | int space = ifc->ifc_len, error = 0; |
297 | ||
9b956fa5 SL |
298 | ifrp = ifc->ifc_req; |
299 | ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; | |
0c33c832 | 300 | for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { |
9b956fa5 SL |
301 | bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); |
302 | for (cp = ifr.ifr_name; cp < ep && *cp; cp++) | |
0c33c832 | 303 | ; |
9b956fa5 | 304 | *cp++ = '0' + ifp->if_unit; *cp = '\0'; |
f211a0b7 MK |
305 | if ((ifa = ifp->if_addrlist) == 0) { |
306 | bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); | |
307 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); | |
308 | if (error) | |
309 | break; | |
310 | space -= sizeof (ifr), ifrp++; | |
311 | } else | |
312 | for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { | |
313 | ifr.ifr_addr = ifa->ifa_addr; | |
314 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); | |
315 | if (error) | |
316 | break; | |
317 | space -= sizeof (ifr), ifrp++; | |
318 | } | |
0c33c832 SL |
319 | } |
320 | ifc->ifc_len -= space; | |
321 | return (error); | |
322 | } |