BSD 4_4_Lite2 release
[unix-history] / usr / src / sys / net / if.c
CommitLineData
cb1c44c2 1/*
ad787160
C
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
cb1c44c2 4 *
ad787160
C
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
5b519e94 20 *
ad787160
C
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
fd88f5c5 33 * @(#)if.c 8.5 (Berkeley) 1/9/95
cb1c44c2 34 */
1bfd8df7 35
5548a02f
KB
36#include <sys/param.h>
37#include <sys/mbuf.h>
38#include <sys/systm.h>
39#include <sys/proc.h>
40#include <sys/socket.h>
41#include <sys/socketvar.h>
42#include <sys/protosw.h>
43#include <sys/kernel.h>
44#include <sys/ioctl.h>
a0369dcf 45
5548a02f 46#include <net/if.h>
5548a02f
KB
47#include <net/if_dl.h>
48#include <net/if_types.h>
1bfd8df7 49
1e977657 50int ifqmaxlen = IFQ_MAXLEN;
88a0c57a 51void if_slowtimo __P((void *arg));
1e977657 52
ee787340
SL
53/*
54 * Network interface utility routines.
55 *
f211a0b7
MK
56 * Routines with ifa_ifwith* names take sockaddr *'s as
57 * parameters.
ee787340 58 */
c4420f77 59void
85ce71f2
BJ
60ifinit()
61{
62 register struct ifnet *ifp;
63
64 for (ifp = ifnet; ifp; ifp = ifp->if_next)
aad26eac
MK
65 if (ifp->if_snd.ifq_maxlen == 0)
66 ifp->if_snd.ifq_maxlen = ifqmaxlen;
88a0c57a 67 if_slowtimo(0);
85ce71f2
BJ
68}
69
a62dd253 70#ifdef vax
ee787340
SL
71/*
72 * Call each interface on a Unibus reset.
73 */
c4420f77 74void
85ce71f2
BJ
75ifubareset(uban)
76 int uban;
77{
78 register struct ifnet *ifp;
79
80 for (ifp = ifnet; ifp; ifp = ifp->if_next)
8af3ca7c 81 if (ifp->if_reset)
9d6a72e7 82 (*ifp->if_reset)(ifp->if_unit, uban);
85ce71f2 83}
14fa60f2 84#endif
85ce71f2 85
02e54a34 86int if_index = 0;
d6bc9b28 87struct ifaddr **ifnet_addrs;
c4420f77 88static char *sprint_d __P((u_int, char *, int));
45081d0b 89
ee787340
SL
90/*
91 * Attach an interface to the
92 * list of "active" interfaces.
93 */
2c57a64d 94void
405c9168
BJ
95if_attach(ifp)
96 struct ifnet *ifp;
97{
02e54a34 98 unsigned socksize, ifasize;
78cafbd4 99 int namelen, unitlen, masklen, ether_output();
45081d0b 100 char workbuf[12], *unitname;
d6bc9b28 101 register struct ifnet **p = &ifnet;
02e54a34
KS
102 register struct sockaddr_dl *sdl;
103 register struct ifaddr *ifa;
d6bc9b28 104 static int if_indexlim = 8;
78cafbd4 105 extern void link_rtrequest();
405c9168 106
c4af8b24
BJ
107 while (*p)
108 p = &((*p)->if_next);
109 *p = ifp;
02e54a34 110 ifp->if_index = ++if_index;
d6bc9b28
KS
111 if (ifnet_addrs == 0 || if_index >= if_indexlim) {
112 unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
113 struct ifaddr **q = (struct ifaddr **)
114 malloc(n, M_IFADDR, M_WAITOK);
115 if (ifnet_addrs) {
116 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
117 free((caddr_t)ifnet_addrs, M_IFADDR);
118 }
119 ifnet_addrs = q;
120 }
f2eb28c8
KS
121 /*
122 * create a Link Level name for this device
123 */
45081d0b 124 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
02e54a34 125 namelen = strlen(ifp->if_name);
45081d0b 126 unitlen = strlen(unitname);
02e54a34 127#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
41290c9a
KS
128 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
129 unitlen + namelen;
130 socksize = masklen + ifp->if_addrlen;
02e54a34
KS
131#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
132 socksize = ROUNDUP(socksize);
d6bc9b28
KS
133 if (socksize < sizeof(*sdl))
134 socksize = sizeof(*sdl);
02e54a34 135 ifasize = sizeof(*ifa) + 2 * socksize;
41290c9a
KS
136 if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
137 bzero((caddr_t)ifa, ifasize);
138 sdl = (struct sockaddr_dl *)(ifa + 1);
139 sdl->sdl_len = socksize;
140 sdl->sdl_family = AF_LINK;
141 bcopy(ifp->if_name, sdl->sdl_data, namelen);
142 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
143 sdl->sdl_nlen = (namelen += unitlen);
144 sdl->sdl_index = ifp->if_index;
145 sdl->sdl_type = ifp->if_type;
146 ifnet_addrs[if_index - 1] = ifa;
147 ifa->ifa_ifp = ifp;
148 ifa->ifa_next = ifp->if_addrlist;
149 ifa->ifa_rtrequest = link_rtrequest;
150 ifp->if_addrlist = ifa;
151 ifa->ifa_addr = (struct sockaddr *)sdl;
152 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
153 ifa->ifa_netmask = (struct sockaddr *)sdl;
154 sdl->sdl_len = masklen;
155 while (namelen != 0)
156 sdl->sdl_data[--namelen] = 0xff;
157 }
158 /* XXX -- Temporary fix before changing 10 ethernet drivers */
159 if (ifp->if_output == ether_output)
160 ether_ifattach(ifp);
405c9168 161}
ee787340
SL
162/*
163 * Locate an interface based on a complete address.
164 */
4ad99bae 165/*ARGSUSED*/
f211a0b7
MK
166struct ifaddr *
167ifa_ifwithaddr(addr)
202403f4 168 register struct sockaddr *addr;
1bfd8df7
BJ
169{
170 register struct ifnet *ifp;
f211a0b7 171 register struct ifaddr *ifa;
1bfd8df7 172
ee787340 173#define equal(a1, a2) \
202403f4 174 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
f211a0b7
MK
175 for (ifp = ifnet; ifp; ifp = ifp->if_next)
176 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 177 if (ifa->ifa_addr->sa_family != addr->sa_family)
ee787340 178 continue;
202403f4 179 if (equal(addr, ifa->ifa_addr))
f211a0b7 180 return (ifa);
d6bc9b28
KS
181 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
182 equal(ifa->ifa_broadaddr, addr))
f211a0b7 183 return (ifa);
ee787340 184 }
f211a0b7 185 return ((struct ifaddr *)0);
1bfd8df7 186}
ae674e00
KS
187/*
188 * Locate the point to point interface with a given destination address.
189 */
190/*ARGSUSED*/
191struct ifaddr *
192ifa_ifwithdstaddr(addr)
202403f4 193 register struct sockaddr *addr;
ae674e00
KS
194{
195 register struct ifnet *ifp;
196 register struct ifaddr *ifa;
197
198 for (ifp = ifnet; ifp; ifp = ifp->if_next)
199 if (ifp->if_flags & IFF_POINTOPOINT)
200 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
d9e30b4d
KS
201 if (ifa->ifa_addr->sa_family != addr->sa_family ||
202 ifa->ifa_dstaddr == NULL)
ae674e00 203 continue;
202403f4 204 if (equal(addr, ifa->ifa_dstaddr))
ae674e00
KS
205 return (ifa);
206 }
207 return ((struct ifaddr *)0);
208}
1bfd8df7 209
ee787340
SL
210/*
211 * Find an interface on a specific network. If many, choice
c1b74e05 212 * is most specific found.
ee787340 213 */
f211a0b7
MK
214struct ifaddr *
215ifa_ifwithnet(addr)
202403f4 216 struct sockaddr *addr;
ee787340
SL
217{
218 register struct ifnet *ifp;
f211a0b7 219 register struct ifaddr *ifa;
c1b74e05 220 struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
202403f4 221 u_int af = addr->sa_family;
c1b74e05 222 char *addr_data = addr->sa_data, *cplim;
ee787340 223
d6bc9b28
KS
224 if (af == AF_LINK) {
225 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
226 if (sdl->sdl_index && sdl->sdl_index <= if_index)
227 return (ifnet_addrs[sdl->sdl_index - 1]);
228 }
f211a0b7
MK
229 for (ifp = ifnet; ifp; ifp = ifp->if_next)
230 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
d6bc9b28 231 register char *cp, *cp2, *cp3;
c1b74e05 232
202403f4 233 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
c1b74e05
KS
234 next: continue;
235 cp = addr_data;
202403f4
KS
236 cp2 = ifa->ifa_addr->sa_data;
237 cp3 = ifa->ifa_netmask->sa_data;
238 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
c1b74e05
KS
239 while (cp3 < cplim)
240 if ((*cp++ ^ *cp2++) & *cp3++)
241 goto next;
242 if (ifa_maybe == 0 ||
c4420f77
KB
243 rn_refines((caddr_t)ifa->ifa_netmask,
244 (caddr_t)ifa_maybe->ifa_netmask))
c1b74e05 245 ifa_maybe = ifa;
202403f4 246 }
c1b74e05 247 return (ifa_maybe);
1bfd8df7
BJ
248}
249
ee787340
SL
250/*
251 * Find an interface using a specific address family
252 */
f211a0b7
MK
253struct ifaddr *
254ifa_ifwithaf(af)
ee787340 255 register int af;
8a13b737 256{
ee787340 257 register struct ifnet *ifp;
f211a0b7 258 register struct ifaddr *ifa;
8a13b737 259
ee787340 260 for (ifp = ifnet; ifp; ifp = ifp->if_next)
f211a0b7 261 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 262 if (ifa->ifa_addr->sa_family == af)
f211a0b7
MK
263 return (ifa);
264 return ((struct ifaddr *)0);
8a13b737 265}
f2eb28c8 266
d6bc9b28
KS
267/*
268 * Find an interface address specific to an interface best matching
269 * a given address.
270 */
271struct ifaddr *
272ifaof_ifpforaddr(addr, ifp)
273 struct sockaddr *addr;
274 register struct ifnet *ifp;
275{
276 register struct ifaddr *ifa;
277 register char *cp, *cp2, *cp3;
278 register char *cplim;
279 struct ifaddr *ifa_maybe = 0;
280 u_int af = addr->sa_family;
281
282 if (af >= AF_MAX)
283 return (0);
284 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
285 if (ifa->ifa_addr->sa_family != af)
286 continue;
287 ifa_maybe = ifa;
288 if (ifa->ifa_netmask == 0) {
289 if (equal(addr, ifa->ifa_addr) ||
290 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
291 return (ifa);
292 continue;
293 }
294 cp = addr->sa_data;
295 cp2 = ifa->ifa_addr->sa_data;
296 cp3 = ifa->ifa_netmask->sa_data;
297 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
298 for (; cp3 < cplim; cp3++)
299 if ((*cp++ ^ *cp2++) & *cp3)
300 break;
301 if (cp3 == cplim)
302 return (ifa);
303 }
304 return (ifa_maybe);
305}
5548a02f
KB
306
307#include <net/route.h>
308
f2eb28c8
KS
309/*
310 * Default action when installing a route with a Link Level gateway.
311 * Lookup an appropriate real ifa to point to.
312 * This should be moved to /sys/net/link.c eventually.
313 */
78cafbd4 314void
f2eb28c8 315link_rtrequest(cmd, rt, sa)
2c57a64d
CT
316 int cmd;
317 register struct rtentry *rt;
318 struct sockaddr *sa;
f2eb28c8
KS
319{
320 register struct ifaddr *ifa;
321 struct sockaddr *dst;
67e8af50 322 struct ifnet *ifp;
f2eb28c8
KS
323
324 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
325 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
326 return;
d6bc9b28 327 if (ifa = ifaof_ifpforaddr(dst, ifp)) {
60876470 328 IFAFREE(rt->rt_ifa);
f2eb28c8 329 rt->rt_ifa = ifa;
60876470 330 ifa->ifa_refcnt++;
f2eb28c8
KS
331 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
332 ifa->ifa_rtrequest(cmd, rt, sa);
d6bc9b28 333 }
f2eb28c8 334}
f1b2fa5b 335
72e4f44e
SL
336/*
337 * Mark an interface down and notify protocols of
338 * the transition.
af0b24db 339 * NOTE: must be called at splnet or eqivalent.
72e4f44e 340 */
c4420f77 341void
72e4f44e
SL
342if_down(ifp)
343 register struct ifnet *ifp;
344{
f211a0b7 345 register struct ifaddr *ifa;
5248a70b 346
72e4f44e 347 ifp->if_flags &= ~IFF_UP;
f211a0b7 348 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 349 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
ce355163 350 if_qflush(&ifp->if_snd);
41290c9a
KS
351 rt_ifmsg(ifp);
352}
353
354/*
355 * Mark an interface up and notify protocols of
356 * the transition.
357 * NOTE: must be called at splnet or eqivalent.
358 */
c4420f77 359void
41290c9a
KS
360if_up(ifp)
361 register struct ifnet *ifp;
362{
363 register struct ifaddr *ifa;
364
365 ifp->if_flags |= IFF_UP;
366#ifdef notyet
367 /* this has no effect on IP, and will kill all iso connections XXX */
368 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
369 pfctlinput(PRC_IFUP, ifa->ifa_addr);
1524bcb8 370#endif
41290c9a 371 rt_ifmsg(ifp);
ce355163
MK
372}
373
374/*
375 * Flush an interface queue.
376 */
c4420f77 377void
ce355163
MK
378if_qflush(ifq)
379 register struct ifqueue *ifq;
380{
381 register struct mbuf *m, *n;
382
383 n = ifq->ifq_head;
384 while (m = n) {
385 n = m->m_act;
386 m_freem(m);
387 }
388 ifq->ifq_head = 0;
389 ifq->ifq_tail = 0;
390 ifq->ifq_len = 0;
72e4f44e 391}
de602274
SL
392
393/*
394 * Handle interface watchdog timer routines. Called
395 * from softclock, we decrement timers (if set) and
396 * call the appropriate interface routine on expiration.
397 */
88a0c57a
CT
398void
399if_slowtimo(arg)
400 void *arg;
de602274
SL
401{
402 register struct ifnet *ifp;
202403f4 403 int s = splimp();
de602274 404
af0b24db
SL
405 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
406 if (ifp->if_timer == 0 || --ifp->if_timer)
407 continue;
408 if (ifp->if_watchdog)
de602274 409 (*ifp->if_watchdog)(ifp->if_unit);
af0b24db 410 }
202403f4 411 splx(s);
88a0c57a 412 timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
de602274 413}
0c33c832
SL
414
415/*
a62dd253
SL
416 * Map interface name to
417 * interface structure pointer.
0c33c832 418 */
a62dd253
SL
419struct ifnet *
420ifunit(name)
421 register char *name;
0c33c832 422{
0c33c832 423 register char *cp;
a62dd253
SL
424 register struct ifnet *ifp;
425 int unit;
725d9baf
MK
426 unsigned len;
427 char *ep, c;
0c33c832 428
a62dd253 429 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
0c33c832
SL
430 if (*cp >= '0' && *cp <= '9')
431 break;
a62dd253
SL
432 if (*cp == '\0' || cp == name + IFNAMSIZ)
433 return ((struct ifnet *)0);
725d9baf
MK
434 /*
435 * Save first char of unit, and pointer to it,
436 * so we can put a null there to avoid matching
437 * initial substrings of interface names.
438 */
439 len = cp - name + 1;
440 c = *cp;
441 ep = cp;
442 for (unit = 0; *cp >= '0' && *cp <= '9'; )
443 unit = unit * 10 + *cp++ - '0';
444 *ep = 0;
0c33c832 445 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
725d9baf 446 if (bcmp(ifp->if_name, name, len))
0c33c832
SL
447 continue;
448 if (unit == ifp->if_unit)
a62dd253 449 break;
0c33c832 450 }
725d9baf 451 *ep = c;
a62dd253
SL
452 return (ifp);
453}
454
455/*
456 * Interface ioctls.
457 */
c4420f77 458int
45081d0b 459ifioctl(so, cmd, data, p)
f211a0b7 460 struct socket *so;
47a652b3 461 u_long cmd;
a62dd253 462 caddr_t data;
45081d0b 463 struct proc *p;
a62dd253
SL
464{
465 register struct ifnet *ifp;
466 register struct ifreq *ifr;
06c16dfa 467 int error;
0c33c832 468
0c33c832
SL
469 switch (cmd) {
470
a62dd253 471 case SIOCGIFCONF:
202403f4 472 case OSIOCGIFCONF:
a62dd253 473 return (ifconf(cmd, data));
a62dd253
SL
474 }
475 ifr = (struct ifreq *)data;
476 ifp = ifunit(ifr->ifr_name);
477 if (ifp == 0)
478 return (ENXIO);
479 switch (cmd) {
0c33c832 480
0c33c832
SL
481 case SIOCGIFFLAGS:
482 ifr->ifr_flags = ifp->if_flags;
483 break;
484
484ee22e
MK
485 case SIOCGIFMETRIC:
486 ifr->ifr_metric = ifp->if_metric;
487 break;
488
81889e84 489 case SIOCSIFFLAGS:
45081d0b 490 if (error = suser(p->p_ucred, &p->p_acflag))
06c16dfa 491 return (error);
81889e84
SL
492 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
493 int s = splimp();
494 if_down(ifp);
495 splx(s);
496 }
41290c9a
KS
497 if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
498 int s = splimp();
499 if_up(ifp);
500 splx(s);
501 }
f211a0b7
MK
502 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
503 (ifr->ifr_flags &~ IFF_CANTCHANGE);
aad26eac
MK
504 if (ifp->if_ioctl)
505 (void) (*ifp->if_ioctl)(ifp, cmd, data);
81889e84
SL
506 break;
507
484ee22e 508 case SIOCSIFMETRIC:
45081d0b 509 if (error = suser(p->p_ucred, &p->p_acflag))
06c16dfa 510 return (error);
484ee22e
MK
511 ifp->if_metric = ifr->ifr_metric;
512 break;
513
78cafbd4
KS
514 case SIOCADDMULTI:
515 case SIOCDELMULTI:
516 if (error = suser(p->p_ucred, &p->p_acflag))
517 return (error);
93aa870c 518 if (ifp->if_ioctl == NULL)
78cafbd4
KS
519 return (EOPNOTSUPP);
520 return ((*ifp->if_ioctl)(ifp, cmd, data));
78cafbd4 521
0c33c832 522 default:
f211a0b7 523 if (so->so_proto == 0)
a62dd253 524 return (EOPNOTSUPP);
202403f4 525#ifndef COMPAT_43
f211a0b7
MK
526 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
527 cmd, data, ifp));
202403f4
KS
528#else
529 {
35c34494 530 int ocmd = cmd;
202403f4
KS
531
532 switch (cmd) {
533
534 case SIOCSIFDSTADDR:
535 case SIOCSIFADDR:
536 case SIOCSIFBRDADDR:
537 case SIOCSIFNETMASK:
538#if BYTE_ORDER != BIG_ENDIAN
539 if (ifr->ifr_addr.sa_family == 0 &&
540 ifr->ifr_addr.sa_len < 16) {
541 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
542 ifr->ifr_addr.sa_len = 16;
543 }
544#else
545 if (ifr->ifr_addr.sa_len == 0)
546 ifr->ifr_addr.sa_len = 16;
547#endif
548 break;
549
550 case OSIOCGIFADDR:
551 cmd = SIOCGIFADDR;
552 break;
553
554 case OSIOCGIFDSTADDR:
555 cmd = SIOCGIFDSTADDR;
556 break;
557
558 case OSIOCGIFBRDADDR:
559 cmd = SIOCGIFBRDADDR;
560 break;
561
562 case OSIOCGIFNETMASK:
563 cmd = SIOCGIFNETMASK;
564 }
565 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
566 cmd, data, ifp));
567 switch (ocmd) {
568
569 case OSIOCGIFADDR:
570 case OSIOCGIFDSTADDR:
571 case OSIOCGIFBRDADDR:
572 case OSIOCGIFNETMASK:
573 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
574 }
575 return (error);
576
577 }
578#endif
0c33c832
SL
579 }
580 return (0);
581}
582
583/*
584 * Return interface configuration
585 * of system. List may be used
586 * in later ioctl's (above) to get
587 * other information.
588 */
9e9695c7 589/*ARGSUSED*/
c4420f77 590int
0c33c832
SL
591ifconf(cmd, data)
592 int cmd;
593 caddr_t data;
594{
595 register struct ifconf *ifc = (struct ifconf *)data;
596 register struct ifnet *ifp = ifnet;
f211a0b7 597 register struct ifaddr *ifa;
9b956fa5
SL
598 register char *cp, *ep;
599 struct ifreq ifr, *ifrp;
0c33c832
SL
600 int space = ifc->ifc_len, error = 0;
601
9b956fa5
SL
602 ifrp = ifc->ifc_req;
603 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
0c33c832 604 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
ad787160 605 strncpy(ifr.ifr_name, ifp->if_name, sizeof (ifr.ifr_name) - 2);
9b956fa5 606 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
a6e3920d 607 continue;
9b956fa5 608 *cp++ = '0' + ifp->if_unit; *cp = '\0';
f211a0b7
MK
609 if ((ifa = ifp->if_addrlist) == 0) {
610 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
ad787160
C
611 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
612 sizeof (ifr));
f211a0b7
MK
613 if (error)
614 break;
615 space -= sizeof (ifr), ifrp++;
616 } else
617 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
202403f4
KS
618 register struct sockaddr *sa = ifa->ifa_addr;
619#ifdef COMPAT_43
620 if (cmd == OSIOCGIFCONF) {
621 struct osockaddr *osa =
622 (struct osockaddr *)&ifr.ifr_addr;
623 ifr.ifr_addr = *sa;
624 osa->sa_family = sa->sa_family;
625 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
626 sizeof (ifr));
627 ifrp++;
628 } else
629#endif
630 if (sa->sa_len <= sizeof(*sa)) {
631 ifr.ifr_addr = *sa;
632 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
633 sizeof (ifr));
634 ifrp++;
635 } else {
636 space -= sa->sa_len - sizeof(*sa);
637 if (space < sizeof (ifr))
638 break;
639 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
640 sizeof (ifr.ifr_name));
641 if (error == 0)
642 error = copyout((caddr_t)sa,
643 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
644 ifrp = (struct ifreq *)
645 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
646 }
f211a0b7
MK
647 if (error)
648 break;
202403f4 649 space -= sizeof (ifr);
f211a0b7 650 }
0c33c832
SL
651 }
652 ifc->ifc_len -= space;
653 return (error);
654}
02e54a34 655
45081d0b
MK
656static char *
657sprint_d(n, buf, buflen)
658 u_int n;
659 char *buf;
660 int buflen;
02e54a34 661{
45081d0b
MK
662 register char *cp = buf + buflen - 1;
663
664 *cp = 0;
02e54a34 665 do {
45081d0b
MK
666 cp--;
667 *cp = "0123456789"[n % 10];
668 n /= 10;
669 } while (n != 0);
670 return (cp);
02e54a34 671}