]> git.meshlink.io Git - catta/blob - avahi-core/iface.c
* be a little bit more verbose about published IP addresses
[catta] / avahi-core / iface.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <asm/types.h>
29 #include <linux/netlink.h>
30 #include <linux/rtnetlink.h>
31 #include <errno.h>
32 #include <net/if.h>
33 #include <stdio.h>
34
35 #include <avahi-common/error.h>
36 #include <avahi-common/malloc.h>
37
38 #include "iface.h"
39 #include "netlink.h"
40 #include "dns.h"
41 #include "socket.h"
42 #include "announce.h"
43 #include "util.h"
44 #include "log.h"
45
46 static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, int remove_rrs) {
47     assert(m);
48     assert(a);
49
50     if (avahi_interface_address_relevant(a) &&
51         !remove_rrs &&
52         m->server->config.publish_addresses &&
53         (m->server->state == AVAHI_SERVER_RUNNING ||
54         m->server->state == AVAHI_SERVER_REGISTERING)) {
55
56         /* Fill the entry group */
57         if (!a->entry_group) 
58             a->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
59
60         if (!a->entry_group) /* OOM */
61             return;
62         
63         if (avahi_s_entry_group_is_empty(a->entry_group)) {
64             char t[64];
65             avahi_address_snprint(t, sizeof(t), &a->address);
66
67             avahi_log_info("Registering new address %s on %s.", t, a->interface->hardware->name);
68
69             if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) {
70                 avahi_log_warn(__FILE__": avahi_server_add_address() failed: %s", avahi_strerror(m->server->error));
71                 avahi_s_entry_group_free(a->entry_group);
72                 a->entry_group = NULL;
73                 return;
74             }
75
76             avahi_s_entry_group_commit(a->entry_group);
77         }
78     } else {
79
80         /* Clear the entry group */
81
82         if (a->entry_group && !avahi_s_entry_group_is_empty(a->entry_group)) {
83             char t[64];
84             avahi_address_snprint(t, sizeof(t), &a->address);
85
86             if (avahi_s_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
87                 avahi_server_decrease_host_rr_pending(m->server);
88
89             avahi_log_info("Withdrawing address %s on %s.", t, a->interface->hardware->name);
90             
91             avahi_s_entry_group_reset(a->entry_group);
92         }
93     } 
94 }
95
96 static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, int remove_rrs) {
97     AvahiInterfaceAddress *a;
98     
99     assert(m);
100     assert(i);
101
102     for (a = i->addresses; a; a = a->address_next)
103         update_address_rr(m, a, remove_rrs);
104 }
105
106 static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int remove_rrs) {
107     AvahiInterface *i;
108
109     assert(m);
110     assert(hw);
111
112     for (i = hw->interfaces; i; i = i->by_hardware_next)
113         update_interface_rr(m, i, remove_rrs);
114
115     if (!remove_rrs &&
116         m->server->config.publish_workstation &&
117         (m->server->state == AVAHI_SERVER_RUNNING ||
118         m->server->state == AVAHI_SERVER_REGISTERING)) {
119
120         if (!hw->entry_group)
121             hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
122
123         if (!hw->entry_group)
124             return; /* OOM */
125         
126         if (avahi_s_entry_group_is_empty(hw->entry_group)) {
127             char *name;
128             char *t;
129
130             if (!(t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size)))
131                 return; /* OOM */
132
133             name = avahi_strdup_printf("%s [%s]", m->server->host_name, t);
134             avahi_free(t);
135
136             if (!name)
137                 return; /* OOM */
138             
139             if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { 
140                 avahi_log_warn(__FILE__": avahi_server_add_service() failed.");
141                 avahi_s_entry_group_free(hw->entry_group);
142                 hw->entry_group = NULL;
143             } else
144                 avahi_s_entry_group_commit(hw->entry_group);
145
146             avahi_free(name);
147         }
148         
149     } else {
150
151         if (hw->entry_group && !avahi_s_entry_group_is_empty(hw->entry_group)) {
152
153             if (avahi_s_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
154                 avahi_server_decrease_host_rr_pending(m->server);
155
156             avahi_s_entry_group_reset(hw->entry_group);
157         }
158     }
159 }
160
161 static void free_address(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
162     assert(m);
163     assert(a);
164     assert(a->interface);
165
166     update_address_rr(m, a, 1);
167     AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
168
169     if (a->entry_group)
170         avahi_s_entry_group_free(a->entry_group);
171     
172     avahi_free(a);
173 }
174
175 static void free_interface(AvahiInterfaceMonitor *m, AvahiInterface *i, int send_goodbye) {
176     assert(m);
177     assert(i);
178
179     avahi_goodbye_interface(m->server, i, send_goodbye);
180     avahi_response_scheduler_force(i->response_scheduler);
181     
182     assert(!i->announcements);
183
184     update_interface_rr(m, i, 1);
185     
186     while (i->addresses)
187         free_address(m, i->addresses);
188
189     avahi_response_scheduler_free(i->response_scheduler);
190     avahi_query_scheduler_free(i->query_scheduler);
191     avahi_probe_scheduler_free(i->probe_scheduler);
192     avahi_cache_free(i->cache);
193     
194     AVAHI_LLIST_REMOVE(AvahiInterface, interface, m->interfaces, i);
195     AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i);
196     
197     avahi_free(i);
198 }
199
200 static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int send_goodbye) {
201     assert(m);
202     assert(hw);
203
204     update_hw_interface_rr(m, hw, 1);
205     
206     while (hw->interfaces)
207         free_interface(m, hw->interfaces, send_goodbye);
208
209     if (hw->entry_group)
210         avahi_s_entry_group_free(hw->entry_group);
211     
212     AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
213     avahi_hashmap_remove(m->hashmap, &hw->index);
214
215     avahi_free(hw->name);
216     avahi_free(hw);
217 }
218
219 static AvahiInterfaceAddress* get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) {
220     AvahiInterfaceAddress *ia;
221     
222     assert(m);
223     assert(i);
224     assert(raddr);
225
226     for (ia = i->addresses; ia; ia = ia->address_next)
227         if (avahi_address_cmp(&ia->address, raddr) == 0)
228             return ia;
229
230     return NULL;
231 }
232
233 static int netlink_list_items(AvahiNetlink *nl, uint16_t type, unsigned *ret_seq) {
234     struct nlmsghdr *n;
235     struct rtgenmsg *gen;
236     uint8_t req[1024];
237     
238     memset(&req, 0, sizeof(req));
239     n = (struct nlmsghdr*) req;
240     n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
241     n->nlmsg_type = type;
242     n->nlmsg_flags = NLM_F_ROOT/*|NLM_F_MATCH*/|NLM_F_REQUEST;
243     n->nlmsg_pid = 0;
244
245     gen = NLMSG_DATA(n);
246     memset(gen, 0, sizeof(struct rtgenmsg));
247     gen->rtgen_family = AF_UNSPEC;
248
249     return avahi_netlink_send(nl, n, ret_seq);
250 }
251
252 static void new_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, AvahiProtocol protocol) {
253     AvahiInterface *i;
254     
255     assert(m);
256     assert(hw);
257     assert(protocol != AVAHI_PROTO_UNSPEC);
258
259     if (!(i = avahi_new(AvahiInterface, 1)))
260         goto fail; /* OOM */
261         
262     i->monitor = m;
263     i->hardware = hw;
264     i->protocol = protocol;
265     i->announcing = 0;
266
267     AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses);
268     AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, i->announcements);
269
270     i->cache = avahi_cache_new(m->server, i);
271     i->response_scheduler = avahi_response_scheduler_new(i);
272     i->query_scheduler = avahi_query_scheduler_new(i);
273     i->probe_scheduler = avahi_probe_scheduler_new(i);
274
275     if (!i->cache || !i->response_scheduler || !i->query_scheduler || !i->probe_scheduler)
276         goto fail; /* OOM */
277
278     AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i);
279     AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i);
280
281     return;
282 fail:
283
284     if (i) {
285         if (i->cache)
286             avahi_cache_free(i->cache);
287         if (i->response_scheduler)
288             avahi_response_scheduler_free(i->response_scheduler);
289         if (i->query_scheduler)
290             avahi_query_scheduler_free(i->query_scheduler);
291         if (i->probe_scheduler)
292             avahi_probe_scheduler_free(i->probe_scheduler);
293     }
294         
295 }
296
297 static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i) {
298     int b;
299
300     assert(m);
301     assert(i);
302
303     b = avahi_interface_relevant(i);
304
305     if (b && !i->announcing) {
306         avahi_log_debug("New relevant interface %s.%i (#%i)", i->hardware->name, i->protocol, i->hardware->index);
307
308         if (i->protocol == AVAHI_PROTO_INET)
309             avahi_mdns_mcast_join_ipv4(m->server->fd_ipv4, i->hardware->index);
310         if (i->protocol == AVAHI_PROTO_INET6)
311             avahi_mdns_mcast_join_ipv6(m->server->fd_ipv6, i->hardware->index);
312
313         i->announcing = 1;
314         avahi_announce_interface(m->server, i);
315         avahi_browser_new_interface(m->server, i);
316     } else if (!b && i->announcing) {
317         avahi_log_debug("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
318
319         if (i->protocol == AVAHI_PROTO_INET)
320             avahi_mdns_mcast_leave_ipv4(m->server->fd_ipv4, i->hardware->index);
321         if (i->protocol == AVAHI_PROTO_INET6)
322             avahi_mdns_mcast_leave_ipv6(m->server->fd_ipv6, i->hardware->index);
323
324         avahi_goodbye_interface(m->server, i, 0);
325         avahi_response_scheduler_clear(i->response_scheduler);
326         avahi_query_scheduler_clear(i->query_scheduler);
327         avahi_probe_scheduler_clear(i->probe_scheduler);
328         avahi_cache_flush(i->cache);
329
330         i->announcing = 0;
331     }
332 }
333
334 static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterface *hw) {
335     AvahiInterface *i;
336     
337     assert(m);
338     assert(hw);
339
340     for (i = hw->interfaces; i; i = i->by_hardware_next)
341         check_interface_relevant(m, i);
342 }
343
344 static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) {
345     AvahiInterfaceMonitor *m = userdata;
346     
347     assert(m);
348     assert(n);
349     assert(m->netlink == nl);
350
351     if (n->nlmsg_type == RTM_NEWLINK) {
352         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
353         AvahiHwInterface *hw;
354         struct rtattr *a = NULL;
355         size_t l;
356         
357         if (ifinfomsg->ifi_family != AF_UNSPEC)
358             return;
359
360         if (!(hw = avahi_hashmap_lookup(m->hashmap, &ifinfomsg->ifi_index))) {
361
362             if (!(hw = avahi_new(AvahiHwInterface, 1)))
363                 return; /* OOM */
364             
365             hw->monitor = m;
366             hw->name = NULL;
367             hw->flags = 0;
368             hw->mtu = 1500;
369             hw->index = (AvahiIfIndex) ifinfomsg->ifi_index;
370             hw->mac_address_size = 0;
371             hw->entry_group = NULL;
372
373             AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces);
374             AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw);
375             
376             avahi_hashmap_insert(m->hashmap, &hw->index, hw);
377
378             if (m->server->fd_ipv4 >= 0)
379                 new_interface(m, hw, AVAHI_PROTO_INET);
380             if (m->server->fd_ipv6 >= 0)
381                 new_interface(m, hw, AVAHI_PROTO_INET6);
382         }
383         
384         hw->flags = ifinfomsg->ifi_flags;
385
386         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
387         a = IFLA_RTA(ifinfomsg);
388
389         while (RTA_OK(a, l)) {
390             switch(a->rta_type) {
391                 case IFLA_IFNAME:
392                     avahi_free(hw->name);
393                     hw->name = avahi_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
394                     break;
395
396                 case IFLA_MTU:
397                     assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
398                     hw->mtu = *((unsigned int*) RTA_DATA(a));
399                     break;
400
401                 case IFLA_ADDRESS: {
402                     hw->mac_address_size = RTA_PAYLOAD(a);
403                     if (hw->mac_address_size > AVAHI_MAX_MAC_ADDRESS)
404                         hw->mac_address_size = AVAHI_MAX_MAC_ADDRESS;
405                     
406                     memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size);
407                     break;
408                 }
409                     
410                 default:
411                     ;
412             }
413
414             a = RTA_NEXT(a, l);
415         }
416
417         update_hw_interface_rr(m, hw, 0);
418         check_hw_interface_relevant(m, hw);
419         
420     } else if (n->nlmsg_type == RTM_DELLINK) {
421         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
422         AvahiHwInterface *hw;
423
424         if (ifinfomsg->ifi_family != AF_UNSPEC)
425             return;
426         
427         if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index)))
428             return;
429
430         update_hw_interface_rr(m, hw, 1);
431         free_hw_interface(m, hw, 0);
432         
433     } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
434
435         struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
436         AvahiInterface *i;
437         struct rtattr *a = NULL;
438         size_t l;
439         AvahiAddress raddr;
440         int raddr_valid = 0;
441
442         if (ifaddrmsg->ifa_family != AVAHI_PROTO_INET && ifaddrmsg->ifa_family != AVAHI_PROTO_INET6)
443             return;
444
445         if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, (AvahiProtocol) ifaddrmsg->ifa_family)))
446             return;
447
448         raddr.family = (AvahiProtocol) ifaddrmsg->ifa_family;
449
450         l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg));
451         a = IFA_RTA(ifaddrmsg);
452
453         while (RTA_OK(a, l)) {
454
455             switch(a->rta_type) {
456                 case IFA_ADDRESS:
457                     if ((raddr.family == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) ||
458                         (raddr.family == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4))
459                         return;
460
461                     memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
462                     raddr_valid = 1;
463
464                     break;
465
466                 default:
467                     ;
468             }
469             
470             a = RTA_NEXT(a, l);
471         }
472         
473         if (!raddr_valid)
474             return;
475
476         if (n->nlmsg_type == RTM_NEWADDR) {
477             AvahiInterfaceAddress *addr;
478             
479             if (!(addr = get_address(m, i, &raddr))) {
480                 if (!(addr = avahi_new(AvahiInterfaceAddress, 1)))
481                     return; /* OOM */
482                 
483                 addr->monitor = m;
484                 addr->address = raddr;
485                 addr->interface = i;
486                 addr->entry_group = NULL;
487
488                 AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, addr);
489             }
490             
491             addr->flags = ifaddrmsg->ifa_flags;
492             addr->scope = ifaddrmsg->ifa_scope;
493             addr->prefix_len = ifaddrmsg->ifa_prefixlen;
494
495             update_address_rr(m, addr, 0);
496         } else {
497             AvahiInterfaceAddress *addr;
498             
499             if (!(addr = get_address(m, i, &raddr)))
500                 return;
501
502             update_address_rr(m, addr, 1);
503             free_address(m, addr);
504         }
505
506         check_interface_relevant(m, i);
507         
508     } else if (n->nlmsg_type == NLMSG_DONE) {
509         
510         if (m->list == LIST_IFACE) {
511             m->list = LIST_DONE;
512             
513             if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0)
514                 avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno));
515             else
516                 m->list = LIST_ADDR;
517         } else {
518             m->list = LIST_DONE;
519             avahi_log_debug("Network interface enumeration completed");
520         }
521         
522     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
523         struct nlmsgerr *e = NLMSG_DATA (n);
524                     
525         if (e->error)
526             avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error));
527     }
528 }
529
530 AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) {
531     AvahiInterfaceMonitor *m = NULL;
532
533     if (!(m = avahi_new0(AvahiInterfaceMonitor, 1)))
534         return NULL; /* OOM */
535         
536     m->server = s;
537     if (!(m->netlink = avahi_netlink_new(s->poll_api, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, netlink_callback, m)))
538         goto fail;
539
540     m->hashmap = avahi_hashmap_new(avahi_int_hash, avahi_int_equal, NULL, NULL);
541
542     AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces);
543     AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces);
544
545     if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
546         goto fail;
547
548     m->list = LIST_IFACE;
549
550     return m;
551
552 fail:
553     avahi_interface_monitor_free(m);
554     return NULL;
555 }
556
557 void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
558     assert(m);
559     
560     while (m->list != LIST_DONE) {
561         if (!avahi_netlink_work(m->netlink, 1))
562             break;
563     } 
564 }
565
566 void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) {
567     assert(m);
568
569     while (m->hw_interfaces)
570         free_hw_interface(m, m->hw_interfaces, 1);
571
572     assert(!m->interfaces);
573
574     
575     if (m->netlink)
576         avahi_netlink_free(m->netlink);
577     
578     if (m->hashmap)
579         avahi_hashmap_free(m->hashmap);
580
581     avahi_free(m);
582 }
583
584
585 AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx, AvahiProtocol protocol) {
586     AvahiHwInterface *hw;
587     AvahiInterface *i;
588     
589     assert(m);
590     assert(idx > 0);
591     assert(protocol != AVAHI_PROTO_UNSPEC);
592
593     if (!(hw = avahi_interface_monitor_get_hw_interface(m, idx)))
594         return NULL;
595
596     for (i = hw->interfaces; i; i = i->by_hardware_next)
597         if (i->protocol == protocol)
598             return i;
599
600     return NULL;
601 }
602
603 AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx) {
604     assert(m);
605     assert(idx > 0);
606
607     return avahi_hashmap_lookup(m->hashmap, &idx);
608 }
609
610 void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) {
611     assert(i);
612     assert(p);
613 /*     char t[64]; */
614
615     if (!avahi_interface_relevant(i))
616         return;
617     
618     assert(!a || a->family == i->protocol);
619
620 /*     if (a) */
621 /*         avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */
622 /*     else */
623 /*         avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
624     
625     if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0)
626         avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
627     else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0)
628         avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port);
629 }
630
631 void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
632     assert(i);
633     assert(p);
634
635     avahi_interface_send_packet_unicast(i, p, NULL, 0);
636 }
637
638 int avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, int immediately) {
639     assert(i);
640     assert(key);
641
642     if (avahi_interface_relevant(i))
643         return avahi_query_scheduler_post(i->query_scheduler, key, immediately);
644
645     return 0;
646 }
647
648 int avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) {
649     assert(i);
650     assert(record);
651
652     if (avahi_interface_relevant(i))
653         return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately);
654
655     return 0;
656 }
657
658 int avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, int immediately) {
659     assert(i);
660     assert(record);
661     
662     if (avahi_interface_relevant(i))
663         return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately);
664
665     return 0;
666 }
667
668 int avahi_dump_caches(AvahiInterfaceMonitor *m, AvahiDumpCallback callback, void* userdata) {
669     AvahiInterface *i;
670     assert(m);
671
672     for (i = m->interfaces; i; i = i->interface_next) {
673         if (avahi_interface_relevant(i)) {
674             char ln[256];
675             snprintf(ln, sizeof(ln), ";;; INTERFACE %s.%i ;;;", i->hardware->name, i->protocol);
676             callback(ln, userdata);
677             if (avahi_cache_dump(i->cache, callback, userdata) < 0)
678                 return -1;
679         }
680     }
681
682     return 0;
683 }
684
685 int avahi_interface_relevant(AvahiInterface *i) {
686     AvahiInterfaceAddress *a;
687     int relevant_address;
688     
689     assert(i);
690
691     relevant_address = 0;
692     
693     for (a = i->addresses; a; a = a->address_next)
694         if (avahi_interface_address_relevant(a)) {
695             relevant_address = 1;
696             break;
697         }
698
699 /*     avahi_log_debug("%p. iface-relevant: %i %i %i %i %i %i", i, relevant_address, */
700 /*               (i->hardware->flags & IFF_UP), */
701 /*               (i->hardware->flags & IFF_RUNNING), */
702 /*               !(i->hardware->flags & IFF_LOOPBACK), */
703 /*               (i->hardware->flags & IFF_MULTICAST), */
704 /*               !(i->hardware->flags & IFF_POINTOPOINT)); */
705     
706     return
707         (i->hardware->flags & IFF_UP) &&
708         (!i->monitor->server->config.use_iff_running || (i->hardware->flags & IFF_RUNNING)) &&
709         !(i->hardware->flags & IFF_LOOPBACK) &&
710         (i->hardware->flags & IFF_MULTICAST) &&
711         !(i->hardware->flags & IFF_POINTOPOINT) && 
712         relevant_address;
713 }
714
715 int avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 
716     assert(a);
717
718     return a->scope == RT_SCOPE_UNIVERSE;
719 }
720
721
722 int avahi_interface_match(AvahiInterface *i, AvahiIfIndex idx, AvahiProtocol protocol) {
723     assert(i);
724     
725     if (idx > 0 && idx != i->hardware->index)
726         return 0;
727
728     if (protocol != AVAHI_PROTO_UNSPEC && protocol != i->protocol)
729         return 0;
730
731     return 1;
732 }
733
734 void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, AvahiIfIndex interface, AvahiProtocol protocol, AvahiInterfaceMonitorWalkCallback callback, void* userdata) {
735     assert(m);
736     assert(callback);
737     
738     if (interface > 0) {
739         if (protocol != AVAHI_PROTO_UNSPEC) {
740             AvahiInterface *i;
741             
742             if ((i = avahi_interface_monitor_get_interface(m, interface, protocol)))
743                 callback(m, i, userdata);
744             
745         } else {
746             AvahiHwInterface *hw;
747             AvahiInterface *i;
748
749             if ((hw = avahi_interface_monitor_get_hw_interface(m, interface)))
750                 for (i = hw->interfaces; i; i = i->by_hardware_next)
751                     if (avahi_interface_match(i, interface, protocol))
752                         callback(m, i, userdata);
753         }
754         
755     } else {
756         AvahiInterface *i;
757         
758         for (i = m->interfaces; i; i = i->interface_next)
759             if (avahi_interface_match(i, interface, protocol))
760                 callback(m, i, userdata);
761     }
762 }
763
764 void avahi_update_host_rrs(AvahiInterfaceMonitor *m, int remove_rrs) {
765     AvahiHwInterface *hw;
766
767     assert(m);
768
769     for (hw = m->hw_interfaces; hw; hw = hw->hardware_next)
770         update_hw_interface_rr(m, hw, remove_rrs);
771 }
772
773 int avahi_address_is_local(AvahiInterfaceMonitor *m, const AvahiAddress *a) {
774     AvahiInterface *i;
775     AvahiInterfaceAddress *ia;
776     assert(m);
777     assert(a);
778
779     for (i = m->interfaces; i; i = i->interface_next)
780         for (ia = i->addresses; ia; ia = ia->address_next)
781             if (avahi_address_cmp(a, &ia->address) == 0)
782                 return 1;
783
784     return 0;
785 }
786
787 int avahi_interface_address_on_link(AvahiInterface *i, const AvahiAddress *a) {
788     AvahiInterfaceAddress *ia;
789     
790     assert(i);
791     assert(a);
792
793     if (a->family != i->protocol)
794         return 0;
795
796     for (ia = i->addresses; ia; ia = ia->address_next) {
797
798         if (a->family == AVAHI_PROTO_INET) {
799             uint32_t m;
800             
801             m = ~(((uint32_t) -1) >> ia->prefix_len);
802             
803             if ((ntohl(a->data.ipv4.address) & m) == (ntohl(ia->address.data.ipv4.address) & m))
804                 return 1;
805         } else {
806             unsigned j;
807             unsigned char pl;
808             assert(a->family == AVAHI_PROTO_INET6);
809
810             pl = ia->prefix_len;
811             
812             for (j = 0; j < 16; j++) {
813                 uint8_t m;
814
815                 if (pl == 0)
816                     return 1;
817                 
818                 if (pl >= 8) {
819                     m = 0xFF;
820                     pl -= 8;
821                 } else {
822                     m = ~(0xFF >> pl);
823                     pl = 0;
824                 }
825                 
826                 if ((a->data.ipv6.address[j] & m) != (ia->address.data.ipv6.address[j] & m))
827                     break;
828             }
829         }
830     }
831
832     return 0;
833 }
834
835 int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, const AvahiAddress *a) {
836     AvahiInterface *i;
837     AvahiInterfaceAddress *j;
838     
839     assert(m);
840     assert(iface != AVAHI_IF_UNSPEC);
841     assert(a);
842
843     if (!(i = avahi_interface_monitor_get_interface(m, iface, a->family)))
844         return 0;
845
846     for (j = i->addresses; j; j = j->address_next)
847         if (avahi_address_cmp(a, &j->address) == 0)
848             return 1;
849
850     return 0;
851 }