Lines Matching defs:*
0 /* rcs tags go here */
2 /* Original author: Bruce M. Simpson <bms@FreeBSD.org> */
5 This file is part of avahi.
7 avahi is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 avahi is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with avahi; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/sysctl.h>
32 #include <net/if.h>
33 #include <net/route.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <string.h>
44 #include <unistd.h>
46 #include <libdaemon/dlog.h>
48 #include <avahi-common/llist.h>
49 #include <avahi-common/malloc.h>
51 #include "iface.h"
53 #ifndef IN_LINKLOCAL
54 #define IN_LINKLOCAL(i) (((u_int32_t)(i) & (0xffff0000)) == (0xa9fe0000))
55 #endif
57 #ifndef elementsof
58 #define elementsof(array) (sizeof(array)/sizeof(array[0]))
59 #endif
61 #ifndef so_set_nonblock
62 #define so_set_nonblock(s, val) \
63 do { \
64 int __flags; \
65 __flags = fcntl((s), F_GETFL); \
66 if (__flags == -1) \
67 break; \
68 if (val != 0) \
69 __flags |= O_NONBLOCK; \
70 else \
71 __flags &= ~O_NONBLOCK; \
72 (void)fcntl((s), F_SETFL, __flags); \
73 } while (0)
74 #endif
76 #define MAX_RTMSG_SIZE 2048
78 struct rtm_dispinfo {
79 u_char *di_buf;
80 ssize_t di_buflen;
81 ssize_t di_len;
84 union rtmunion {
85 struct rt_msghdr rtm;
86 struct if_msghdr ifm;
87 struct ifa_msghdr ifam;
88 struct ifma_msghdr ifmam;
89 struct if_announcemsghdr ifan;
91 typedef union rtmunion rtmunion_t;
93 struct Address;
94 typedef struct Address Address;
96 struct Address {
97 in_addr_t address;
98 AVAHI_LLIST_FIELDS(Address, addresses);
101 static int rtm_dispatch(void);
102 static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di);
103 static int rtm_dispatch_ifannounce(struct rtm_dispinfo *di);
104 static struct sockaddr *next_sa(struct sockaddr *sa);
106 static int fd = -1;
107 static int ifindex = -1;
108 static AVAHI_LLIST_HEAD(Address, addresses) = NULL;
110 int
111 iface_init(int idx)
114 fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
115 if (fd == -1) {
116 daemon_log(LOG_ERR, "socket(PF_ROUTE): %s", strerror(errno));
117 return (-1);
120 so_set_nonblock(fd, 1);
122 ifindex = idx;
124 return (fd);
127 int
128 iface_get_initial_state(State *state)
130 int mib[6];
131 char *buf;
132 struct if_msghdr *ifm;
133 struct ifa_msghdr *ifam;
134 char *lim;
135 char *next;
136 struct sockaddr *sa;
137 size_t len;
138 int naddrs;
140 assert(state != NULL);
141 assert(fd != -1);
143 naddrs = 0;
145 mib[0] = CTL_NET;
146 mib[1] = PF_ROUTE;
147 mib[2] = 0;
148 mib[3] = 0;
149 mib[4] = NET_RT_IFLIST;
150 mib[5] = ifindex;
152 if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) {
153 daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
154 strerror(errno));
155 return (-1);
158 buf = malloc(len);
159 if (buf == NULL) {
160 daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno));
161 return (-1);
164 if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) {
165 daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
166 strerror(errno));
167 free(buf);
168 return (-1);
171 lim = buf + len;
172 for (next = buf; next < lim; next += ifm->ifm_msglen) {
173 ifm = (struct if_msghdr *)next;
174 if (ifm->ifm_type == RTM_NEWADDR) {
175 ifam = (struct ifa_msghdr *)next;
176 sa = (struct sockaddr *)(ifam + 1);
177 if (sa->sa_family != AF_INET)
178 continue;
179 ++naddrs;
182 free(buf);
184 *state = (naddrs > 0) ? STATE_SLEEPING : STATE_START;
186 return (0);
189 int
190 iface_process(Event *event)
192 int routable;
194 assert(fd != -1);
196 routable = !!addresses;
198 if (rtm_dispatch() == -1)
199 return (-1);
201 if (routable && !addresses)
202 *event = EVENT_ROUTABLE_ADDR_UNCONFIGURED;
203 else if (!routable && addresses)
204 *event = EVENT_ROUTABLE_ADDR_CONFIGURED;
206 return (0);
209 void
210 iface_done(void)
212 Address *a;
214 if (fd != -1) {
215 close(fd);
216 fd = -1;
219 while ((a = addresses) != NULL) {
220 AVAHI_LLIST_REMOVE(Address, addresses, addresses, a);
221 avahi_free(a);
226 * Dispatch kernel routing socket messages.
228 static int
229 rtm_dispatch(void)
231 struct msghdr mh;
232 struct iovec iov[1];
233 struct rt_msghdr *rtm;
234 struct rtm_dispinfo *di;
235 ssize_t len;
236 int retval;
238 di = malloc(sizeof(*di));
239 if (di == NULL) {
240 daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di),
241 strerror(errno));
242 return (-1);
244 di->di_buflen = MAX_RTMSG_SIZE;
245 di->di_buf = calloc(MAX_RTMSG_SIZE, 1);
246 if (di->di_buf == NULL) {
247 free(di);
248 daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE,
249 strerror(errno));
250 return (-1);
253 memset(&mh, 0, sizeof(mh));
254 iov[0].iov_base = di->di_buf;
255 iov[0].iov_len = di->di_buflen;
256 mh.msg_iov = iov;
257 mh.msg_iovlen = 1;
259 retval = 0;
260 for (;;) {
261 len = recvmsg(fd, &mh, MSG_DONTWAIT);
262 if (len == -1) {
263 if (errno == EWOULDBLOCK)
264 break;
265 else {
266 daemon_log(LOG_ERR, "recvmsg(): %s",
267 strerror(errno));
268 retval = -1;
269 break;
273 rtm = (void *)di->di_buf;
274 if (rtm->rtm_version != RTM_VERSION) {
275 daemon_log(LOG_ERR,
276 "unknown routing socket message (version %d)\n",
277 rtm->rtm_version);
278 /* this is non-fatal; just ignore it for now. */
279 continue;
282 switch (rtm->rtm_type) {
283 case RTM_NEWADDR:
284 case RTM_DELADDR:
285 retval = rtm_dispatch_newdeladdr(di);
286 break;
287 case RTM_IFANNOUNCE:
288 retval = rtm_dispatch_ifannounce(di);
289 break;
290 default:
291 daemon_log(LOG_DEBUG, "%s: rtm_type %d ignored", __func__, rtm->rtm_type);
292 break;
296 * If we got an error; assume our position on the call
297 * stack is enclosed by a level-triggered event loop,
298 * and signal the error condition.
300 if (retval != 0)
301 break;
303 free(di->di_buf);
304 free(di);
306 return (retval);
309 /* handle link coming or going away */
310 static int
311 rtm_dispatch_ifannounce(struct rtm_dispinfo *di)
313 rtmunion_t *rtm = (void *)di->di_buf;
315 assert(rtm->rtm.rtm_type == RTM_IFANNOUNCE);
317 daemon_log(LOG_DEBUG, "%s: IFANNOUNCE for ifindex %d",
318 __func__, rtm->ifan.ifan_index);
320 switch (rtm->ifan.ifan_what) {
321 case IFAN_ARRIVAL:
322 if (rtm->ifan.ifan_index == ifindex) {
323 daemon_log(LOG_ERR,
324 "RTM_IFANNOUNCE IFAN_ARRIVAL, for ifindex %d, which we already manage.",
325 ifindex);
326 return (-1);
328 break;
329 case IFAN_DEPARTURE:
330 if (rtm->ifan.ifan_index == ifindex) {
331 daemon_log(LOG_ERR, "Interface vanished.");
332 return (-1);
334 break;
335 default:
336 /* ignore */
337 break;
340 return (0);
343 static struct sockaddr *
344 next_sa(struct sockaddr *sa)
346 void *p;
347 size_t sa_size;
349 #ifdef SA_SIZE
350 sa_size = SA_SIZE(sa);
351 #else
352 /* This is not foolproof, kernel may round. */
353 sa_size = sa->sa_len;
354 if (sa_size < sizeof(u_long))
355 sa_size = sizeof(u_long);
356 #endif
358 p = ((char *)sa) + sa_size;
360 return (struct sockaddr *)p;
363 /* handle address coming or going away */
364 static int
365 rtm_dispatch_newdeladdr(struct rtm_dispinfo *di)
367 Address *ap;
368 struct ifa_msghdr *ifam;
369 struct sockaddr *sa;
370 struct sockaddr_in *sin;
371 int link_local;
373 /* macro to skip to next RTA; has side-effects */
374 #define SKIPRTA(ifamsgp, rta, sa) \
375 do { \
376 if ((ifamsgp)->ifam_addrs & (rta)) \
377 (sa) = next_sa((sa)); \
378 } while (0)
380 ifam = &((rtmunion_t *)di->di_buf)->ifam;
382 assert(ifam->ifam_type == RTM_NEWADDR ||
383 ifam->ifam_type == RTM_DELADDR);
385 daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__,
386 ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR",
387 ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours");
389 if (ifam->ifam_index != ifindex)
390 return (0);
392 if (!(ifam->ifam_addrs & RTA_IFA)) {
393 daemon_log(LOG_ERR, "ifa msg has no RTA_IFA.");
394 return (0);
397 /* skip over rtmsg padding correctly */
398 sa = (struct sockaddr *)(ifam + 1);
399 SKIPRTA(ifam, RTA_DST, sa);
400 SKIPRTA(ifam, RTA_GATEWAY, sa);
401 SKIPRTA(ifam, RTA_NETMASK, sa);
402 SKIPRTA(ifam, RTA_GENMASK, sa);
403 SKIPRTA(ifam, RTA_IFP, sa);
406 * sa now points to RTA_IFA sockaddr; we are only interested
407 * in updates for routable addresses.
409 if (sa->sa_family != AF_INET) {
410 daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family);
411 return (0);
414 sin = (struct sockaddr_in *)sa;
415 link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr));
417 daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__,
418 ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR",
419 inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable");
421 if (link_local)
422 return (0);
424 for (ap = addresses; ap; ap = ap->addresses_next) {
425 if (ap->address == sin->sin_addr.s_addr)
426 break;
428 if (ifam->ifam_type == RTM_DELADDR && ap != NULL) {
429 AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap);
430 avahi_free(ap);
432 if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) {
433 ap = avahi_new(Address, 1);
434 ap->address = sin->sin_addr.s_addr;
435 AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap);
438 return (0);
439 #undef SKIPRTA