#include "util.h" // catta_format_mac_address
-// for the luid-to-idx hashmap
-static unsigned luid_hash(const void *data)
+// integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
+// given CattaHwInterface into the CattaInterfaceMonitor
+static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
+ CattaHwInterface *hw,
+ IP_ADAPTER_UNICAST_ADDRESS *a)
{
- return ((NET_LUID *)data)->Info.NetLuidIndex;
-}
-static int luid_equal(const void *a, const void *b)
-{
- return (((NET_LUID *)a)->Value == ((NET_LUID *)b)->Value);
-}
+ CattaInterface *iface;
+ CattaAddress addr;
+ CattaInterfaceAddress *ifaddr;
+ struct sockaddr *sa = a->Address.lpSockaddr;
+
+ // skip transient addresses; to quote MSDN: "The IP address is a cluster
+ // address and should not be used by most applications."
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366066(v=vs.85).aspx
+ if(a->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
+ return;
-static CattaIfIndex find_ifindex(CattaInterfaceMonitor *m, NET_LUID luid)
-{
- CattaIfIndex *pi = NULL;
- NET_LUID *key = NULL;
-
- if((pi = catta_hashmap_lookup(m->osdep.idxmap, &luid)) == NULL) {
- // allocate memory for the hashmap key and value
- key = catta_malloc(sizeof(luid));
- pi = catta_malloc(sizeof(CattaIfIndex));
- if(!key || !pi)
- goto fail;
-
- *key = luid;
-
- // find an index for this luid
- *pi = m->osdep.nidx;
- if(*pi < 0) // overflow
- goto fail;
-
- // register the index
- if(catta_hashmap_replace(m->osdep.idxmap, key, pi) < 0)
- goto fail;
- m->osdep.nidx++;
+ // fill addr struct for address lookup
+ switch(sa->sa_family) {
+ case AF_INET:
+ memcpy(addr.data.data, &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memcpy(addr.data.data, &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr));
+ break;
+ default:
+ catta_log_debug("unexpected address family on interface %d: %u", hw->index, sa->sa_family);
+ return;
}
+ addr.proto = catta_af_to_proto(sa->sa_family);
- return *pi;
+ // get protocol-specific CattaInterface object
+ if(!(iface = catta_interface_monitor_get_interface(m, hw->index, addr.proto))) {
+ catta_log_error("CattaInterface (index %d, proto %d) not found", hw->index, addr.proto);
+ return;
+ }
-fail:
- catta_free(key);
- catta_free(pi);
- return -1;
+ // find or allocate a CattaInterfaceAddress struct for this address
+ if(!(ifaddr = catta_interface_monitor_get_address(m, iface, &addr))) {
+ if(!(ifaddr = catta_interface_address_new(m, iface, &addr, a->OnLinkPrefixLength))) {
+ catta_log_error("out of memory in ip_adapter_unicast_address");
+ return;
+ }
+ }
+
+ // set global scope flag
+ if(addr.proto == CATTA_PROTO_INET6)
+ ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr.data.data)
+ || IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr.data.data));
+ else
+ ifaddr->global_scope = 1;
+
+ // XXX debugging, remove
+ {
+ char s[CATTA_ADDRESS_STR_MAX];
+ catta_log_debug(" address: %s\n"
+ " global_scope: %d\n"
+ " flags: 0x%.4x",
+ catta_address_snprint(s, sizeof(s), &addr),
+ ifaddr->global_scope,
+ (unsigned int)a->Flags);
+ }
}
// integrate the information from an IP_ADAPTER_ADDRESSES structure
// as returned by GetAdaptersAddresses into the CattaInterfaceMonitor
-static void ip_adapter_address(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
+static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
{
+ IP_ADAPTER_UNICAST_ADDRESS *a;
CattaIfIndex idx;
CattaHwInterface *hw;
size_t n;
- // look up the interface index by LUID
- if((idx = find_ifindex(m, p->Luid)) < 0) {
- catta_log_error("could not allocate index ip_adapter_address");
+ // we want an index specific to the hardware interface, but Windows
+ // has one for IPv4 and one for IPv6. it seems like these are always the
+ // same unless one of the protocols is not available. let's have a bunch of
+ // checks...
+ if(!p->IfIndex && !p->Ipv6IfIndex) {
+ return; // no usable protocols
+ } else if(!p->IfIndex) {
+ idx = p->Ipv6IfIndex; // IPv6 but no IPv4 (huh!)
+ } else if(!p->Ipv6IfIndex) {
+ idx = p->IfIndex; // IPv4 but no IPv6
+ } else if(p->IfIndex == p->Ipv6IfIndex) {
+ idx = p->IfIndex; // same index for both protocols
+ } else {
+ // both indexes valid but not equal
+ catta_log_error("unsupported interface: %ls (IfIndex and Ipv6IfIndex differ: %u/%u)",
+ p->FriendlyName, (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex);
return;
}
// fill the CattaHwInterface struct with data
hw->flags_ok =
- (p->OperStatus & IfOperStatusUp) &&
- !(p->IfType & IF_TYPE_SOFTWARE_LOOPBACK) &&
+ (p->OperStatus == IfOperStatusUp) &&
+ !(p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) &&
!(p->Flags & IP_ADAPTER_NO_MULTICAST) &&
- (m->server->config.allow_point_to_point || !(p->IfType & IF_TYPE_PPP));
+ (m->server->config.allow_point_to_point || !(p->IfType == IF_TYPE_PPP));
// XXX what about IF_TYPE_TUNNEL?
n = wcstombs(NULL, p->FriendlyName, 0) + 1;
hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
- // XXX process addresses
-
// XXX debugging, remove
- {
- char mac[256];
- catta_log_debug("======\n name: %s\n index:%d\n mtu:%d\n mac:%s\n flags_ok:%d\n======",
- hw->name, hw->index,
- hw->mtu,
- catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
- hw->flags_ok);
- }
+ {
+ char mac[256];
+ catta_log_debug(" name: %s\n"
+ " index: %d\n"
+ " IfIndex: %u\n"
+ " Ipv6IfIndex: %u\n"
+ " mtu: %d\n"
+ " mac: %s\n"
+ " flags_ok: %d\n"
+ " type: %u\n"
+ " status: %u\n"
+ " multicast: %d\n"
+ " flags: 0x%.4x",
+ hw->name, hw->index,
+ (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex,
+ hw->mtu,
+ catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
+ hw->flags_ok,
+ (unsigned int)p->IfType,
+ (unsigned int)p->OperStatus,
+ !(p->Flags & IP_ADAPTER_NO_MULTICAST),
+ (unsigned int)p->Flags);
+ }
+
+ // process addresses
+ // XXX remove addresses that are no longer in the list
+ for(a=p->FirstUnicastAddress; a; a=a->Next)
+ ip_adapter_unicast_address(m, hw, a);
+ catta_log_debug("=====");
}
int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
{
- m->osdep.nidx = 0;
- m->osdep.idxmap = catta_hashmap_new(luid_hash, luid_equal, catta_free, catta_free);
- if(m->osdep.idxmap == NULL) {
- catta_log_error("out of memory in catta_interface_monitor_init_osdep");
- return -1;
- }
+ (void)*m; // silence "unused paramter" warning
// XXX register callbacks to get notified of interface/address changes
void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)
{
- catta_hashmap_free(m->osdep.idxmap);
+ (void)*m; // silence "unused paramter" warning
}
void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
// create 'CattaInterface's for every adapter
for(p=buf; p; p=p->Next)
- ip_adapter_address(m, p);
+ ip_adapter(m, p);
catta_free(buf);