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