2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * Copyright (c) 1980, 1986 Regents of the University of California.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * @(#)if.c 7.14 (Berkeley) 4/20/91
60 #include <dos/rdargs.h>
61 #include <net/route.h>
63 #include <sys/malloc.h>
65 #include <sys/systm.h>
66 #include <sys/socket.h>
67 #include <sys/socketvar.h>
68 #include <sys/protosw.h>
69 #include <sys/kernel.h>
70 #include <sys/sockio.h>
71 #include <sys/synch.h>
74 #include <net/if_dl.h>
75 #include <netinet/in.h> /* for findid */
78 void if_attach(struct ifnet
*);
79 struct ifaddr
*ifa_ifwithaddr(register struct sockaddr
*);
80 struct ifaddr
*ifa_ifwithdstaddr(register struct sockaddr
*);
81 struct ifaddr
*ifa_ifwithnet(struct sockaddr
*);
82 struct ifaddr
*ifa_ifwithaf(register int );
83 struct ifaddr
*ifaof_ifpforaddr(struct sockaddr
*, register struct ifnet
*);
84 void link_rtrequest(int, struct rtentry
*, struct sockaddr
*);
85 void if_down(register struct ifnet
*);
86 void if_qflush(register struct ifqueue
*);
87 void if_slowtimo(void);
88 struct ifnet
*ifunit(register char *);
89 int ifioctl(struct socket
*, long, caddr_t
);
90 int ifconf(int, caddr_t
);
92 /* Compatibility with AmiTCP/IP 2 */
93 #include <sys/a_ioctl.h>
95 struct ifnet
*aifunit(register char *name
);
96 int aifconf(int cmd
, caddr_t data
);
98 #include <kern/uipc_domain_protos.h>
100 static char *sprint_d(u_int n
, char *buf
, int buflen
);
101 int ifqmaxlen
= IFQ_MAXLEN
;
103 struct ifnet
*ifnet
= NULL
;
106 * Network interface utility routines.
108 * Routines with ifa_ifwith* names take sockaddr *'s as
114 register struct ifnet
*ifp
;
116 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
117 if (ifp
->if_snd
.ifq_maxlen
== 0)
118 ifp
->if_snd
.ifq_maxlen
= ifqmaxlen
;
124 * Call each interface on a Unibus reset.
129 register struct ifnet
*ifp
;
131 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
133 (*ifp
->if_reset
)(ifp
->if_unit
, uban
);
138 struct ifaddr
**ifnet_addrs
;
141 * Attach an interface to the
142 * list of "active" interfaces.
148 unsigned socksize
, ifasize
;
149 int namelen
, unitlen
;
150 char workbuf
[12], *unitname
;
151 register struct sockaddr_dl
*sdl
;
152 register struct ifaddr
*ifa
;
153 static int if_indexlim
= 8;
154 register struct ifnet
**p
= &ifnet
;
157 p
= &((*p
)->if_next
);
159 ifp
->if_index
= ++if_index
;
160 if (ifnet_addrs
== 0 || if_index
>= if_indexlim
) {
161 unsigned n
= (if_indexlim
<<= 1) * sizeof(ifa
);
162 struct ifaddr
**q
= (struct ifaddr
**)
163 bsd_malloc(n
, M_IFADDR
, M_WAITOK
);
165 aligned_bcopy((caddr_t
)ifnet_addrs
, (caddr_t
)q
, n
/2);
166 bsd_free((caddr_t
)ifnet_addrs
, M_IFADDR
);
171 * create a Link Level name for this device
173 unitname
= sprint_d((u_int
)ifp
->if_unit
, workbuf
, sizeof(workbuf
));
174 namelen
= strlen(ifp
->if_name
);
175 unitlen
= strlen(unitname
);
176 #define _offsetof(t, m) ((IPTR)((caddr_t)&((t *)0)->m))
177 socksize
= _offsetof(struct sockaddr_dl
, sdl_data
[0]) +
178 unitlen
+ namelen
+ ifp
->if_addrlen
;
179 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
180 socksize
= ROUNDUP(socksize
);
181 if (socksize
< sizeof(*sdl
))
182 socksize
= sizeof(*sdl
);
183 ifasize
= sizeof(*ifa
) + 2 * socksize
;
184 ifa
= (struct ifaddr
*)bsd_malloc(ifasize
, M_IFADDR
, M_WAITOK
);
187 ifnet_addrs
[if_index
- 1] = ifa
;
188 aligned_bzero((caddr_t
)ifa
, ifasize
);
189 sdl
= (struct sockaddr_dl
*)(ifa
+ 1);
190 ifa
->ifa_addr
= (struct sockaddr
*)sdl
;
192 sdl
->sdl_len
= socksize
;
193 sdl
->sdl_family
= AF_LINK
;
194 bcopy(ifp
->if_name
, sdl
->sdl_data
, namelen
);
195 bcopy(unitname
, namelen
+ (caddr_t
)sdl
->sdl_data
, unitlen
);
196 sdl
->sdl_nlen
= (namelen
+= unitlen
);
197 sdl
->sdl_index
= ifp
->if_index
;
198 /* Fill in the hardware address */
199 sdl
->sdl_type
= ifp
->if_type
;
200 sdl
->sdl_alen
= ifp
->if_addrlen
;
201 if ((ifp
->if_output
== sana_output
) && (sdl
->sdl_alen
))
202 bcopy((caddr_t
)((struct sana_softc
*)ifp
)->ss_hwaddr
,LLADDR(sdl
), sdl
->sdl_alen
);
203 sdl
= (struct sockaddr_dl
*)(socksize
+ (caddr_t
)sdl
);
204 ifa
->ifa_netmask
= (struct sockaddr
*)sdl
;
205 sdl
->sdl_len
= socksize
- ifp
->if_addrlen
;
207 sdl
->sdl_data
[--namelen
] = (char)0xff;
208 ifa
->ifa_next
= ifp
->if_addrlist
;
209 ifa
->ifa_rtrequest
= link_rtrequest
;
210 ifp
->if_addrlist
= ifa
;
214 * Locate an interface based on a complete address.
218 * Find an interface address suitable for host id. If no suitable interface
219 * address is found, the *id is not touched.
221 * This routine stops after the first non-loopback AF_INET address is found.
223 * This routine is specially made for the gethostid() system call.
226 findid(unsigned long *id
)
233 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
234 if (ifp
->if_flags
& IFF_UP
)
235 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
236 if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
237 *id
= ((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr
.s_addr
;
238 if (!(ifp
->if_flags
& IFF_LOOPBACK
))
248 register struct sockaddr
*addr
;
250 register struct ifnet
*ifp
;
251 register struct ifaddr
*ifa
;
253 #define equal(a1, a2) \
254 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
255 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
256 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
257 if (ifa
->ifa_addr
->sa_family
!= addr
->sa_family
)
259 if (equal(addr
, ifa
->ifa_addr
))
261 if ((ifp
->if_flags
& IFF_BROADCAST
) && ifa
->ifa_broadaddr
&&
262 equal(ifa
->ifa_broadaddr
, addr
))
265 return ((struct ifaddr
*)0);
268 * Locate the point to point interface with a given destination address.
272 ifa_ifwithdstaddr(addr
)
273 register struct sockaddr
*addr
;
275 register struct ifnet
*ifp
;
276 register struct ifaddr
*ifa
;
278 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
279 if (ifp
->if_flags
& IFF_POINTOPOINT
)
280 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
281 if (ifa
->ifa_addr
->sa_family
!= addr
->sa_family
)
283 if (equal(addr
, ifa
->ifa_dstaddr
))
286 return ((struct ifaddr
*)0);
290 * Find an interface on a specific network. If many, choice
295 struct sockaddr
*addr
;
297 register struct ifnet
*ifp
;
298 register struct ifaddr
*ifa
;
299 u_int af
= addr
->sa_family
;
304 register struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)addr
;
305 if (sdl
->sdl_index
&& sdl
->sdl_index
<= if_index
)
306 return (ifnet_addrs
[sdl
->sdl_index
- 1]);
308 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
309 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
310 register char *cp
, *cp2
, *cp3
;
311 register char *cplim
;
312 if (ifa
->ifa_addr
->sa_family
!= af
|| ifa
->ifa_netmask
== 0)
315 cp2
= ifa
->ifa_addr
->sa_data
;
316 cp3
= ifa
->ifa_netmask
->sa_data
;
317 cplim
= ifa
->ifa_netmask
->sa_len
+ (char *)ifa
->ifa_netmask
;
318 for (; cp3
< cplim
; cp3
++)
319 if ((*cp
++ ^ *cp2
++) & *cp3
)
324 return ((struct ifaddr
*)0);
328 * Find an interface using a specific address family
334 register struct ifnet
*ifp
;
335 register struct ifaddr
*ifa
;
337 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
338 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
339 if (ifa
->ifa_addr
->sa_family
== af
)
341 return ((struct ifaddr
*)0);
345 * Find an interface address specific to an interface best matching
349 ifaof_ifpforaddr(addr
, ifp
)
350 struct sockaddr
*addr
;
351 register struct ifnet
*ifp
;
353 register struct ifaddr
*ifa
;
354 register char *cp
, *cp2
, *cp3
;
355 register char *cplim
;
356 struct ifaddr
*ifa_maybe
= 0;
357 u_int af
= addr
->sa_family
;
361 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
362 if (ifa
->ifa_addr
->sa_family
!= af
)
365 if (ifa
->ifa_netmask
== 0) {
366 if (equal(addr
, ifa
->ifa_addr
) ||
367 (ifa
->ifa_dstaddr
&& equal(addr
, ifa
->ifa_dstaddr
)))
372 cp2
= ifa
->ifa_addr
->sa_data
;
373 cp3
= ifa
->ifa_netmask
->sa_data
;
374 cplim
= ifa
->ifa_netmask
->sa_len
+ (char *)ifa
->ifa_netmask
;
375 for (; cp3
< cplim
; cp3
++)
376 if ((*cp
++ ^ *cp2
++) & *cp3
)
384 #include <net/route.h>
387 * Default action when installing a route with a Link Level gateway.
388 * Lookup an appropriate real ifa to point to.
389 * This should be moved to /sys/net/link.c eventually.
392 link_rtrequest(int cmd
, struct rtentry
*rt
, struct sockaddr
*sa
)
394 register struct ifaddr
*ifa
;
395 struct sockaddr
*dst
;
398 if (cmd
!= RTM_ADD
|| ((ifa
= rt
->rt_ifa
) == 0) ||
399 ((ifp
= ifa
->ifa_ifp
) == 0) || ((dst
= rt_key(rt
)) == 0))
401 if (ifa
= ifaof_ifpforaddr(dst
, ifp
)) {
403 if (ifa
->ifa_rtrequest
&&
404 ifa
->ifa_rtrequest
!= link_rtrequest
)
405 ifa
->ifa_rtrequest(cmd
, rt
, sa
);
410 * Mark an interface down and notify protocols of
412 * NOTE: must be called at splnet or eqivalent.
416 register struct ifnet
*ifp
;
418 register struct ifaddr
*ifa
;
420 ifp
->if_flags
&= ~IFF_UP
;
421 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
422 pfctlinput(PRC_IFDOWN
, ifa
->ifa_addr
);
423 if_qflush(&ifp
->if_snd
);
427 * Flush an interface queue.
431 register struct ifqueue
*ifq
;
433 register struct mbuf
*m
, *n
;
446 * Handle interface watchdog timer routines. Called
447 * from softclock, we decrement timers (if set) and
448 * call the appropriate interface routine on expiration.
454 * This routine is disabled since there are
455 * no timeouts in our network interfaces
458 register struct ifnet
*ifp
;
461 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
462 if (ifp
->if_timer
== 0 || --ifp
->if_timer
)
464 if (ifp
->if_watchdog
)
465 (*ifp
->if_watchdog
)(ifp
->if_unit
);
470 * Timeouts are scheduled from amiga_time.c in AmiTCP/IP.
472 timeout(if_slowtimo
, (caddr_t
)0, hz
/ IFNET_SLOWHZ
);
478 * Map interface name to
479 * interface structure pointer.
484 register struct ifnet
*ifp
;
490 for (cp
= name
; cp
< name
+ IFNAMSIZ
&& *cp
; cp
++)
491 if (*cp
>= '0' && *cp
<= '9')
493 if (*cp
== '\0' || cp
== name
+ IFNAMSIZ
)
494 return ((struct ifnet
*)0);
496 * Save first char of unit, and pointer to it,
497 * so we can put a null there to avoid matching
498 * initial substrings of interface names.
503 for (unit
= 0; *cp
>= '0' && *cp
<= '9'; )
504 unit
= unit
* 10 + *cp
++ - '0';
507 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
508 if (bcmp(ifp
->if_name
, name
, len
))
510 if (unit
== ifp
->if_unit
)
521 ifioctl(so
, cmd
, data
)
526 register struct ifnet
*ifp
;
527 register struct ifreq
*ifr
;
531 extern int arpioctl(int cmd
, caddr_t data
);
536 return (ifconf(cmd
, data
));
538 #ifdef COMPAT_AMITCP2
540 return (aifconf(cmd
, data
));
543 #if INET && NETHER > 0
546 #ifndef AMITCP /* no protection on AmigaOS */
547 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
554 return (arpioctl(cmd
, data
));
558 #ifndef COMPAT_AMITCP2
559 /* Do we have old ioctl? */
560 if (IOCGROUP(cmd
) == 'I') {
562 aifr
= (struct aifreq
*)data
;
563 /* Nobody needs interface name after we have got ifp */
564 ifp
= aifunit(aifr
->ifr_name
);
565 ifr
= (struct ifreq
*)(data
+ AIFNAMSIZ
- IFNAMSIZ
);
566 cmd
-= ASIOCSIFADDR
- SIOCSIFADDR
;
571 ifr
= (struct ifreq
*)data
;
572 ifp
= ifunit(ifr
->ifr_name
);
580 ifr
->ifr_index
= ifp
->if_index
;
584 ifr
->ifr_flags
= ifp
->if_flags
;
588 ifr
->ifr_metric
= ifp
->if_metric
;
592 ifr
->ifr_mtu
= ifp
->if_mtu
;
596 /* if_down() is kludged for Sana-II driver ioctl */
597 if (ifp
->if_flags
& IFF_UP
&& (ifr
->ifr_flags
& IFF_UP
) == 0) {
604 (void) (*ifp
->if_ioctl
)(ifp
, cmd
, data
);
606 ifp
->if_flags
= (ifp
->if_flags
& IFF_CANTCHANGE
) |
607 (ifr
->ifr_flags
&~ IFF_CANTCHANGE
);
611 #ifndef AMITCP /* no protection on AmigaOS */
612 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
615 ifp
->if_metric
= ifr
->ifr_metric
;
619 if (so
->so_proto
== 0)
621 return ((*so
->so_proto
->pr_usrreq
)(so
,
625 (struct mbuf
*)ifp
));
631 * A helper routine for internal interface control
632 * Here we do the same as SIOCSIFFLAGS processing code from net/if.c
635 void ifupdown(struct ifnet
*ifp
, int up
) {
639 ifr
.ifr_flags
= ifp
->if_flags
& ~IFF_UP
;
640 if (ifp
->if_flags
& IFF_UP
) {
646 ifr
.ifr_flags
= ifp
->if_flags
| IFF_UP
;
649 (void) (*ifp
->if_ioctl
)(ifp
, SIOCSIFFLAGS
, (caddr_t
)&ifr
);
650 ifp
->if_flags
= ifr
.ifr_flags
;
654 * Return interface configuration
655 * of system. List may be used
656 * in later ioctl's (above) to get
664 register struct ifconf
*ifc
= (struct ifconf
*)data
;
665 register struct ifnet
*ifp
= ifnet
;
666 register struct ifaddr
*ifa
;
667 register char *cp
, *ep
;
668 struct ifreq ifr
, *ifrp
;
669 int space
= ifc
->ifc_len
, error
= 0;
673 ep
= ifr
.ifr_name
+ sizeof (ifr
.ifr_name
) - 2;
675 for (; space
> sizeof (ifr
) && ifp
; ifp
= ifp
->if_next
) {
677 ep
= sprint_d(ifp
->if_unit
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
));
678 /* Copy the interface name into ifr */
679 bcopy(ifp
->if_name
, ifr
.ifr_name
, ep
- ifr
.ifr_name
);
680 /* Find the end of interface name */
681 for (cp
= ifr
.ifr_name
; cp
< ep
&& *cp
; cp
++)
683 /* Append unit number to it */
684 for (; *cp
= *ep
; cp
++, ep
++)
687 bcopy(ifp
->if_name
, ifr
.ifr_name
, sizeof (ifr
.ifr_name
) - 2);
688 for (cp
= ifr
.ifr_name
; cp
< ep
&& *cp
; cp
++)
690 *cp
++ = '0' + ifp
->if_unit
; *cp
= '\0';
692 if ((ifa
= ifp
->if_addrlist
) == 0) {
693 aligned_bzero_const((caddr_t
)&ifr
.ifr_addr
, sizeof(ifr
.ifr_addr
));
694 bcopy(&ifr
, ifrp
, sizeof(ifr
));
695 space
-= sizeof (ifr
), ifrp
++;
697 for ( ; space
> sizeof (ifr
) && ifa
; ifa
= ifa
->ifa_next
) {
698 register struct sockaddr
*sa
= ifa
->ifa_addr
;
700 if (cmd
== OSIOCGIFCONF
) {
701 struct osockaddr
*osa
=
702 (struct osockaddr
*)&ifr
.ifr_addr
;
704 osa
->sa_family
= sa
->sa_family
;
705 error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
,
710 if (sa
->sa_len
<= sizeof(*sa
)) {
712 bcopy(&ifr
, ifrp
, sizeof(ifr
));
715 space
-= sa
->sa_len
- sizeof(*sa
);
716 if (space
< sizeof (ifr
))
719 aligned_bcopy_const((caddr_t
)&ifr
,
721 sizeof (ifr
.ifr_name
));
722 aligned_bcopy((caddr_t
)sa
,
723 (caddr_t
)&ifrp
->ifr_addr
, sa
->sa_len
);
725 error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
,
726 sizeof (ifr
.ifr_name
));
728 error
= copyout((caddr_t
)sa
,
729 (caddr_t
)&ifrp
->ifr_addr
, sa
->sa_len
);
731 ifrp
= (struct ifreq
*)
732 (sa
->sa_len
+ (caddr_t
)&ifrp
->ifr_addr
);
738 space
-= sizeof (ifr
);
741 ifc
->ifc_len
-= space
;
745 int aifconf(int cmd
, caddr_t data
)
751 sprint_d(n
, buf
, buflen
)
756 register char *cp
= buf
+ buflen
- 1;
761 *cp
= "0123456789"[n
% 10];