plug memory leak; check in for ``alpha'' tape
[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 *
65c6d60a 17 * @(#)if.c 7.8 (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 25#include "protosw.h"
a0369dcf
JB
26#include "user.h"
27#include "kernel.h"
28#include "ioctl.h"
29#include "errno.h"
30
31#include "if.h"
32#include "af.h"
1bfd8df7 33
17fcfec5
MK
34#include "ether.h"
35
1e977657
BJ
36int ifqmaxlen = IFQ_MAXLEN;
37
ee787340
SL
38/*
39 * Network interface utility routines.
40 *
f211a0b7
MK
41 * Routines with ifa_ifwith* names take sockaddr *'s as
42 * parameters.
ee787340
SL
43 */
44
85ce71f2
BJ
45ifinit()
46{
47 register struct ifnet *ifp;
48
49 for (ifp = ifnet; ifp; ifp = ifp->if_next)
aad26eac
MK
50 if (ifp->if_snd.ifq_maxlen == 0)
51 ifp->if_snd.ifq_maxlen = ifqmaxlen;
5248a70b 52 if_slowtimo();
85ce71f2
BJ
53}
54
a62dd253 55#ifdef vax
ee787340
SL
56/*
57 * Call each interface on a Unibus reset.
58 */
85ce71f2
BJ
59ifubareset(uban)
60 int uban;
61{
62 register struct ifnet *ifp;
63
64 for (ifp = ifnet; ifp; ifp = ifp->if_next)
8af3ca7c 65 if (ifp->if_reset)
9d6a72e7 66 (*ifp->if_reset)(ifp->if_unit, uban);
85ce71f2 67}
14fa60f2 68#endif
85ce71f2 69
ee787340
SL
70/*
71 * Attach an interface to the
72 * list of "active" interfaces.
73 */
405c9168
BJ
74if_attach(ifp)
75 struct ifnet *ifp;
76{
c4af8b24 77 register struct ifnet **p = &ifnet;
405c9168 78
c4af8b24
BJ
79 while (*p)
80 p = &((*p)->if_next);
81 *p = ifp;
405c9168
BJ
82}
83
ee787340
SL
84/*
85 * Locate an interface based on a complete address.
86 */
4ad99bae 87/*ARGSUSED*/
f211a0b7
MK
88struct ifaddr *
89ifa_ifwithaddr(addr)
202403f4 90 register struct sockaddr *addr;
1bfd8df7
BJ
91{
92 register struct ifnet *ifp;
f211a0b7 93 register struct ifaddr *ifa;
1bfd8df7 94
ee787340 95#define equal(a1, a2) \
202403f4 96 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
f211a0b7
MK
97 for (ifp = ifnet; ifp; ifp = ifp->if_next)
98 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 99 if (ifa->ifa_addr->sa_family != addr->sa_family)
ee787340 100 continue;
202403f4 101 if (equal(addr, ifa->ifa_addr))
f211a0b7 102 return (ifa);
ee787340 103 if ((ifp->if_flags & IFF_BROADCAST) &&
f211a0b7
MK
104 equal(&ifa->ifa_broadaddr, addr))
105 return (ifa);
ee787340 106 }
f211a0b7 107 return ((struct ifaddr *)0);
1bfd8df7 108}
ae674e00
KS
109/*
110 * Locate the point to point interface with a given destination address.
111 */
112/*ARGSUSED*/
113struct ifaddr *
114ifa_ifwithdstaddr(addr)
202403f4 115 register struct sockaddr *addr;
ae674e00
KS
116{
117 register struct ifnet *ifp;
118 register struct ifaddr *ifa;
119
120 for (ifp = ifnet; ifp; ifp = ifp->if_next)
121 if (ifp->if_flags & IFF_POINTOPOINT)
122 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 123 if (ifa->ifa_addr->sa_family != addr->sa_family)
ae674e00 124 continue;
202403f4 125 if (equal(addr, ifa->ifa_dstaddr))
ae674e00
KS
126 return (ifa);
127 }
128 return ((struct ifaddr *)0);
129}
1bfd8df7 130
ee787340
SL
131/*
132 * Find an interface on a specific network. If many, choice
133 * is first found.
134 */
f211a0b7
MK
135struct ifaddr *
136ifa_ifwithnet(addr)
202403f4 137 struct sockaddr *addr;
ee787340
SL
138{
139 register struct ifnet *ifp;
f211a0b7 140 register struct ifaddr *ifa;
202403f4
KS
141 register char *cp, *cp2, *cp3;
142 register char *cplim;
143 u_int af = addr->sa_family;
ee787340 144
e65dcd4c
SL
145 if (af >= AF_MAX)
146 return (0);
f211a0b7
MK
147 for (ifp = ifnet; ifp; ifp = ifp->if_next)
148 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 149 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
ee787340 150 continue;
202403f4
KS
151 cp = addr->sa_data;
152 cp2 = ifa->ifa_addr->sa_data;
153 cp3 = ifa->ifa_netmask->sa_data;
154 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
155 for (; cp3 < cplim; cp3++)
156 if ((*cp++ ^ *cp2++) & *cp3)
157 break;
158 if (cp3 == cplim)
f211a0b7 159 return (ifa);
202403f4 160 }
f211a0b7 161 return ((struct ifaddr *)0);
1bfd8df7
BJ
162}
163
2612fc91 164#ifdef notdef
ee787340
SL
165/*
166 * Find an interface using a specific address family
167 */
f211a0b7
MK
168struct ifaddr *
169ifa_ifwithaf(af)
ee787340 170 register int af;
8a13b737 171{
ee787340 172 register struct ifnet *ifp;
f211a0b7 173 register struct ifaddr *ifa;
8a13b737 174
ee787340 175 for (ifp = ifnet; ifp; ifp = ifp->if_next)
f211a0b7 176 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 177 if (ifa->ifa_addr->sa_family == af)
f211a0b7
MK
178 return (ifa);
179 return ((struct ifaddr *)0);
8a13b737 180}
2612fc91 181#endif
f1b2fa5b 182
72e4f44e
SL
183/*
184 * Mark an interface down and notify protocols of
185 * the transition.
af0b24db 186 * NOTE: must be called at splnet or eqivalent.
72e4f44e
SL
187 */
188if_down(ifp)
189 register struct ifnet *ifp;
190{
f211a0b7 191 register struct ifaddr *ifa;
5248a70b 192
72e4f44e 193 ifp->if_flags &= ~IFF_UP;
f211a0b7 194 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 195 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
ce355163
MK
196 if_qflush(&ifp->if_snd);
197}
198
199/*
200 * Flush an interface queue.
201 */
202if_qflush(ifq)
203 register struct ifqueue *ifq;
204{
205 register struct mbuf *m, *n;
206
207 n = ifq->ifq_head;
208 while (m = n) {
209 n = m->m_act;
210 m_freem(m);
211 }
212 ifq->ifq_head = 0;
213 ifq->ifq_tail = 0;
214 ifq->ifq_len = 0;
72e4f44e 215}
de602274
SL
216
217/*
218 * Handle interface watchdog timer routines. Called
219 * from softclock, we decrement timers (if set) and
220 * call the appropriate interface routine on expiration.
221 */
222if_slowtimo()
223{
224 register struct ifnet *ifp;
202403f4 225 int s = splimp();
de602274 226
af0b24db
SL
227 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
228 if (ifp->if_timer == 0 || --ifp->if_timer)
229 continue;
230 if (ifp->if_watchdog)
de602274 231 (*ifp->if_watchdog)(ifp->if_unit);
af0b24db 232 }
202403f4 233 splx(s);
6e7edb25 234 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
de602274 235}
0c33c832
SL
236
237/*
a62dd253
SL
238 * Map interface name to
239 * interface structure pointer.
0c33c832 240 */
a62dd253
SL
241struct ifnet *
242ifunit(name)
243 register char *name;
0c33c832 244{
0c33c832 245 register char *cp;
a62dd253
SL
246 register struct ifnet *ifp;
247 int unit;
725d9baf
MK
248 unsigned len;
249 char *ep, c;
0c33c832 250
a62dd253 251 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
0c33c832
SL
252 if (*cp >= '0' && *cp <= '9')
253 break;
a62dd253
SL
254 if (*cp == '\0' || cp == name + IFNAMSIZ)
255 return ((struct ifnet *)0);
725d9baf
MK
256 /*
257 * Save first char of unit, and pointer to it,
258 * so we can put a null there to avoid matching
259 * initial substrings of interface names.
260 */
261 len = cp - name + 1;
262 c = *cp;
263 ep = cp;
264 for (unit = 0; *cp >= '0' && *cp <= '9'; )
265 unit = unit * 10 + *cp++ - '0';
266 *ep = 0;
0c33c832 267 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
725d9baf 268 if (bcmp(ifp->if_name, name, len))
0c33c832
SL
269 continue;
270 if (unit == ifp->if_unit)
a62dd253 271 break;
0c33c832 272 }
725d9baf 273 *ep = c;
a62dd253
SL
274 return (ifp);
275}
276
277/*
278 * Interface ioctls.
279 */
f211a0b7
MK
280ifioctl(so, cmd, data)
281 struct socket *so;
a62dd253
SL
282 int cmd;
283 caddr_t data;
284{
285 register struct ifnet *ifp;
286 register struct ifreq *ifr;
06c16dfa 287 int error;
0c33c832 288
0c33c832
SL
289 switch (cmd) {
290
a62dd253 291 case SIOCGIFCONF:
202403f4 292 case OSIOCGIFCONF:
a62dd253 293 return (ifconf(cmd, data));
0c33c832 294
799358ac 295#if defined(INET) && NETHER > 0
17fcfec5
MK
296 case SIOCSARP:
297 case SIOCDARP:
06c16dfa
KM
298 if (error = suser(u.u_cred, &u.u_acflag))
299 return (error);
17fcfec5
MK
300 /* FALL THROUGH */
301 case SIOCGARP:
202403f4 302 case OSIOCGARP:
17fcfec5
MK
303 return (arpioctl(cmd, data));
304#endif
a62dd253
SL
305 }
306 ifr = (struct ifreq *)data;
307 ifp = ifunit(ifr->ifr_name);
308 if (ifp == 0)
309 return (ENXIO);
310 switch (cmd) {
0c33c832 311
0c33c832
SL
312 case SIOCGIFFLAGS:
313 ifr->ifr_flags = ifp->if_flags;
314 break;
315
484ee22e
MK
316 case SIOCGIFMETRIC:
317 ifr->ifr_metric = ifp->if_metric;
318 break;
319
81889e84 320 case SIOCSIFFLAGS:
06c16dfa
KM
321 if (error = suser(u.u_cred, &u.u_acflag))
322 return (error);
81889e84
SL
323 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
324 int s = splimp();
325 if_down(ifp);
326 splx(s);
327 }
f211a0b7
MK
328 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
329 (ifr->ifr_flags &~ IFF_CANTCHANGE);
aad26eac
MK
330 if (ifp->if_ioctl)
331 (void) (*ifp->if_ioctl)(ifp, cmd, data);
81889e84
SL
332 break;
333
484ee22e 334 case SIOCSIFMETRIC:
06c16dfa
KM
335 if (error = suser(u.u_cred, &u.u_acflag))
336 return (error);
484ee22e
MK
337 ifp->if_metric = ifr->ifr_metric;
338 break;
339
0c33c832 340 default:
f211a0b7 341 if (so->so_proto == 0)
a62dd253 342 return (EOPNOTSUPP);
202403f4 343#ifndef COMPAT_43
f211a0b7
MK
344 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
345 cmd, data, ifp));
202403f4
KS
346#else
347 {
348 int error, ocmd = cmd;
349
350 switch (cmd) {
351
352 case SIOCSIFDSTADDR:
353 case SIOCSIFADDR:
354 case SIOCSIFBRDADDR:
355 case SIOCSIFNETMASK:
356#if BYTE_ORDER != BIG_ENDIAN
357 if (ifr->ifr_addr.sa_family == 0 &&
358 ifr->ifr_addr.sa_len < 16) {
359 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
360 ifr->ifr_addr.sa_len = 16;
361 }
362#else
363 if (ifr->ifr_addr.sa_len == 0)
364 ifr->ifr_addr.sa_len = 16;
365#endif
366 break;
367
368 case OSIOCGIFADDR:
369 cmd = SIOCGIFADDR;
370 break;
371
372 case OSIOCGIFDSTADDR:
373 cmd = SIOCGIFDSTADDR;
374 break;
375
376 case OSIOCGIFBRDADDR:
377 cmd = SIOCGIFBRDADDR;
378 break;
379
380 case OSIOCGIFNETMASK:
381 cmd = SIOCGIFNETMASK;
382 }
383 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
384 cmd, data, ifp));
385 switch (ocmd) {
386
387 case OSIOCGIFADDR:
388 case OSIOCGIFDSTADDR:
389 case OSIOCGIFBRDADDR:
390 case OSIOCGIFNETMASK:
391 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
392 }
393 return (error);
394
395 }
396#endif
0c33c832
SL
397 }
398 return (0);
399}
400
401/*
402 * Return interface configuration
403 * of system. List may be used
404 * in later ioctl's (above) to get
405 * other information.
406 */
9e9695c7 407/*ARGSUSED*/
0c33c832
SL
408ifconf(cmd, data)
409 int cmd;
410 caddr_t data;
411{
412 register struct ifconf *ifc = (struct ifconf *)data;
413 register struct ifnet *ifp = ifnet;
f211a0b7 414 register struct ifaddr *ifa;
9b956fa5
SL
415 register char *cp, *ep;
416 struct ifreq ifr, *ifrp;
0c33c832
SL
417 int space = ifc->ifc_len, error = 0;
418
9b956fa5
SL
419 ifrp = ifc->ifc_req;
420 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
0c33c832 421 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
9b956fa5
SL
422 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
423 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
0c33c832 424 ;
9b956fa5 425 *cp++ = '0' + ifp->if_unit; *cp = '\0';
f211a0b7
MK
426 if ((ifa = ifp->if_addrlist) == 0) {
427 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
428 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
429 if (error)
430 break;
431 space -= sizeof (ifr), ifrp++;
432 } else
433 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
202403f4
KS
434 register struct sockaddr *sa = ifa->ifa_addr;
435#ifdef COMPAT_43
436 if (cmd == OSIOCGIFCONF) {
437 struct osockaddr *osa =
438 (struct osockaddr *)&ifr.ifr_addr;
439 ifr.ifr_addr = *sa;
440 osa->sa_family = sa->sa_family;
441 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
442 sizeof (ifr));
443 ifrp++;
444 } else
445#endif
446 if (sa->sa_len <= sizeof(*sa)) {
447 ifr.ifr_addr = *sa;
448 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
449 sizeof (ifr));
450 ifrp++;
451 } else {
452 space -= sa->sa_len - sizeof(*sa);
453 if (space < sizeof (ifr))
454 break;
455 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
456 sizeof (ifr.ifr_name));
457 if (error == 0)
458 error = copyout((caddr_t)sa,
459 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
460 ifrp = (struct ifreq *)
461 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
462 }
f211a0b7
MK
463 if (error)
464 break;
202403f4 465 space -= sizeof (ifr);
f211a0b7 466 }
0c33c832
SL
467 }
468 ifc->ifc_len -= space;
469 return (error);
470}