Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2009-06-16 00:04:15 +0400
committerCorinna Vinschen <corinna@vinschen.de>2009-06-16 00:04:15 +0400
commitea3923078a6e2d189595ff8671b34769982556a9 (patch)
treec5a2d62f3cc8fbadd90963fa01bc45c72ae54956
parenta02f102db22995fb23757ef9fba7e04a36495f71 (diff)
* net.cc (get_flags): New static function to generate interface flags
value. (get_ipv4fromreg_ipcnt): New static function to fetch number of configured IPv4 addresses for a given NIC from registry. (get_ipv4fromreg): New static function to fetch configured IPv4 addresses for a given NIC from registry. (get_friendlyname): New static function to generate friendly name. (get_hwaddr): New static function to copy hardware address. (get_xp_ifs): Restructure slightly. Add code to generate IPv4 entries entries for interfaces which are disconnected.
-rw-r--r--winsup/cygwin/ChangeLog13
-rw-r--r--winsup/cygwin/net.cc402
2 files changed, 300 insertions, 115 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index b41486066..a64306723 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,16 @@
+2009-06-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * net.cc (get_flags): New static function to generate interface flags
+ value.
+ (get_ipv4fromreg_ipcnt): New static function to fetch number of
+ configured IPv4 addresses for a given NIC from registry.
+ (get_ipv4fromreg): New static function to fetch configured IPv4
+ addresses for a given NIC from registry.
+ (get_friendlyname): New static function to generate friendly name.
+ (get_hwaddr): New static function to copy hardware address.
+ (get_xp_ifs): Restructure slightly. Add code to generate IPv4 entries
+ entries for interfaces which are disconnected.
+
2009-06-14 Christopher Faylor <me+cygwin@cgf.cx>
* errno.cc (errmap): Add mapping for ERROR_IO_INCOMPLETE.
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 4260b20e0..b6ec47744 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -1587,6 +1587,149 @@ struct ifall {
struct ifreq_frndlyname ifa_frndlyname;
};
+static unsigned int
+get_flags (PIP_ADAPTER_ADDRESSES pap)
+{
+ unsigned int flags = IFF_UP;
+ if (pap->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
+ flags |= IFF_LOOPBACK;
+ else if (pap->IfType == IF_TYPE_PPP)
+ flags |= IFF_POINTOPOINT;
+ if (!(pap->Flags & IP_ADAPTER_NO_MULTICAST))
+ flags |= IFF_MULTICAST;
+ if (pap->OperStatus == IfOperStatusUp
+ || pap->OperStatus == IfOperStatusUnknown)
+ flags |= IFF_RUNNING;
+ if (pap->OperStatus != IfOperStatusLowerLayerDown)
+ flags |= IFF_LOWER_UP;
+ if (pap->OperStatus == IfOperStatusDormant)
+ flags |= IFF_DORMANT;
+ return flags;
+}
+
+static ULONG
+get_ipv4fromreg_ipcnt (const char *name)
+{
+ HKEY key;
+ LONG ret;
+ char regkey[256], *c;
+ ULONG ifs = 1;
+ DWORD dhcp, size;
+
+ c = stpcpy (regkey, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\"
+ "Parameters\\Interfaces\\");
+ stpcpy (c, name);
+ if ((ret = RegOpenKeyEx (HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ,
+ &key)) != ERROR_SUCCESS)
+ {
+ debug_printf ("RegOpenKeyEx(%s), win32 error %ld", ret);
+ return 0;
+ }
+ /* If DHCP is used, we have only one address. */
+ if ((ret = RegQueryValueEx (key, "EnableDHCP", NULL, NULL, (PBYTE) &dhcp,
+ (size = sizeof dhcp, &size))) == ERROR_SUCCESS
+ && dhcp == 0
+ && (ret = RegQueryValueEx (key, "IPAddress", NULL, NULL, NULL,
+ &size)) == ERROR_SUCCESS)
+ {
+ char *ipa = (char *) alloca (size);
+ RegQueryValueEx (key, "IPAddress", NULL, NULL, (PBYTE) ipa, &size);
+ for (ifs = 0, c = ipa; *c; c += strlen (c) + 1)
+ ifs++;
+ }
+ RegCloseKey (key);
+ return ifs;
+}
+
+static void
+get_ipv4fromreg (struct ifall *ifp, const char *name, DWORD idx)
+{
+ HKEY key;
+ LONG ret;
+ char regkey[256], *c;
+ DWORD ifs;
+ DWORD dhcp, size;
+
+ c = stpcpy (regkey, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\"
+ "Parameters\\Interfaces\\");
+ stpcpy (c, name);
+ if ((ret = RegOpenKeyEx (HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ, &key))
+ != ERROR_SUCCESS)
+ {
+ debug_printf ("RegOpenKeyEx(%s), win32 error %ld", ret);
+ return;
+ }
+ /* If DHCP is used, we have only one address. */
+ if ((ret = RegQueryValueEx (key, "EnableDHCP", NULL, NULL, (PBYTE) &dhcp,
+ (size = sizeof dhcp, &size))) == ERROR_SUCCESS)
+ {
+#define addr ((struct sockaddr_in *) &ifp->ifa_addr)
+#define mask ((struct sockaddr_in *) &ifp->ifa_netmask)
+#define brdc ((struct sockaddr_in *) &ifp->ifa_brddstaddr)
+ if (dhcp)
+ {
+ if ((ret = RegQueryValueEx (key, "DhcpIPAddress", NULL, NULL,
+ (PBYTE) regkey, (size = 256, &size)))
+ == ERROR_SUCCESS)
+ cygwin_inet_aton (regkey, &addr->sin_addr);
+ if ((ret = RegQueryValueEx (key, "DhcpSubnetMask", NULL, NULL,
+ (PBYTE) regkey, (size = 256, &size)))
+ == ERROR_SUCCESS)
+ cygwin_inet_aton (regkey, &mask->sin_addr);
+ }
+ else
+ {
+ if ((ret = RegQueryValueEx (key, "IPAddress", NULL, NULL, NULL,
+ &size)) == ERROR_SUCCESS)
+ {
+ char *ipa = (char *) alloca (size);
+ RegQueryValueEx (key, "IPAddress", NULL, NULL, (PBYTE) ipa, &size);
+ for (ifs = 0, c = ipa; *c && ifs < idx; c += strlen (c) + 1)
+ ifs++;
+ if (*c)
+ cygwin_inet_aton (c, &addr->sin_addr);
+ }
+ if ((ret = RegQueryValueEx (key, "SubnetMask", NULL, NULL, NULL,
+ &size)) == ERROR_SUCCESS)
+ {
+ char *ipa = (char *) alloca (size);
+ RegQueryValueEx (key, "SubnetMask", NULL, NULL, (PBYTE) ipa, &size);
+ for (ifs = 0, c = ipa; *c && ifs < idx; c += strlen (c) + 1)
+ ifs++;
+ if (*c)
+ cygwin_inet_aton (c, &mask->sin_addr);
+ }
+ }
+ if (ifp->ifa_ifa.ifa_flags & IFF_BROADCAST)
+ brdc->sin_addr.s_addr = (addr->sin_addr.s_addr
+ & mask->sin_addr.s_addr)
+ | ~mask->sin_addr.s_addr;
+#undef addr
+#undef mask
+#undef brdc
+ }
+ RegCloseKey (key);
+}
+
+static void
+get_friendlyname (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap)
+{
+ struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+ &ifp->ifa_frndlyname;
+ iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
+ IFRF_FRIENDLYNAMESIZ,
+ pap->FriendlyName);
+}
+
+static void
+get_hwaddr (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap)
+{
+ for (UINT i = 0; i < IFHWADDRLEN; ++i)
+ if (i >= pap->PhysicalAddressLength)
+ ifp->ifa_hwaddr.sa_data[i] = '\0';
+ else
+ ifp->ifa_hwaddr.sa_data[i] = pap->PhysicalAddress[i];
+}
/*
* Get network interfaces XP SP1 and above.
* Use IP Helper function GetAdaptersAddresses.
@@ -1605,7 +1748,15 @@ get_xp_ifs (ULONG family)
goto done;
for (pap = pa0; pap; pap = pap->Next)
- for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
+ if (!pap->FirstUnicastAddress)
+ {
+ /* FirstUnicastAddress is NULL for interfaces which are disconnected.
+ Fetch number of configured IPva addresses from registry and
+ store in an unused member of the adapter addresses structure. */
+ pap->Ipv6IfIndex = get_ipv4fromreg_ipcnt (pap->AdapterName);
+ cnt += pap->Ipv6IfIndex;
+ }
+ else for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
++cnt;
if (!(ifret = (struct ifall *) calloc (cnt, sizeof (struct ifall))))
@@ -1614,125 +1765,146 @@ get_xp_ifs (ULONG family)
for (pap = pa0; pap; pap = pap->Next)
{
- int idx = 0;
- for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
- {
- struct sockaddr *sa = (struct sockaddr *) pua->Address.lpSockaddr;
+ DWORD idx = 0;
+ if (!pap->FirstUnicastAddress)
+ for (idx = 0; idx < pap->Ipv6IfIndex; ++idx)
+ {
+ /* Next in chain */
+ ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+ /* Interface name */
+ if (idx)
+ __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx);
+ else
+ strcpy (ifp->ifa_name, pap->AdapterName);
+ ifp->ifa_ifa.ifa_name = ifp->ifa_name;
+ /* Flags */
+ ifp->ifa_ifa.ifa_flags = get_flags (pap);
+ if (pap->IfType != IF_TYPE_PPP)
+ ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
+ /* Address */
+ ifp->ifa_addr.ss_family = AF_INET;
+ ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+ /* Broadcast/Destination address */
+ ifp->ifa_brddstaddr.ss_family = AF_INET;
+ ifp->ifa_ifa.ifa_dstaddr = NULL;
+ /* Netmask */
+ ifp->ifa_netmask.ss_family = AF_INET;
+ ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+ /* Try to fetch real IPv4 address information from registry. */
+ get_ipv4fromreg (ifp, pap->AdapterName, idx);
+ /* Hardware address */
+ get_hwaddr (ifp, pap);
+ /* Metric */
+ ifp->ifa_metric = 1;
+ /* MTU */
+ ifp->ifa_mtu = pap->Mtu;
+ /* Interface index */
+ ifp->ifa_ifindex = pap->IfIndex;
+ /* Friendly name */
+ get_friendlyname (ifp, pap);
+ ++ifp;
+ }
+ else
+ for (idx = 0, pua = pap->FirstUnicastAddress; pua;
+ ++idx, pua = pua->Next)
+ {
+ struct sockaddr *sa = (struct sockaddr *) pua->Address.lpSockaddr;
# define sin ((struct sockaddr_in *) sa)
# define sin6 ((struct sockaddr_in6 *) sa)
- size_t sa_size = (sa->sa_family == AF_INET6
- ? sizeof *sin6 : sizeof *sin);
- /* Next in chain */
- ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
- /* Interface name */
- if (!idx)
- strcpy (ifp->ifa_name, pap->AdapterName);
- else
- __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx);
- ifp->ifa_ifa.ifa_name = ifp->ifa_name;
- ++idx;
- /* Flags */
- ifp->ifa_ifa.ifa_flags = IFF_UP;
- if (pap->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
- ifp->ifa_ifa.ifa_flags |= IFF_LOOPBACK;
- else if (pap->IfType == IF_TYPE_PPP)
- ifp->ifa_ifa.ifa_flags |= IFF_POINTOPOINT;
- else if (sa->sa_family == AF_INET)
- ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
- if (!(pap->Flags & IP_ADAPTER_NO_MULTICAST))
- ifp->ifa_ifa.ifa_flags |= IFF_MULTICAST;
- if (pap->OperStatus == IfOperStatusUp
- || pap->OperStatus == IfOperStatusUnknown)
- ifp->ifa_ifa.ifa_flags |= IFF_RUNNING;
- if (pap->OperStatus != IfOperStatusLowerLayerDown)
- ifp->ifa_ifa.ifa_flags |= IFF_LOWER_UP;
- if (pap->OperStatus == IfOperStatusDormant)
- ifp->ifa_ifa.ifa_flags |= IFF_DORMANT;
- if (sa->sa_family == AF_INET)
- {
- ULONG hwaddr[2], hwlen = 6;
- if (SendARP (sin->sin_addr.s_addr, 0, hwaddr, &hwlen))
- ifp->ifa_ifa.ifa_flags |= IFF_NOARP;
- }
- /* Address */
- memcpy (&ifp->ifa_addr, sa, sa_size);
- ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
- /* Netmask */
- int prefix = ip_addr_prefix (pua, pap->FirstPrefix);
- switch (sa->sa_family)
- {
- case AF_INET:
- if_sin = (struct sockaddr_in *) &ifp->ifa_netmask;
- if_sin->sin_addr.s_addr = htonl (UINT32_MAX << (32 - prefix));
- if_sin->sin_family = AF_INET;
- break;
- case AF_INET6:
- if_sin6 = (struct sockaddr_in6 *) &ifp->ifa_netmask;
- for (cnt = 0; cnt < 4 && prefix; ++cnt, prefix -= 32)
- if_sin6->sin6_addr.s6_addr32[cnt] = UINT32_MAX;
- if (prefix < 32)
- if_sin6->sin6_addr.s6_addr32[cnt] <<= 32 - prefix;
- break;
- }
- ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
- if (pap->IfType == IF_TYPE_PPP)
- {
- /* Destination address */
- if (sa->sa_family == AF_INET)
- {
- if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
- if_sin->sin_addr.s_addr = get_routedst (pap->IfIndex);
- if_sin->sin_family = AF_INET;
- }
- else
- /* FIXME: No official way to get the dstaddr for ipv6? */
- memcpy (&ifp->ifa_addr, sa, sa_size);
- ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *)
- &ifp->ifa_brddstaddr;
- }
- else
- {
- /* Broadcast address */
- if (sa->sa_family == AF_INET)
- {
- if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
- uint32_t mask =
- ((struct sockaddr_in *) &ifp->ifa_netmask)->sin_addr.s_addr;
- if_sin->sin_addr.s_addr = (sin->sin_addr.s_addr & mask) | ~mask;
- if_sin->sin_family = AF_INET;
- ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *)
- &ifp->ifa_brddstaddr;
- }
- else /* No IPv6 broadcast */
- ifp->ifa_ifa.ifa_broadaddr = NULL;
- }
- /* Hardware address */
- for (UINT i = 0; i < IFHWADDRLEN; ++i)
- if (i >= pap->PhysicalAddressLength)
- ifp->ifa_hwaddr.sa_data[i] = '\0';
+ size_t sa_size = (sa->sa_family == AF_INET6
+ ? sizeof *sin6 : sizeof *sin);
+ /* Next in chain */
+ ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+ /* Interface name */
+ if (idx && sa->sa_family == AF_INET)
+ __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx);
else
- ifp->ifa_hwaddr.sa_data[i] = pap->PhysicalAddress[i];
- /* Metric */
- if (wincap.has_gaa_on_link_prefix ())
- ifp->ifa_metric = (sa->sa_family == AF_INET
- ? ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric
- : ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv6Metric);
- else
- ifp->ifa_metric = 1;
- /* MTU */
- ifp->ifa_mtu = pap->Mtu;
- /* Interface index */
- ifp->ifa_ifindex = pap->IfIndex;
- /* Friendly name */
- struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
- &ifp->ifa_frndlyname;
- iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
- IFRF_FRIENDLYNAMESIZ,
- pap->FriendlyName);
- ++ifp;
+ strcpy (ifp->ifa_name, pap->AdapterName);
+ ifp->ifa_ifa.ifa_name = ifp->ifa_name;
+ /* Flags */
+ ifp->ifa_ifa.ifa_flags = get_flags (pap);
+ if (sa->sa_family == AF_INET
+ && pap->IfType != IF_TYPE_SOFTWARE_LOOPBACK
+ && pap->IfType != IF_TYPE_PPP)
+ ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
+ if (sa->sa_family == AF_INET)
+ {
+ ULONG hwaddr[2], hwlen = 6;
+ if (SendARP (sin->sin_addr.s_addr, 0, hwaddr, &hwlen))
+ ifp->ifa_ifa.ifa_flags |= IFF_NOARP;
+ }
+ /* Address */
+ memcpy (&ifp->ifa_addr, sa, sa_size);
+ ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+ /* Netmask */
+ int prefix = ip_addr_prefix (pua, pap->FirstPrefix);
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if_sin = (struct sockaddr_in *) &ifp->ifa_netmask;
+ if_sin->sin_addr.s_addr = htonl (UINT32_MAX << (32 - prefix));
+ if_sin->sin_family = AF_INET;
+ break;
+ case AF_INET6:
+ if_sin6 = (struct sockaddr_in6 *) &ifp->ifa_netmask;
+ for (cnt = 0; cnt < 4 && prefix; ++cnt, prefix -= 32)
+ if_sin6->sin6_addr.s6_addr32[cnt] = UINT32_MAX;
+ if (prefix < 32)
+ if_sin6->sin6_addr.s6_addr32[cnt] <<= 32 - prefix;
+ break;
+ }
+ ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+ if (pap->IfType == IF_TYPE_PPP)
+ {
+ /* Destination address */
+ if (sa->sa_family == AF_INET)
+ {
+ if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+ if_sin->sin_addr.s_addr = get_routedst (pap->IfIndex);
+ if_sin->sin_family = AF_INET;
+ }
+ else
+ /* FIXME: No official way to get the dstaddr for ipv6? */
+ memcpy (&ifp->ifa_addr, sa, sa_size);
+ ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *)
+ &ifp->ifa_brddstaddr;
+ }
+ else
+ {
+ /* Broadcast address */
+ if (sa->sa_family == AF_INET)
+ {
+ if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+ uint32_t mask =
+ ((struct sockaddr_in *) &ifp->ifa_netmask)->sin_addr.s_addr;
+ if_sin->sin_addr.s_addr = (sin->sin_addr.s_addr & mask)
+ | ~mask;
+ if_sin->sin_family = AF_INET;
+ ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *)
+ &ifp->ifa_brddstaddr;
+ }
+ else /* No IPv6 broadcast */
+ ifp->ifa_ifa.ifa_broadaddr = NULL;
+ }
+ /* Hardware address */
+ get_hwaddr (ifp, pap);
+ /* Metric */
+ if (wincap.has_gaa_on_link_prefix ())
+ ifp->ifa_metric = (sa->sa_family == AF_INET
+ ? ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric
+ : ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv6Metric);
+ else
+ ifp->ifa_metric = 1;
+ /* MTU */
+ ifp->ifa_mtu = pap->Mtu;
+ /* Interface index */
+ ifp->ifa_ifindex = pap->IfIndex;
+ /* Friendly name */
+ get_friendlyname (ifp, pap);
+ ++ifp;
# undef sin
# undef sin6
- }
+ }
}
/* Since every entry is set to the next entry, the last entry points to an
invalid next entry now. Fix it retroactively. */