add per-protocol options in rawcb (freed at detach)
[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 *
799358ac 6 * @(#)if.c 6.11 (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)
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
48ifubareset(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
63if_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
77struct ifaddr *
78ifa_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*/
102struct ifaddr *
103ifa_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
124struct ifaddr *
125ifa_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
149struct ifaddr *
150ifa_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 */
168if_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 */
183if_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
200struct ifnet *
201ifunit(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
226ifioctl(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
799358ac 239#if defined(INET) && 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 259 case SIOCSIFFLAGS:
beb1ee55
JB
260 if (!suser())
261 return (u.u_error);
81889e84
SL
262 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
263 int s = splimp();
264 if_down(ifp);
265 splx(s);
266 }
f211a0b7
MK
267 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
268 (ifr->ifr_flags &~ IFF_CANTCHANGE);
aad26eac
MK
269 if (ifp->if_ioctl)
270 (void) (*ifp->if_ioctl)(ifp, cmd, data);
81889e84
SL
271 break;
272
0c33c832 273 default:
f211a0b7 274 if (so->so_proto == 0)
a62dd253 275 return (EOPNOTSUPP);
f211a0b7
MK
276 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
277 cmd, data, ifp));
0c33c832
SL
278 }
279 return (0);
280}
281
282/*
283 * Return interface configuration
284 * of system. List may be used
285 * in later ioctl's (above) to get
286 * other information.
287 */
9e9695c7 288/*ARGSUSED*/
0c33c832
SL
289ifconf(cmd, data)
290 int cmd;
291 caddr_t data;
292{
293 register struct ifconf *ifc = (struct ifconf *)data;
294 register struct ifnet *ifp = ifnet;
f211a0b7 295 register struct ifaddr *ifa;
9b956fa5
SL
296 register char *cp, *ep;
297 struct ifreq ifr, *ifrp;
0c33c832
SL
298 int space = ifc->ifc_len, error = 0;
299
9b956fa5
SL
300 ifrp = ifc->ifc_req;
301 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
0c33c832 302 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
9b956fa5
SL
303 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
304 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
0c33c832 305 ;
9b956fa5 306 *cp++ = '0' + ifp->if_unit; *cp = '\0';
f211a0b7
MK
307 if ((ifa = ifp->if_addrlist) == 0) {
308 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
309 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
310 if (error)
311 break;
312 space -= sizeof (ifr), ifrp++;
313 } else
314 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
315 ifr.ifr_addr = ifa->ifa_addr;
316 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
317 if (error)
318 break;
319 space -= sizeof (ifr), ifrp++;
320 }
0c33c832
SL
321 }
322 ifc->ifc_len -= space;
323 return (error);
324}