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