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