4 This file is part of avahi.
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.
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.
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
31 #include <avahi-common/malloc.h>
35 #include "iface-linux.h"
37 static int netlink_list_items(AvahiNetlink *nl, uint16_t type, unsigned *ret_seq) {
42 memset(&req, 0, sizeof(req));
43 n = (struct nlmsghdr*) req;
44 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
46 n->nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
50 memset(gen, 0, sizeof(struct rtgenmsg));
51 gen->rtgen_family = AF_UNSPEC;
53 return avahi_netlink_send(nl, n, ret_seq);
56 static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) {
57 AvahiInterfaceMonitor *m = userdata;
61 assert(m->osdep.netlink == nl);
63 if (n->nlmsg_type == RTM_NEWLINK) {
64 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
66 struct rtattr *a = NULL;
69 if (ifinfomsg->ifi_family != AF_UNSPEC)
72 if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
73 if (!(hw = avahi_hw_interface_new(m, (AvahiIfIndex) ifinfomsg->ifi_index)))
76 /* Check whether the flags of this interface are OK for us */
78 (ifinfomsg->ifi_flags & IFF_UP) &&
79 (!m->server->config.use_iff_running || (ifinfomsg->ifi_flags & IFF_RUNNING)) &&
80 !(ifinfomsg->ifi_flags & IFF_LOOPBACK) &&
81 (ifinfomsg->ifi_flags & IFF_MULTICAST) &&
82 !(ifinfomsg->ifi_flags & IFF_POINTOPOINT);
85 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
86 a = IFLA_RTA(ifinfomsg);
88 while (RTA_OK(a, l)) {
92 hw->name = avahi_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
96 assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
97 hw->mtu = *((unsigned int*) RTA_DATA(a));
101 hw->mac_address_size = RTA_PAYLOAD(a);
102 if (hw->mac_address_size > AVAHI_MAX_MAC_ADDRESS)
103 hw->mac_address_size = AVAHI_MAX_MAC_ADDRESS;
105 memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size);
116 avahi_hw_interface_check_relevant(hw);
117 avahi_hw_interface_update_rrs(hw, 0);
119 } else if (n->nlmsg_type == RTM_DELLINK) {
120 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
121 AvahiHwInterface *hw;
123 if (ifinfomsg->ifi_family != AF_UNSPEC)
126 if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index)))
129 avahi_hw_interface_free(hw, 0);
131 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
133 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
135 struct rtattr *a = NULL;
140 if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
143 if (!(i = avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, avahi_af_to_proto(ifaddrmsg->ifa_family))))
146 raddr.proto = avahi_af_to_proto(ifaddrmsg->ifa_family);
148 l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg));
149 a = IFA_RTA(ifaddrmsg);
151 while (RTA_OK(a, l)) {
153 switch(a->rta_type) {
155 if ((raddr.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) ||
156 (raddr.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4))
159 memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
174 if (n->nlmsg_type == RTM_NEWADDR) {
175 AvahiInterfaceAddress *addr;
177 if (!(addr = avahi_interface_monitor_get_address(m, i, &raddr)))
178 if (!(addr = avahi_interface_address_new(m, i, &raddr, ifaddrmsg->ifa_prefixlen)))
181 addr->global_scope = ifaddrmsg->ifa_scope == RT_SCOPE_UNIVERSE || ifaddrmsg->ifa_scope == RT_SCOPE_SITE;
183 AvahiInterfaceAddress *addr;
185 if (!(addr = avahi_interface_monitor_get_address(m, i, &raddr)))
188 avahi_interface_address_free(addr);
191 avahi_interface_check_relevant(i);
192 avahi_interface_update_rrs(i, 0);
194 } else if (n->nlmsg_type == NLMSG_DONE) {
196 if (m->osdep.list == LIST_IFACE) {
198 if (netlink_list_items(m->osdep.netlink, RTM_GETADDR, &m->osdep.query_addr_seq) < 0) {
199 avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno));
200 m->osdep.list = LIST_DONE;
202 m->osdep.list = LIST_ADDR;
206 m->osdep.list = LIST_DONE;
208 if (m->osdep.list == LIST_DONE) {
209 m->list_complete = 1;
210 avahi_interface_monitor_check_relevant(m);
211 avahi_interface_monitor_update_rrs(m, 0);
212 avahi_log_info("Network interface enumeration completed.");
215 } else if (n->nlmsg_type == NLMSG_ERROR &&
216 (n->nlmsg_seq == m->osdep.query_link_seq || n->nlmsg_seq == m->osdep.query_addr_seq)) {
217 struct nlmsgerr *e = NLMSG_DATA (n);
220 avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error));
224 int avahi_interface_monitor_init_osdep(AvahiInterfaceMonitor *m) {
227 m->osdep.netlink = NULL;
228 m->osdep.query_addr_seq = m->osdep.query_link_seq = 0;
230 if (!(m->osdep.netlink = avahi_netlink_new(m->server->poll_api, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, netlink_callback, m)))
233 if (netlink_list_items(m->osdep.netlink, RTM_GETLINK, &m->osdep.query_link_seq) < 0)
236 m->osdep.list = LIST_IFACE;
242 if (m->osdep.netlink) {
243 avahi_netlink_free(m->osdep.netlink);
244 m->osdep.netlink = NULL;
250 void avahi_interface_monitor_free_osdep(AvahiInterfaceMonitor *m) {
253 if (m->osdep.netlink) {
254 avahi_netlink_free(m->osdep.netlink);
255 m->osdep.netlink = NULL;
259 void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
262 while (m->osdep.list != LIST_DONE) {
263 if (!avahi_netlink_work(m->osdep.netlink, 1))