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