]> git.meshlink.io Git - catta/blob - avahi-core/iface-pfroute.c
* many trivial fix to make avahi compile on OpenBSD
[catta] / avahi-core / iface-pfroute.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 <avahi-common/malloc.h>
27
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36
37 #include <net/route.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41
42 #include "log.h"
43 #include "iface.h"
44 #include "iface-pfroute.h"
45 #include "util.h"
46
47 static int bitcount (unsigned int n)  
48 {  
49   int count=0 ;
50   while (n)
51     {
52       count++ ;
53       n &= (n - 1) ;
54     }
55   return count ;
56 }
57
58 static void rtm_info(struct rt_msghdr *rtm, AvahiInterfaceMonitor *m)
59 {
60   AvahiHwInterface *hw;
61   struct if_msghdr *ifm = (struct if_msghdr *)rtm;
62   struct sockaddr_dl *sdl = (struct sockaddr_dl *)(ifm + 1);
63   
64   if (sdl->sdl_family != AF_LINK)
65     return;
66   
67   if (ifm->ifm_addrs == 0 && ifm->ifm_index > 0) {
68     if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifm->ifm_index)))
69       return;
70     avahi_hw_interface_free(hw, 0);
71     return;
72   }
73   
74   if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifm->ifm_index)))
75     if (!(hw = avahi_hw_interface_new(m, (AvahiIfIndex) ifm->ifm_index)))
76       return; /* OOM */
77   
78   hw->flags_ok =
79     (ifm->ifm_flags & IFF_UP) &&
80     (!m->server->config.use_iff_running || (ifm->ifm_flags & IFF_RUNNING)) &&
81     !(ifm->ifm_flags & IFF_LOOPBACK) &&
82     (ifm->ifm_flags & IFF_MULTICAST) &&
83     !(ifm->ifm_flags & IFF_POINTOPOINT);
84   
85   avahi_free(hw->name);
86   hw->name = avahi_strndup(sdl->sdl_data, sdl->sdl_nlen);
87       
88   hw->mtu = ifm->ifm_data.ifi_mtu;
89   
90   hw->mac_address_size = sdl->sdl_alen;
91   if (hw->mac_address_size > AVAHI_MAC_ADDRESS_MAX)
92     hw->mac_address_size = AVAHI_MAC_ADDRESS_MAX;
93   
94   memcpy(hw->mac_address, sdl->sdl_data + sdl->sdl_nlen, hw->mac_address_size);
95   
96   avahi_log_debug("======\n name: %s\n index:%d\n mtu:%d\n mac:%s\n flags_ok:%d\n======", 
97                   hw->name, hw->index, 
98                   hw->mtu, 
99                   avahi_format_mac_address(hw->mac_address, hw->mac_address_size),
100                   hw->flags_ok);
101   
102   avahi_hw_interface_check_relevant(hw);
103   avahi_hw_interface_update_rrs(hw, 0);
104 }
105
106 #define ROUNDUP(a) \
107      ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
108 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
109
110 static void rtm_addr(struct rt_msghdr *rtm, AvahiInterfaceMonitor *m)
111 {
112   AvahiInterface *iface;
113   AvahiAddress raddr;
114   int raddr_valid = 0;
115   struct ifa_msghdr *ifam = (struct ifa_msghdr *) rtm;
116   char *cp = (char *)(ifam + 1);
117   int addrs = ifam->ifam_addrs;
118   int i;
119   int prefixlen = 0;
120   struct sockaddr *sa  =NULL;
121
122 #if defined(__NetBSD__) || defined(__OpenBSD__)
123   if(((struct sockaddr *)cp)->sa_family == AF_UNSPEC)
124     ((struct sockaddr *)cp)->sa_family = AF_INET;
125 #endif
126
127   if(((struct sockaddr *)cp)->sa_family != AF_INET && ((struct sockaddr *)cp)->sa_family != AF_INET6)
128     return;
129
130   if (!(iface = avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifam->ifam_index, avahi_af_to_proto(((struct sockaddr *)cp)->sa_family))))
131     return;
132
133   raddr.proto = avahi_af_to_proto(((struct sockaddr *)cp)->sa_family);
134   
135   for(i = 0; addrs != 0 && i < RTAX_MAX; addrs &= ~(1<<i), i++)
136     {
137       if (!(addrs & 1<<i))
138         continue;
139       sa = (struct sockaddr *)cp;
140       if (sa->sa_len == 0) 
141         continue;
142       switch(sa->sa_family) {
143       case AF_INET:
144         switch (1<<i) {
145         case RTA_NETMASK:
146           prefixlen = bitcount(((struct sockaddr_in *)sa)->sin_addr.s_addr);
147           break;
148         case RTA_IFA:
149           memcpy(raddr.data.data, &((struct sockaddr_in *)sa)->sin_addr,  sizeof(struct in_addr));
150           raddr_valid = 1;
151         default:
152           break;
153         }
154         break;
155       case AF_INET6:
156         switch (1<<i) {
157         case RTA_NETMASK:
158           prefixlen = bitcount(((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr);
159           break;
160         case RTA_IFA:
161           memcpy(raddr.data.data, &((struct sockaddr_in6 *)sa)->sin6_addr,  sizeof(struct in6_addr));
162           raddr_valid = 1;
163         default:
164           break;
165         }
166         break;
167       default:
168         break;
169       }
170 #ifdef SA_SIZE
171       cp += SA_SIZE(sa);
172 #else
173       ADVANCE(cp, sa);
174 #endif
175     }
176
177   if (!raddr_valid)
178     return;
179
180   if(rtm->rtm_type == RTM_NEWADDR)
181     {
182       AvahiInterfaceAddress *addriface;
183       if (!(addriface = avahi_interface_monitor_get_address(m, iface, &raddr)))
184         if (!(addriface = avahi_interface_address_new(m, iface, &raddr, prefixlen)))
185           return; /* OOM */
186       /*       FIXME */
187       /*       addriface->global_scope = ifaddrmsg->ifa_scope == RT_SCOPE_UNIVERSE || ifaddrmsg->ifa_scope == RT_SCOPE_SITE; */
188       addriface->global_scope = 1;
189     }
190   else
191     {
192       AvahiInterfaceAddress *addriface;
193       assert(rtm->rtm_type == RTM_DELADDR);
194       if (!(addriface = avahi_interface_monitor_get_address(m, iface, &raddr)))
195         return;
196       avahi_interface_address_free(addriface);
197     }
198   
199   avahi_interface_check_relevant(iface);
200   avahi_interface_update_rrs(iface, 0);
201 }
202
203 static void parse_rtmsg(struct rt_msghdr *rtm, int msglen, AvahiInterfaceMonitor *m)
204 {
205   assert(m);
206   assert(rtm);
207   
208   if (rtm->rtm_version != RTM_VERSION) {
209     avahi_log_warn("routing message version %d not understood",
210                    rtm->rtm_version);
211     return;
212   }
213
214   switch (rtm->rtm_type) {
215   case RTM_IFINFO:
216     rtm_info(rtm,m);
217     break;
218   case RTM_NEWADDR:
219   case RTM_DELADDR:
220     rtm_addr(rtm,m);
221     break;
222   default:
223     break;
224   }
225 }
226
227 static void socket_event(AvahiWatch *w, int fd, AvahiWatchEvent event,void *userdata) {
228   AvahiInterfaceMonitor *m = (AvahiInterfaceMonitor *)userdata;
229   AvahiPfRoute *nl = m->osdep.pfroute;
230     ssize_t bytes;
231     char msg[2048];
232
233     assert(m);
234     assert(w);
235     assert(nl);
236     assert(fd == nl->fd);
237
238     do {
239       if((bytes = recv(nl->fd, msg, 2048, MSG_DONTWAIT)) < 0) {
240         if (errno == EAGAIN || errno == EINTR)
241           return;
242         avahi_log_error(__FILE__": recv() failed: %s", strerror(errno));
243         return;
244       }
245       parse_rtmsg((struct rt_msghdr *)msg, bytes ,m);
246     }
247     while (bytes > 0);
248 }
249
250 int avahi_interface_monitor_init_osdep(AvahiInterfaceMonitor *m) {
251     int fd = -1;
252     m->osdep.pfroute = NULL;
253
254     assert(m);
255
256     if ((fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) {
257         avahi_log_error(__FILE__": socket(PF_ROUTE): %s", strerror(errno));
258         goto fail;
259     }
260
261     if (!(m->osdep.pfroute = avahi_new(AvahiPfRoute , 1))) {
262         avahi_log_error(__FILE__": avahi_new() failed.");
263         goto fail;
264     }
265     m->osdep.pfroute->fd = fd;
266
267     if (!(m->osdep.pfroute->watch = m->server->poll_api->watch_new(m->server->poll_api, 
268                                                                    m->osdep.pfroute->fd, 
269                                                                    AVAHI_WATCH_IN, 
270                                                                    socket_event, 
271                                                                    m))) {
272       avahi_log_error(__FILE__": Failed to create watch.");
273       goto fail;
274     }
275     
276     return 0;
277
278 fail:
279
280     if (m->osdep.pfroute) {
281       if (m->osdep.pfroute->watch)
282         m->server->poll_api->watch_free(m->osdep.pfroute->watch);
283       
284       if (fd >= 0)
285         close(fd);
286       
287       m->osdep.pfroute = NULL;
288     }
289
290     return -1;
291 }
292
293 void avahi_interface_monitor_free_osdep(AvahiInterfaceMonitor *m) {
294     assert(m);
295
296     if (m->osdep.pfroute) {
297       if (m->osdep.pfroute->watch)
298         m->server->poll_api->watch_free(m->osdep.pfroute->watch);
299       
300       if (m->osdep.pfroute->fd >= 0)
301         close(m->osdep.pfroute->fd);
302
303       avahi_free(m->osdep.pfroute);
304       m->osdep.pfroute = NULL;
305     }
306 }
307
308 void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
309   size_t needed;
310   int mib[6];
311   char *buf, *lim, *next, count = 0;
312   struct rt_msghdr *rtm;
313
314   assert(m);
315   
316  retry2:
317   mib[0] = CTL_NET;
318   mib[1] = PF_ROUTE;
319   mib[2] = 0;             /* protocol */
320   mib[3] = 0;             /* wildcard address family */
321   mib[4] = NET_RT_IFLIST;
322   mib[5] = 0;             /* no flags */
323   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
324     return;
325   if ((buf = avahi_malloc(needed)) == NULL)
326     return;
327   if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
328     if (errno == ENOMEM && count++ < 10) {
329       sleep(1);
330       avahi_free(buf);
331       goto retry2;
332     }
333   }
334   lim = buf + needed;
335   for (next = buf; next < lim; next += rtm->rtm_msglen) {
336     rtm = (struct rt_msghdr *)next;
337     parse_rtmsg(rtm, rtm->rtm_msglen, m);
338   }
339   
340   m->list_complete = 1;
341   avahi_interface_monitor_check_relevant(m);
342   avahi_interface_monitor_update_rrs(m, 0);
343   avahi_log_info("Network interface enumeration completed.");
344 }