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