xref: /netbsd-src/sys/net/if.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
1 /*
2  * Copyright (c) 1980, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
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.
20  *
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  *
33  *	from: @(#)if.c	7.14 (Berkeley) 4/20/91
34  *	$Id: if.c,v 1.6 1993/08/27 10:26:08 mycroft Exp $
35  */
36 
37 #include "param.h"
38 #include "mbuf.h"
39 #include "systm.h"
40 #include "socket.h"
41 #include "socketvar.h"
42 #include "protosw.h"
43 #include "proc.h"
44 #include "kernel.h"
45 #include "ioctl.h"
46 
47 #include "if.h"
48 #include "af.h"
49 #include "if_dl.h"
50 #include "if_types.h"
51 
52 #include "ether.h"
53 
54 int	ifqmaxlen = IFQ_MAXLEN;
55 
56 void if_slowtimo(caddr_t);
57 
58 /*
59  * Network interface utility routines.
60  *
61  * Routines with ifa_ifwith* names take sockaddr *'s as
62  * parameters.
63  */
64 
65 void
66 ifinit()
67 {
68 	register struct ifnet *ifp;
69 
70 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
71 		if (ifp->if_snd.ifq_maxlen == 0)
72 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
73 	if_slowtimo(NULL);
74 }
75 
76 #ifdef vax
77 /*
78  * Call each interface on a Unibus reset.
79  */
80 ifubareset(uban)
81 	int uban;
82 {
83 	register struct ifnet *ifp;
84 
85 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
86 		if (ifp->if_reset)
87 			(*ifp->if_reset)(ifp->if_unit, uban);
88 }
89 #endif
90 
91 int if_index = 0;
92 struct ifaddr **ifnet_addrs;
93 static char *sprint_d();
94 
95 /*
96  * Attach an interface to the
97  * list of "active" interfaces.
98  */
99 if_attach(ifp)
100 	struct ifnet *ifp;
101 {
102 	unsigned socksize, ifasize;
103 	int namelen, unitlen;
104 	char workbuf[12], *unitname;
105 	register struct ifnet **p = &ifnet;
106 	register struct sockaddr_dl *sdl;
107 	register struct ifaddr *ifa;
108 	static int if_indexlim = 8;
109 	extern link_rtrequest(), ether_output();
110 
111 	while (*p)
112 		p = &((*p)->if_next);
113 	*p = ifp;
114 	ifp->if_index = ++if_index;
115 	if (ifnet_addrs == 0 || if_index >= if_indexlim) {
116 		unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
117 		struct ifaddr **q = (struct ifaddr **)
118 					malloc(n, M_IFADDR, M_WAITOK);
119 		if (ifnet_addrs) {
120 			bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
121 			free((caddr_t)ifnet_addrs, M_IFADDR);
122 		}
123 		ifnet_addrs = q;
124 	}
125 #if defined(INET) && NETHER > 0
126 	/* XXX -- Temporary fix before changing 10 ethernet drivers */
127 	if (ifp->if_output == ether_output) {
128 		ifp->if_type = IFT_ETHER;
129 		ifp->if_addrlen = 6;
130 		ifp->if_hdrlen = 14;
131 	}
132 #endif
133 	/*
134 	 * create a Link Level name for this device
135 	 */
136 	unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
137 	namelen = strlen(ifp->if_name);
138 	unitlen = strlen(unitname);
139 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
140 	socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
141 			       unitlen + namelen + ifp->if_addrlen;
142 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
143 	socksize = ROUNDUP(socksize);
144 	if (socksize < sizeof(*sdl))
145 		socksize = sizeof(*sdl);
146 	ifasize = sizeof(*ifa) + 2 * socksize;
147 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
148 	if (ifa == 0)
149 		return;
150 	ifnet_addrs[if_index - 1] = ifa;
151 	bzero((caddr_t)ifa, ifasize);
152 	sdl = (struct sockaddr_dl *)(ifa + 1);
153 	ifa->ifa_addr = (struct sockaddr *)sdl;
154 	ifa->ifa_ifp = ifp;
155 	sdl->sdl_len = socksize;
156 	sdl->sdl_family = AF_LINK;
157 	bcopy(ifp->if_name, sdl->sdl_data, namelen);
158 	bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
159 	sdl->sdl_nlen = (namelen += unitlen);
160 	sdl->sdl_index = ifp->if_index;
161 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
162 	ifa->ifa_netmask = (struct sockaddr *)sdl;
163 	sdl->sdl_len = socksize - ifp->if_addrlen;
164 	while (namelen != 0)
165 		sdl->sdl_data[--namelen] = 0xff;
166 	ifa->ifa_next = ifp->if_addrlist;
167 	ifa->ifa_rtrequest = link_rtrequest;
168 	ifp->if_addrlist = ifa;
169 }
170 /*
171  * Locate an interface based on a complete address.
172  */
173 /*ARGSUSED*/
174 struct ifaddr *
175 ifa_ifwithaddr(addr)
176 	register struct sockaddr *addr;
177 {
178 	register struct ifnet *ifp;
179 	register struct ifaddr *ifa;
180 
181 #define	equal(a1, a2) \
182   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
183 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
184 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
185 		if (ifa->ifa_addr->sa_family != addr->sa_family)
186 			continue;
187 		if (equal(addr, ifa->ifa_addr))
188 			return (ifa);
189 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
190 		    equal(ifa->ifa_broadaddr, addr))
191 			return (ifa);
192 	}
193 	return ((struct ifaddr *)0);
194 }
195 /*
196  * Locate the point to point interface with a given destination address.
197  */
198 /*ARGSUSED*/
199 struct ifaddr *
200 ifa_ifwithdstaddr(addr)
201 	register struct sockaddr *addr;
202 {
203 	register struct ifnet *ifp;
204 	register struct ifaddr *ifa;
205 
206 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
207 	    if (ifp->if_flags & IFF_POINTOPOINT)
208 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
209 			if (ifa->ifa_addr->sa_family != addr->sa_family)
210 				continue;
211 			if (equal(addr, ifa->ifa_dstaddr))
212 				return (ifa);
213 	}
214 	return ((struct ifaddr *)0);
215 }
216 
217 /*
218  * Find an interface on a specific network.  If many, choice
219  * is first found.
220  */
221 struct ifaddr *
222 ifa_ifwithnet(addr)
223 	struct sockaddr *addr;
224 {
225 	register struct ifnet *ifp;
226 	register struct ifaddr *ifa;
227 	u_int af = addr->sa_family;
228 
229 	if (af >= AF_MAX)
230 		return (0);
231 	if (af == AF_LINK) {
232 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
233 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
234 		return (ifnet_addrs[sdl->sdl_index - 1]);
235 	}
236 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
237 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
238 		register char *cp, *cp2, *cp3;
239 		register char *cplim;
240 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
241 			continue;
242 		cp = addr->sa_data;
243 		cp2 = ifa->ifa_addr->sa_data;
244 		cp3 = ifa->ifa_netmask->sa_data;
245 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
246 		for (; cp3 < cplim; cp3++)
247 			if ((*cp++ ^ *cp2++) & *cp3)
248 				break;
249 		if (cp3 == cplim)
250 			return (ifa);
251 	    }
252 	return ((struct ifaddr *)0);
253 }
254 
255 /*
256  * Find an interface using a specific address family
257  */
258 struct ifaddr *
259 ifa_ifwithaf(af)
260 	register int af;
261 {
262 	register struct ifnet *ifp;
263 	register struct ifaddr *ifa;
264 
265 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
266 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
267 		if (ifa->ifa_addr->sa_family == af)
268 			return (ifa);
269 	return ((struct ifaddr *)0);
270 }
271 
272 /*
273  * Find an interface address specific to an interface best matching
274  * a given address.
275  */
276 struct ifaddr *
277 ifaof_ifpforaddr(addr, ifp)
278 	struct sockaddr *addr;
279 	register struct ifnet *ifp;
280 {
281 	register struct ifaddr *ifa;
282 	register char *cp, *cp2, *cp3;
283 	register char *cplim;
284 	struct ifaddr *ifa_maybe = 0;
285 	u_int af = addr->sa_family;
286 
287 	if (af >= AF_MAX)
288 		return (0);
289 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
290 		if (ifa->ifa_addr->sa_family != af)
291 			continue;
292 		ifa_maybe = ifa;
293 		if (ifa->ifa_netmask == 0) {
294 			if (equal(addr, ifa->ifa_addr) ||
295 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
296 				return (ifa);
297 			continue;
298 		}
299 		cp = addr->sa_data;
300 		cp2 = ifa->ifa_addr->sa_data;
301 		cp3 = ifa->ifa_netmask->sa_data;
302 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
303 		for (; cp3 < cplim; cp3++)
304 			if ((*cp++ ^ *cp2++) & *cp3)
305 				break;
306 		if (cp3 == cplim)
307 			return (ifa);
308 	}
309 	return (ifa_maybe);
310 }
311 #include "route.h"
312 /*
313  * Default action when installing a route with a Link Level gateway.
314  * Lookup an appropriate real ifa to point to.
315  * This should be moved to /sys/net/link.c eventually.
316  */
317 link_rtrequest(cmd, rt, sa)
318 register struct rtentry *rt;
319 struct sockaddr *sa;
320 {
321 	register struct ifaddr *ifa;
322 	struct sockaddr *dst;
323 	struct ifnet *ifp, *oldifnet = ifnet;
324 
325 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
326 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
327 		return;
328 	if (ifa = ifaof_ifpforaddr(dst, ifp)) {
329 		rt->rt_ifa = ifa;
330 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
331 			ifa->ifa_rtrequest(cmd, rt, sa);
332 	}
333 }
334 
335 /*
336  * Mark an interface down and notify protocols of
337  * the transition.
338  * NOTE: must be called at splnet or eqivalent.
339  */
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; ifa; ifa = ifa->ifa_next)
347 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
348 	if_qflush(&ifp->if_snd);
349 }
350 
351 /*
352  * Flush an interface queue.
353  */
354 if_qflush(ifq)
355 	register struct ifqueue *ifq;
356 {
357 	register struct mbuf *m, *n;
358 
359 	n = ifq->ifq_head;
360 	while (m = n) {
361 		n = m->m_act;
362 		m_freem(m);
363 	}
364 	ifq->ifq_head = 0;
365 	ifq->ifq_tail = 0;
366 	ifq->ifq_len = 0;
367 }
368 
369 /*
370  * Handle interface watchdog timer routines.  Called
371  * from softclock, we decrement timers (if set) and
372  * call the appropriate interface routine on expiration.
373  */
374 /* ARGSUSED */
375 void
376 if_slowtimo(caddr_t arg)
377 {
378 	register struct ifnet *ifp;
379 	int s = splimp();
380 
381 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
382 		if (ifp->if_timer == 0 || --ifp->if_timer)
383 			continue;
384 		if (ifp->if_watchdog)
385 			(*ifp->if_watchdog)(ifp->if_unit);
386 	}
387 	splx(s);
388 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
389 }
390 
391 /*
392  * Map interface name to
393  * interface structure pointer.
394  */
395 struct ifnet *
396 ifunit(name)
397 	register char *name;
398 {
399 	register char *cp;
400 	register struct ifnet *ifp;
401 	int unit;
402 	unsigned len;
403 	char *ep, c;
404 
405 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
406 		if (*cp >= '0' && *cp <= '9')
407 			break;
408 	if (*cp == '\0' || cp == name + IFNAMSIZ)
409 		return ((struct ifnet *)0);
410 	/*
411 	 * Save first char of unit, and pointer to it,
412 	 * so we can put a null there to avoid matching
413 	 * initial substrings of interface names.
414 	 */
415 	len = cp - name + 1;
416 	c = *cp;
417 	ep = cp;
418 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
419 		unit = unit * 10 + *cp++ - '0';
420 	*ep = 0;
421 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
422 		if (bcmp(ifp->if_name, name, len))
423 			continue;
424 		if (unit == ifp->if_unit)
425 			break;
426 	}
427 	*ep = c;
428 	return (ifp);
429 }
430 
431 /*
432  * Interface ioctls.
433  */
434 ifioctl(so, cmd, data, p)
435 	struct socket *so;
436 	int cmd;
437 	caddr_t data;
438 	struct proc *p;
439 {
440 	register struct ifnet *ifp;
441 	register struct ifreq *ifr;
442 	int error;
443 
444 	switch (cmd) {
445 
446 	case SIOCGIFCONF:
447 	case OSIOCGIFCONF:
448 		return (ifconf(cmd, data));
449 
450 #if defined(INET) && NETHER > 0
451 	case SIOCSARP:
452 	case SIOCDARP:
453 		if (error = suser(p->p_ucred, &p->p_acflag))
454 			return (error);
455 		/* FALL THROUGH */
456 	case SIOCGARP:
457 	case OSIOCGARP:
458 		return (arpioctl(cmd, data));
459 #endif
460 	}
461 	ifr = (struct ifreq *)data;
462 	ifp = ifunit(ifr->ifr_name);
463 	if (ifp == 0)
464 		return (ENXIO);
465 	switch (cmd) {
466 
467 	case SIOCGIFFLAGS:
468 		ifr->ifr_flags = ifp->if_flags;
469 		break;
470 
471 	case SIOCGIFMETRIC:
472 		ifr->ifr_metric = ifp->if_metric;
473 		break;
474 
475 	case SIOCSIFFLAGS:
476 		if (error = suser(p->p_ucred, &p->p_acflag))
477 			return (error);
478 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
479 			int s = splimp();
480 			if_down(ifp);
481 			splx(s);
482 		}
483 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
484 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
485 		if (ifp->if_ioctl)
486 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
487 		break;
488 
489 	case SIOCSIFMETRIC:
490 		if (error = suser(p->p_ucred, &p->p_acflag))
491 			return (error);
492 		ifp->if_metric = ifr->ifr_metric;
493 		break;
494 
495 	case SIOCSIFMTU:
496 	case SIOCGIFMTU:
497 	case SIOCSIFASYNCMAP:
498 	case SIOCGIFASYNCMAP:
499 		if (!ifp->if_ioctl)
500 			return (EOPNOTSUPP);
501 		return ((*ifp->if_ioctl)(ifp, cmd, data));
502 		break;
503 
504 	default:
505 		if (so->so_proto == 0)
506 			return (EOPNOTSUPP);
507 #ifndef COMPAT_43
508 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
509 			cmd, data, ifp));
510 #else
511 	    {
512 		int ocmd = cmd;
513 
514 		switch (cmd) {
515 
516 		case SIOCSIFDSTADDR:
517 		case SIOCSIFADDR:
518 		case SIOCSIFBRDADDR:
519 		case SIOCSIFNETMASK:
520 #if BYTE_ORDER != BIG_ENDIAN
521 			if (ifr->ifr_addr.sa_family == 0 &&
522 			    ifr->ifr_addr.sa_len < 16) {
523 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
524 				ifr->ifr_addr.sa_len = 16;
525 			}
526 #else
527 			if (ifr->ifr_addr.sa_len == 0)
528 				ifr->ifr_addr.sa_len = 16;
529 #endif
530 			break;
531 
532 		case OSIOCGIFADDR:
533 			cmd = SIOCGIFADDR;
534 			break;
535 
536 		case OSIOCGIFDSTADDR:
537 			cmd = SIOCGIFDSTADDR;
538 			break;
539 
540 		case OSIOCGIFBRDADDR:
541 			cmd = SIOCGIFBRDADDR;
542 			break;
543 
544 		case OSIOCGIFNETMASK:
545 			cmd = SIOCGIFNETMASK;
546 		}
547 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
548 							    cmd, data, ifp));
549 		switch (ocmd) {
550 
551 		case OSIOCGIFADDR:
552 		case OSIOCGIFDSTADDR:
553 		case OSIOCGIFBRDADDR:
554 		case OSIOCGIFNETMASK:
555 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
556 		}
557 		return (error);
558 
559 	    }
560 #endif
561 	}
562 	return (0);
563 }
564 
565 /*
566  * Return interface configuration
567  * of system.  List may be used
568  * in later ioctl's (above) to get
569  * other information.
570  */
571 /*ARGSUSED*/
572 ifconf(cmd, data)
573 	int cmd;
574 	caddr_t data;
575 {
576 	register struct ifconf *ifc = (struct ifconf *)data;
577 	register struct ifnet *ifp = ifnet;
578 	register struct ifaddr *ifa;
579 	register char *cp, *ep;
580 	struct ifreq ifr, *ifrp;
581 	int space = ifc->ifc_len, error = 0;
582 
583 	ifrp = ifc->ifc_req;
584 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
585 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
586 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
587 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
588 			;
589 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
590 		if ((ifa = ifp->if_addrlist) == 0) {
591 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
592 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
593 			if (error)
594 				break;
595 			space -= sizeof (ifr), ifrp++;
596 		} else
597 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
598 			register struct sockaddr *sa = ifa->ifa_addr;
599 #ifdef COMPAT_43
600 			if (cmd == OSIOCGIFCONF) {
601 				struct osockaddr *osa =
602 					 (struct osockaddr *)&ifr.ifr_addr;
603 				ifr.ifr_addr = *sa;
604 				osa->sa_family = sa->sa_family;
605 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
606 						sizeof (ifr));
607 				ifrp++;
608 			} else
609 #endif
610 			if (sa->sa_len <= sizeof(*sa)) {
611 				ifr.ifr_addr = *sa;
612 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
613 						sizeof (ifr));
614 				ifrp++;
615 			} else {
616 				space -= sa->sa_len - sizeof(*sa);
617 				if (space < sizeof (ifr))
618 					break;
619 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
620 						sizeof (ifr.ifr_name));
621 				if (error == 0)
622 				    error = copyout((caddr_t)sa,
623 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
624 				ifrp = (struct ifreq *)
625 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
626 			}
627 			if (error)
628 				break;
629 			space -= sizeof (ifr);
630 		}
631 	}
632 	ifc->ifc_len -= space;
633 	return (error);
634 }
635 
636 static char *
637 sprint_d(n, buf, buflen)
638 	u_int n;
639 	char *buf;
640 	int buflen;
641 {
642 	register char *cp = buf + buflen - 1;
643 
644 	*cp = 0;
645 	do {
646 		cp--;
647 		*cp = "0123456789"[n % 10];
648 		n /= 10;
649 	} while (n != 0);
650 	return (cp);
651 }
652