]> git.meshlink.io Git - catta/blob - avahi-core/iface.c
* include dbus-protocol.h in dbus-protocol.c
[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
34 #include "iface.h"
35 #include "netlink.h"
36 #include "dns.h"
37 #include "socket.h"
38 #include "announce.h"
39 #include "util.h"
40 #include "log.h"
41
42 static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, gboolean remove) {
43     g_assert(m);
44     g_assert(a);
45
46     if (avahi_interface_address_relevant(a) &&
47         !remove &&
48         m->server->config.register_addresses &&
49         (m->server->state == AVAHI_SERVER_RUNNING ||
50         m->server->state == AVAHI_SERVER_REGISTERING)) {
51
52         if (!a->entry_group) {
53             a->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
54             avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address); 
55             avahi_entry_group_commit(a->entry_group);
56         }
57     } else {
58
59         if (a->entry_group) {
60
61             if (avahi_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
62                 avahi_server_decrease_host_rr_pending(m->server);
63             
64             avahi_entry_group_free(a->entry_group);
65             a->entry_group = NULL;
66         }
67     } 
68 }
69
70 static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, gboolean remove) {
71     AvahiInterfaceAddress *a;
72     
73     g_assert(m);
74     g_assert(i);
75
76     for (a = i->addresses; a; a = a->address_next)
77         update_address_rr(m, a, remove);
78 }
79
80 static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gboolean remove) {
81     AvahiInterface *i;
82
83     g_assert(m);
84     g_assert(hw);
85
86     for (i = hw->interfaces; i; i = i->by_hardware_next)
87         update_interface_rr(m, i, remove);
88
89     if (!remove &&
90         m->server->config.register_workstation &&
91         (m->server->state == AVAHI_SERVER_RUNNING ||
92         m->server->state == AVAHI_SERVER_REGISTERING)) {
93
94         if (!hw->entry_group) {
95             gchar *name;
96             gchar *t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size);
97             name = g_strdup_printf("%s [%s]", m->server->host_name, t);
98             g_free(t);
99             
100             hw->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
101             avahi_server_add_service(m->server, hw->entry_group, hw->index, AF_UNSPEC, "_workstation._tcp", name, NULL, NULL, 9, NULL); 
102             avahi_entry_group_commit(hw->entry_group);
103
104             g_free(name);
105         }
106         
107     } else {
108
109         if (hw->entry_group) {
110
111             if (avahi_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
112                 avahi_server_decrease_host_rr_pending(m->server);
113
114             avahi_entry_group_free(hw->entry_group);
115             hw->entry_group = NULL;
116         }
117     }
118 }
119
120 static void free_address(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
121     g_assert(m);
122     g_assert(a);
123     g_assert(a->interface);
124
125     update_address_rr(m, a, TRUE);
126     AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
127     
128     g_free(a);
129 }
130
131 static void free_interface(AvahiInterfaceMonitor *m, AvahiInterface *i, gboolean send_goodbye) {
132     g_assert(m);
133     g_assert(i);
134
135     avahi_goodbye_interface(m->server, i, send_goodbye);
136     avahi_response_scheduler_force(i->response_scheduler);
137     
138     g_assert(!i->announcements);
139
140     update_interface_rr(m, i, TRUE);
141     
142     while (i->addresses)
143         free_address(m, i->addresses);
144
145     avahi_response_scheduler_free(i->response_scheduler);
146     avahi_query_scheduler_free(i->query_scheduler);
147     avahi_probe_scheduler_free(i->probe_scheduler);
148     avahi_cache_free(i->cache);
149     
150     AVAHI_LLIST_REMOVE(AvahiInterface, interface, m->interfaces, i);
151     AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i);
152     
153     g_free(i);
154 }
155
156 static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gboolean send_goodbye) {
157     g_assert(m);
158     g_assert(hw);
159
160     update_hw_interface_rr(m, hw, TRUE);
161     
162     while (hw->interfaces)
163         free_interface(m, hw->interfaces, send_goodbye);
164
165     AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
166     g_hash_table_remove(m->hash_table, &hw->index);
167
168     g_free(hw->name);
169     g_free(hw);
170 }
171
172 static AvahiInterfaceAddress* get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) {
173     AvahiInterfaceAddress *ia;
174     
175     g_assert(m);
176     g_assert(i);
177     g_assert(raddr);
178
179     for (ia = i->addresses; ia; ia = ia->address_next)
180         if (avahi_address_cmp(&ia->address, raddr) == 0)
181             return ia;
182
183     return NULL;
184 }
185
186 static int netlink_list_items(AvahiNetlink *nl, guint16 type, guint *ret_seq) {
187     struct nlmsghdr *n;
188     struct rtgenmsg *gen;
189     guint8 req[1024];
190     
191     memset(&req, 0, sizeof(req));
192     n = (struct nlmsghdr*) req;
193     n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
194     n->nlmsg_type = type;
195     n->nlmsg_flags = NLM_F_ROOT/*|NLM_F_MATCH*/|NLM_F_REQUEST;
196     n->nlmsg_pid = 0;
197
198     gen = NLMSG_DATA(n);
199     memset(gen, 0, sizeof(struct rtgenmsg));
200     gen->rtgen_family = AF_UNSPEC;
201
202     return avahi_netlink_send(nl, n, ret_seq);
203 }
204
205 static void new_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, guchar protocol) {
206     AvahiInterface *i;
207     
208     g_assert(m);
209     g_assert(hw);
210     g_assert(protocol != AF_UNSPEC);
211
212     i = g_new(AvahiInterface, 1);
213     i->monitor = m;
214     i->hardware = hw;
215     i->protocol = protocol;
216     i->announcing = FALSE;
217
218     AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses);
219     AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, i->announcements);
220
221     i->cache = avahi_cache_new(m->server, i);
222     i->response_scheduler = avahi_response_scheduler_new(i);
223     i->query_scheduler = avahi_query_scheduler_new(i);
224     i->probe_scheduler = avahi_probe_scheduler_new(i);
225
226     AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i);
227     AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i);
228 }
229
230 static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i) {
231     gboolean b;
232
233     g_assert(m);
234     g_assert(i);
235
236     b = avahi_interface_relevant(i);
237
238     if (b && !i->announcing) {
239         avahi_log_debug("New relevant interface %s.%i (#%i)", i->hardware->name, i->protocol, i->hardware->index);
240
241         if (i->protocol == AF_INET)
242             avahi_mdns_mcast_join_ipv4(i->hardware->index, m->server->fd_ipv4);
243         if (i->protocol == AF_INET6)
244             avahi_mdns_mcast_join_ipv6(i->hardware->index, m->server->fd_ipv6);
245
246         i->announcing = TRUE;
247         avahi_announce_interface(m->server, i);
248         avahi_browser_new_interface(m->server, i);
249     } else if (!b && i->announcing) {
250         avahi_log_debug("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
251
252         if (i->protocol == AF_INET)
253             avahi_mdns_mcast_leave_ipv4(i->hardware->index, m->server->fd_ipv4);
254         if (i->protocol == AF_INET6)
255             avahi_mdns_mcast_leave_ipv6(i->hardware->index, m->server->fd_ipv6);
256
257         avahi_goodbye_interface(m->server, i, FALSE);
258         avahi_response_scheduler_clear(i->response_scheduler);
259         avahi_query_scheduler_clear(i->query_scheduler);
260         avahi_probe_scheduler_clear(i->probe_scheduler);
261         avahi_cache_flush(i->cache);
262
263         i->announcing = FALSE;
264     }
265 }
266
267 static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterface *hw) {
268     AvahiInterface *i;
269     
270     g_assert(m);
271     g_assert(hw);
272
273     for (i = hw->interfaces; i; i = i->by_hardware_next)
274         check_interface_relevant(m, i);
275 }
276
277 static void callback(AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
278     AvahiInterfaceMonitor *m = userdata;
279     
280     g_assert(m);
281     g_assert(n);
282     g_assert(m->netlink == nl);
283
284     if (n->nlmsg_type == RTM_NEWLINK) {
285         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
286         AvahiHwInterface *hw;
287         struct rtattr *a = NULL;
288         size_t l;
289
290         if (ifinfomsg->ifi_family != AF_UNSPEC)
291             return;
292
293         if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) {
294             hw = g_new(AvahiHwInterface, 1);
295             hw->monitor = m;
296             hw->name = NULL;
297             hw->flags = 0;
298             hw->mtu = 1500;
299             hw->index = ifinfomsg->ifi_index;
300             hw->mac_address_size = 0;
301             hw->entry_group = NULL;
302
303             AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces);
304             AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw);
305             
306             g_hash_table_insert(m->hash_table, &hw->index, hw);
307
308             if (m->server->fd_ipv4 >= 0)
309                 new_interface(m, hw, AF_INET);
310             if (m->server->fd_ipv6 >= 0)
311                 new_interface(m, hw, AF_INET6);
312         }
313         
314         hw->flags = ifinfomsg->ifi_flags;
315
316         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
317         a = IFLA_RTA(ifinfomsg);
318
319         while (RTA_OK(a, l)) {
320             switch(a->rta_type) {
321                 case IFLA_IFNAME:
322                     g_free(hw->name);
323                     hw->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
324                     break;
325
326                 case IFLA_MTU:
327                     g_assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
328                     hw->mtu = *((unsigned int*) RTA_DATA(a));
329                     break;
330
331                 case IFLA_ADDRESS: {
332                     hw->mac_address_size = RTA_PAYLOAD(a);
333                     if (hw->mac_address_size > AVAHI_MAX_MAC_ADDRESS)
334                         hw->mac_address_size = AVAHI_MAX_MAC_ADDRESS;
335                     
336                     memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size);
337                     break;
338                 }
339                     
340                 default:
341                     ;
342             }
343
344             a = RTA_NEXT(a, l);
345         }
346
347         update_hw_interface_rr(m, hw, FALSE);
348         check_hw_interface_relevant(m, hw);
349         
350     } else if (n->nlmsg_type == RTM_DELLINK) {
351         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
352         AvahiHwInterface *hw;
353
354         if (ifinfomsg->ifi_family != AF_UNSPEC)
355             return;
356         
357         if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
358             return;
359
360         update_hw_interface_rr(m, hw, TRUE);
361         free_hw_interface(m, hw, FALSE);
362         
363     } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
364
365         struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
366         AvahiInterface *i;
367         struct rtattr *a = NULL;
368         size_t l;
369         AvahiAddress raddr;
370         gboolean raddr_valid = FALSE;
371
372         if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
373             return;
374
375         if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
376             return;
377
378         raddr.family = ifaddrmsg->ifa_family;
379
380         l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg));
381         a = IFA_RTA(ifaddrmsg);
382
383         while (RTA_OK(a, l)) {
384
385             switch(a->rta_type) {
386                 case IFA_ADDRESS:
387                     if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
388                         (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
389                         return;
390
391                     memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
392                     raddr_valid = TRUE;
393
394                     break;
395                     
396                 default:
397                     ;
398             }
399             
400             a = RTA_NEXT(a, l);
401         }
402         
403         if (!raddr_valid)
404             return;
405
406         if (n->nlmsg_type == RTM_NEWADDR) {
407             AvahiInterfaceAddress *addr;
408             
409             if (!(addr = get_address(m, i, &raddr))) {
410                 addr = g_new(AvahiInterfaceAddress, 1);
411                 addr->monitor = m;
412                 addr->address = raddr;
413                 addr->interface = i;
414                 addr->entry_group = NULL;
415
416                 AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, addr);
417             }
418             
419             addr->flags = ifaddrmsg->ifa_flags;
420             addr->scope = ifaddrmsg->ifa_scope;
421
422             update_address_rr(m, addr, FALSE);
423             check_interface_relevant(m, i);
424         } else {
425             AvahiInterfaceAddress *addr;
426             
427             if (!(addr = get_address(m, i, &raddr)))
428                 return;
429
430             update_address_rr(m, addr, TRUE);
431             free_address(m, addr);
432
433             check_interface_relevant(m, i);
434         }
435                 
436     } else if (n->nlmsg_type == NLMSG_DONE) {
437         
438         if (m->list == LIST_IFACE) {
439             m->list = LIST_DONE;
440             
441             if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0)
442                 avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno));
443             else
444                 m->list = LIST_ADDR;
445         } else {
446             m->list = LIST_DONE;
447             avahi_log_debug("Enumeration complete");
448         }
449         
450     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
451         struct nlmsgerr *e = NLMSG_DATA (n);
452                     
453         if (e->error)
454             avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error));
455     }
456 }
457
458 AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) {
459     AvahiInterfaceMonitor *m = NULL;
460
461     m = g_new0(AvahiInterfaceMonitor, 1);
462     m->server = s;
463     if (!(m->netlink = avahi_netlink_new(s->context, G_PRIORITY_DEFAULT-10, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
464         goto fail;
465
466     m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
467
468     AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces);
469     AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces);
470
471     if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
472         goto fail;
473
474     m->list = LIST_IFACE;
475
476     return m;
477
478 fail:
479     avahi_interface_monitor_free(m);
480     return NULL;
481 }
482
483 void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
484     g_assert(m);
485     
486     while (m->list != LIST_DONE) {
487         if (!avahi_netlink_work(m->netlink, TRUE))
488             break;
489     } 
490 }
491
492 void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) {
493     g_assert(m);
494
495     while (m->hw_interfaces)
496         free_hw_interface(m, m->hw_interfaces, TRUE);
497
498     g_assert(!m->interfaces);
499
500     
501     if (m->netlink)
502         avahi_netlink_free(m->netlink);
503     
504     if (m->hash_table)
505         g_hash_table_destroy(m->hash_table);
506
507     g_free(m);
508 }
509
510
511 AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, gint index, guchar protocol) {
512     AvahiHwInterface *hw;
513     AvahiInterface *i;
514     
515     g_assert(m);
516     g_assert(index > 0);
517     g_assert(protocol != AF_UNSPEC);
518
519     if (!(hw = avahi_interface_monitor_get_hw_interface(m, index)))
520         return NULL;
521
522     for (i = hw->interfaces; i; i = i->by_hardware_next)
523         if (i->protocol == protocol)
524             return i;
525
526     return NULL;
527 }
528
529 AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index) {
530     g_assert(m);
531     g_assert(index > 0);
532
533     return g_hash_table_lookup(m->hash_table, &index);
534 }
535
536
537 void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port) {
538     g_assert(i);
539     g_assert(p);
540 /*     char t[64]; */
541
542     if (!avahi_interface_relevant(i))
543         return;
544     
545     g_assert(!a || a->family == i->protocol);
546
547 /*     if (a) */
548 /*         avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */
549 /*     else */
550 /*         avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
551     
552     if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
553         avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
554     else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
555         avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port);
556 }
557
558 void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
559     g_assert(i);
560     g_assert(p);
561
562     avahi_interface_send_packet_unicast(i, p, NULL, 0);
563 }
564
565 gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
566     g_assert(i);
567     g_assert(key);
568
569     if (avahi_interface_relevant(i))
570         return avahi_query_scheduler_post(i->query_scheduler, key, immediately);
571
572     return FALSE;
573 }
574
575 gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, const AvahiAddress *querier, gboolean immediately) {
576     g_assert(i);
577     g_assert(record);
578
579     if (avahi_interface_relevant(i))
580         return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately);
581
582     return FALSE;
583 }
584
585 gboolean avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
586     g_assert(i);
587     g_assert(record);
588     
589     if (avahi_interface_relevant(i))
590         return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately);
591
592     return FALSE;
593 }
594
595 void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f) {
596     AvahiInterface *i;
597     g_assert(m);
598
599     for (i = m->interfaces; i; i = i->interface_next) {
600         if (avahi_interface_relevant(i)) {
601             fprintf(f, "\n;;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol);
602             avahi_cache_dump(i->cache, f);
603         }
604     }
605     fprintf(f, "\n");
606 }
607
608 gboolean avahi_interface_relevant(AvahiInterface *i) {
609     AvahiInterfaceAddress *a;
610     gboolean relevant_address;
611     
612     g_assert(i);
613
614     relevant_address = FALSE;
615     
616     for (a = i->addresses; a; a = a->address_next)
617         if (avahi_interface_address_relevant(a)) {
618             relevant_address = TRUE;
619             break;
620         }
621
622 /*     avahi_log_debug("%p. iface-relevant: %i %i %i %i %i %i", i, relevant_address, */
623 /*               (i->hardware->flags & IFF_UP), */
624 /*               (i->hardware->flags & IFF_RUNNING), */
625 /*               !(i->hardware->flags & IFF_LOOPBACK), */
626 /*               (i->hardware->flags & IFF_MULTICAST), */
627 /*               !(i->hardware->flags & IFF_POINTOPOINT)); */
628     
629     return
630         (i->hardware->flags & IFF_UP) &&
631         (!i->monitor->server->config.use_iff_running || (i->hardware->flags & IFF_RUNNING)) &&
632         !(i->hardware->flags & IFF_LOOPBACK) &&
633         (i->hardware->flags & IFF_MULTICAST) &&
634         !(i->hardware->flags & IFF_POINTOPOINT) && 
635         relevant_address;
636 }
637
638 gboolean avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 
639     g_assert(a);
640
641     return a->scope == RT_SCOPE_UNIVERSE;
642 }
643
644
645 gboolean avahi_interface_match(AvahiInterface *i, gint index, guchar protocol) {
646     g_assert(i);
647     
648     if (index > 0 && index != i->hardware->index)
649         return FALSE;
650
651     if (protocol != AF_UNSPEC && protocol != i->protocol)
652         return FALSE;
653
654     return TRUE;
655 }
656
657 void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint interface, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata) {
658     g_assert(m);
659     g_assert(callback);
660     
661     if (interface > 0) {
662         if (protocol != AF_UNSPEC) {
663             AvahiInterface *i;
664             
665             if ((i = avahi_interface_monitor_get_interface(m, interface, protocol)))
666                 callback(m, i, userdata);
667             
668         } else {
669             AvahiHwInterface *hw;
670             AvahiInterface *i;
671
672             if ((hw = avahi_interface_monitor_get_hw_interface(m, interface)))
673                 for (i = hw->interfaces; i; i = i->by_hardware_next)
674                     if (avahi_interface_match(i, interface, protocol))
675                         callback(m, i, userdata);
676         }
677         
678     } else {
679         AvahiInterface *i;
680         
681         for (i = m->interfaces; i; i = i->interface_next)
682             if (avahi_interface_match(i, interface, protocol))
683                 callback(m, i, userdata);
684     }
685 }
686
687 void avahi_update_host_rrs(AvahiInterfaceMonitor *m, gboolean remove) {
688     AvahiHwInterface *hw;
689
690     g_assert(m);
691
692     for (hw = m->hw_interfaces; hw; hw = hw->hardware_next)
693         update_hw_interface_rr(m, hw, remove);
694 }
695
696 gboolean avahi_address_is_local(AvahiInterfaceMonitor *m, const AvahiAddress *a) {
697     AvahiInterface *i;
698     AvahiInterfaceAddress *ia;
699     g_assert(m);
700     g_assert(a);
701
702     for (i = m->interfaces; i; i = i->interface_next)
703         for (ia = i->addresses; ia; ia = ia->address_next)
704             if (avahi_address_cmp(a, &ia->address) == 0)
705                 return TRUE;
706
707     return FALSE;
708 }