* Copyright (c) 1982, 1986, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)in.c 7.32 (Berkeley) %G%
#include <sys/socketvar.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
* Return the network number from an internet address.
register u_long i
= ntohl(in
.s_addr
);
register struct in_ifaddr
*ia
;
* Check whether network is a subnet;
* if so, return subnet number.
for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
return (i
& ia
->ia_subnetmask
);
#define SUBNETSARELOCAL 1
int subnetsarelocal
= SUBNETSARELOCAL
;
* Return 1 if an internet address is for a ``local'' host
* (one to which we have a connection). If subnetsarelocal
* is true, this includes other subnets of the local net.
* Otherwise, it includes only the directly-connected (sub)nets.
register u_long i
= ntohl(in
.s_addr
);
register struct in_ifaddr
*ia
;
for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
if ((i
& ia
->ia_netmask
) == ia
->ia_net
)
for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
if ((i
& ia
->ia_subnetmask
) == ia
->ia_subnet
)
* Determine whether an IP address is in a reserved set of addresses
* that may not be forwarded, or whether datagrams to that destination
register u_long i
= ntohl(in
.s_addr
);
if (IN_EXPERIMENTAL(i
) || IN_MULTICAST(i
))
if (net
== 0 || net
== (IN_LOOPBACKNET
<< IN_CLASSA_NSHIFT
))
* Trim a mask in a sockaddr
register char *cplim
= (char *) &ap
->sin_addr
;
register char *cp
= (char *) (&ap
->sin_addr
+ 1);
(ap
)->sin_len
= cp
- (char *) (ap
) + 1;
int in_interfaces
; /* number of external internet interfaces */
extern struct ifnet loif
;
* Generic internet control operations (ioctl's).
* Ifp is 0 if not an interface-specific ioctl.
in_control(so
, cmd
, data
, ifp
)
register struct ifnet
*ifp
;
register struct ifreq
*ifr
= (struct ifreq
*)data
;
register struct in_ifaddr
*ia
= 0;
register struct ifaddr
*ifa
;
struct in_aliasreq
*ifra
= (struct in_aliasreq
*)data
;
struct sockaddr_in oldaddr
;
int error
, hostIsNew
, maskIsNew
;
* Find address for this interface, if it exists.
for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
if (ifra
->ifra_addr
.sin_family
== AF_INET
)
for (oia
= ia
; ia
; ia
= ia
->ia_next
) {
ia
->ia_addr
.sin_addr
.s_addr
==
ifra
->ifra_addr
.sin_addr
.s_addr
)
if (cmd
== SIOCDIFADDR
&& ia
== 0)
if ((so
->so_state
& SS_PRIV
) == 0)
if (ia
== (struct in_ifaddr
*)0) {
oia
= (struct in_ifaddr
*)
malloc(sizeof *oia
, M_IFADDR
, M_WAITOK
);
if (oia
== (struct in_ifaddr
*)NULL
)
bzero((caddr_t
)oia
, sizeof *oia
);
for ( ; ia
->ia_next
; ia
= ia
->ia_next
)
if (ifa
= ifp
->if_addrlist
) {
for ( ; ifa
->ifa_next
; ifa
= ifa
->ifa_next
)
ifa
->ifa_next
= (struct ifaddr
*) ia
;
ifp
->if_addrlist
= (struct ifaddr
*) ia
;
ia
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&ia
->ia_addr
;
= (struct sockaddr
*)&ia
->ia_dstaddr
;
= (struct sockaddr
*)&ia
->ia_sockmask
;
ia
->ia_sockmask
.sin_len
= 8;
if (ifp
->if_flags
& IFF_BROADCAST
) {
ia
->ia_broadaddr
.sin_len
= sizeof(ia
->ia_addr
);
ia
->ia_broadaddr
.sin_family
= AF_INET
;
if ((so
->so_state
& SS_PRIV
) == 0)
if (ia
== (struct in_ifaddr
*)0)
*((struct sockaddr_in
*)&ifr
->ifr_addr
) = ia
->ia_addr
;
if ((ifp
->if_flags
& IFF_BROADCAST
) == 0)
*((struct sockaddr_in
*)&ifr
->ifr_dstaddr
) = ia
->ia_broadaddr
;
if ((ifp
->if_flags
& IFF_POINTOPOINT
) == 0)
*((struct sockaddr_in
*)&ifr
->ifr_dstaddr
) = ia
->ia_dstaddr
;
*((struct sockaddr_in
*)&ifr
->ifr_addr
) = ia
->ia_sockmask
;
if ((ifp
->if_flags
& IFF_POINTOPOINT
) == 0)
oldaddr
= ia
->ia_dstaddr
;
ia
->ia_dstaddr
= *(struct sockaddr_in
*)&ifr
->ifr_dstaddr
;
if (ifp
->if_ioctl
&& (error
= (*ifp
->if_ioctl
)
(ifp
, SIOCSIFDSTADDR
, (caddr_t
)ia
))) {
ia
->ia_dstaddr
= oldaddr
;
if (ia
->ia_flags
& IFA_ROUTE
) {
ia
->ia_ifa
.ifa_dstaddr
= (struct sockaddr
*)&oldaddr
;
rtinit(&(ia
->ia_ifa
), (int)RTM_DELETE
, RTF_HOST
);
(struct sockaddr
*)&ia
->ia_dstaddr
;
rtinit(&(ia
->ia_ifa
), (int)RTM_ADD
, RTF_HOST
|RTF_UP
);
if ((ifp
->if_flags
& IFF_BROADCAST
) == 0)
ia
->ia_broadaddr
= *(struct sockaddr_in
*)&ifr
->ifr_broadaddr
;
return (in_ifinit(ifp
, ia
,
(struct sockaddr_in
*) &ifr
->ifr_addr
, 1));
i
= ifra
->ifra_addr
.sin_addr
.s_addr
;
ia
->ia_subnetmask
= ntohl(ia
->ia_sockmask
.sin_addr
.s_addr
= i
);
if (ia
->ia_addr
.sin_family
== AF_INET
) {
if (ifra
->ifra_addr
.sin_len
== 0) {
ifra
->ifra_addr
= ia
->ia_addr
;
} else if (ifra
->ifra_addr
.sin_addr
.s_addr
==
ia
->ia_addr
.sin_addr
.s_addr
)
if (ifra
->ifra_mask
.sin_len
) {
ia
->ia_sockmask
= ifra
->ifra_mask
;
ntohl(ia
->ia_sockmask
.sin_addr
.s_addr
);
if ((ifp
->if_flags
& IFF_POINTOPOINT
) &&
(ifra
->ifra_dstaddr
.sin_family
== AF_INET
)) {
ia
->ia_dstaddr
= ifra
->ifra_dstaddr
;
maskIsNew
= 1; /* We lie; but the effect's the same */
if (ifra
->ifra_addr
.sin_family
== AF_INET
&&
(hostIsNew
|| maskIsNew
))
error
= in_ifinit(ifp
, ia
, &ifra
->ifra_addr
, 0);
if ((ifp
->if_flags
& IFF_BROADCAST
) &&
(ifra
->ifra_broadaddr
.sin_family
== AF_INET
))
ia
->ia_broadaddr
= ifra
->ifra_broadaddr
;
if ((ifa
= ifp
->if_addrlist
) == (struct ifaddr
*)ia
)
ifp
->if_addrlist
= ifa
->ifa_next
;
(ifa
->ifa_next
!= (struct ifaddr
*)ia
))
ifa
->ifa_next
= ((struct ifaddr
*)ia
)->ifa_next
;
printf("Couldn't unlink inifaddr from ifp\n");
if (oia
== (ia
= in_ifaddr
))
while (ia
->ia_next
&& (ia
->ia_next
!= oia
))
ia
->ia_next
= oia
->ia_next
;
printf("Didn't unlink inifadr from list\n");
if (ifp
== 0 || ifp
->if_ioctl
== 0)
return ((*ifp
->if_ioctl
)(ifp
, cmd
, data
));
* Delete any existing route for an interface.
register struct ifnet
*ifp
;
register struct in_ifaddr
*ia
;
if ((ia
->ia_flags
& IFA_ROUTE
) == 0)
if (ifp
->if_flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
))
rtinit(&(ia
->ia_ifa
), (int)RTM_DELETE
, RTF_HOST
);
rtinit(&(ia
->ia_ifa
), (int)RTM_DELETE
, 0);
ia
->ia_flags
&= ~IFA_ROUTE
;
* Initialize an interface's internet address
* and routing table entry.
in_ifinit(ifp
, ia
, sin
, scrub
)
register struct ifnet
*ifp
;
register struct in_ifaddr
*ia
;
register u_long i
= ntohl(sin
->sin_addr
.s_addr
);
struct sockaddr_in oldaddr
;
int s
= splimp(), flags
= RTF_UP
, error
, ether_output();
* Give the interface a chance to initialize
* if this is its first address,
* and to validate the address if necessary.
(error
= (*ifp
->if_ioctl
)(ifp
, SIOCSIFADDR
, (caddr_t
)ia
))) {
if (ifp
->if_output
== ether_output
) { /* XXX: Another Kludge */
ia
->ia_ifa
.ifa_rtrequest
= arp_rtrequest
;
ia
->ia_ifa
.ifa_flags
|= RTF_CLONING
;
ia
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&oldaddr
;
ia
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&ia
->ia_addr
;
ia
->ia_netmask
= IN_CLASSA_NET
;
ia
->ia_netmask
= IN_CLASSB_NET
;
ia
->ia_netmask
= IN_CLASSC_NET
;
ia
->ia_net
= i
& ia
->ia_netmask
;
* The subnet mask includes at least the standard network part,
* but may already have been set to a larger value.
ia
->ia_subnetmask
|= ia
->ia_netmask
;
ia
->ia_subnet
= i
& ia
->ia_subnetmask
;
ia
->ia_sockmask
.sin_addr
.s_addr
= htonl(ia
->ia_subnetmask
);
in_socktrim(&ia
->ia_sockmask
);
* Add route for the network.
ia
->ia_ifa
.ifa_metric
= ifp
->if_metric
;
if (ifp
->if_flags
& IFF_BROADCAST
) {
ia
->ia_broadaddr
.sin_addr
.s_addr
=
htonl(ia
->ia_subnet
| ~ia
->ia_subnetmask
);
ia
->ia_netbroadcast
.s_addr
=
htonl(ia
->ia_net
| ~ ia
->ia_netmask
);
} else if (ifp
->if_flags
& IFF_LOOPBACK
) {
ia
->ia_ifa
.ifa_dstaddr
= ia
->ia_ifa
.ifa_addr
;
} else if (ifp
->if_flags
& IFF_POINTOPOINT
) {
if (ia
->ia_dstaddr
.sin_family
!= AF_INET
)
if ((error
= rtinit(&(ia
->ia_ifa
), (int)RTM_ADD
, flags
)) == 0)
ia
->ia_flags
|= IFA_ROUTE
;
* If the interface supports multicast, join the "all hosts"
* multicast group on that interface.
if (ifp
->if_flags
& IFF_MULTICAST
) {
addr
.s_addr
= htonl(INADDR_ALLHOSTS_GROUP
);
* Return 1 if the address might be a local broadcast address.
register struct ifaddr
*ifa
;
if (in
.s_addr
== INADDR_BROADCAST
||
if ((ifp
->if_flags
& IFF_BROADCAST
) == 0)
* Look through the list of addresses for a match
* with a broadcast address.
#define ia ((struct in_ifaddr *)ifa)
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
(in
.s_addr
== ia
->ia_broadaddr
.sin_addr
.s_addr
||
in
.s_addr
== ia
->ia_netbroadcast
.s_addr
||
* Check for old-style (host 0) broadcast.
t
== ia
->ia_subnet
|| t
== ia
->ia_net
))
* Add an address to the list of IP multicast addresses for a given interface.
register struct in_addr
*ap
;
register struct ifnet
*ifp
;
register struct in_multi
*inm
;
* See if address already in list.
IN_LOOKUP_MULTI(*ap
, ifp
, inm
);
* Found it; just increment the reference count.
* New address; allocate a new multicast record
* and link it into the interface's multicast list.
inm
= (struct in_multi
*)malloc(sizeof(*inm
),
inm
->inm_next
= ia
->ia_multiaddrs
;
* Ask the network driver to update its multicast reception
* filter appropriately for the new address.
((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_family
= AF_INET
;
((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
= *ap
;
if ((ifp
->if_ioctl
== NULL
) ||
(*ifp
->if_ioctl
)(ifp
, SIOCADDMULTI
,(caddr_t
)&ifr
) != 0) {
ia
->ia_multiaddrs
= inm
->inm_next
;
* Let IGMP know that we have joined a new IP multicast group.
* Delete a multicast address record.
register struct in_multi
*inm
;
register struct in_multi
**p
;
if (--inm
->inm_refcount
== 0) {
* No remaining claims to this record; let IGMP know that
* we are leaving the multicast group.
for (p
= &inm
->inm_ia
->ia_multiaddrs
;
* Notify the network driver to update its multicast reception
((struct sockaddr_in
*)&(ifr
.ifr_addr
))->sin_family
= AF_INET
;
((struct sockaddr_in
*)&(ifr
.ifr_addr
))->sin_addr
=
(*inm
->inm_ifp
->if_ioctl
)(inm
->inm_ifp
, SIOCDELMULTI
,