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