iface.c revision 907bf2598220828a50b22cc00395524bb74feb8e
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 46static 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 99static 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 109static 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 165static 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 179static 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 204static 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 223static 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 237static 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 256static 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; 286fail: 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 301static 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 338static 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 348static 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 356static 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 545AvahiInterfaceMonitor *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 567fail: 568 avahi_interface_monitor_free(m); 569 return NULL; 570} 571 572void 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 581void 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 600AvahiInterface* 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 618AvahiHwInterface* 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 625void 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 646void 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 653int 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 663int 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 673int 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 683int 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 700int 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 730int 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 757int 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 769void 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 799void 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 808int 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 822int 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 870int 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} 887