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