Rename "subsystems" directory to "base"
[oonf.git] / src / base / oonf_packet_socket.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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  * @file
44  */
45
46 #include <errno.h>
47
48 #include <oonf/libcommon/autobuf.h>
49 #include <oonf/oonf.h>
50 #include <oonf/libcommon/list.h>
51 #include <oonf/libcommon/netaddr.h>
52 #include <oonf/libcommon/netaddr_acl.h>
53 #include <oonf/libcore/oonf_logging.h>
54 #include <oonf/libcore/oonf_subsystem.h>
55 #include <oonf/base/oonf_packet_socket.h>
56 #include <oonf/base/oonf_socket.h>
57 #include <oonf/base/os_fd.h>
58 #include <oonf/base/os_interface.h>
59
60 /* Defintions */
61 #define LOG_PACKET _oonf_packet_socket_subsystem.logging
62
63 /* prototypes */
64 static int _init(void);
65 static void _cleanup(void);
66
67 static void _handle_errno1(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote);
68
69 static void _packet_add(struct oonf_packet_socket *pktsocket, union netaddr_socket *local, struct os_interface *os_if);
70 static int _apply_managed(struct oonf_packet_managed *managed);
71 static int _apply_managed_socketpair(int af_type, struct oonf_packet_managed *managed, struct os_interface *os_if,
72   bool *changed, struct oonf_packet_socket *sock, struct oonf_packet_socket *mc_sock, struct netaddr *mc_ip);
73 static int _apply_managed_socket(struct oonf_packet_managed *managed, struct oonf_packet_socket *stream,
74   const struct netaddr *bindto, int port, uint8_t dscp, int protocol, struct os_interface *os_if);
75 static void _cb_packet_event_unicast(struct oonf_socket_entry *);
76 static void _cb_packet_event_multicast(struct oonf_socket_entry *);
77 static void _cb_packet_event(struct oonf_socket_entry *, bool mc);
78 static int _cb_interface_listener(struct os_interface_listener *l);
79
80 /* subsystem definition */
81 static const char *_dependencies[] = {
82   OONF_OS_INTERFACE_SUBSYSTEM,
83   OONF_SOCKET_SUBSYSTEM,
84   OONF_OS_FD_SUBSYSTEM,
85 };
86
87 static struct oonf_subsystem _oonf_packet_socket_subsystem = {
88   .name = OONF_PACKET_SUBSYSTEM,
89   .dependencies = _dependencies,
90   .dependencies_count = ARRAYSIZE(_dependencies),
91   .init = _init,
92   .cleanup = _cleanup,
93 };
94 DECLARE_OONF_PLUGIN(_oonf_packet_socket_subsystem);
95
96 /* other global variables */
97 static struct list_entity _packet_sockets = { NULL, NULL };
98 static char _input_buffer[65536];
99
100 /**
101  * Initialize packet socket handler
102  * @return always returns 0
103  */
104 static int
105 _init(void) {
106   list_init_head(&_packet_sockets);
107   return 0;
108 }
109
110 /**
111  * Cleanup all resources allocated by packet socket handler
112  */
113 static void
114 _cleanup(void) {
115   struct oonf_packet_socket *skt;
116
117   while (!list_is_empty(&_packet_sockets)) {
118     skt = list_first_element(&_packet_sockets, skt, node);
119
120     oonf_packet_remove(skt, true);
121   }
122 }
123
124 /**
125  * Add a new packet socket handler
126  * @param pktsocket pointer to an initialized packet socket struct
127  * @param local pointer local IP address of packet socket
128  * @param os_if pointer to interface to bind socket on, NULL
129  *   if socket should not be bound to interface
130  * @return -1 if an error happened, 0 otherwise
131  */
132 int
133 oonf_packet_add(struct oonf_packet_socket *pktsocket, union netaddr_socket *local, struct os_interface *os_if) {
134   /* Init socket */
135   if (os_fd_getsocket(&pktsocket->scheduler_entry.fd, local, false, 0, os_if, LOG_PACKET)) {
136     return -1;
137   }
138
139   _packet_add(pktsocket, local, os_if);
140   return 0;
141 }
142
143 /**
144  * Add a new raw packet socket handler
145  * @param pktsocket pointer to an initialized packet socket struct
146  * @param protocol IP protocol number
147  * @param local pointer local IP address of packet socket
148  * @param interf pointer to interface to bind socket on, NULL
149  *   if socket should not be bound to interface
150  * @return -1 if an error happened, 0 otherwise
151  */
152 int
153 oonf_packet_raw_add(
154   struct oonf_packet_socket *pktsocket, int protocol, union netaddr_socket *local, struct os_interface *interf) {
155   /* Init socket */
156   if (os_fd_getrawsocket(&pktsocket->scheduler_entry.fd, local, false, 0, interf, LOG_PACKET)) {
157     return -1;
158   }
159
160   _packet_add(pktsocket, local, interf);
161   pktsocket->protocol = protocol;
162   return 0;
163 }
164
165 static void
166 _packet_add(struct oonf_packet_socket *pktsocket, union netaddr_socket *local, struct os_interface *interf) {
167   struct netaddr_str nbuf;
168
169   pktsocket->os_if = interf;
170   pktsocket->scheduler_entry.name = pktsocket->socket_name;
171   pktsocket->scheduler_entry.process = _cb_packet_event_unicast;
172
173   abuf_init(&pktsocket->out);
174   list_add_tail(&_packet_sockets, &pktsocket->node);
175   memcpy(&pktsocket->local_socket, local, sizeof(pktsocket->local_socket));
176
177   /* generate socket name */
178   snprintf(pktsocket->socket_name, sizeof(pktsocket->socket_name), "udp: %s",
179     netaddr_socket_to_string(&nbuf, &pktsocket->local_socket));
180
181   pktsocket->_errno1_measurement_time = oonf_clock_getNow();
182
183   if (pktsocket->config.input_buffer_length == 0) {
184     pktsocket->config.input_buffer = _input_buffer;
185     pktsocket->config.input_buffer_length = sizeof(_input_buffer);
186   }
187
188   oonf_socket_add(&pktsocket->scheduler_entry);
189   oonf_socket_set_read(&pktsocket->scheduler_entry, true);
190 }
191
192 /**
193  * Remove a packet socket from the global scheduler
194  * @param pktsocket pointer to packet socket
195  * @param force true if the socket should be removed instantly,
196  *   false if it should be removed after the last packet in queue is sent
197  */
198 void
199 oonf_packet_remove(struct oonf_packet_socket *pktsocket, bool force __attribute__((unused))) {
200   // TODO: implement non-force behavior for UDP sockets
201   if (list_is_node_added(&pktsocket->node)) {
202     oonf_socket_remove(&pktsocket->scheduler_entry);
203     os_fd_close(&pktsocket->scheduler_entry.fd);
204     abuf_free(&pktsocket->out);
205
206     list_remove(&pktsocket->node);
207   }
208 }
209
210 /**
211  * Send a data packet through a packet socket. The transmission might not
212  * be happen synchronously if the socket would block.
213  * @param pktsocket pointer to packet socket
214  * @param remote ip/address to send packet to
215  * @param data pointer to data to be sent
216  * @param length length of data
217  * @return -1 if an error happened, 0 otherwise
218  */
219 int
220 oonf_packet_send(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote, const void *data, size_t length) {
221   int result;
222   struct netaddr_str buf;
223
224   if (abuf_getlen(&pktsocket->out) == 0) {
225     /* no backlog of outgoing packets, try to send directly */
226     result = os_fd_sendto(&pktsocket->scheduler_entry.fd, data, length, remote, pktsocket->config.dont_route);
227     if (result > 0) {
228       /* successful */
229       OONF_DEBUG(LOG_PACKET, "Sent %d bytes to %s %s", result, netaddr_socket_to_string(&buf, remote),
230         pktsocket->os_if != NULL ? pktsocket->os_if->name : "");
231       oonf_socket_register_direct_send(&pktsocket->scheduler_entry);
232       return 0;
233     }
234
235     if (errno == EPERM) {
236       _handle_errno1(pktsocket, remote);
237       return -1;
238     }
239     if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
240       OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)", netaddr_socket_to_string(&buf, remote),
241         strerror(errno), errno);
242       return -1;
243     }
244   }
245
246   /* append destination */
247   abuf_memcpy(&pktsocket->out, remote, sizeof(*remote));
248
249   /* append data length */
250   abuf_append_uint16(&pktsocket->out, length);
251
252   /* append data */
253   abuf_memcpy(&pktsocket->out, data, length);
254
255   /* activate outgoing socket scheduler */
256   oonf_socket_set_write(&pktsocket->scheduler_entry, true);
257   return 0;
258 }
259
260 /**
261  * Initialize a new managed packet socket
262  * @param managed pointer to packet socket
263  */
264 void
265 oonf_packet_add_managed(struct oonf_packet_managed *managed) {
266   if (managed->config.input_buffer_length == 0) {
267     managed->config.input_buffer = _input_buffer;
268     managed->config.input_buffer_length = sizeof(_input_buffer);
269   }
270
271   managed->_if_listener.if_changed = _cb_interface_listener;
272   managed->_if_listener.name = managed->_managed_config.interface;
273   managed->_if_listener.mesh = managed->_managed_config.mesh;
274 }
275
276 /**
277  * Cleanup an initialized managed packet socket
278  * @param managed pointer to packet socket
279  * @param forced true if socket should be closed instantly
280  */
281 void
282 oonf_packet_remove_managed(struct oonf_packet_managed *managed, bool forced) {
283   oonf_packet_remove(&managed->socket_v4, forced);
284   oonf_packet_remove(&managed->socket_v6, forced);
285   oonf_packet_remove(&managed->multicast_v4, forced);
286   oonf_packet_remove(&managed->multicast_v6, forced);
287
288   os_interface_remove(&managed->_if_listener);
289   oonf_packet_free_managed_config(&managed->_managed_config);
290 }
291
292 /**
293  * Apply a new configuration to a managed socket. This might close and
294  * reopen sockets because of changed binding IPs or ports.
295  * @param managed pointer to managed packet socket
296  * @param config pointer to new configuration
297  * @return -1 if an error happened, 0 otherwise
298  */
299 int
300 oonf_packet_apply_managed(struct oonf_packet_managed *managed, const struct oonf_packet_managed_config *config) {
301   bool if_changed;
302   int result;
303
304   if_changed = strcmp(config->interface, managed->_managed_config.interface) != 0 ||
305                !list_is_node_added(&managed->_if_listener._node);
306
307   oonf_packet_copy_managed_config(&managed->_managed_config, config);
308
309   /* handle change in interface listener */
310   if (if_changed) {
311     /* interface changed, remove old listener if necessary */
312     os_interface_remove(&managed->_if_listener);
313
314     /* create new interface listener */
315     managed->_if_listener.mesh = managed->_managed_config.mesh;
316     os_interface_add(&managed->_if_listener);
317   }
318
319   OONF_DEBUG(LOG_PACKET, "Apply changes for managed socket (if %s) with port %d/%d",
320     config->interface[0] == 0 ? "any" : config->interface, config->port, config->multicast_port);
321
322   result = _apply_managed(managed);
323   if (result) {
324     /* did not work, trigger interface handler to try later again */
325     os_interface_trigger_handler(&managed->_if_listener);
326   }
327   return result;
328 }
329
330 /**
331  * Send a packet out over one of the managed sockets, depending on the
332  * address family type of the remote address
333  * @param managed pointer to managed packet socket
334  * @param remote pointer to remote socket
335  * @param data pointer to data to send
336  * @param length length of data
337  * @return -1 if an error happened, 0 if packet was sent, 1 if this
338  *    type of address was switched off
339  */
340 int
341 oonf_packet_send_managed(
342   struct oonf_packet_managed *managed, union netaddr_socket *remote, const void *data, size_t length) {
343   int result;
344 #ifdef OONF_LOG_DEBUG_INFO
345   struct netaddr_str buf;
346 #endif
347
348   if (netaddr_socket_get_addressfamily(remote) == AF_UNSPEC) {
349     return 0;
350   }
351
352   result = 1;
353   errno = 0;
354   if (list_is_node_added(&managed->socket_v4.scheduler_entry._node) &&
355       netaddr_socket_get_addressfamily(remote) == AF_INET) {
356     result = oonf_packet_send(&managed->socket_v4, remote, data, length);
357   }
358   if (list_is_node_added(&managed->socket_v6.scheduler_entry._node) &&
359       netaddr_socket_get_addressfamily(remote) == AF_INET6) {
360     result = oonf_packet_send(&managed->socket_v6, remote, data, length);
361   }
362   else {
363     OONF_DEBUG(LOG_PACKET, "Managed socket did not sent packet to %s because socket was not active",
364       netaddr_socket_to_string(&buf, remote));
365   }
366
367   if (errno == EBADF) {
368     /* file descriptor is not working anymore */
369     if (netaddr_socket_get_addressfamily(remote) == AF_INET) {
370       oonf_packet_remove(&managed->socket_v4, true);
371     }
372     else {
373       oonf_packet_remove(&managed->socket_v6, true);
374     }
375
376     /* try to re-open */
377     _apply_managed(managed);
378   }
379   return result;
380 }
381
382 /**
383  * Send a packet out over one of the managed sockets, depending on the
384  * address family type of the remote address
385  * @param managed pointer to managed packet socket
386  * @param data pointer to data to send
387  * @param length length of data
388  * @param af_type address family to send multicast
389  * @return -1 if an error happened, 0 if packet was sent, 1 if this
390  *    type of address was switched off
391  */
392 int
393 oonf_packet_send_managed_multicast(struct oonf_packet_managed *managed, const void *data, size_t length, int af_type) {
394   if (af_type == AF_INET) {
395     return oonf_packet_send_managed(managed, &managed->multicast_v4.local_socket, data, length);
396   }
397   else if (af_type == AF_INET6) {
398     return oonf_packet_send_managed(managed, &managed->multicast_v6.local_socket, data, length);
399   }
400   errno = 0;
401   return 1;
402 }
403
404 /**
405  * Returns true if the socket for IPv4/6 is active to send data.
406  * @param managed pointer to managed UDP socket
407  * @param af_type address familty
408  * @return true if the selected socket is active.
409  */
410 bool
411 oonf_packet_managed_is_active(struct oonf_packet_managed *managed, int af_type) {
412   switch (af_type) {
413     case AF_INET:
414       return oonf_packet_is_active(&managed->socket_v4);
415     case AF_INET6:
416       return oonf_packet_is_active(&managed->socket_v6);
417     default:
418       return false;
419   }
420 }
421
422 /**
423  * copies a packet managed configuration object
424  * @param dst Destination
425  * @param src Source
426  */
427 void
428 oonf_packet_copy_managed_config(struct oonf_packet_managed_config *dst, const struct oonf_packet_managed_config *src) {
429   oonf_packet_free_managed_config(dst);
430
431   /* careful, we are doing a shallow copy, so both ACLs are BAD after this */
432   memcpy(dst, src, sizeof(*dst));
433
434   /* fix it to make sure we don't use-after-free or double-free */
435   memset(&dst->acl, 0, sizeof(dst->acl));
436   memset(&dst->bindto, 0, sizeof(dst->bindto));
437
438   /* now do a deep copy of the ACLs */
439   netaddr_acl_copy(&dst->acl, &src->acl);
440   netaddr_acl_copy(&dst->bindto, &src->bindto);
441 }
442
443 /**
444  * Free dynamically allocated parts of managed packet configuration
445  * @param config packet configuration
446  */
447 void
448 oonf_packet_free_managed_config(struct oonf_packet_managed_config *config) {
449   netaddr_acl_remove(&config->acl);
450   netaddr_acl_remove(&config->bindto);
451 }
452
453 /**
454  * Handle rate limitation of errno==1 warnings
455  * @param pktsocket packet socket the error happened
456  * @param remote target of UDP packet
457  */
458 static void
459 _handle_errno1(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote) {
460   int64_t interval;
461   uint32_t count, normalized;
462   struct netaddr_str buf;
463   const char *ifname = "-";
464   bool triggered;
465
466   /* we do a rate limitation for EPERM */
467   interval = -oonf_clock_get_relative(pktsocket->_errno1_measurement_time);
468   count = pktsocket->_errno1_count;
469   normalized = count;
470   if (interval >= 60000) {
471     normalized /= (interval / 60000);
472   }
473
474   /* increase error counter */
475   pktsocket->_errno1_count++;
476
477   triggered = false;
478   if (interval >= 60000 && pktsocket->_errno1_suppression && normalized < 5) {
479     /* switch suppression on */
480     pktsocket->_errno1_suppression = false;
481   }
482   else if (!pktsocket->_errno1_suppression && normalized > 10) {
483     /* switch suppression off */
484     pktsocket->_errno1_suppression = true;
485     count = 0;
486     triggered = true;
487   }
488
489   if (interval >= 60000 || triggered) {
490     /* start new measurement interval */
491     pktsocket->_errno1_measurement_time = oonf_clock_getNow();
492     pktsocket->_errno1_count = 1;
493   }
494
495   if (pktsocket->os_if) {
496     /* remember interface name */
497     ifname = pktsocket->os_if->name;
498   }
499
500   if (pktsocket->_errno1_suppression && count != 0) {
501     if (pktsocket->_errno1_count > 1) {
502       /* suppress warning */
503       return;
504     }
505
506     OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s (%s): %s (%d) (%d similar errors suppressed)",
507       netaddr_socket_to_string(&buf, remote), ifname, strerror(errno), errno, count);
508   }
509   else {
510     OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s (%s): %s (%d)", netaddr_socket_to_string(&buf, remote), ifname,
511       strerror(errno), errno);
512   }
513 }
514
515 /**
516  * Apply a new configuration to all attached sockets
517  * @param managed pointer to managed socket
518  * @return -1 if an error happened, 0 otherwise
519  */
520 static int
521 _apply_managed(struct oonf_packet_managed *managed) {
522   struct os_interface *os_if = NULL;
523   bool changed = false;
524   int result = 0;
525
526   /* get interface */
527   if (managed->_if_listener.name) {
528     os_if = managed->_if_listener.data;
529   }
530
531   if (_apply_managed_socketpair(AF_INET, managed, os_if, &changed, &managed->socket_v4, &managed->multicast_v4,
532         &managed->_managed_config.multicast_v4)) {
533     result = -1;
534   }
535
536   if (_apply_managed_socketpair(AF_INET6, managed, os_if, &changed, &managed->socket_v6, &managed->multicast_v6,
537         &managed->_managed_config.multicast_v6)) {
538     result = -1;
539   }
540
541   if (managed->cb_settings_change) {
542     managed->cb_settings_change(managed, changed);
543   }
544   return result;
545 }
546
547 /**
548  * Apply a new configuration to an unicast/multicast socket pair
549  * @param managed managed socket
550  * @param os_if OS interface to bind sockets, NULL if unbound socket
551  * @param changed buffer for boolean, will be set to true if sockets changed
552  * @param sock unicast packet socket
553  * @param mc_sock pointer to multicast packet socket
554  * @param mc_ip multicast address
555  * @return 0 if okay, -1 if an error happened
556  */
557 static int
558 _apply_managed_socketpair(int af_type, struct oonf_packet_managed *managed, struct os_interface *os_if, bool *changed,
559   struct oonf_packet_socket *sock, struct oonf_packet_socket *mc_sock, struct netaddr *mc_ip) {
560   struct netaddr_acl *bind_ip_acl;
561   int sockstate = 0, result = 0;
562   uint16_t mc_port;
563   bool real_multicast;
564   const struct netaddr *bind_ip;
565
566   bind_ip_acl = &managed->_managed_config.bindto;
567
568   /* copy unicast port if necessary */
569   mc_port = managed->_managed_config.multicast_port;
570   if (mc_port == 0) {
571     mc_port = managed->_managed_config.port;
572   }
573
574   /* Get address the unicast socket should bind on */
575   if (os_if != NULL && !os_if->flags.up) {
576     bind_ip = NULL;
577   }
578   else if (os_if != NULL && netaddr_get_address_family(os_if->if_linklocal_v6) == af_type &&
579            netaddr_acl_check_accept(bind_ip_acl, os_if->if_linklocal_v6)) {
580     bind_ip = os_if->if_linklocal_v6;
581   }
582   else if (os_if != NULL && netaddr_get_address_family(os_if->if_linklocal_v4) == af_type &&
583            netaddr_acl_check_accept(bind_ip_acl, os_if->if_linklocal_v4)) {
584     bind_ip = os_if->if_linklocal_v4;
585   }
586   else {
587     bind_ip = os_interface_get_bindaddress(af_type, bind_ip_acl, os_if);
588   }
589   if (!bind_ip) {
590     oonf_packet_remove(sock, false);
591     oonf_packet_remove(mc_sock, false);
592     return 0;
593   }
594
595   /* handle loopback interface */
596   if (os_if != NULL && os_if->flags.loopback && netaddr_get_address_family(mc_ip) != AF_UNSPEC) {
597     memcpy(mc_ip, bind_ip, sizeof(*mc_ip));
598   }
599
600   /* check if multicast IP is a real multicast (and not a broadcast) */
601   real_multicast = netaddr_is_in_subnet(
602     netaddr_get_address_family(mc_ip) == AF_INET ? &NETADDR_IPV4_MULTICAST : &NETADDR_IPV6_MULTICAST, mc_ip);
603
604   sockstate = _apply_managed_socket(managed, sock, bind_ip, managed->_managed_config.port,
605     managed->_managed_config.dscp, managed->_managed_config.rawip ? managed->_managed_config.protocol : 0, os_if);
606   if (sockstate == 0) {
607     /* settings really changed */
608     *changed = true;
609
610     if (real_multicast && os_if != NULL && os_if->flags.up) {
611       os_fd_join_mcast_send(&sock->scheduler_entry.fd, mc_ip, os_if, managed->_managed_config.loop_multicast,
612         managed->_managed_config.ttl_multicast, LOG_PACKET);
613     }
614   }
615   else if (sockstate < 0) {
616     /* error */
617     result = -1;
618     oonf_packet_remove(sock, true);
619   }
620
621   if (real_multicast && netaddr_get_address_family(mc_ip) != AF_UNSPEC) {
622     /* multicast */
623     sockstate = _apply_managed_socket(managed, mc_sock, mc_ip, mc_port, managed->_managed_config.dscp,
624       managed->_managed_config.rawip ? managed->_managed_config.protocol : 0, os_if);
625     if (sockstate == 0) {
626       /* settings really changed */
627       *changed = true;
628
629       mc_sock->scheduler_entry.process = _cb_packet_event_multicast;
630
631       /* join multicast group */
632       os_fd_join_mcast_recv(&mc_sock->scheduler_entry.fd, mc_ip, os_if, LOG_PACKET);
633     }
634     else if (sockstate < 0) {
635       /* error */
636       result = -1;
637       oonf_packet_remove(sock, true);
638     }
639   }
640   else {
641     oonf_packet_remove(mc_sock, true);
642
643     /*
644      * initialize anyways because we use it for sending broadcasts with
645      * oonf_packet_send_managed_multicast()
646      */
647     netaddr_socket_init(&mc_sock->local_socket, mc_ip, mc_port, os_if == NULL ? 0 : os_if->index);
648   }
649   return result;
650 }
651
652 /**
653  * Apply new configuration to a managed stream socket
654  * @param managed managed packet socket (pair)
655  * @param packet packet socket
656  * @param bindto local address to bind socket to
657  *   set to AF_UNSPEC for simple reinitialization
658  * @param port local port number
659  * @param dscp dscp value for outgoing traffic
660  * @param protocol IP protocol for raw IP socket, 0 otherwise
661  * @param data interface data to bind socket to, might be NULL
662  * @return -1 if an error happened, 0 if everything is okay,
663  *   1 if the socket wasn't touched.
664  */
665 static int
666 _apply_managed_socket(struct oonf_packet_managed *managed, struct oonf_packet_socket *packet,
667   const struct netaddr *bindto, int port, uint8_t dscp, int protocol, struct os_interface *data) {
668   union netaddr_socket sock;
669   struct netaddr_str buf;
670
671   /* create binding socket */
672   if (netaddr_socket_init(&sock, bindto, port, data == NULL ? 0 : data->index)) {
673     OONF_WARN(LOG_PACKET, "Cannot create managed socket address: %s/%u", netaddr_to_string(&buf, bindto), port);
674     return -1;
675   }
676
677   if (list_is_node_added(&packet->node)) {
678     if (data == packet->os_if && memcmp(&sock, &packet->local_socket, sizeof(sock)) == 0 &&
679         protocol == packet->protocol) {
680       /* nothing changed */
681       return 1;
682     }
683   }
684   else {
685     if (data != NULL && !data->flags.up) {
686       /* nothing changed */
687       return 1;
688     }
689   }
690
691   /* remove old socket */
692   oonf_packet_remove(packet, true);
693
694   if (data != NULL && !data->flags.up) {
695     OONF_DEBUG(LOG_PACKET, "Interface %s of socket is down", data->name);
696     return 0;
697   }
698
699   /* copy configuration */
700   memcpy(&packet->config, &managed->config, sizeof(packet->config));
701   if (packet->config.user == NULL) {
702     packet->config.user = managed;
703   }
704
705   /* create new socket */
706   if (protocol) {
707     if (oonf_packet_raw_add(packet, protocol, &sock, data)) {
708       return -1;
709     }
710   }
711   else {
712     if (oonf_packet_add(packet, &sock, data)) {
713       return -1;
714     }
715   }
716
717   if (os_fd_set_dscp(&packet->scheduler_entry.fd, dscp, netaddr_get_address_family(bindto) == AF_INET6)) {
718     OONF_WARN(LOG_PACKET, "Could not set DSCP value for socket: %s (%d)", strerror(errno), errno);
719     oonf_packet_remove(packet, true);
720     return -1;
721   }
722   packet->os_if = data;
723
724   OONF_DEBUG(LOG_PACKET, "Opened new socket and bound it to %s (if %s)", netaddr_to_string(&buf, bindto),
725     data != NULL ? data->name : "any");
726   return 0;
727 }
728
729 /**
730  * callback for unicast events in socket scheduler
731  * @param entry socket entry that fired event
732  */
733 static void
734 _cb_packet_event_unicast(struct oonf_socket_entry *entry) {
735   _cb_packet_event(entry, false);
736 }
737
738 /**
739  * callback for multicast events in socket scheduler
740  * @param entry socket entry that fired event
741  */
742 static void
743 _cb_packet_event_multicast(struct oonf_socket_entry *entry) {
744   _cb_packet_event(entry, true);
745 }
746
747 /**
748  * Callback to handle data from the olsr socket scheduler
749  * @param entry socket entry that fired event
750  * @param multicast true if the multicast socket fired the event,
751  *   false otherwise
752  */
753 static void
754 _cb_packet_event(struct oonf_socket_entry *entry, bool multicast __attribute__((unused))) {
755   struct oonf_packet_socket *pktsocket;
756   union netaddr_socket sock;
757   uint16_t length;
758   char *pkt;
759   ssize_t result;
760   struct netaddr_str netbuf;
761
762 #ifdef OONF_LOG_DEBUG_INFO
763   const char *interf = "";
764 #endif
765
766   pktsocket = container_of(entry, typeof(*pktsocket), scheduler_entry);
767
768 #ifdef OONF_LOG_DEBUG_INFO
769   if (pktsocket->os_if) {
770     interf = pktsocket->os_if->name;
771   }
772 #endif
773
774   if (oonf_socket_is_read(entry)) {
775     uint8_t *buf;
776
777     /* clear recvfrom memory */
778     memset(&sock, 0, sizeof(sock));
779
780     /* handle incoming data */
781     buf = pktsocket->config.input_buffer;
782
783     result = os_fd_recvfrom(&entry->fd, buf, pktsocket->config.input_buffer_length - 1, &sock, pktsocket->os_if);
784     if (result > 0 && pktsocket->config.receive_data != NULL) {
785       /* handle raw socket */
786       if (pktsocket->protocol) {
787         buf = os_fd_skip_rawsocket_prefix(buf, &result, pktsocket->local_socket.std.sa_family);
788         if (!buf) {
789           OONF_WARN(LOG_PACKET, "Error while skipping IP header for socket %s:",
790             netaddr_socket_to_string(&netbuf, &pktsocket->local_socket));
791           return;
792         }
793       }
794       /* null terminate it */
795       buf[result] = 0;
796
797       /* received valid packet */
798       OONF_DEBUG(LOG_PACKET, "Received %" PRINTF_SSIZE_T_SPECIFIER " bytes from %s %s (%s)", result,
799         netaddr_socket_to_string(&netbuf, &sock), interf, multicast ? "multicast" : "unicast");
800       pktsocket->config.receive_data(pktsocket, &sock, buf, result);
801     }
802     else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) {
803       OONF_WARN(LOG_PACKET, "Cannot read packet from socket %s: %s (%d)",
804         netaddr_socket_to_string(&netbuf, &pktsocket->local_socket), strerror(errno), errno);
805     }
806   }
807
808   if (oonf_socket_is_write(entry) && abuf_getlen(&pktsocket->out) > 0) {
809     /* handle outgoing data */
810     pkt = abuf_getptr(&pktsocket->out);
811
812     /* copy remote socket */
813     memcpy(&sock, pkt, sizeof(sock));
814     pkt += sizeof(sock);
815
816     /* copy length */
817     memcpy(&length, pkt, 2);
818     pkt += 2;
819
820     /* try to send packet */
821     result = os_fd_sendto(&entry->fd, pkt, length, &sock, pktsocket->config.dont_route);
822     if (result < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
823       /* try again later */
824       OONF_DEBUG(
825         LOG_PACKET, "Sending to %s %s could block, try again later", netaddr_socket_to_string(&netbuf, &sock), interf);
826       return;
827     }
828
829     if (result < 0) {
830       /* display error message */
831       OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)", netaddr_socket_to_string(&netbuf, &sock),
832         strerror(errno), errno);
833     }
834     else {
835       OONF_DEBUG(LOG_PACKET, "Sent %" PRINTF_SSIZE_T_SPECIFIER " bytes to %s %s", result,
836         netaddr_socket_to_string(&netbuf, &sock), interf);
837     }
838     /* remove data from outgoing buffer (both for success and for final error */
839     abuf_pull(&pktsocket->out, sizeof(sock) + 2 + length);
840   }
841
842   if (abuf_getlen(&pktsocket->out) == 0) {
843     /* nothing left to send, disable outgoing events */
844     oonf_socket_set_write(&pktsocket->scheduler_entry, false);
845   }
846 }
847
848 /**
849  * Callbacks for events on the interface
850  * @param l OS interface listener
851  * @return -1 if an error happened, 0 otherwise
852  */
853 static int
854 _cb_interface_listener(struct os_interface_listener *l) {
855   struct oonf_packet_managed *managed;
856   int result;
857
858   /* calculate managed socket for this event */
859   managed = container_of(l, struct oonf_packet_managed, _if_listener);
860
861   result = _apply_managed(managed);
862   OONF_DEBUG(LOG_PACKET, "Result from interface %s triggered socket reconfiguration: %d",
863              l->data->name, result);
864
865   return result;
866 }