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