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