* Copyright (c) 1980, 1986 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)if.c 7.14 (Berkeley) 4/20/91
int ifqmaxlen
= IFQ_MAXLEN
;
* Network interface utility routines.
* Routines with ifa_ifwith* names take sockaddr *'s as
register struct ifnet
*ifp
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
if (ifp
->if_snd
.ifq_maxlen
== 0)
ifp
->if_snd
.ifq_maxlen
= ifqmaxlen
;
* Call each interface on a Unibus reset.
register struct ifnet
*ifp
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
(*ifp
->if_reset
)(ifp
->if_unit
, uban
);
struct ifaddr
**ifnet_addrs
;
* Attach an interface to the
* list of "active" interfaces.
unsigned socksize
, ifasize
;
char workbuf
[12], *unitname
;
register struct ifnet
**p
= &ifnet
;
register struct sockaddr_dl
*sdl
;
register struct ifaddr
*ifa
;
static int if_indexlim
= 8;
extern link_rtrequest(), ether_output();
ifp
->if_index
= ++if_index
;
if (ifnet_addrs
== 0 || if_index
>= if_indexlim
) {
unsigned n
= (if_indexlim
<<= 1) * sizeof(ifa
);
struct ifaddr
**q
= (struct ifaddr
**)
malloc(n
, M_IFADDR
, M_WAITOK
);
bcopy((caddr_t
)ifnet_addrs
, (caddr_t
)q
, n
/2);
free((caddr_t
)ifnet_addrs
, M_IFADDR
);
/* XXX -- Temporary fix before changing 10 ethernet drivers */
if (ifp
->if_output
== ether_output
) {
ifp
->if_type
= IFT_ETHER
;
* create a Link Level name for this device
unitname
= sprint_d((u_int
)ifp
->if_unit
, workbuf
, sizeof(workbuf
));
namelen
= strlen(ifp
->if_name
);
unitlen
= strlen(unitname
);
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
socksize
= _offsetof(struct sockaddr_dl
, sdl_data
[0]) +
unitlen
+ namelen
+ ifp
->if_addrlen
;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
socksize
= ROUNDUP(socksize
);
if (socksize
< sizeof(*sdl
))
ifasize
= sizeof(*ifa
) + 2 * socksize
;
ifa
= (struct ifaddr
*)malloc(ifasize
, M_IFADDR
, M_WAITOK
);
ifnet_addrs
[if_index
- 1] = ifa
;
bzero((caddr_t
)ifa
, ifasize
);
sdl
= (struct sockaddr_dl
*)(ifa
+ 1);
ifa
->ifa_addr
= (struct sockaddr
*)sdl
;
sdl
->sdl_family
= AF_LINK
;
bcopy(ifp
->if_name
, sdl
->sdl_data
, namelen
);
bcopy(unitname
, namelen
+ (caddr_t
)sdl
->sdl_data
, unitlen
);
sdl
->sdl_nlen
= (namelen
+= unitlen
);
sdl
->sdl_index
= ifp
->if_index
;
sdl
= (struct sockaddr_dl
*)(socksize
+ (caddr_t
)sdl
);
ifa
->ifa_netmask
= (struct sockaddr
*)sdl
;
sdl
->sdl_len
= socksize
- ifp
->if_addrlen
;
sdl
->sdl_data
[--namelen
] = 0xff;
ifa
->ifa_next
= ifp
->if_addrlist
;
ifa
->ifa_rtrequest
= link_rtrequest
;
* Locate an interface based on a complete address.
register struct sockaddr
*addr
;
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
(bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
!= addr
->sa_family
)
if (equal(addr
, ifa
->ifa_addr
))
if ((ifp
->if_flags
& IFF_BROADCAST
) && ifa
->ifa_broadaddr
&&
equal(ifa
->ifa_broadaddr
, addr
))
return ((struct ifaddr
*)0);
* Locate the point to point interface with a given destination address.
register struct sockaddr
*addr
;
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
if (ifp
->if_flags
& IFF_POINTOPOINT
)
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
!= addr
->sa_family
)
if (equal(addr
, ifa
->ifa_dstaddr
))
return ((struct ifaddr
*)0);
* Find an interface on a specific network. If many, choice
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
u_int af
= addr
->sa_family
;
register struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)addr
;
if (sdl
->sdl_index
&& sdl
->sdl_index
<= if_index
)
return (ifnet_addrs
[sdl
->sdl_index
- 1]);
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
register char *cp
, *cp2
, *cp3
;
if (ifa
->ifa_addr
->sa_family
!= af
|| ifa
->ifa_netmask
== 0)
cp2
= ifa
->ifa_addr
->sa_data
;
cp3
= ifa
->ifa_netmask
->sa_data
;
cplim
= ifa
->ifa_netmask
->sa_len
+ (char *)ifa
->ifa_netmask
;
for (; cp3
< cplim
; cp3
++)
if ((*cp
++ ^ *cp2
++) & *cp3
)
return ((struct ifaddr
*)0);
* Find an interface using a specific address family
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
->sa_family
== af
)
return ((struct ifaddr
*)0);
* Find an interface address specific to an interface best matching
ifaof_ifpforaddr(addr
, ifp
)
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
register char *cp
, *cp2
, *cp3
;
struct ifaddr
*ifa_maybe
= 0;
u_int af
= addr
->sa_family
;
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
!= af
)
if (ifa
->ifa_netmask
== 0) {
if (equal(addr
, ifa
->ifa_addr
) ||
(ifa
->ifa_dstaddr
&& equal(addr
, ifa
->ifa_dstaddr
)))
cp2
= ifa
->ifa_addr
->sa_data
;
cp3
= ifa
->ifa_netmask
->sa_data
;
cplim
= ifa
->ifa_netmask
->sa_len
+ (char *)ifa
->ifa_netmask
;
for (; cp3
< cplim
; cp3
++)
if ((*cp
++ ^ *cp2
++) & *cp3
)
* Default action when installing a route with a Link Level gateway.
* Lookup an appropriate real ifa to point to.
* This should be moved to /sys/net/link.c eventually.
link_rtrequest(cmd
, rt
, sa
)
register struct rtentry
*rt
;
register struct ifaddr
*ifa
;
struct ifnet
*ifp
, *oldifnet
= ifnet
;
if (cmd
!= RTM_ADD
|| ((ifa
= rt
->rt_ifa
) == 0) ||
((ifp
= ifa
->ifa_ifp
) == 0) || ((dst
= rt_key(rt
)) == 0))
if (ifa
= ifaof_ifpforaddr(dst
, ifp
)) {
if (ifa
->ifa_rtrequest
&& ifa
->ifa_rtrequest
!= link_rtrequest
)
ifa
->ifa_rtrequest(cmd
, rt
, sa
);
* Mark an interface down and notify protocols of
* NOTE: must be called at splnet or eqivalent.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
ifp
->if_flags
&= ~IFF_UP
;
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
pfctlinput(PRC_IFDOWN
, ifa
->ifa_addr
);
* Flush an interface queue.
register struct ifqueue
*ifq
;
register struct mbuf
*m
, *n
;
* Handle interface watchdog timer routines. Called
* from softclock, we decrement timers (if set) and
* call the appropriate interface routine on expiration.
register struct ifnet
*ifp
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
if (ifp
->if_timer
== 0 || --ifp
->if_timer
)
(*ifp
->if_watchdog
)(ifp
->if_unit
);
timeout(if_slowtimo
, (caddr_t
)0, hz
/ IFNET_SLOWHZ
);
* interface structure pointer.
register struct ifnet
*ifp
;
for (cp
= name
; cp
< name
+ IFNAMSIZ
&& *cp
; cp
++)
if (*cp
>= '0' && *cp
<= '9')
if (*cp
== '\0' || cp
== name
+ IFNAMSIZ
)
return ((struct ifnet
*)0);
* Save first char of unit, and pointer to it,
* so we can put a null there to avoid matching
* initial substrings of interface names.
for (unit
= 0; *cp
>= '0' && *cp
<= '9'; )
unit
= unit
* 10 + *cp
++ - '0';
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
if (bcmp(ifp
->if_name
, name
, len
))
if (unit
== ifp
->if_unit
)
ifioctl(so
, cmd
, data
, p
)
register struct ifnet
*ifp
;
register struct ifreq
*ifr
;
return (ifconf(cmd
, data
));
#if defined(INET) && NETHER > 0
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
return (arpioctl(cmd
, data
));
ifr
= (struct ifreq
*)data
;
ifp
= ifunit(ifr
->ifr_name
);
ifr
->ifr_flags
= ifp
->if_flags
;
ifr
->ifr_metric
= ifp
->if_metric
;
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if (ifp
->if_flags
& IFF_UP
&& (ifr
->ifr_flags
& IFF_UP
) == 0) {
ifp
->if_flags
= (ifp
->if_flags
& IFF_CANTCHANGE
) |
(ifr
->ifr_flags
&~ IFF_CANTCHANGE
);
(void) (*ifp
->if_ioctl
)(ifp
, cmd
, data
);
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
ifp
->if_metric
= ifr
->ifr_metric
;
return ((*so
->so_proto
->pr_usrreq
)(so
, PRU_CONTROL
,
#if BYTE_ORDER != BIG_ENDIAN
if (ifr
->ifr_addr
.sa_family
== 0 &&
ifr
->ifr_addr
.sa_len
< 16) {
ifr
->ifr_addr
.sa_family
= ifr
->ifr_addr
.sa_len
;
ifr
->ifr_addr
.sa_len
= 16;
if (ifr
->ifr_addr
.sa_len
== 0)
ifr
->ifr_addr
.sa_len
= 16;
error
= ((*so
->so_proto
->pr_usrreq
)(so
, PRU_CONTROL
,
*(u_short
*)&ifr
->ifr_addr
= ifr
->ifr_addr
.sa_family
;
* Return interface configuration
* of system. List may be used
* in later ioctl's (above) to get
register struct ifconf
*ifc
= (struct ifconf
*)data
;
register struct ifnet
*ifp
= ifnet
;
register struct ifaddr
*ifa
;
int space
= ifc
->ifc_len
, error
= 0;
ep
= ifr
.ifr_name
+ sizeof (ifr
.ifr_name
) - 2;
for (; space
> sizeof (ifr
) && ifp
; ifp
= ifp
->if_next
) {
bcopy(ifp
->if_name
, ifr
.ifr_name
, sizeof (ifr
.ifr_name
) - 2);
for (cp
= ifr
.ifr_name
; cp
< ep
&& *cp
; cp
++)
*cp
++ = '0' + ifp
->if_unit
; *cp
= '\0';
if ((ifa
= ifp
->if_addrlist
) == 0) {
bzero((caddr_t
)&ifr
.ifr_addr
, sizeof(ifr
.ifr_addr
));
error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
, sizeof (ifr
));
space
-= sizeof (ifr
), ifrp
++;
for ( ; space
> sizeof (ifr
) && ifa
; ifa
= ifa
->ifa_next
) {
register struct sockaddr
*sa
= ifa
->ifa_addr
;
if (cmd
== OSIOCGIFCONF
) {
(struct osockaddr
*)&ifr
.ifr_addr
;
osa
->sa_family
= sa
->sa_family
;
error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
,
if (sa
->sa_len
<= sizeof(*sa
)) {
error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
,
space
-= sa
->sa_len
- sizeof(*sa
);
if (space
< sizeof (ifr
))
error
= copyout((caddr_t
)&ifr
, (caddr_t
)ifrp
,
error
= copyout((caddr_t
)sa
,
(caddr_t
)&ifrp
->ifr_addr
, sa
->sa_len
);
(sa
->sa_len
+ (caddr_t
)&ifrp
->ifr_addr
);
register char *cp
= buf
+ buflen
- 1;
*cp
= "0123456789"[n
% 10];