version 1.208, 2007/12/06 02:23:42 |
version 1.208.4.2, 2008/01/23 19:27:44 |
Line 261 struct ifaddr **ifnet_addrs = NULL; |
|
Line 261 struct ifaddr **ifnet_addrs = NULL; |
|
struct ifnet **ifindex2ifnet = NULL; |
struct ifnet **ifindex2ifnet = NULL; |
struct ifnet *lo0ifp; |
struct ifnet *lo0ifp; |
|
|
/* |
|
* Allocate the link level name for the specified interface. This |
|
* is an attachment helper. It must be called after ifp->if_addrlen |
|
* is initialized, which may not be the case when if_attach() is |
|
* called. |
|
*/ |
|
void |
void |
if_alloc_sadl(struct ifnet *ifp) |
if_set_sadl(struct ifnet *ifp, const void *lla, u_char addrlen) |
|
{ |
|
struct ifaddr *ifa; |
|
struct sockaddr_dl *sdl; |
|
|
|
ifp->if_addrlen = addrlen; |
|
if_alloc_sadl(ifp); |
|
ifa = ifp->if_dl; |
|
sdl = satosdl(ifa->ifa_addr); |
|
|
|
(void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lla, ifp->if_addrlen); |
|
} |
|
|
|
struct ifaddr * |
|
if_dl_create(const struct ifnet *ifp, const struct sockaddr_dl **sdlp) |
{ |
{ |
unsigned socksize, ifasize; |
unsigned socksize, ifasize; |
int addrlen, namelen; |
int addrlen, namelen; |
struct sockaddr_dl *mask, *sdl; |
struct sockaddr_dl *mask, *sdl; |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
|
|
/* |
|
* If the interface already has a link name, release it |
|
* now. This is useful for interfaces that can change |
|
* link types, and thus switch link names often. |
|
*/ |
|
if (ifp->if_sadl != NULL) |
|
if_free_sadl(ifp); |
|
|
|
namelen = strlen(ifp->if_xname); |
namelen = strlen(ifp->if_xname); |
addrlen = ifp->if_addrlen; |
addrlen = ifp->if_addrlen; |
socksize = roundup(sockaddr_dl_measure(namelen, addrlen), sizeof(long)); |
socksize = roundup(sockaddr_dl_measure(namelen, addrlen), sizeof(long)); |
Line 296 if_alloc_sadl(struct ifnet *ifp) |
|
Line 296 if_alloc_sadl(struct ifnet *ifp) |
|
ifp->if_xname, namelen, NULL, addrlen); |
ifp->if_xname, namelen, NULL, addrlen); |
mask->sdl_len = sockaddr_dl_measure(namelen, 0); |
mask->sdl_len = sockaddr_dl_measure(namelen, 0); |
memset(&mask->sdl_data[0], 0xff, namelen); |
memset(&mask->sdl_data[0], 0xff, namelen); |
|
ifa->ifa_rtrequest = link_rtrequest; |
|
ifa->ifa_addr = (struct sockaddr *)sdl; |
|
ifa->ifa_netmask = (struct sockaddr *)mask; |
|
|
|
*sdlp = sdl; |
|
|
|
return ifa; |
|
} |
|
|
|
/* |
|
* Allocate the link level name for the specified interface. This |
|
* is an attachment helper. It must be called after ifp->if_addrlen |
|
* is initialized, which may not be the case when if_attach() is |
|
* called. |
|
*/ |
|
void |
|
if_alloc_sadl(struct ifnet *ifp) |
|
{ |
|
struct ifaddr *ifa; |
|
const struct sockaddr_dl *sdl; |
|
|
|
/* |
|
* If the interface already has a link name, release it |
|
* now. This is useful for interfaces that can change |
|
* link types, and thus switch link names often. |
|
*/ |
|
if (ifp->if_sadl != NULL) |
|
if_free_sadl(ifp); |
|
|
|
ifa = if_dl_create(ifp, &sdl); |
|
|
ifnet_addrs[ifp->if_index] = ifa; |
ifnet_addrs[ifp->if_index] = ifa; |
IFAREF(ifa); |
IFAREF(ifa); |
ifa_insert(ifp, ifa); |
ifa_insert(ifp, ifa); |
ifa->ifa_rtrequest = link_rtrequest; |
ifp->if_dl = ifa; |
ifa->ifa_addr = (struct sockaddr *)sdl; |
IFAREF(ifa); |
ifp->if_sadl = sdl; |
ifp->if_sadl = sdl; |
ifa->ifa_netmask = (struct sockaddr *)mask; |
|
} |
} |
|
|
/* |
/* |
Line 320 if_free_sadl(struct ifnet *ifp) |
|
Line 349 if_free_sadl(struct ifnet *ifp) |
|
ifa = ifnet_addrs[ifp->if_index]; |
ifa = ifnet_addrs[ifp->if_index]; |
if (ifa == NULL) { |
if (ifa == NULL) { |
KASSERT(ifp->if_sadl == NULL); |
KASSERT(ifp->if_sadl == NULL); |
|
KASSERT(ifp->if_dl == NULL); |
return; |
return; |
} |
} |
|
|
KASSERT(ifp->if_sadl != NULL); |
KASSERT(ifp->if_sadl != NULL); |
|
KASSERT(ifp->if_dl != NULL); |
|
|
s = splnet(); |
s = splnet(); |
rtinit(ifa, RTM_DELETE, 0); |
rtinit(ifa, RTM_DELETE, 0); |
Line 333 if_free_sadl(struct ifnet *ifp) |
|
Line 364 if_free_sadl(struct ifnet *ifp) |
|
|
|
ifnet_addrs[ifp->if_index] = NULL; |
ifnet_addrs[ifp->if_index] = NULL; |
IFAFREE(ifa); |
IFAFREE(ifa); |
|
ifp->if_dl = NULL; |
|
IFAFREE(ifa); |
splx(s); |
splx(s); |
} |
} |
|
|
Line 1325 ifunit(const char *name) |
|
Line 1358 ifunit(const char *name) |
|
return NULL; |
return NULL; |
} |
} |
|
|
|
/* common */ |
|
static int |
|
ifioctl_common(u_long cmd, struct ifnet *ifp, struct ifreq *ifr, |
|
struct ifcapreq *ifcr, struct ifdatareq *ifdr) |
|
{ |
|
int s; |
|
|
|
switch (cmd) { |
|
case SIOCSIFCAP: |
|
if ((ifcr->ifcr_capenable & ~ifp->if_capabilities) != 0) |
|
return EINVAL; |
|
|
|
if (ifcr->ifcr_capenable == ifp->if_capenable) |
|
return 0; |
|
|
|
ifp->if_capenable = ifcr->ifcr_capenable; |
|
|
|
/* Pre-compute the checksum flags mask. */ |
|
ifp->if_csum_flags_tx = 0; |
|
ifp->if_csum_flags_rx = 0; |
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_IPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_IPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv6; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv6; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv6; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv6; |
|
} |
|
return ENETRESET; |
|
case SIOCSIFFLAGS: |
|
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { |
|
s = splnet(); |
|
if_down(ifp); |
|
splx(s); |
|
} |
|
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { |
|
s = splnet(); |
|
if_up(ifp); |
|
splx(s); |
|
} |
|
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
|
(ifr->ifr_flags &~ IFF_CANTCHANGE); |
|
break; |
|
case SIOCGIFFLAGS: |
|
ifr->ifr_flags = ifp->if_flags; |
|
break; |
|
|
|
case SIOCGIFMETRIC: |
|
ifr->ifr_metric = ifp->if_metric; |
|
break; |
|
|
|
case SIOCGIFMTU: |
|
ifr->ifr_mtu = ifp->if_mtu; |
|
break; |
|
|
|
case SIOCGIFDLT: |
|
ifr->ifr_dlt = ifp->if_dlt; |
|
break; |
|
|
|
case SIOCGIFCAP: |
|
ifcr->ifcr_capabilities = ifp->if_capabilities; |
|
ifcr->ifcr_capenable = ifp->if_capenable; |
|
break; |
|
|
|
case SIOCSIFMETRIC: |
|
ifp->if_metric = ifr->ifr_metric; |
|
break; |
|
|
|
case SIOCGIFDATA: |
|
ifdr->ifdr_data = ifp->if_data; |
|
break; |
|
|
|
case SIOCZIFDATA: |
|
ifdr->ifdr_data = ifp->if_data; |
|
/* |
|
* Assumes that the volatile counters that can be |
|
* zero'ed are at the end of if_data. |
|
*/ |
|
memset(&ifp->if_data.ifi_ipackets, 0, sizeof(ifp->if_data) - |
|
offsetof(struct if_data, ifi_ipackets)); |
|
break; |
|
default: |
|
return EOPNOTSUPP; |
|
} |
|
return 0; |
|
} |
|
|
/* |
/* |
* Interface ioctls. |
* Interface ioctls. |
*/ |
*/ |
Line 1427 ifioctl(struct socket *so, u_long cmd, v |
|
Line 1573 ifioctl(struct socket *so, u_long cmd, v |
|
oif_flags = ifp->if_flags; |
oif_flags = ifp->if_flags; |
switch (cmd) { |
switch (cmd) { |
|
|
case SIOCGIFFLAGS: |
|
ifr->ifr_flags = ifp->if_flags; |
|
break; |
|
|
|
case SIOCGIFMETRIC: |
|
ifr->ifr_metric = ifp->if_metric; |
|
break; |
|
|
|
case SIOCGIFMTU: |
|
ifr->ifr_mtu = ifp->if_mtu; |
|
break; |
|
|
|
case SIOCGIFDLT: |
|
ifr->ifr_dlt = ifp->if_dlt; |
|
break; |
|
|
|
case SIOCSIFFLAGS: |
case SIOCSIFFLAGS: |
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { |
ifioctl_common(cmd, ifp, ifr, NULL, NULL); |
s = splnet(); |
|
if_down(ifp); |
|
splx(s); |
|
} |
|
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { |
|
s = splnet(); |
|
if_up(ifp); |
|
splx(s); |
|
} |
|
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
|
(ifr->ifr_flags &~ IFF_CANTCHANGE); |
|
if (ifp->if_ioctl) |
if (ifp->if_ioctl) |
(void)(*ifp->if_ioctl)(ifp, cmd, data); |
(void)(*ifp->if_ioctl)(ifp, cmd, data); |
break; |
break; |
|
|
case SIOCGIFCAP: |
|
ifcr->ifcr_capabilities = ifp->if_capabilities; |
|
ifcr->ifcr_capenable = ifp->if_capenable; |
|
break; |
|
|
|
case SIOCSIFCAP: |
case SIOCSIFCAP: |
if ((ifcr->ifcr_capenable & ~ifp->if_capabilities) != 0) |
|
return EINVAL; |
|
if (ifp->if_ioctl == NULL) |
if (ifp->if_ioctl == NULL) |
return EOPNOTSUPP; |
return EOPNOTSUPP; |
|
|
/* Must prevent race with packet reception here. */ |
/* Must prevent race with packet reception here. */ |
s = splnet(); |
s = splnet(); |
if (ifcr->ifcr_capenable != ifp->if_capenable) { |
error = ifioctl_common(cmd, ifp, NULL, ifcr, NULL); |
|
if (error != ENETRESET) |
|
; |
|
else if (ifp->if_flags & IFF_UP) { |
struct ifreq ifrq; |
struct ifreq ifrq; |
|
|
ifrq.ifr_flags = ifp->if_flags; |
ifrq.ifr_flags = ifp->if_flags; |
ifp->if_capenable = ifcr->ifcr_capenable; |
|
|
|
/* Pre-compute the checksum flags mask. */ |
|
ifp->if_csum_flags_tx = 0; |
|
ifp->if_csum_flags_rx = 0; |
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_IPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_IPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv4; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv4; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv6; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv6; |
|
} |
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) { |
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv6; |
|
} |
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) { |
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv6; |
|
} |
|
|
|
/* |
/* |
* Only kick the interface if it's up. If it's |
* Only kick the interface if it's up. If it's |
* not up now, it will notice the cap enables |
* not up now, it will notice the cap enables |
* when it is brought up later. |
* when it is brought up later. |
*/ |
*/ |
if (ifp->if_flags & IFF_UP) |
(void)(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, |
(void)(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, |
(void *)&ifrq); |
(void *)&ifrq); |
error = 0; |
} |
} |
splx(s); |
splx(s); |
break; |
|
|
|
case SIOCSIFMETRIC: |
|
ifp->if_metric = ifr->ifr_metric; |
|
break; |
|
|
|
case SIOCGIFDATA: |
|
ifdr->ifdr_data = ifp->if_data; |
|
break; |
|
|
|
case SIOCZIFDATA: |
|
ifdr->ifdr_data = ifp->if_data; |
|
/* |
|
* Assumes that the volatile counters that can be |
|
* zero'ed are at the end of if_data. |
|
*/ |
|
memset(&ifp->if_data.ifi_ipackets, 0, sizeof(ifp->if_data) - |
|
offsetof(struct if_data, ifi_ipackets)); |
|
break; |
break; |
|
|
case SIOCSIFMTU: |
case SIOCSIFMTU: |
Line 1590 ifioctl(struct socket *so, u_long cmd, v |
|
Line 1648 ifioctl(struct socket *so, u_long cmd, v |
|
error = (*ifp->if_ioctl)(ifp, cmd, data); |
error = (*ifp->if_ioctl)(ifp, cmd, data); |
break; |
break; |
|
|
case SIOCSDRVSPEC: |
|
default: |
default: |
|
error = ifioctl_common(cmd, ifp, ifr, ifcr, ifdr); |
|
if (error != EOPNOTSUPP) |
|
break; |
if (so->so_proto == NULL) |
if (so->so_proto == NULL) |
return EOPNOTSUPP; |
return EOPNOTSUPP; |
#ifdef COMPAT_OSOCK |
#ifdef COMPAT_OSOCK |