]> git.meshlink.io Git - catta/blob - avahi-core/iface.c
f639821876ca5858454b2ae521b3c0c25b0d8a67
[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 <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <netinet/in.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33
34 #include <avahi-common/error.h>
35 #include <avahi-common/malloc.h>
36 #include <avahi-common/domain.h>
37
38 #include "iface.h"
39 #include "dns.h"
40 #include "socket.h"
41 #include "announce.h"
42 #include "util.h"
43 #include "log.h"
44 #include "multicast-lookup.h"
45 #include "querier.h"
46
47 void avahi_interface_address_update_rrs(AvahiInterfaceAddress *a, int remove_rrs) {
48     AvahiInterfaceMonitor *m;
49
50     assert(a);
51     m = a->monitor;
52
53     if (a->interface->announcing &&
54         m->list_complete &&
55         avahi_interface_address_is_relevant(a) &&
56         !remove_rrs &&
57         m->server->config.publish_addresses &&
58         (m->server->state == AVAHI_SERVER_RUNNING ||
59         m->server->state == AVAHI_SERVER_REGISTERING)) {
60
61         /* Fill the entry group */
62         if (!a->entry_group) 
63             a->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
64
65         if (!a->entry_group) /* OOM */
66             return;
67         
68         if (avahi_s_entry_group_is_empty(a->entry_group)) {
69             char t[AVAHI_ADDRESS_STR_MAX];
70             avahi_address_snprint(t, sizeof(t), &a->address);
71
72             avahi_log_info("Registering new address record for %s on %s.", t, a->interface->hardware->name);
73
74             if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) {
75                 avahi_log_warn(__FILE__": avahi_server_add_address() failed: %s", avahi_strerror(m->server->error));
76                 avahi_s_entry_group_free(a->entry_group);
77                 a->entry_group = NULL;
78                 return;
79             }
80
81             avahi_s_entry_group_commit(a->entry_group);
82         }
83     } else {
84
85         /* Clear the entry group */
86
87         if (a->entry_group && !avahi_s_entry_group_is_empty(a->entry_group)) {
88             char t[AVAHI_ADDRESS_STR_MAX];
89             avahi_address_snprint(t, sizeof(t), &a->address);
90
91             if (avahi_s_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING &&
92                 m->server->state == AVAHI_SERVER_REGISTERING)
93                 avahi_server_decrease_host_rr_pending(m->server);
94
95             avahi_log_info("Withdrawing address record for %s on %s.", t, a->interface->hardware->name);
96             
97             avahi_s_entry_group_reset(a->entry_group);
98         }
99     } 
100 }
101
102 void avahi_interface_update_rrs(AvahiInterface *i, int remove_rrs) {
103     AvahiInterfaceAddress *a;
104     
105     assert(i);
106
107     for (a = i->addresses; a; a = a->address_next)
108         avahi_interface_address_update_rrs(a, remove_rrs);
109 }
110
111 void avahi_hw_interface_update_rrs(AvahiHwInterface *hw, int remove_rrs) {
112     AvahiInterface *i;
113     AvahiInterfaceMonitor *m;
114
115     assert(hw);
116     m = hw->monitor;
117
118     for (i = hw->interfaces; i; i = i->by_hardware_next)
119         avahi_interface_update_rrs(i, remove_rrs);
120
121     if (m->list_complete &&
122         !remove_rrs &&
123         m->server->config.publish_workstation &&
124         (m->server->state == AVAHI_SERVER_RUNNING ||
125         m->server->state == AVAHI_SERVER_REGISTERING)) {
126
127         if (!hw->entry_group)
128             hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
129
130         if (!hw->entry_group)
131             return; /* OOM */
132         
133         if (avahi_s_entry_group_is_empty(hw->entry_group)) {
134             char name[AVAHI_LABEL_MAX];
135             char *t;
136
137             if (!(t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size)))
138                 return; /* OOM */
139
140             snprintf(name, sizeof(name), "%s [%s]", m->server->host_name, t);
141             avahi_free(t);
142
143             if (!name)
144                 return; /* OOM */
145             
146             if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, 0, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { 
147                 avahi_log_warn(__FILE__": avahi_server_add_service() failed: %s", avahi_strerror(m->server->error));
148                 avahi_s_entry_group_free(hw->entry_group);
149                 hw->entry_group = NULL;
150             } else
151                 avahi_s_entry_group_commit(hw->entry_group);
152         }
153         
154     } else {
155
156         if (hw->entry_group && !avahi_s_entry_group_is_empty(hw->entry_group)) {
157
158             if (avahi_s_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
159                 avahi_server_decrease_host_rr_pending(m->server);
160
161             avahi_s_entry_group_reset(hw->entry_group);
162         }
163     }
164 }
165
166 void avahi_interface_monitor_update_rrs(AvahiInterfaceMonitor *m, int remove_rrs) {
167     AvahiHwInterface *hw;
168
169     assert(m);
170
171     for (hw = m->hw_interfaces; hw; hw = hw->hardware_next)
172         avahi_hw_interface_update_rrs(hw, remove_rrs);
173 }
174
175 static int interface_mdns_mcast_join(AvahiInterface *i, int join) {
176     char at[AVAHI_ADDRESS_STR_MAX];
177     assert(i);
178
179     assert((join && !i->mcast_joined) || (!join && i->mcast_joined));
180     
181     if (join) {
182         AvahiInterfaceAddress *a;
183
184         /* Look if there's an address with global scope */
185         for (a = i->addresses; a; a = a->address_next)
186             if (a->global_scope)
187                 break;
188
189         /* No address with a global scope has been found, so let's use
190          * any. */
191         if (!a)
192             a = i->addresses;
193
194         /* Hmm, there is no address available. */
195         if (!a) {
196             avahi_log_warn(__FILE__": interface_mdns_mcast_join() called but no local address available."); 
197             return -1;
198         }
199
200         i->local_mcast_address = a->address;
201     }
202
203     avahi_log_info("%s mDNS multicast group on interface %s.%s with address %s.",
204                    join ? "Joining" : "Leaving",
205                    i->hardware->name,
206                    avahi_proto_to_string(i->protocol),
207                    avahi_address_snprint(at, sizeof(at), &i->local_mcast_address));
208
209     if (i->protocol == AVAHI_PROTO_INET6)
210         avahi_mdns_mcast_join_ipv6(i->monitor->server->fd_ipv6, &i->local_mcast_address.data.ipv6, i->hardware->index, join);
211     else {
212         assert(i->protocol == AVAHI_PROTO_INET);
213             
214         avahi_mdns_mcast_join_ipv4(i->monitor->server->fd_ipv4, &i->local_mcast_address.data.ipv4, i->hardware->index, join);
215     }
216
217     i->mcast_joined = join;
218     return 0;
219 }
220
221 static int interface_mdns_mcast_rejoin(AvahiInterface *i) {
222     AvahiInterfaceAddress *a, *usable = NULL, *found = NULL;
223     assert(i);
224
225     if (!i->mcast_joined)
226         return 0;
227
228     /* Check whether old address we joined with is still available. If
229      * not, rejoin using an other address. */
230     
231     for (a = i->addresses; a; a = a->address_next) {
232         if (a->global_scope && !usable)
233             usable = a;
234         
235         if (avahi_address_cmp(&a->address, &i->local_mcast_address) == 0) {
236
237             if (a->global_scope)
238                 /* No action necessary: the address still exists and
239                  * has global scope. */
240                 return 0;
241
242             found = a;
243         }
244     }
245
246     if (found && !usable)
247         /* No action necessary: the address still exists and no better one has been found */
248         return 0;
249     
250     interface_mdns_mcast_join(i, 0);
251     return interface_mdns_mcast_join(i, 1);
252 }
253
254 void avahi_interface_address_free(AvahiInterfaceAddress *a) {
255     assert(a);
256     assert(a->interface);
257
258     avahi_interface_address_update_rrs(a, 1);
259     AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
260
261     if (a->entry_group)
262         avahi_s_entry_group_free(a->entry_group);
263
264     interface_mdns_mcast_rejoin(a->interface);
265     
266     avahi_free(a);
267 }
268
269 void avahi_interface_free(AvahiInterface *i, int send_goodbye) {
270     assert(i);
271
272     /* Handle goodbyes and remove announcers */
273     avahi_goodbye_interface(i->monitor->server, i, send_goodbye, 1);
274     avahi_response_scheduler_force(i->response_scheduler);
275     assert(!i->announcers);
276
277     if (i->mcast_joined)
278         interface_mdns_mcast_join(i, 0);
279     
280     /* Remove queriers */
281     avahi_querier_free_all(i);
282     avahi_hashmap_free(i->queriers_by_key);
283
284     /* Remove local RRs */
285     avahi_interface_update_rrs(i, 1);
286     
287     while (i->addresses)
288         avahi_interface_address_free(i->addresses);
289
290     avahi_response_scheduler_free(i->response_scheduler);
291     avahi_query_scheduler_free(i->query_scheduler);
292     avahi_probe_scheduler_free(i->probe_scheduler);
293     avahi_cache_free(i->cache);
294     
295     AVAHI_LLIST_REMOVE(AvahiInterface, interface, i->monitor->interfaces, i);
296     AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i);
297     
298     avahi_free(i);
299 }
300
301 void avahi_hw_interface_free(AvahiHwInterface *hw, int send_goodbye) {
302     assert(hw);
303
304     avahi_hw_interface_update_rrs(hw, 1);
305     
306     while (hw->interfaces)
307         avahi_interface_free(hw->interfaces, send_goodbye);
308
309     if (hw->entry_group)
310         avahi_s_entry_group_free(hw->entry_group);
311     
312     AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, hw->monitor->hw_interfaces, hw);
313     avahi_hashmap_remove(hw->monitor->hashmap, &hw->index);
314
315     avahi_free(hw->name);
316     avahi_free(hw);
317 }
318
319 AvahiInterface* avahi_interface_new(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, AvahiProtocol protocol) {
320     AvahiInterface *i;
321     
322     assert(m);
323     assert(hw);
324     assert(AVAHI_PROTO_VALID(protocol));
325
326     if (!(i = avahi_new(AvahiInterface, 1)))
327         goto fail; /* OOM */
328         
329     i->monitor = m;
330     i->hardware = hw;
331     i->protocol = protocol;
332     i->announcing = 0;
333     i->mcast_joined = 0;
334
335     AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses);
336     AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, i->announcers);
337
338     AVAHI_LLIST_HEAD_INIT(AvahiQuerier, i->queriers);
339     i->queriers_by_key = avahi_hashmap_new((AvahiHashFunc) avahi_key_hash, (AvahiEqualFunc) avahi_key_equal, NULL, NULL);
340
341     i->cache = avahi_cache_new(m->server, i);
342     i->response_scheduler = avahi_response_scheduler_new(i);
343     i->query_scheduler = avahi_query_scheduler_new(i);
344     i->probe_scheduler = avahi_probe_scheduler_new(i);
345
346     if (!i->cache || !i->response_scheduler || !i->query_scheduler || !i->probe_scheduler)
347         goto fail; /* OOM */
348
349     AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i);
350     AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i);
351
352     return i;
353     
354 fail:
355
356     if (i) {
357         if (i->cache)
358             avahi_cache_free(i->cache);
359         if (i->response_scheduler)
360             avahi_response_scheduler_free(i->response_scheduler);
361         if (i->query_scheduler)
362             avahi_query_scheduler_free(i->query_scheduler);
363         if (i->probe_scheduler)
364             avahi_probe_scheduler_free(i->probe_scheduler);
365     }
366
367     return NULL;
368 }
369
370 AvahiHwInterface *avahi_hw_interface_new(AvahiInterfaceMonitor *m, AvahiIfIndex idx) {
371     AvahiHwInterface *hw;
372     
373     assert(m);
374     assert(AVAHI_IF_VALID(idx));
375
376     if  (!(hw = avahi_new(AvahiHwInterface, 1)))
377         return NULL;
378         
379     hw->monitor = m;
380     hw->name = NULL;
381     hw->flags_ok = 0;
382     hw->mtu = 1500;
383     hw->index = idx;
384     hw->mac_address_size = 0;
385     hw->entry_group = NULL;
386
387     AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces);
388     AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw);
389             
390     avahi_hashmap_insert(m->hashmap, &hw->index, hw);
391
392     if (m->server->fd_ipv4 >= 0)
393         avahi_interface_new(m, hw, AVAHI_PROTO_INET);
394     if (m->server->fd_ipv6 >= 0)
395         avahi_interface_new(m, hw, AVAHI_PROTO_INET6);
396
397     return hw;
398 }
399
400 AvahiInterfaceAddress *avahi_interface_address_new(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *addr, unsigned prefix_len) {
401     AvahiInterfaceAddress *a;
402
403     assert(m);
404     assert(i);
405
406     if (!(a = avahi_new(AvahiInterfaceAddress, 1)))
407         return NULL;
408
409     a->interface = i;
410     a->monitor = m;
411     a->address = *addr;
412     a->prefix_len = prefix_len;
413     a->global_scope = 0;
414     a->entry_group = NULL;
415
416     AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, a);
417
418     return a;
419 }
420
421 void avahi_interface_check_relevant(AvahiInterface *i) {
422     int b;
423     AvahiInterfaceMonitor *m;
424
425     assert(i);
426     m = i->monitor;
427
428     b = avahi_interface_is_relevant(i);
429
430     if (m->list_complete && b && !i->announcing) {
431         avahi_log_info("New relevant interface %s.%s for mDNS.", i->hardware->name, avahi_proto_to_string(i->protocol));
432
433         interface_mdns_mcast_join(i, 1);
434
435         i->announcing = 1;
436         avahi_announce_interface(m->server, i);
437         avahi_multicast_lookup_engine_new_interface(m->server->multicast_lookup_engine, i);
438     } else if (!b && i->announcing) {
439         avahi_log_info("Interface %s.%s no longer relevant for mDNS.", i->hardware->name, avahi_proto_to_string(i->protocol));
440
441         interface_mdns_mcast_join(i, 0);
442
443         avahi_goodbye_interface(m->server, i, 0, 1);
444         avahi_querier_free_all(i);
445
446         avahi_response_scheduler_clear(i->response_scheduler);
447         avahi_query_scheduler_clear(i->query_scheduler);
448         avahi_probe_scheduler_clear(i->probe_scheduler);
449         avahi_cache_flush(i->cache);
450
451         i->announcing = 0;
452         
453     } else
454         interface_mdns_mcast_rejoin(i);
455 }
456
457 void avahi_hw_interface_check_relevant(AvahiHwInterface *hw) {
458     AvahiInterface *i;
459     
460     assert(hw);
461
462     for (i = hw->interfaces; i; i = i->by_hardware_next)
463         avahi_interface_check_relevant(i);
464 }
465
466 void avahi_interface_monitor_check_relevant(AvahiInterfaceMonitor *m) {
467     AvahiInterface *i;
468
469     assert(m);
470
471     for (i = m->interfaces; i; i = i->interface_next)
472         avahi_interface_check_relevant(i);
473 }
474
475 AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) {
476     AvahiInterfaceMonitor *m = NULL;
477
478     if (!(m = avahi_new0(AvahiInterfaceMonitor, 1)))
479         return NULL; /* OOM */
480         
481     m->server = s;
482     m->list_complete = 0;
483     m->hashmap = avahi_hashmap_new(avahi_int_hash, avahi_int_equal, NULL, NULL);
484
485     AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces);
486     AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces);
487
488     if (avahi_interface_monitor_init_osdep(m) < 0)
489         goto fail;
490
491     return m;
492
493 fail:
494     avahi_interface_monitor_free(m);
495     return NULL;
496 }
497
498 void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) {
499     assert(m);
500
501     while (m->hw_interfaces)
502         avahi_hw_interface_free(m->hw_interfaces, 1);
503
504     assert(!m->interfaces);
505
506     avahi_interface_monitor_free_osdep(m);
507     
508     if (m->hashmap)
509         avahi_hashmap_free(m->hashmap);
510
511     avahi_free(m);
512 }
513
514
515 AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx, AvahiProtocol protocol) {
516     AvahiHwInterface *hw;
517     AvahiInterface *i;
518     
519     assert(m);
520     assert(idx >= 0);
521     assert(protocol != AVAHI_PROTO_UNSPEC);
522
523     if (!(hw = avahi_interface_monitor_get_hw_interface(m, idx)))
524         return NULL;
525
526     for (i = hw->interfaces; i; i = i->by_hardware_next)
527         if (i->protocol == protocol)
528             return i;
529
530     return NULL;
531 }
532
533 AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx) {
534     assert(m);
535     assert(idx > 0);
536
537     return avahi_hashmap_lookup(m->hashmap, &idx);
538 }
539
540 AvahiInterfaceAddress* avahi_interface_monitor_get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) {
541     AvahiInterfaceAddress *ia;
542     
543     assert(m);
544     assert(i);
545     assert(raddr);
546
547     for (ia = i->addresses; ia; ia = ia->address_next)
548         if (avahi_address_cmp(&ia->address, raddr) == 0)
549             return ia;
550
551     return NULL;
552 }
553
554
555 void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) {
556     assert(i);
557     assert(p);
558 /*     char t[AVAHI_ADDRESS_STR_MAX]; */
559
560     if (!avahi_interface_is_relevant(i))
561         return;
562     
563     assert(!a || a->proto == i->protocol);
564
565 /*     if (a) */
566 /*         avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */
567 /*     else */
568 /*         avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
569     
570     if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0)
571         avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv4 : NULL, a ? &a->data.ipv4 : NULL, port);
572     else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0)
573         avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv6 : NULL, a ? &a->data.ipv6 : NULL, port);
574 }
575
576 void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
577     assert(i);
578     assert(p);
579
580     avahi_interface_send_packet_unicast(i, p, NULL, 0);
581 }
582
583 int avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, int immediately, unsigned *ret_id) {
584     assert(i);
585     assert(key);
586
587     if (avahi_interface_is_relevant(i))
588         return avahi_query_scheduler_post(i->query_scheduler, key, immediately, ret_id);
589
590     return 0;
591 }
592
593 int avahi_interface_withraw_query(AvahiInterface *i, unsigned id) {
594
595     return avahi_query_scheduler_withdraw_by_id(i->query_scheduler, id);
596 }
597
598 int avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) {
599     assert(i);
600     assert(record);
601
602     if (avahi_interface_is_relevant(i))
603         return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately);
604
605     return 0;
606 }
607
608 int avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, int immediately) {
609     assert(i);
610     assert(record);
611     
612     if (avahi_interface_is_relevant(i))
613         return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately);
614
615     return 0;
616 }
617
618 int avahi_dump_caches(AvahiInterfaceMonitor *m, AvahiDumpCallback callback, void* userdata) {
619     AvahiInterface *i;
620     assert(m);
621
622     for (i = m->interfaces; i; i = i->interface_next) {
623         if (avahi_interface_is_relevant(i)) {
624             char ln[256];
625             snprintf(ln, sizeof(ln), ";;; INTERFACE %s.%s ;;;", i->hardware->name, avahi_proto_to_string(i->protocol));
626             callback(ln, userdata);
627             if (avahi_cache_dump(i->cache, callback, userdata) < 0)
628                 return -1;
629         }
630     }
631
632     return 0;
633 }
634
635 int avahi_interface_is_relevant(AvahiInterface *i) {
636     AvahiInterfaceAddress *a;
637     int relevant_address;
638     
639     assert(i);
640
641     relevant_address = 0;
642     
643     for (a = i->addresses; a; a = a->address_next)
644         if (avahi_interface_address_is_relevant(a)) {
645             relevant_address = 1;
646             break;
647         }
648
649     return i->hardware->flags_ok && relevant_address;
650 }
651
652 int avahi_interface_address_is_relevant(AvahiInterfaceAddress *a) {
653     AvahiInterfaceAddress *b;
654     assert(a);
655
656     /* Publish public IP addresses */
657     if (a->global_scope)
658         return 1;
659     else {
660         
661         /* Publish link local IP addresses if they are the only ones on the link */
662         for (b = a->interface->addresses; b; b = b->address_next) {
663             if (b == a)
664                 continue;
665             
666             if (b->global_scope)
667                 return 0;
668         }
669
670         return 1;
671     }
672
673     return 0;
674 }
675
676 int avahi_interface_match(AvahiInterface *i, AvahiIfIndex idx, AvahiProtocol protocol) {
677     assert(i);
678     
679     if (idx != AVAHI_IF_UNSPEC && idx != i->hardware->index)
680         return 0;
681
682     if (protocol != AVAHI_PROTO_UNSPEC && protocol != i->protocol)
683         return 0;
684
685     return 1;
686 }
687
688 void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, AvahiIfIndex interface, AvahiProtocol protocol, AvahiInterfaceMonitorWalkCallback callback, void* userdata) {
689     assert(m);
690     assert(callback);
691     
692     if (interface != AVAHI_IF_UNSPEC) {
693         if (protocol != AVAHI_PROTO_UNSPEC) {
694             AvahiInterface *i;
695             
696             if ((i = avahi_interface_monitor_get_interface(m, interface, protocol)))
697                 callback(m, i, userdata);
698             
699         } else {
700             AvahiHwInterface *hw;
701             AvahiInterface *i;
702
703             if ((hw = avahi_interface_monitor_get_hw_interface(m, interface)))
704                 for (i = hw->interfaces; i; i = i->by_hardware_next)
705                     if (avahi_interface_match(i, interface, protocol))
706                         callback(m, i, userdata);
707         }
708         
709     } else {
710         AvahiInterface *i;
711         
712         for (i = m->interfaces; i; i = i->interface_next)
713             if (avahi_interface_match(i, interface, protocol))
714                 callback(m, i, userdata);
715     }
716 }
717
718
719 int avahi_address_is_local(AvahiInterfaceMonitor *m, const AvahiAddress *a) {
720     AvahiInterface *i;
721     AvahiInterfaceAddress *ia;
722     assert(m);
723     assert(a);
724
725     for (i = m->interfaces; i; i = i->interface_next)
726         for (ia = i->addresses; ia; ia = ia->address_next)
727             if (avahi_address_cmp(a, &ia->address) == 0)
728                 return 1;
729
730     return 0;
731 }
732
733 int avahi_interface_address_on_link(AvahiInterface *i, const AvahiAddress *a) {
734     AvahiInterfaceAddress *ia;
735     
736     assert(i);
737     assert(a);
738
739     if (a->proto != i->protocol)
740         return 0;
741
742     for (ia = i->addresses; ia; ia = ia->address_next) {
743
744         if (a->proto == AVAHI_PROTO_INET) {
745             uint32_t m;
746             
747             m = ~(((uint32_t) -1) >> ia->prefix_len);
748             
749             if ((ntohl(a->data.ipv4.address) & m) == (ntohl(ia->address.data.ipv4.address) & m))
750                 return 1;
751         } else {
752             unsigned j;
753             unsigned char pl;
754             assert(a->proto == AVAHI_PROTO_INET6);
755
756             pl = ia->prefix_len;
757             
758             for (j = 0; j < 16; j++) {
759                 uint8_t m;
760
761                 if (pl == 0)
762                     return 1;
763                 
764                 if (pl >= 8) {
765                     m = 0xFF;
766                     pl -= 8;
767                 } else {
768                     m = ~(0xFF >> pl);
769                     pl = 0;
770                 }
771                 
772                 if ((a->data.ipv6.address[j] & m) != (ia->address.data.ipv6.address[j] & m))
773                     break;
774             }
775         }
776     }
777
778     return 0;
779 }
780
781 int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, const AvahiAddress *a) {
782     AvahiInterface *i;
783     AvahiInterfaceAddress *j;
784     
785     assert(m);
786     assert(iface != AVAHI_IF_UNSPEC);
787     assert(a);
788
789     if (!(i = avahi_interface_monitor_get_interface(m, iface, a->proto)))
790         return 0;
791
792     for (j = i->addresses; j; j = j->address_next)
793         if (avahi_address_cmp(a, &j->address) == 0)
794             return 1;
795
796     return 0;
797 }
798
799 AvahiIfIndex avahi_find_interface_for_address(AvahiInterfaceMonitor *m, const AvahiAddress *a) {
800     AvahiInterface *i;
801     assert(m);
802
803     /* Some stupid OS don't support passing the interface index when a
804      * packet is recieved. We have to work around that limitation by
805      * looking for an interface that has the incoming address
806      * attached. This is sometimes ambiguous, but we have to live with
807      * it. */
808
809     for (i = m->interfaces; i; i = i->interface_next) {
810         AvahiInterfaceAddress *ai;
811
812         if (i->protocol != a->proto)
813             continue;
814         
815         for (ai = i->addresses; ai; ai = ai->address_next)
816             if (avahi_address_cmp(a, &ai->address) == 0)
817                 return i->hardware->index;
818     }
819
820     return AVAHI_IF_UNSPEC;
821 }