Port all olsrd 0.6.0 OS specific files and adapt them to the new interface.
[olsrd.git] / src / unix / ifnet.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42
43 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
44 #define ifr_netmask ifr_addr
45 #endif
46
47 #include "ipcalc.h"
48 #include "interfaces.h"
49 #include "defs.h"
50 #include "olsr.h"
51 #include "os_net.h"
52 #include "net_olsr.h"
53 #include "parser.h"
54 #include "scheduler.h"
55 #include "olsr_time.h"
56 #include "lq_packet.h"
57 #include "link_set.h"
58 #include "mid_set.h"
59 #include "hna_set.h"
60 #include "common/string.h"
61
62 #ifdef linux
63 #include "linux/linux_net.h"
64 #endif
65
66 #include <assert.h>
67 #include <signal.h>
68 #include <sys/types.h>
69 #include <net/if.h>
70 #include <net/if_arp.h>
71 #include <netinet/in_systm.h>
72 #include <netinet/ip.h>
73 #include <arpa/inet.h>
74 #include <netdb.h>
75 #include <unistd.h>
76 #include <errno.h>
77 #include <fcntl.h>
78
79 #define BUFSPACE  (127*1024)    /* max. input buffer size to request */
80
81 /**
82  * Checks if an initialized interface is changed
83  * that is if it has been set down or the address
84  * has been changed.
85  *
86  *@param iface the olsr_if_config struct describing the interface
87  */
88 int
89 chk_if_changed(struct olsr_if_config *iface)
90 {
91 #if !defined REMOVE_LOG_DEBUG || !defined REMOVE_LOG_INFO
92   struct ipaddr_str buf;
93 #endif
94   struct interface *ifp;
95   struct ifreq ifr;
96   int if_changes = 0;
97   int int_flags;
98
99   OLSR_DEBUG(LOG_INTERFACE, "Checking if %s is set down or changed\n", iface->name);
100
101   ifp = iface->interf;
102   if (!ifp) {
103     return 0;
104   }
105
106   memset(&ifr, 0, sizeof(ifr));
107   strscpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
108   /* Get flags (and check if interface exists) */
109   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
110     OLSR_WARN(LOG_INTERFACE, "No such interface: %s\n", iface->name);
111     remove_interface(iface->interf);
112     return 0;
113   }
114   int_flags = ifr.ifr_flags;
115
116   /*
117    * First check if the interface is set DOWN
118    */
119   if ((int_flags & IFF_UP) == 0) {
120     OLSR_DEBUG(LOG_INTERFACE, "\tInterface %s not up - removing it...\n", iface->name);
121     remove_interface(iface->interf);
122     return 0;
123   }
124
125   /*
126    * We do all the interface type checks over.
127    * This is because the interface might be a PCMCIA card. Therefore
128    * it might not be the same physical interface as we configured earlier.
129    */
130
131   /* Check broadcast */
132   if (olsr_cnf->ip_version == AF_INET && !iface->cnf->ipv4_broadcast.v4.s_addr &&       /* Skip if fixed bcast */
133       ((int_flags & IFF_BROADCAST)) == 0) {
134     OLSR_DEBUG(LOG_INTERFACE, "\tNo broadcast - removing\n");
135     remove_interface(iface->interf);
136     return 0;
137   }
138
139   if (int_flags & IFF_LOOPBACK) {
140     OLSR_DEBUG(LOG_INTERFACE, "\tThis is a loopback interface - removing it...\n");
141     remove_interface(iface->interf);
142     return 0;
143   }
144
145   /* Get MTU */
146   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0) {
147     ifp->int_mtu = 0;
148   } else {
149     ifr.ifr_mtu -= olsr_cnf->ip_version == AF_INET6 ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;
150     if (ifp->int_mtu != ifr.ifr_mtu) {
151       ifp->int_mtu = ifr.ifr_mtu;
152       /* Create new outputbuffer */
153       net_remove_buffer(ifp);   /* Remove old */
154       net_add_buffer(ifp);
155     }
156   }
157
158   /* Get interface index */
159   ifp->if_index = if_nametoindex(ifr.ifr_name);
160
161   /*
162    * Now check if the IP has changed
163    */
164
165   /* IP version 6 */
166   if (olsr_cnf->ip_version == AF_INET6) {
167     struct sockaddr_in6 tmp_saddr6;
168
169     /* Get interface address */
170     if (get_ipv6_address(ifr.ifr_name, &tmp_saddr6, iface->cnf->ipv6_addrtype) <= 0) {
171       if (iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL)
172         OLSR_WARN(LOG_INTERFACE, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
173       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_UNIQUELOCAL)
174         OLSR_WARN(LOG_INTERFACE, "\tCould not find unique-local IPv6 address for %s\n", ifr.ifr_name);
175       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_GLOBAL)
176         OLSR_WARN(LOG_INTERFACE, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
177       else
178         OLSR_WARN(LOG_INTERFACE, "\tCould not find an IPv6 address for %s\n", ifr.ifr_name);
179       remove_interface(iface->interf);
180       return 0;
181     }
182
183     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &tmp_saddr6.sin6_addr));
184
185     if (ip6cmp(&tmp_saddr6.sin6_addr, &ifp->int_src.v6.sin6_addr) != 0) {
186       OLSR_DEBUG(LOG_INTERFACE, "New IP address for %s:\n"
187                  "\tOld: %s\n\tNew: %s\n",
188                  ifr.ifr_name, ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr), ip6_to_string(&buf, &tmp_saddr6.sin6_addr));
189
190       /* Update address */
191       ifp->int_src.v6.sin6_addr = tmp_saddr6.sin6_addr;
192       ifp->ip_addr.v6 = tmp_saddr6.sin6_addr;
193
194       if_changes = 1;
195     }
196   } else {
197     /* IP version 4 */
198     const struct sockaddr_in *tmp_saddr4 = (struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
199
200     /* Check interface address (IPv4) */
201     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) {
202       OLSR_DEBUG(LOG_INTERFACE, "\tCould not get address of interface - removing it\n");
203       remove_interface(iface->interf);
204       return 0;
205     }
206
207     OLSR_DEBUG(LOG_INTERFACE, "\tAddress:%s\n", ip4_to_string(&buf, ifp->int_src.v4.sin_addr));
208
209     if (ip4cmp(&ifp->int_src.v4.sin_addr, &tmp_saddr4->sin_addr) != 0) {
210       /* New address */
211       OLSR_DEBUG(LOG_INTERFACE, "IPv4 address changed for %s\n"
212                  "\tOld:%s\n\tNew:%s\n",
213                  ifr.ifr_name, ip4_to_string(&buf, ifp->int_src.v4.sin_addr), ip4_to_string(&buf, tmp_saddr4->sin_addr));
214
215       ifp->int_src.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
216       ifp->ip_addr.v4 = tmp_saddr4->sin_addr;
217
218       if_changes = 1;
219     }
220
221     /* Check netmask */
222     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFNETMASK, &ifr) < 0) {
223       OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
224       remove_interface(iface->interf);
225       return 0;
226     }
227
228     OLSR_DEBUG(LOG_INTERFACE, "\tNetmask:%s\n", ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_netmask)))->sin_addr));
229
230     if (!iface->cnf->ipv4_broadcast.v4.s_addr) {
231       /* Check broadcast address */
232       if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) {
233         OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
234         return 0;
235       }
236
237       OLSR_DEBUG(LOG_INTERFACE, "\tBroadcast address:%s\n",
238                  ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr));
239
240       if (ifp->int_multicast.v4.sin_addr.s_addr != ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr.s_addr) {
241         /* New address */
242         OLSR_DEBUG(LOG_INTERFACE, "IPv4 broadcast changed for %s\n"
243                    "\tOld:%s\n\tNew:%s\n",
244                    ifr.ifr_name,
245                    ip4_to_string(&buf, ifp->int_multicast.v4.sin_addr),
246                    ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr));
247
248         ifp->int_multicast.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr));
249         if_changes = 1;
250       }
251     }
252   }
253   if (if_changes) {
254     run_ifchg_cbs(ifp, IFCHG_IF_UPDATE);
255   }
256   return if_changes;
257 }
258
259 static char basenamestr[32];
260 static const char *if_basename(const char *name);
261 static const char *
262 if_basename(const char *name)
263 {
264   const char *p = strchr(name, ':');
265   if (NULL == p || p - name >= (int)(ARRAYSIZE(basenamestr) - 1)) {
266     return name;
267   }
268   memcpy(basenamestr, name, p - name);
269   basenamestr[p - name] = 0;
270   return basenamestr;
271 }
272
273 /**
274  * Initializes a interface described by iface,
275  * if it is set up and is of the correct type.
276  *
277  *@param iface the olsr_if_config struct describing the interface
278  *@param so the socket to use for ioctls
279  *
280  */
281 int
282 os_init_interface(struct interface *ifp, struct olsr_if_config *iface)
283 {
284   struct ifreq ifr;
285   const char *ifr_basename;
286   int int_flags;
287 #if !defined REMOVE_LOG_DEBUG || !defined REMOVE_LOG_INFO
288   struct ipaddr_str buf;
289 #endif
290
291   /*
292    * Sanity check.
293    */
294   assert (iface->interf == NULL);
295   assert (ifp);
296
297    /*
298    * Setup query block.
299    */
300   memset(&ifr, 0, sizeof(ifr));
301   strscpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
302
303   OLSR_DEBUG(LOG_INTERFACE, "Checking %s:\n", ifr.ifr_name);
304
305   /* Get flags (and check if interface exists) */
306   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
307     OLSR_DEBUG(LOG_INTERFACE, "\tNo such interface!\n");
308     return -1;
309   }
310
311   int_flags = ifr.ifr_flags;
312   if ((int_flags & IFF_UP) == 0) {
313     OLSR_DEBUG(LOG_INTERFACE, "\tInterface not up - skipping it...\n");
314     return -1;
315   }
316
317   /* Check broadcast */
318   if (olsr_cnf->ip_version == AF_INET && !iface->cnf->ipv4_broadcast.v4.s_addr &&       /* Skip if fixed bcast */
319       (int_flags & IFF_BROADCAST) == 0) {
320     OLSR_DEBUG(LOG_INTERFACE, "\tNo broadcast - skipping\n");
321     return -1;
322   }
323
324   if (int_flags & IFF_LOOPBACK) {
325     OLSR_DEBUG(LOG_INTERFACE, "\tThis is a loopback interface - skipping it...\n");
326     return -1;
327   }
328
329   ifr_basename = if_basename(ifr.ifr_name);
330
331   /* IP version 6 */
332   if (olsr_cnf->ip_version == AF_INET6) {
333     /* Get interface address */
334     int result;
335
336     memset(&ifp->int_src, 0, sizeof(ifp->int_multicast));
337     ifp->int_src.v6.sin6_family = AF_INET6;
338     ifp->int_src.v6.sin6_flowinfo = htonl(0);
339     ifp->int_src.v6.sin6_scope_id = if_nametoindex(ifr.ifr_name);
340     ifp->int_src.v6.sin6_port = htons(olsr_cnf->olsr_port);
341
342     if (iface->cnf->ipv6_addrtype == OLSR_IP6T_AUTO) {
343       if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_SITELOCAL)) > 0) {
344         iface->cnf->ipv6_addrtype = OLSR_IP6T_SITELOCAL;
345       } else {
346         if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_UNIQUELOCAL)) > 0) {
347           iface->cnf->ipv6_addrtype = OLSR_IP6T_UNIQUELOCAL;
348         } else {
349           if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_GLOBAL)) > 0) {
350             iface->cnf->ipv6_addrtype = OLSR_IP6T_GLOBAL;
351           }
352         }
353       }
354     } else {
355       result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, iface->cnf->ipv6_addrtype);
356     }
357
358     if (result <= 0) {
359       if (iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL)
360         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
361       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_UNIQUELOCAL)
362         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find unique-local IPv6 address for %s\n", ifr.ifr_name);
363       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_GLOBAL)
364         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
365       else
366         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find an IPv6 address for %s\n", ifr.ifr_name);
367       return -1;
368     }
369
370     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr));
371
372     /* Multicast */
373     memset(&ifp->int_multicast, 0, sizeof(ifp->int_multicast));
374     ifp->int_multicast.v6.sin6_family = AF_INET6;
375     ifp->int_multicast.v6.sin6_flowinfo = htonl(0);
376     ifp->int_multicast.v6.sin6_scope_id = if_nametoindex(ifr.ifr_name);
377     ifp->int_multicast.v6.sin6_port = htons(olsr_cnf->olsr_port);
378     ifp->int_multicast.v6.sin6_addr = iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL
379       ? iface->cnf->ipv6_multi_site.v6 : iface->cnf->ipv6_multi_glbl.v6;
380
381 #ifdef __MacOSX__
382     ifp->int6_multaddr.sin6_scope_id = 0;
383 #endif
384
385     OLSR_DEBUG(LOG_INTERFACE, "\tMulticast: %s\n", ip6_to_string(&buf, &ifp->int_multicast.v6.sin6_addr));
386
387     ifp->ip_addr.v6 = ifp->int_src.v6.sin6_addr;
388   } else {
389     /* IP version 4 */
390     memset(&ifp->int_src, 0, sizeof(ifp->int_src));
391     memset(&ifp->int_multicast, 0, sizeof(ifp->int_multicast));
392
393     /* Get interface address (IPv4) */
394     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) {
395       OLSR_WARN(LOG_INTERFACE, "\tCould not get address of interface - skipping it\n");
396       return -1;
397     }
398
399     ifp->int_src.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
400
401     /* Find broadcast address */
402     if (iface->cnf->ipv4_broadcast.v4.s_addr) {
403       /* Specified broadcast */
404       ifp->int_multicast.v4.sin_addr = iface->cnf->ipv4_broadcast.v4;
405     } else {
406       /* Autodetect */
407       if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) {
408         OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
409         return -1;
410       }
411
412       ifp->int_multicast.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr));
413     }
414
415     ifp->int_src.v4.sin_family = AF_INET;
416     ifp->int_src.v4.sin_port = htons(olsr_cnf->olsr_port);
417     ifp->int_multicast.v4.sin_family = AF_INET;
418     ifp->int_multicast.v4.sin_port = htons(olsr_cnf->olsr_port);
419
420     ifp->ip_addr.v4 = ifp->int_src.v4.sin_addr;
421   }
422
423   /* check if interface with this IP already exists */
424   if (if_ifwithaddr(&ifp->ip_addr)) {
425     OLSR_ERROR(LOG_INTERFACE, "Warning, multiple interfaces with the same IP are deprecated. Use 'OriginatorAddress'"
426                " option if you fear a changing main address. Future versions of OLSR might block using multiple"
427                " interfaces with the same IP\n");
428   }
429
430   /* Get interface index */
431   ifp->if_index = if_nametoindex(ifr.ifr_name);
432
433   /* Get MTU */
434   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0) {
435     ifp->int_mtu = OLSR_DEFAULT_MTU;
436   } else {
437     ifp->int_mtu = ifr.ifr_mtu;
438   }
439   ifp->int_mtu -= olsr_cnf->ip_version == AF_INET6 ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;
440
441   OLSR_DEBUG(LOG_INTERFACE, "\tMTU - IPhdr: %d\n", ifp->int_mtu);
442
443   OLSR_INFO(LOG_INTERFACE, "Adding interface %s\n", iface->name);
444   OLSR_DEBUG(LOG_INTERFACE, "\tIndex %d\n", ifp->if_index);
445
446   if (olsr_cnf->ip_version == AF_INET) {
447     OLSR_DEBUG(LOG_INTERFACE, "\tAddress:%s\n", ip4_to_string(&buf, ifp->int_src.v4.sin_addr));
448     OLSR_DEBUG(LOG_INTERFACE, "\tBroadcast address:%s\n", ip4_to_string(&buf, ifp->int_multicast.v4.sin_addr));
449   } else {
450     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr));
451     OLSR_DEBUG(LOG_INTERFACE, "\tMulticast: %s\n", ip6_to_string(&buf, &ifp->int_multicast.v6.sin6_addr));
452   }
453
454   /*
455    * Clone interface name.
456    */
457   ifp->int_name = olsr_strdup(ifr_basename);
458
459   if (olsr_cnf->ip_version == AF_INET6) {
460     join_mcast(ifp, ifp->olsr_socket);
461     join_mcast(ifp, ifp->send_socket);
462   }
463   /* Set interface options */
464 #ifdef linux
465   net_os_set_ifoptions(ifr_basename, ifp);
466 #endif
467
468   return 0;
469 }
470
471 void
472 os_cleanup_interface(struct interface *ifp) {
473 #ifdef linux
474   net_os_restore_ifoption(ifp);
475 #endif
476 }
477
478 int
479 set_nonblocking(int fd)
480 {
481   /* make the fd non-blocking */
482   int socket_flags = fcntl(fd, F_GETFL);
483   if (socket_flags < 0) {
484     OLSR_WARN(LOG_NETWORKING, "Cannot get the socket flags: %s", strerror(errno));
485     return -1;
486   }
487   if (fcntl(fd, F_SETFL, socket_flags | O_NONBLOCK) < 0) {
488     OLSR_WARN(LOG_NETWORKING, "Cannot set the socket flags: %s", strerror(errno));
489     return -1;
490   }
491   return 0;
492 }
493
494
495 /*
496  * Local Variables:
497  * c-basic-offset: 2
498  * indent-tabs-mode: nil
499  * End:
500  */