* Copyright (c) 1980, 1986 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)if.c 7.10 (Berkeley) %G%
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
);
* Attach an interface to the
* list of "active" interfaces.
register struct ifnet
**p
= &ifnet
;
unsigned socksize
, ifasize
;
register struct sockaddr_dl
*sdl
;
register struct ifaddr
*ifa
;
ifp
->if_index
= ++if_index
;
/* create a link level name for this device */
sprint_d(workbuf
, ifp
->if_unit
);
namelen
= strlen(ifp
->if_name
);
unitlen
= strlen(workbuf
);
#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
);
ifasize
= sizeof(*ifa
) + 2 * socksize
;
ifa
= (struct ifaddr
*)malloc(ifasize
, M_IFADDR
, M_WAITOK
);
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((caddr_t
)workbuf
, 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
;
* 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
) &&
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
;
register char *cp
, *cp2
, *cp3
;
u_int af
= addr
->sa_family
;
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
|| 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);
* 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
)
register struct ifnet
*ifp
;
register struct ifreq
*ifr
;
return (ifconf(cmd
, data
));
#if defined(INET) && NETHER > 0
if (error
= suser(u
.u_cred
, &u
.u_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(u
.u_cred
, &u
.u_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(u
.u_cred
, &u
.u_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
);
if (n
>= 10000) m
= 10000;
else if (n
>= 1000) m
= 1000;
else if (n
>= 100) m
= 100;
else if (n
>= 10) m
= 10;
if (q
> 9) q
= 10; /* For crays with more than 100K interfaces */
*cp
++ = "0123456789Z"[q
];