date and time created 88/12/14 15:29:27 by sklower
[unix-history] / usr / src / sys / net / if.c
CommitLineData
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
37int 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
46ifinit()
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
60ifubareset(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
75if_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
89struct ifaddr *
90ifa_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*/
114struct ifaddr *
115ifa_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
136struct ifaddr *
137ifa_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
162struct ifaddr *
163ifa_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 */
182if_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 */
196if_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 */
216if_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
233struct ifnet *
234ifunit(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
259ifioctl(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
332ifconf(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}