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