2 This file is part of catta.
4 catta is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 catta is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with catta; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 #include "iface-windows.h"
23 #include <stdlib.h> // wcstombs
24 #include <catta/malloc.h>
25 #include <catta/log.h>
28 #include "util.h" // catta_format_mac_address
31 // integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
32 // given CattaHwInterface into the CattaInterfaceMonitor
33 static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
35 IP_ADAPTER_UNICAST_ADDRESS *a)
37 CattaInterface *iface;
39 CattaInterfaceAddress *ifaddr;
40 struct sockaddr *sa = a->Address.lpSockaddr;
42 // skip transient addresses; to quote MSDN: "The IP address is a cluster
43 // address and should not be used by most applications."
44 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366066(v=vs.85).aspx
45 if(a->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
48 // fill addr struct for address lookup
49 switch(sa->sa_family) {
51 memcpy(addr.data.data, &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr));
54 memcpy(addr.data.data, &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr));
57 catta_log_debug("unexpected address family on interface %d: %u", hw->index, sa->sa_family);
60 addr.proto = catta_af_to_proto(sa->sa_family);
62 // get protocol-specific CattaInterface object
63 if(!(iface = catta_interface_monitor_get_interface(m, hw->index, addr.proto))) {
64 catta_log_error("CattaInterface (index %d, proto %d) not found", hw->index, addr.proto);
68 // find or allocate a CattaInterfaceAddress struct for this address
69 if(!(ifaddr = catta_interface_monitor_get_address(m, iface, &addr))) {
70 if(!(ifaddr = catta_interface_address_new(m, iface, &addr, a->OnLinkPrefixLength))) {
71 catta_log_error("out of memory in ip_adapter_unicast_address");
76 // set global scope flag
77 // XXX should we use the IP_ADAPTER_ADDRESS_DNS_ELIGIBLE flag for this?
78 // it looks like it gets set for IPv4 addresses that are not localhost
79 // and for IPv6 addresses with global scope. not sure about multicast
81 if(addr.proto == CATTA_PROTO_INET6)
82 ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr.data.data)
83 || IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr.data.data));
85 ifaddr->global_scope = 1;
87 // XXX debugging, remove
89 char s[CATTA_ADDRESS_STR_MAX];
90 catta_log_debug(" address: %s\n"
93 catta_address_snprint(s, sizeof(s), &addr),
95 (unsigned int)a->Flags);
99 // integrate the information from an IP_ADAPTER_ADDRESSES structure
100 // as returned by GetAdaptersAddresses into the CattaInterfaceMonitor
101 static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
103 IP_ADAPTER_UNICAST_ADDRESS *a;
105 CattaHwInterface *hw;
108 // we want an index specific to the hardware interface, but Windows
109 // has one for IPv4 and one for IPv6. it seems like these are always the
110 // same unless one of the protocols is not available. let's have a bunch of
112 if(!p->IfIndex && !p->Ipv6IfIndex) {
113 return; // no usable protocols
114 } else if(!p->IfIndex) {
115 idx = p->Ipv6IfIndex; // IPv6 but no IPv4 (huh!)
116 } else if(!p->Ipv6IfIndex) {
117 idx = p->IfIndex; // IPv4 but no IPv6
118 } else if(p->IfIndex == p->Ipv6IfIndex) {
119 idx = p->IfIndex; // same index for both protocols
121 // both indexes valid but not equal
122 catta_log_error("unsupported interface: %ls (IfIndex and Ipv6IfIndex differ: %u/%u)",
123 p->FriendlyName, (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex);
127 // find the CattaHwInterface by index or allocate a new one
128 if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
129 if((hw = catta_hw_interface_new(m, idx)) == NULL) {
130 catta_log_error("catta_hw_interface_new failed in ip_adapter_address");
135 // fill the CattaHwInterface struct with data
137 (p->OperStatus == IfOperStatusUp) &&
138 !(p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) &&
139 !(p->Flags & IP_ADAPTER_NO_MULTICAST) &&
140 (m->server->config.allow_point_to_point || !(p->IfType == IF_TYPE_PPP));
141 // XXX what about IF_TYPE_TUNNEL?
143 n = wcstombs(NULL, p->FriendlyName, 0) + 1;
144 catta_free(hw->name);
145 hw->name = catta_new(char, n);
146 wcstombs(hw->name, p->FriendlyName, n);
150 hw->mac_address_size = p->PhysicalAddressLength;
151 if(hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
152 hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
153 memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
155 // XXX debugging, remove
158 catta_log_debug(" name: %s\n"
170 (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex,
172 catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
174 (unsigned int)p->IfType,
175 (unsigned int)p->OperStatus,
176 !(p->Flags & IP_ADAPTER_NO_MULTICAST),
177 (unsigned int)p->Flags);
181 // XXX remove addresses that are no longer in the list
182 for(a=p->FirstUnicastAddress; a; a=a->Next)
183 ip_adapter_unicast_address(m, hw, a);
184 catta_log_debug("=====");
188 int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
190 (void)*m; // silence "unused paramter" warning
192 // XXX register callbacks to get notified of interface/address changes
197 void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)
199 (void)*m; // silence "unused paramter" warning
202 void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
204 IP_ADAPTER_ADDRESSES *buf = NULL;
205 IP_ADAPTER_ADDRESSES *p;
206 ULONG bufsize = 15000;
209 // allocate a buffer and call GetAdaptersAddresses
210 // retry with the correct size if the buffer was too small
212 catta_free(buf); // no-op on first iteration
213 if((buf = catta_malloc(bufsize)) == NULL) {
214 catta_log_error("malloc failed in catta_interface_monitor_sync");
218 r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, buf, &bufsize);
219 } while(r == ERROR_BUFFER_OVERFLOW);
222 catta_log_error("GetAdaptersAddresses failed: %u", (unsigned int)r);
226 // XXX remove interfaces for adapters that are no longer in the list
228 // create 'CattaInterface's for every adapter
229 for(p=buf; p; p=p->Next)
234 m->list_complete = 1;
235 catta_interface_monitor_check_relevant(m);
236 catta_interface_monitor_update_rrs(m, 0);
237 catta_log_info("Network interface enumeration completed.");