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