};
+// helper: determine the global_scope flag for an address
+static void set_global_scope_flag(CattaInterfaceAddress *ifaddr, const CattaAddress *addr)
+{
+ if(addr->proto == CATTA_PROTO_INET6) {
+ const struct in6_addr *ia = (struct in6_addr *)addr->data.ipv6.address;
+ ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL(ia) || IN6_IS_ADDR_MULTICAST(ia));
+ } else {
+ ifaddr->global_scope = 1;
+ }
+}
+
// integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
// given CattaHwInterface into the CattaInterfaceMonitor
static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
}
}
- // set global scope flag
- // XXX should we use the IP_ADAPTER_ADDRESS_DNS_ELIGIBLE flag for this?
- // it looks like it gets set for IPv4 addresses that are not localhost
- // and for IPv6 addresses with global scope. not sure about multicast
- // addresses.
- 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);
- }
+ set_global_scope_flag(ifaddr, &addr);
}
// integrate the information from an IP_ADAPTER_ADDRESSES structure
hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
- // XXX debugging, remove
- {
- 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("=====");
}
if(!pthread_mutex_lock(&m->osdep.mutex)) {
// queue the event
- // XXX event ordering!!
- CATTA_LLIST_PREPEND(ChangeEvent, event, m->osdep.events, ev);
+ CATTA_LLIST_APPEND(ChangeEvent, event, m->osdep.events, ev);
// wake the handler
writepipe(m->osdep.pipefd[1], &c, sizeof(c));
queue_event(m, new_event(ADDRESS_CHANGE_EVENT, type, row, sizeof(*row)));
}
-void update_hw_interface(CattaHwInterface *hw)
+static void update_hw_interface(CattaHwInterface *hw)
{
MIB_IF_ROW2 row;
DWORD r;
hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
memcpy(hw->mac_address, row.PhysicalAddress, hw->mac_address_size);
- // XXX debugging, remove
- {
- char mac[256];
- catta_log_debug(" name: %s\n"
- " mtu: %d\n"
- " mac: %s\n"
- " flags_ok: %d\n"
- " type: %u\n"
- " status: %u\n"
- " multicast: %d\n"
- " access type: %d",
- hw->name,
- hw->mtu,
- catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
- hw->flags_ok,
- (unsigned int)row.Type,
- (unsigned int)row.OperStatus,
- multicast,
- (int)row.AccessType);
- }
+ catta_hw_interface_check_relevant(hw);
+ catta_hw_interface_update_rrs(hw, 0);
}
static void handle_iface_event(CattaInterfaceMonitor *m, MIB_IPINTERFACE_ROW *row, MIB_NOTIFICATION_TYPE type)
CattaInterface *iface;
CattaHwInterface *hw;
- // XXX debug, remove
- {
- const char *typestr = NULL;
-
- switch(type) {
- case MibParameterNotification: typestr = "ParameterNotification"; break;
- case MibAddInstance: typestr = "AddInstance"; break;
- case MibDeleteInstance: typestr = "DeleteInstance"; break;
- default: typestr = "Unknown";
- }
-
- catta_log_debug("interface %s on iface %d for %s", typestr, idx, protostr);
- }
-
// see if we know this interface
iface = catta_interface_monitor_get_interface(m, idx, proto);
hw = iface ? iface->hardware : catta_interface_monitor_get_hw_interface(m, idx);
static void handle_addr_event(CattaInterfaceMonitor *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE type)
{
CattaIfIndex idx = row->InterfaceIndex;
- CattaProtocol proto = catta_af_to_proto(row->Address.si_family);
- const char *protostr = catta_proto_to_string(proto);
+ CattaInterfaceAddress *ifaddr;
+ CattaInterface *iface;
+ CattaAddress addr;
+ const char *protostr;
- // XXX debug, remove
- {
- const char *typestr = NULL;
+ // fill addr struct for address lookup
+ switch(row->Address.si_family) {
+ case AF_INET:
+ memcpy(addr.data.data, &row->Address.Ipv4.sin_addr, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memcpy(addr.data.data, &row->Address.Ipv6.sin6_addr, sizeof(struct in6_addr));
+ break;
+ default:
+ catta_log_debug("unexpected address family on interface %d: %u", idx, row->Address.si_family);
+ return;
+ }
+ addr.proto = catta_af_to_proto(row->Address.si_family);
+ protostr = catta_proto_to_string(addr.proto);
- switch(type) {
- case MibParameterNotification: typestr = "ParameterNotification"; break;
- case MibAddInstance: typestr = "AddInstance"; break;
- case MibDeleteInstance: typestr = "DeleteInstance"; break;
- default: typestr = "Unknown";
- }
+ // see if we know this address/interface
+ iface = catta_interface_monitor_get_interface(m, idx, addr.proto);
+ ifaddr = iface ? catta_interface_monitor_get_address(m, iface, &addr) : NULL;
- catta_log_debug("address %s on iface %d for %s", typestr, idx, protostr);
- }
+ // print debug messages for some unexpected cases
+ if(type==MibParameterNotification && !ifaddr)
+ catta_log_debug("ParameterNotification received for unknown address on interface %d (%s)", idx, protostr);
+ if(type==MibDeleteInstance && !ifaddr)
+ catta_log_debug("DeleteInstance received for unknown address on interface %d (%s)", idx, protostr);
+ if(type==MibAddInstance && ifaddr)
+ catta_log_debug("AddInstance received for existing address on interface %d (%s)", idx, protostr);
+ if(ifaddr && !iface)
+ catta_log_debug("missing CattaInterface for address on interface %d (%s)", idx, protostr);
switch(type) {
case MibParameterNotification:
- break;
case MibAddInstance:
+ // fetch the full event data
+ if(GetUnicastIpAddressEntry(row) != NO_ERROR) {
+ catta_log_error("GetUnicastIpAddressEntry failed in handle_addr_event");
+ return;
+ }
+
+ // skip addresses that are not suitable as source addresses
+ if(row->SkipAsSource)
+ return;
+
+ // create the interface if it is missing
+ if(!iface) {
+ CattaHwInterface *hw;
+
+ if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
+ catta_log_error("interface %d not found in handle_addr_event", idx);
+ return;
+ }
+
+ if((iface = catta_interface_new(m, hw, addr.proto)) == NULL) {
+ catta_log_error("catta_interface_new failed in handle_addr_event");
+ return;
+ }
+ }
+ assert(iface != NULL);
+
+ // create the interface-associated address if it is missing
+ if(!ifaddr) {
+ unsigned prefixlen = row->OnLinkPrefixLength;
+
+ if((ifaddr = catta_interface_address_new(m, iface, &addr, prefixlen)) == NULL) {
+ catta_log_error("catta_interface_address_new failed in handle_addr_event");
+ return;
+ }
+ }
+ assert(ifaddr != NULL);
+
+ set_global_scope_flag(ifaddr, &addr);
break;
case MibDeleteInstance:
+ if(ifaddr)
+ catta_interface_address_free(ifaddr);
break;
default:
catta_log_debug("unexpected type (%d) of address change notification received", type);
}
+
+ if(iface) {
+ catta_interface_check_relevant(iface);
+ catta_interface_update_rrs(iface, 0);
+ }
}
static void handle_events(CattaInterfaceMonitor *m)
catta_log_error("pipe() in catta_interface_monitor_init_osdep failed");
return -1;
}
- catta_set_nonblock(m->osdep.pipefd[0]);
- catta_set_nonblock(m->osdep.pipefd[1]);
+ if(catta_set_nonblock(m->osdep.pipefd[0]) < 0 ||
+ catta_set_nonblock(m->osdep.pipefd[1]) < 0)
+ {
+ catta_log_error(__FILE__": catta_set_nonblock failed: %s", errnostrsocket());
+ goto fail;
+ }
m->osdep.icnhandle = NULL;
m->osdep.acnhandle = NULL;
m);
if(!m->osdep.watch) {
catta_log_error(__FILE__": Failed to create watch.");
- return -1;
+ goto fail;
}
// request async notification on interface changes
catta_log_error("NotifyUnicastIpAddressChange failed: %u", (unsigned int)r);
return 0;
+
+fail:
+ closesocket(m->osdep.pipefd[0]);
+ closesocket(m->osdep.pipefd[1]);
+ return -1;
}
void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)