summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/net.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r--winsup/cygwin/net.cc503
1 files changed, 497 insertions, 6 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 13a1ee9df..c6cf34b60 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -1125,6 +1125,315 @@ getdomainname (char *domain, size_t len)
/* Fill out an ifconf struct. */
+/* Vista/Longhorn: unicast address has additional OnLinkPrefixLength member. */
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
+ _ANONYMOUS_UNION union {
+ ULONGLONG Alignment;
+ _ANONYMOUS_UNION struct {
+ ULONG Length;
+ DWORD Flags;
+ } DUMMYSTRUCTNAME;
+ } DUMMYUNIONNAME;
+ struct _IP_ADAPTER_UNICAST_ADDRESS_VISTA *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+ unsigned char OnLinkPrefixLength;
+} IP_ADAPTER_UNICAST_ADDRESS_LH, *PIP_ADAPTER_UNICAST_ADDRESS_LH;
+
+/* Vista/Longhorn: IP_ADAPTER_ADDRESSES has a lot more info. We pick only
+ what we need for now. */
+typedef struct _IP_ADAPTER_ADDRESSES_LH {
+ _ANONYMOUS_UNION union {
+ ULONGLONG Alignment;
+ _ANONYMOUS_STRUCT struct {
+ ULONG Length;
+ DWORD IfIndex;
+ } DUMMYSTRUCTNAME;
+ } DUMMYUNIONNAME;
+ struct _IP_ADAPTER_ADDRESSES* Next;
+ PCHAR AdapterName;
+ PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
+ PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
+ PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
+ PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
+ PWCHAR DnsSuffix;
+ PWCHAR Description;
+ PWCHAR FriendlyName;
+ BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD PhysicalAddressLength;
+ DWORD Flags;
+ DWORD Mtu;
+ DWORD IfType;
+ IF_OPER_STATUS OperStatus;
+ DWORD Ipv6IfIndex;
+ DWORD ZoneIndices[16];
+ PIP_ADAPTER_PREFIX FirstPrefix;
+
+ ULONG64 TransmitLinkSpeed;
+ ULONG64 ReceiveLinkSpeed;
+ PVOID FirstWinsServerAddress;
+ PVOID FirstGatewayAddress;
+ ULONG Ipv4Metric;
+ ULONG Ipv6Metric;
+} IP_ADAPTER_ADDRESSES_LH,*PIP_ADAPTER_ADDRESSES_LH;
+
+/* We can't include ws2tcpip.h. */
+
+#define SIO_GET_INTERFACE_LIST _IOR('t', 127, u_long)
+
+struct sockaddr_in6_old {
+ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ struct in6_addr sin6_addr;
+};
+
+typedef union sockaddr_gen{
+ struct sockaddr Address;
+ struct sockaddr_in AddressIn;
+ struct sockaddr_in6_old AddressIn6;
+} sockaddr_gen;
+
+typedef struct _INTERFACE_INFO {
+ u_long iiFlags;
+ sockaddr_gen iiAddress;
+ sockaddr_gen iiBroadcastAddress;
+ sockaddr_gen iiNetmask;
+} INTERFACE_INFO, *LPINTERFACE_INFO;
+
+#ifndef IN_LOOPBACK
+#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
+#endif
+
+static int in6_are_prefix_equal (struct in6_addr *, struct in6_addr *, int);
+
+static int in_are_prefix_equal (struct in_addr *p1, struct in_addr *p2, int len)
+{
+ if (0 > len || len > 32)
+ return 0;
+ uint32_t pfxmask = 0xffffffff << (32 - len);
+ return (p1->s_addr & pfxmask) == (p2->s_addr & pfxmask);
+}
+
+extern "C" int
+ip_addr_prefix (PIP_ADAPTER_UNICAST_ADDRESS pua, PIP_ADAPTER_PREFIX pap)
+{
+ if (wincap.has_gaa_on_link_prefix ())
+ return (int) ((PIP_ADAPTER_UNICAST_ADDRESS_LH) pua)->OnLinkPrefixLength;
+ switch (pua->Address.lpSockaddr->sa_family)
+ {
+ case AF_INET:
+ /* Prior to Vista, the loopback prefix is not available. */
+ if (IN_LOOPBACK (((struct sockaddr_in *)
+ pua->Address.lpSockaddr)->sin_addr.s_addr))
+ return 8;
+ for ( ; pap; pap = pap->Next)
+ if (in_are_prefix_equal (
+ &((struct sockaddr_in *) pua->Address.lpSockaddr)->sin_addr,
+ &((struct sockaddr_in *) pap->Address.lpSockaddr)->sin_addr,
+ pap->PrefixLength))
+ return pap->PrefixLength;
+ break;
+ case AF_INET6:
+ /* Prior to Vista, the loopback prefix is not available. */
+ if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)
+ pua->Address.lpSockaddr)->sin6_addr))
+ return 128;
+ for ( ; pap; pap = pap->Next)
+ if (in6_are_prefix_equal (
+ &((struct sockaddr_in6 *) pua->Address.lpSockaddr)->sin6_addr,
+ &((struct sockaddr_in6 *) pap->Address.lpSockaddr)->sin6_addr,
+ pap->PrefixLength))
+ return pap->PrefixLength;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+#ifndef GAA_FLAG_INCLUDE_ALL_INTERFACES
+#define GAA_FLAG_INCLUDE_ALL_INTERFACES 0x0100
+#endif
+
+bool
+get_adapters_addresses (PIP_ADAPTER_ADDRESSES *pa_ret, ULONG family)
+{
+ DWORD ret, size = 0;
+ PIP_ADAPTER_ADDRESSES pa0 = NULL;
+
+ if (!pa_ret)
+ return ERROR_BUFFER_OVERFLOW
+ == GetAdaptersAddresses (family, GAA_FLAG_INCLUDE_PREFIX
+ | GAA_FLAG_INCLUDE_ALL_INTERFACES,
+ NULL, NULL, &size);
+ do
+ {
+ ret = GetAdaptersAddresses (family, GAA_FLAG_INCLUDE_PREFIX
+ | GAA_FLAG_INCLUDE_ALL_INTERFACES,
+ NULL, pa0, &size);
+ if (ret == ERROR_BUFFER_OVERFLOW
+ && !(pa0 = (PIP_ADAPTER_ADDRESSES) realloc (pa0, size)))
+ break;
+ }
+ while (ret == ERROR_BUFFER_OVERFLOW);
+ if (ret != ERROR_SUCCESS)
+ {
+ if (pa0)
+ free (pa0);
+ *pa_ret = NULL;
+ return false;
+ }
+ *pa_ret = pa0;
+ return true;
+}
+
+#define WS_IFF_UP 1
+#define WS_IFF_BROADCAST 2
+#define WS_IFF_LOOPBACK 4
+#define WS_IFF_POINTTOPOINT 8
+#define WS_IFF_MULTICAST 16
+
+static inline short
+convert_ifr_flags (u_long ws_flags)
+{
+ return (ws_flags & (WS_IFF_UP | WS_IFF_BROADCAST))
+ | ((ws_flags & (WS_IFF_LOOPBACK | WS_IFF_POINTTOPOINT)) << 1)
+ | ((ws_flags & WS_IFF_MULTICAST) << 8);
+}
+
+/*
+ * IFCONF XP SP1 and above.
+ * Use IP Helpper function GetAdaptersAddresses.
+ */
+
+static void
+get_xp_ifconf (SOCKET s, struct ifconf *ifc, int what)
+{
+ PIP_ADAPTER_ADDRESSES pa0 = NULL, pap;
+ PIP_ADAPTER_UNICAST_ADDRESS pua;
+ LPINTERFACE_INFO iie;
+ int cnt = 0;
+ DWORD size = 0;
+
+ if (!get_adapters_addresses (&pa0, AF_INET))
+ goto done;
+
+ for (pap = pa0; pap; pap = pap->Next)
+ for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
+ ++cnt;
+ /* If the size matches exactly the number of interfaces, WSAIoctl fails
+ with WSAError set to WSAEFAULT, for no apparent reason. So we allocate
+ space for one more INTERFACE_INFO structure here. */
+ iie = (LPINTERFACE_INFO) alloca ((cnt + 1) * sizeof (INTERFACE_INFO));
+ if (WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, iie,
+ (cnt + 1) * sizeof (INTERFACE_INFO), &size, NULL, NULL))
+ {
+ set_winsock_errno ();
+ cnt = 0;
+ goto done;
+ }
+
+ struct ifreq *ifr = ifc->ifc_req;
+ for (pap = pa0; pap; pap = pap->Next)
+ {
+ int idx = 0;
+ for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
+ {
+ int iinf_idx;
+ for (iinf_idx = 0; iinf_idx < cnt; ++iinf_idx)
+ if (iie[iinf_idx].iiAddress.AddressIn.sin_addr.s_addr
+ == ((sockaddr_in *) pua->Address.lpSockaddr)->sin_addr.s_addr)
+ break;
+ if (iinf_idx >= cnt)
+ continue;
+ if (!idx)
+ strcpy (ifr->ifr_name, pap->AdapterName);
+ else
+ __small_sprintf (ifr->ifr_name, "%s:%u", pap->AdapterName, idx);
+ ++idx;
+ switch (what)
+ {
+ case SIOCGIFFLAGS:
+ {
+ ifr->ifr_flags = convert_ifr_flags (iie[iinf_idx].iiFlags);
+ if (pap->OperStatus == IfOperStatusUp
+ || pap->OperStatus == IfOperStatusUnknown)
+ ifr->ifr_flags |= IFF_RUNNING;
+ if (pap->OperStatus != IfOperStatusLowerLayerDown)
+ ifr->ifr_flags |= IFF_LOWER_UP;
+ if (pap->OperStatus == IfOperStatusDormant)
+ ifr->ifr_flags |= IFF_DORMANT;
+ ULONG hwaddr[2], hwlen = 6;
+ if (SendARP (iie[iinf_idx].iiAddress.AddressIn.sin_addr.s_addr,
+ 0, hwaddr, &hwlen))
+ ifr->ifr_flags |= IFF_NOARP;
+ }
+ break;
+ case SIOCGIFCONF:
+ case SIOCGIFADDR:
+ memcpy (&ifr->ifr_addr,
+ &iie[iinf_idx].iiAddress.AddressIn,
+ sizeof (struct sockaddr_in));
+ break;
+ case SIOCGIFBRDADDR:
+ memcpy (&ifr->ifr_broadaddr,
+ &iie[iinf_idx].iiBroadcastAddress.AddressIn,
+ sizeof (struct sockaddr_in));
+ break;
+ case SIOCGIFNETMASK:
+ memcpy (&ifr->ifr_netmask,
+ &iie[iinf_idx].iiNetmask.AddressIn,
+ sizeof (struct sockaddr_in));
+ break;
+ case SIOCGIFHWADDR:
+ for (UINT i = 0; i < IFHWADDRLEN; ++i)
+ if (i >= pap->PhysicalAddressLength)
+ ifr->ifr_hwaddr.sa_data[i] = '\0';
+ else
+ ifr->ifr_hwaddr.sa_data[i] = pap->PhysicalAddress[i];
+ ifr->ifr_hwaddr.sa_family = AF_INET;
+ break;
+ case SIOCGIFMETRIC:
+ if (wincap.has_gaa_on_link_prefix ())
+ ifr->ifr_metric = ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric;
+ else
+ ifr->ifr_metric = 1;
+ break;
+ case SIOCGIFMTU:
+ ifr->ifr_mtu = pap->Mtu;
+ break;
+ case SIOCGIFINDEX:
+ ifr->ifr_ifindex = pap->IfIndex;
+ break;
+ case SIOCGIFFRNDLYNAM:
+ {
+ struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+ ifr->ifr_frndlyname;
+ iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
+ IFRF_FRIENDLYNAMESIZ,
+ pap->FriendlyName);
+ }
+ break;
+ }
+ if ((caddr_t) ++ifr >
+ ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
+ goto done;
+ }
+ }
+
+done:
+ if (pa0)
+ free (pa0);
+ /* Set the correct length */
+ ifc->ifc_len = cnt * sizeof (struct ifreq);
+}
+
/*
* IFCONF 98/ME, NTSP4, W2K:
* Use IP Helper Library
@@ -1239,7 +1548,7 @@ get_2k_ifconf (struct ifconf *ifc, int what)
__small_sprintf (ifr->ifr_name, "%s%u", name, ifEntry->classId);
else
__small_sprintf (ifr->ifr_name, "%s%u:%u", name,
- ifEntry->classId, ifEntry->enumerated - 1);
+ ifEntry->classId, ifEntry->enumerated);
ifEntry->enumerated++;
}
@@ -1304,7 +1613,7 @@ get_2k_ifconf (struct ifconf *ifc, int what)
break;
}
++cnt;
- if ((caddr_t)++ ifr >
+ if ((caddr_t) ++ifr >
ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
goto done;
}
@@ -1396,7 +1705,7 @@ get_nt_ifconf (struct ifconf *ifc, int what)
*ip && *np;
ip += strlen (ip) + 1, np += strlen (np) + 1)
{
- if ((caddr_t)++ ifr > ifc->ifc_buf
+ if ((caddr_t) ++ifr > ifc->ifc_buf
+ ifc->ifc_len - sizeof (struct ifreq))
break;
@@ -1606,7 +1915,7 @@ get_95_ifconf (struct ifconf *ifc, int what)
NULL, (unsigned char *) np,
(size = sizeof np, &size)) == ERROR_SUCCESS)
{
- if ((caddr_t)++ ifr > ifc->ifc_buf
+ if ((caddr_t) ++ifr > ifc->ifc_buf
+ ifc->ifc_len - sizeof (struct ifreq))
goto out;
@@ -1697,7 +2006,7 @@ out:
}
int
-get_ifconf (struct ifconf *ifc, int what)
+get_ifconf (SOCKET s, struct ifconf *ifc, int what)
{
unsigned long lip, lnp;
struct sockaddr_in *sa;
@@ -1768,7 +2077,9 @@ get_ifconf (struct ifconf *ifc, int what)
}
}
- if (wincap.has_ip_helper_lib ())
+ if (wincap.has_gaa_prefixes () && !CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ)
+ get_xp_ifconf (s, ifc, what);
+ else if (wincap.has_ip_helper_lib ())
get_2k_ifconf (ifc, what);
else if (wincap.is_winnt ())
get_nt_ifconf (ifc, what);
@@ -1777,6 +2088,102 @@ get_ifconf (struct ifconf *ifc, int what)
return 0;
}
+extern "C" unsigned
+if_nametoindex (const char *name)
+{
+ PIP_ADAPTER_ADDRESSES pap = NULL;
+
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return 0;
+
+ if (wincap.has_gaa_prefixes ()
+ && get_adapters_addresses (&pap, AF_UNSPEC))
+ {
+ char lname[IF_NAMESIZE], *c;
+
+ lname[0] = '\0';
+ strncat (lname, name, IF_NAMESIZE - 1);
+ if (lname[0] == '{' && (c = strchr (lname, ':')))
+ *c = '\0';
+ for (; pap; pap = pap->Next)
+ if (strcasematch (lname, pap->AdapterName))
+ return pap->IfIndex;
+ }
+ return 0;
+}
+
+extern "C" char *
+if_indextoname (unsigned ifindex, char *ifname)
+{
+ PIP_ADAPTER_ADDRESSES pap = NULL;
+
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return NULL;
+
+ if (wincap.has_gaa_prefixes ()
+ && get_adapters_addresses (&pap, AF_UNSPEC))
+ {
+ for (; pap; pap = pap->Next)
+ if (ifindex == pap->IfIndex)
+ {
+ strcpy (ifname, pap->AdapterName);
+ return ifname;
+ }
+ }
+ set_errno (ENXIO);
+ return NULL;
+}
+
+extern "C" struct if_nameindex *
+if_nameindex (void)
+{
+ PIP_ADAPTER_ADDRESSES pa0 = NULL, pap;
+ struct if_nameindex *iflist = NULL;
+ char (*ifnamelist)[IF_NAMESIZE];
+
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return NULL;
+
+ if (wincap.has_gaa_prefixes ()
+ && get_adapters_addresses (&pa0, AF_UNSPEC))
+ {
+ int cnt = 0;
+ for (pap = pa0; pap; pap = pap->Next)
+ ++cnt;
+ iflist = (struct if_nameindex *)
+ malloc ((cnt + 1) * sizeof (struct if_nameindex)
+ + cnt * IF_NAMESIZE);
+ if (!iflist)
+ {
+ set_errno (ENOBUFS);
+ return NULL;
+ }
+ ifnamelist = (char (*)[IF_NAMESIZE]) (iflist + cnt + 1);
+ for (pap = pa0, cnt = 0; pap; pap = pap->Next, ++cnt)
+ {
+ iflist[cnt].if_index = pap->IfIndex ?: pap->Ipv6IfIndex;
+ strcpy (iflist[cnt].if_name = ifnamelist[cnt], pap->AdapterName);
+ }
+ iflist[cnt].if_index = 0;
+ iflist[cnt].if_name = NULL;
+ return iflist;
+ }
+ set_errno (ENXIO);
+ return NULL;
+}
+
+extern "C" void
+if_freenameindex (struct if_nameindex *ptr)
+{
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return;
+ free (ptr);
+}
+
#define PORT_LOW (IPPORT_EFSSERVER + 1)
#define PORT_HIGH (IPPORT_RESERVED - 1)
#define NUM_PORTS (PORT_HIGH - PORT_LOW + 1)
@@ -3493,3 +3900,87 @@ cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen,
return ipv4_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags);
}
+/* The below function has been taken from OpenBSD's src/sys/netinet6/in6.c. */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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. 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
+ * SUCH DAMAGE.
+ *
+ * @(#)in.c 8.2 (Berkeley) 11/15/93
+ */
+
+static int
+in6_are_prefix_equal (struct in6_addr *p1, struct in6_addr *p2, int len)
+{
+ int bytelen, bitlen;
+
+ /* sanity check */
+ if (0 > len || len > 128)
+ return 0;
+
+ bytelen = len / 8;
+ bitlen = len % 8;
+
+ if (memcmp (&p1->s6_addr, &p2->s6_addr, bytelen))
+ return 0;
+ /* len == 128 is ok because bitlen == 0 then */
+ if (bitlen != 0 &&
+ p1->s6_addr[bytelen] >> (8 - bitlen) !=
+ p2->s6_addr[bytelen] >> (8 - bitlen))
+ return 0;
+
+ return 1;
+}