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