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