ee0993bcf3e4536198a0345261badccebf188db8
[oonf.git] / src / subsystems / oonf_rfc5444.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 <oonf/libcommon/avl.h>
47 #include <oonf/libcommon/avl_comp.h>
48 #include <oonf/oonf.h>
49 #include <oonf/libconfig/cfg_db.h>
50 #include <oonf/libconfig/cfg_schema.h>
51 #include <oonf/libcore/oonf_logging.h>
52 #include <oonf/libcore/oonf_subsystem.h>
53 #include <oonf/libcore/os_core.h>
54 #include <oonf/librfc5444/rfc5444_iana.h>
55 #include <oonf/librfc5444/rfc5444_print.h>
56 #include <oonf/librfc5444/rfc5444_reader.h>
57 #include <oonf/librfc5444/rfc5444_writer.h>
58 #include <oonf/subsystems/oonf_class.h>
59 #include <oonf/subsystems/oonf_duplicate_set.h>
60 #include <oonf/subsystems/oonf_packet_socket.h>
61 #include <oonf/subsystems/oonf_timer.h>
62
63 #include <oonf/subsystems/oonf_rfc5444.h>
64
65 /* constants and definitions */
66 #define LOG_RFC5444 _oonf_rfc5444_subsystem.logging
67
68 /**
69  * RFC5444 configuration
70  */
71 struct _rfc5444_config {
72   /*! port number to be used for RFC5444 communication */
73   int32_t port;
74
75   /*! IP protocol number to be used for RFC5444 communication */
76   int ip_proto;
77 };
78
79 /**
80  * RFC5444 interface specific configuration
81  */
82 struct _rfc5444_if_config {
83   /*! packet socket configuration */
84   struct oonf_packet_managed_config sock;
85
86   /*! maximum aggregation interval for this interface */
87   uint64_t aggregation_interval;
88 };
89
90 /* prototypes */
91 static int _init(void);
92 static void _cleanup(void);
93
94 static struct oonf_rfc5444_target *_create_target(struct oonf_rfc5444_interface *, struct netaddr *dst, bool unicast);
95 static void _destroy_target(struct oonf_rfc5444_target *);
96 static void _print_packet_to_buffer(enum oonf_log_source source, union netaddr_socket *sock,
97   struct oonf_rfc5444_interface *interf, const uint8_t *ptr, size_t len, const char *success, const char *error);
98
99 static void _cb_receive_data(struct oonf_packet_socket *, union netaddr_socket *from, void *ptr, size_t length);
100 static void _cb_send_unicast_packet(struct rfc5444_writer *, struct rfc5444_writer_target *, void *, size_t);
101 static void _cb_send_multicast_packet(struct rfc5444_writer *, struct rfc5444_writer_target *, void *, size_t);
102 static void _cb_forward_message(struct rfc5444_reader_tlvblock_context *context, const uint8_t *buffer, size_t length);
103 static void _cb_msggen_notifier(struct rfc5444_writer_target *);
104
105 static bool _cb_single_target_selector(struct rfc5444_writer *, struct rfc5444_writer_target *, void *);
106 static bool _cb_filtered_targets_selector(
107   struct rfc5444_writer *writer, struct rfc5444_writer_target *rfc5444_target, void *ptr);
108
109 static struct rfc5444_reader_addrblock_entry *_alloc_addrblock_entry(void);
110 static struct rfc5444_reader_tlvblock_entry *_alloc_tlvblock_entry(void);
111 static struct rfc5444_writer_address *_alloc_address_entry(void);
112 static struct rfc5444_writer_addrtlv *_alloc_addrtlv_entry(void);
113 static void _free_addrblock_entry(struct rfc5444_reader_addrblock_entry *addrblock);
114 static void _free_tlvblock_entry(struct rfc5444_reader_tlvblock_entry *tlvblock);
115 static void _free_address_entry(struct rfc5444_writer_address *);
116 static void _free_addrtlv_entry(struct rfc5444_writer_addrtlv *);
117
118 static void _cb_add_seqno(struct rfc5444_writer *, struct rfc5444_writer_target *);
119 static void _cb_aggregation_event(struct oonf_timer_instance *);
120
121 static void _cb_cfg_rfc5444_changed(void);
122 static void _cb_cfg_interface_changed(void);
123 static void _cb_interface_changed(struct oonf_packet_managed *managed, bool);
124
125 /* memory block for rfc5444 targets plus MTU sized packet buffer */
126 static struct oonf_class _protocol_memcookie = {
127   .name = RFC5444_CLASS_PROTOCOL,
128   .size = sizeof(struct oonf_rfc5444_protocol),
129 };
130
131 static struct oonf_class _interface_memcookie = {
132   .name = RFC5444_CLASS_INTERFACE,
133   .size = sizeof(struct oonf_rfc5444_interface),
134 };
135
136 static struct oonf_class _target_memcookie = {
137   .name = RFC5444_CLASS_TARGET,
138   .size = sizeof(struct oonf_rfc5444_target),
139 };
140
141 static struct oonf_class _tlvblock_memcookie = {
142   .name = "RFC5444 TLVblock",
143   .size = sizeof(struct rfc5444_reader_tlvblock_entry),
144   .min_free_count = 32,
145 };
146
147 static struct oonf_class _addrblock_memcookie = {
148   .name = "RFC5444 Addrblock",
149   .size = sizeof(struct rfc5444_reader_addrblock_entry),
150   .min_free_count = 32,
151 };
152
153 static struct oonf_class _address_memcookie = {
154   .name = "RFC5444 Address",
155   .size = sizeof(struct rfc5444_writer_address),
156   .min_free_count = 32,
157 };
158
159 static struct oonf_class _addrtlv_memcookie = {
160   .name = "RFC5444 AddrTLV",
161   .size = sizeof(struct rfc5444_writer_addrtlv),
162   .min_free_count = 32,
163 };
164
165 /* timer for aggregating multiple rfc5444 messages to the same target */
166 static struct oonf_timer_class _aggregation_timer = {
167   .name = "RFC5444 aggregation",
168   .callback = _cb_aggregation_event,
169 };
170
171 /* configuration settings for handler */
172 static struct cfg_schema_entry _rfc5444_entries[] = {
173   CFG_MAP_INT32_MINMAX(
174     _rfc5444_config, port, "port", RFC5444_MANET_UDP_PORT_TXT, "UDP port for RFC5444 interface", 0, 1, 65535),
175   CFG_MAP_INT32_MINMAX(
176     _rfc5444_config, ip_proto, "ip_proto", RFC5444_MANET_IPPROTO_TXT, "IP protocol for RFC5444 interface", 0, 1, 255),
177 };
178
179 static struct cfg_schema_section _rfc5444_section = {
180   .type = CFG_RFC5444_SECTION,
181   .mode = CFG_SSMODE_UNNAMED,
182   .cb_delta_handler = _cb_cfg_rfc5444_changed,
183   .entries = _rfc5444_entries,
184   .entry_count = ARRAYSIZE(_rfc5444_entries),
185 };
186
187 static struct cfg_schema_entry _interface_entries[] = {
188   CFG_MAP_ACL_V46(_rfc5444_if_config, sock.acl, "acl", ACL_DEFAULT_ACCEPT, "Access control list for RFC5444 interface"),
189   CFG_MAP_ACL_V46(_rfc5444_if_config, sock.bindto, "bindto",
190     "-127.0.0.0/8\0"
191     "fe80::/10\0"
192     "-::/0\0" ACL_FIRST_ACCEPT "\0" ACL_DEFAULT_ACCEPT,
193     "Bind RFC5444 socket to an address matching this filter (both IPv4 and IPv6)"),
194   CFG_MAP_NETADDR_V4(_rfc5444_if_config, sock.multicast_v4, "multicast_v4", RFC5444_MANET_MULTICAST_V4_TXT,
195     "ipv4 multicast address of this socket", false, true),
196   CFG_MAP_NETADDR_V6(_rfc5444_if_config, sock.multicast_v6, "multicast_v6", RFC5444_MANET_MULTICAST_V6_TXT,
197     "ipv6 multicast address of this socket", false, true),
198   CFG_MAP_INT32_MINMAX(
199     _rfc5444_if_config, sock.dscp, "dscp", "192", "DSCP field for outgoing UDP protocol traffic", 0, 0, 255),
200   CFG_MAP_BOOL(
201     _rfc5444_if_config, sock.rawip, "rawip", "false", "True if a raw IP socket should be used, false to use UDP"),
202   CFG_MAP_INT32_MINMAX(
203     _rfc5444_if_config, sock.ttl_multicast, "multicast_ttl", "1", "TTL value of outgoing multicast traffic", 0, 1, 255),
204   CFG_MAP_CLOCK(_rfc5444_if_config, aggregation_interval, "aggregation_interval", "0.100",
205     "Interval in seconds for message aggregation"),
206
207 };
208
209 static struct cfg_schema_section _interface_section = {
210   CFG_OSIF_SCHEMA_INTERFACE_SECTION_INIT,
211
212   .cb_delta_handler = _cb_cfg_interface_changed,
213   .entries = _interface_entries,
214   .entry_count = ARRAYSIZE(_interface_entries),
215   .next_section = &_rfc5444_section,
216 };
217
218 /* rfc5444 handling */
219 static const struct rfc5444_reader _reader_template = {
220   .forward_message = _cb_forward_message,
221   .malloc_addrblock_entry = _alloc_addrblock_entry,
222   .malloc_tlvblock_entry = _alloc_tlvblock_entry,
223   .free_addrblock_entry = _free_addrblock_entry,
224   .free_tlvblock_entry = _free_tlvblock_entry,
225 };
226 static const struct rfc5444_writer _writer_template = {
227   .malloc_address_entry = _alloc_address_entry,
228   .malloc_addrtlv_entry = _alloc_addrtlv_entry,
229   .free_address_entry = _free_address_entry,
230   .free_addrtlv_entry = _free_addrtlv_entry,
231   .msg_size = RFC5444_MAX_MESSAGE_SIZE,
232   .addrtlv_size = RFC5444_ADDRTLV_BUFFER,
233 };
234
235 /* rfc5444_printer */
236 static struct autobuf _printer_buffer;
237 static struct rfc5444_print_session _printer_session;
238
239 static struct rfc5444_reader _printer = {
240   .malloc_addrblock_entry = _alloc_addrblock_entry,
241   .malloc_tlvblock_entry = _alloc_tlvblock_entry,
242   .free_addrblock_entry = _free_addrblock_entry,
243   .free_tlvblock_entry = _free_tlvblock_entry,
244 };
245
246 /* configuration for RFC5444 socket */
247 static uint8_t _incoming_buffer[RFC5444_MAX_PACKET_SIZE];
248
249 static struct oonf_packet_config _socket_config = {
250   .input_buffer = _incoming_buffer,
251   .input_buffer_length = sizeof(_incoming_buffer),
252   .receive_data = _cb_receive_data,
253 };
254
255 /* tree of active rfc5444 protocols */
256 static struct avl_tree _protocol_tree;
257
258 /* default protocol */
259 static struct oonf_rfc5444_protocol *_rfc5444_protocol = NULL;
260 static struct oonf_rfc5444_interface *_rfc5444_unicast = NULL;
261
262 static const struct const_strarray _unicast_bindto_acl_value = STRARRAY_INIT("0.0.0.0\0::");
263
264 /* subsystem definition */
265 static const char *_dependencies[] = {
266   OONF_CLASS_SUBSYSTEM,
267   OONF_DUPSET_SUBSYSTEM,
268   OONF_PACKET_SUBSYSTEM,
269   OONF_TIMER_SUBSYSTEM,
270 };
271
272 static struct oonf_subsystem _oonf_rfc5444_subsystem = {
273   .name = OONF_RFC5444_SUBSYSTEM,
274   .dependencies = _dependencies,
275   .dependencies_count = ARRAYSIZE(_dependencies),
276   .init = _init,
277   .cleanup = _cleanup,
278   .cfg_section = &_interface_section,
279 };
280 DECLARE_OONF_PLUGIN(_oonf_rfc5444_subsystem);
281
282 /* static blocking of RFC5444 output */
283 static bool _block_output = false;
284
285 /* additional logging targets */
286 static enum oonf_log_source LOG_RFC5444_R, LOG_RFC5444_W;
287
288 /**
289  * Initialize RFC5444 handling system
290  * @return -1 if an error happened, 0 otherwise
291  */
292 static int
293 _init(void) {
294   avl_init(&_protocol_tree, avl_comp_strcasecmp, false);
295
296   oonf_class_add(&_protocol_memcookie);
297   oonf_class_add(&_target_memcookie);
298   oonf_class_add(&_addrblock_memcookie);
299   oonf_class_add(&_tlvblock_memcookie);
300   oonf_class_add(&_address_memcookie);
301   oonf_class_add(&_addrtlv_memcookie);
302
303   oonf_timer_add(&_aggregation_timer);
304
305   _rfc5444_protocol = oonf_rfc5444_add_protocol("rfc5444_iana", true);
306   if (_rfc5444_protocol == NULL) {
307     _cleanup();
308     return -1;
309   }
310
311   oonf_class_add(&_interface_memcookie);
312   _rfc5444_unicast = oonf_rfc5444_add_interface(_rfc5444_protocol, NULL, RFC5444_UNICAST_INTERFACE);
313   if (_rfc5444_unicast == NULL) {
314     _cleanup();
315     return -1;
316   }
317
318   if (abuf_init(&_printer_buffer)) {
319     _cleanup();
320     return -1;
321   }
322
323   memset(&_printer_session, 0, sizeof(_printer_session));
324   _printer_session.output = &_printer_buffer;
325
326   rfc5444_reader_init(&_printer);
327   rfc5444_print_add(&_printer_session, &_printer);
328
329   LOG_RFC5444_R = oonf_log_register_source(OONF_RFC5444_SUBSYSTEM "_r");
330   LOG_RFC5444_W = oonf_log_register_source(OONF_RFC5444_SUBSYSTEM "_w");
331   return 0;
332 }
333
334 /**
335  * Cleanup all allocated resources of RFC5444 handling
336  */
337 void
338 _cleanup(void) {
339   struct oonf_rfc5444_protocol *protocol, *p_it;
340   struct oonf_rfc5444_interface *interf, *i_it;
341   struct oonf_rfc5444_target *target, *t_it;
342
343   /* cleanup existing instances */
344   avl_for_each_element_safe(&_protocol_tree, protocol, _node, p_it) {
345     avl_for_each_element_safe(&protocol->_interface_tree, interf, _node, i_it) {
346       avl_for_each_element_safe(&interf->_target_tree, target, _node, t_it) {
347         /* always remove target but never remove interface */
348         target->_refcount = 1;
349         interf->_refcount = 2;
350         oonf_rfc5444_remove_target(target);
351       }
352       /* always remove interface but never remove protocol */
353       interf->_refcount = 1;
354       protocol->_refcount = 2;
355       oonf_rfc5444_remove_interface(interf, NULL);
356     }
357     /* always remove protocol */
358     protocol->_refcount = 1;
359     oonf_rfc5444_remove_protocol(protocol);
360   }
361
362   oonf_timer_remove(&_aggregation_timer);
363
364   if (_printer_session.output) {
365     rfc5444_print_remove(&_printer_session);
366     rfc5444_reader_cleanup(&_printer);
367   }
368   abuf_free(&_printer_buffer);
369
370   oonf_class_remove(&_protocol_memcookie);
371   oonf_class_remove(&_interface_memcookie);
372   oonf_class_remove(&_target_memcookie);
373   oonf_class_remove(&_tlvblock_memcookie);
374   oonf_class_remove(&_addrblock_memcookie);
375   oonf_class_remove(&_address_memcookie);
376   oonf_class_remove(&_addrtlv_memcookie);
377   return;
378 }
379
380 /**
381  * Trigger the creation of a RFC5444 message for a specific interface
382  * @param target interface for outgoing message
383  * @param msgid id of created message
384  * @return return code of rfc5444 writer
385  */
386 enum rfc5444_result
387 oonf_rfc5444_send_if(struct oonf_rfc5444_target *target, uint8_t msgid)
388 {
389   uint8_t addr_len;
390
391 #ifdef OONF_LOG_INFO
392   struct netaddr_str buf;
393 #endif
394
395   /* check if socket can send data */
396   if (!oonf_rfc5444_is_target_active(target)) {
397     return RFC5444_OKAY;
398   }
399
400   /* create message */
401   OONF_INFO(LOG_RFC5444, "Create message id %d for protocol %s/target %s on interface %s", msgid,
402     target->interface->protocol->name, netaddr_to_string(&buf, &target->dst), target->interface->name);
403
404   addr_len = netaddr_get_address_family(&target->dst) == AF_INET ? 4 : 16;
405   return rfc5444_writer_create_message(
406     &target->interface->protocol->writer, msgid, addr_len, _cb_single_target_selector, target);
407 }
408
409 /**
410  * Trigger the creation of a RFC5444 message for a group of interfaces
411  * @param protocol protocol for outgoing message
412  * @param msgid id of created message
413  * @param addr_len length of address for this message
414  * @param useIf callback to selector for interfaces
415  * @return return code of rfc5444 writer
416  */
417 enum rfc5444_result
418 oonf_rfc5444_send_all(
419   struct oonf_rfc5444_protocol *protocol, uint8_t msgid, uint8_t addr_len, rfc5444_writer_targetselector useIf)
420 {
421   /* create message */
422   OONF_INFO(LOG_RFC5444, "Create message id %d", msgid);
423
424   return rfc5444_writer_create_message(&protocol->writer, msgid, addr_len, _cb_filtered_targets_selector, useIf);
425 }
426
427 /**
428  * Add a new protocol to the rfc5444 framework
429  * @param name name of protocol, must be an unique identifier
430  * @param fixed_local_port true if the local port must be fixed to the
431  *   external port
432  * @return pointer to new protocol instance, NULL if out of memory
433  */
434 struct oonf_rfc5444_protocol *
435 oonf_rfc5444_add_protocol(const char *name, bool fixed_local_port) {
436   struct oonf_rfc5444_protocol *protocol;
437
438   protocol = avl_find_element(&_protocol_tree, name, protocol, _node);
439   if (!protocol) {
440     protocol = oonf_class_malloc(&_protocol_memcookie);
441     if (protocol == NULL) {
442       return NULL;
443     }
444
445     /* set name */
446     strscpy(protocol->name, name, sizeof(protocol->name));
447     protocol->fixed_local_port = fixed_local_port;
448
449     /* hook into global protocol tree */
450     protocol->_node.key = protocol->name;
451     avl_insert(&_protocol_tree, &protocol->_node);
452
453     /* initialize rfc5444 reader/writer */
454     memcpy(&protocol->reader, &_reader_template, sizeof(_reader_template));
455     memcpy(&protocol->writer, &_writer_template, sizeof(_writer_template));
456     protocol->writer.msg_buffer = protocol->_msg_buffer;
457     protocol->writer.addrtlv_buffer = protocol->_addrtlv_buffer;
458     rfc5444_reader_init(&protocol->reader);
459     rfc5444_writer_init(&protocol->writer);
460
461     protocol->writer.message_generation_notifier = _cb_msggen_notifier;
462
463     /* initialize processing and forwarding set */
464     oonf_duplicate_set_add(&protocol->forwarded_set, OONF_DUPSET_16BIT);
465     oonf_duplicate_set_add(&protocol->processed_set, OONF_DUPSET_16BIT);
466
467     /* init interface subtree */
468     avl_init(&protocol->_interface_tree, avl_comp_strcasecmp, false);
469   }
470
471   OONF_INFO(LOG_RFC5444, "Add protocol %s (refcount was %d)", name, protocol->_refcount);
472
473   /* keep track of reference count */
474   protocol->_refcount++;
475
476   return protocol;
477 }
478
479 /**
480  * Remove a protocol instance from the framework
481  * @param protocol pointer to protocol
482  */
483 void
484 oonf_rfc5444_remove_protocol(struct oonf_rfc5444_protocol *protocol) {
485   struct oonf_rfc5444_interface *interf, *i_it;
486
487   OONF_INFO(LOG_RFC5444, "Remove protocol %s (refcount was %d)", protocol->name, protocol->_refcount);
488
489   if (protocol->_refcount > 1) {
490     /* There are still users left for this protocol */
491     protocol->_refcount--;
492     return;
493   }
494
495   /* free all remaining interfaces */
496   avl_for_each_element_safe(&protocol->_interface_tree, interf, _node, i_it) {
497     oonf_rfc5444_remove_interface(interf, NULL);
498   }
499
500   /* free processing/forwarding set */
501   oonf_duplicate_set_remove(&protocol->forwarded_set);
502   oonf_duplicate_set_remove(&protocol->processed_set);
503
504   /* free reader, writer and protocol itself */
505   rfc5444_reader_cleanup(&protocol->reader);
506   rfc5444_writer_cleanup(&protocol->writer);
507
508   avl_remove(&_protocol_tree, &protocol->_node);
509   oonf_class_free(&_protocol_memcookie, protocol);
510 }
511
512 /**
513  * Set the port of a protocol
514  * @param protocol pointer to protocol instance
515  * @param port port number in host byteorder
516  * @param ip_proto ip protocol number in host byteorder
517  */
518 void
519 oonf_rfc5444_reconfigure_protocol(struct oonf_rfc5444_protocol *protocol, uint16_t port, int ip_proto) {
520   struct oonf_rfc5444_interface *interf;
521
522   /* nothing to do? */
523   if (port == protocol->port && ip_proto == protocol->ip_proto) {
524     return;
525   }
526
527   OONF_INFO(LOG_RFC5444, "Reconfigure protocol %s to port %u and ip-protocol %d", protocol->name, port, ip_proto);
528
529   /* store protocol port */
530   protocol->port = port;
531   protocol->ip_proto = ip_proto;
532
533   avl_for_each_element(&protocol->_interface_tree, interf, _node) {
534     oonf_packet_remove_managed(&interf->_socket, true);
535     oonf_packet_add_managed(&interf->_socket);
536
537     if (port) {
538       oonf_rfc5444_reconfigure_interface(interf, NULL);
539     }
540   }
541 }
542
543 /**
544  * @return default IANA RFC5444 protocol instance
545  */
546 struct oonf_rfc5444_protocol *
547 oonf_rfc5444_get_default_protocol(void) {
548   return _rfc5444_protocol;
549 }
550
551 /**
552  * Add a new interface to a rfc5444 protocol.
553  * @param protocol pointer to protocol instance
554  * @param listener pointer to interface listener, NULL if none
555  * @param name name of interface
556  * @return pointer to rfc5444 interface instance, NULL if out of memory
557  */
558 struct oonf_rfc5444_interface *
559 oonf_rfc5444_add_interface(
560   struct oonf_rfc5444_protocol *protocol, struct oonf_rfc5444_interface_listener *listener, const char *name) {
561   struct oonf_rfc5444_interface *interf;
562   uint16_t rnd;
563
564   interf = oonf_rfc5444_get_interface(protocol, name);
565   if (interf == NULL) {
566     if (os_core_get_random(&rnd, sizeof(rnd))) {
567       OONF_WARN(LOG_RFC5444, "Could not get random data");
568       return NULL;
569     }
570
571     interf = oonf_class_malloc(&_interface_memcookie);
572     if (interf == NULL) {
573       return NULL;
574     }
575
576     /* set name */
577     strscpy(interf->name, name, sizeof(interf->name));
578
579     /* set protocol reference */
580     interf->protocol = protocol;
581
582     /* hook into protocol */
583     interf->_node.key = interf->name;
584     avl_insert(&protocol->_interface_tree, &interf->_node);
585
586     /* initialize target subtree */
587     avl_init(&interf->_target_tree, avl_comp_netaddr, false);
588
589     /* initialize socket config */
590     memcpy(&interf->_socket.config, &_socket_config, sizeof(_socket_config));
591     interf->_socket.config.user = interf;
592     interf->_socket.cb_settings_change = _cb_interface_changed;
593
594     /* prevent routing of RFC5444 packets */
595     interf->_socket.config.dont_route = true;
596
597     /* initialize socket */
598     oonf_packet_add_managed(&interf->_socket);
599
600     /* initialize message sequence number */
601     protocol->_msg_seqno = rnd;
602
603     /* initialize listener list */
604     list_init_head(&interf->_listener);
605
606     /* increase protocol refcount */
607     protocol->_refcount++;
608   }
609
610   OONF_INFO(LOG_RFC5444, "Add interface %s to protocol %s (refcount was %d)", name, protocol->name, interf->_refcount);
611
612   /* increase reference count */
613   interf->_refcount += 1;
614
615   if (listener) {
616     /* hookup listener */
617     list_add_tail(&interf->_listener, &listener->_node);
618     listener->interface = interf;
619   }
620   return interf;
621 }
622
623 /**
624  * Remove a rfc5444 interface instance
625  * @param interf pointer to interface instance
626  * @param listener pointer to interface listener, NULL if none
627  */
628 void
629 oonf_rfc5444_remove_interface(struct oonf_rfc5444_interface *interf, struct oonf_rfc5444_interface_listener *listener) {
630   struct oonf_rfc5444_target *target, *t_it;
631
632   OONF_INFO(LOG_RFC5444, "Remove interface %s from protocol %s (refcount was %d)", interf->name, interf->protocol->name,
633     interf->_refcount);
634
635   if (interf->_refcount > 1) {
636     /* still users left for this interface */
637     interf->_refcount--;
638     return;
639   }
640
641   if (listener != NULL && listener->interface != NULL) {
642     list_remove(&listener->_node);
643     listener->interface = NULL;
644   }
645
646   /* remove all remaining targets */
647   avl_for_each_element_safe(&interf->_target_tree, target, _node, t_it) {
648     _destroy_target(target);
649   }
650
651   /* remove multicast targets */
652   if (interf->multicast4) {
653     _destroy_target(interf->multicast4);
654   }
655   if (interf->multicast6) {
656     _destroy_target(interf->multicast6);
657   }
658
659   /* remove from protocol tree */
660   avl_remove(&interf->protocol->_interface_tree, &interf->_node);
661
662   /* decrease protocol refcount */
663   oonf_rfc5444_remove_protocol(interf->protocol);
664
665   /* remove socket */
666   oonf_packet_remove_managed(&interf->_socket, false);
667
668   /* cleanup configuration copy */
669   oonf_packet_free_managed_config(&interf->_socket_config);
670
671   /* free memory */
672   oonf_class_free(&_interface_memcookie, interf);
673 }
674
675 /**
676  * Reconfigure the parameters of an rfc5444 interface. You cannot reconfigure
677  * the interface name with this command.
678  * @param interf pointer to existing rfc5444 interface
679  * @param config new socket configuration, NULL to just reapply the current
680  *  configuration
681  */
682 void
683 oonf_rfc5444_reconfigure_interface(struct oonf_rfc5444_interface *interf, struct oonf_packet_managed_config *config) {
684   struct oonf_rfc5444_target *target, *old;
685   uint16_t port;
686   struct netaddr_str buf;
687
688   if (config != NULL) {
689     /* copy socket configuration */
690     oonf_packet_copy_managed_config(&interf->_socket_config, config);
691
692     /* overwrite interface name */
693     strscpy(interf->_socket_config.interface, interf->name, sizeof(interf->_socket_config.interface));
694   }
695   else {
696     config = &interf->_socket_config;
697   }
698
699   /* always mesh socket */
700   interf->_socket_config.mesh = true;
701
702   /* get port */
703   port = interf->protocol->port;
704
705   /* set fixed configuration options */
706   if (interf->_socket_config.rawip) {
707     interf->_socket_config.port = 0;
708     interf->_socket_config.multicast_port = 0;
709     interf->_socket_config.protocol = interf->protocol->ip_proto;
710   }
711   else {
712     if (interf->_socket_config.multicast_port == 0) {
713       interf->_socket_config.multicast_port = port;
714     }
715     if (interf->protocol->fixed_local_port && interf->_socket_config.port == 0) {
716       interf->_socket_config.port = port;
717     }
718   }
719
720   OONF_INFO(LOG_RFC5444, "Reconfigure RFC5444 interface %s to port %u/%u and protocol %d", interf->name,
721     interf->_socket_config.port, interf->_socket_config.multicast_port, interf->_socket_config.protocol);
722
723   if (strcmp(interf->name, RFC5444_UNICAST_INTERFACE) == 0) {
724     /* unicast interface */
725     netaddr_invalidate(&interf->_socket_config.multicast_v4);
726     netaddr_invalidate(&interf->_socket_config.multicast_v6);
727     interf->_socket_config.port = port;
728     interf->_socket_config.interface[0] = 0;
729     netaddr_acl_from_strarray(&interf->_socket_config.bindto, &_unicast_bindto_acl_value);
730   }
731
732   if (port == 0) {
733     /* delay configuration apply */
734     OONF_INFO(LOG_RFC5444, "    delay configuration, we still lack to protocol port");
735     return;
736   }
737
738   /* apply socket configuration */
739   oonf_packet_apply_managed(&interf->_socket, &interf->_socket_config);
740
741   /* handle IPv4 multicast target */
742   if (interf->multicast4) {
743     old = interf->multicast4;
744     interf->multicast4 = NULL;
745   }
746   else {
747     old = NULL;
748   }
749   if (netaddr_get_address_family(&config->multicast_v4) != AF_UNSPEC) {
750     target = _create_target(interf, &config->multicast_v4, false);
751     if (target == NULL) {
752       OONF_WARN(LOG_RFC5444, "Could not create multicast target %s for interface %s",
753         netaddr_to_string(&buf, &config->multicast_v4), interf->name);
754       interf->multicast4 = old;
755       old = NULL;
756     }
757     else {
758       interf->multicast4 = target;
759     }
760   }
761   if (old) {
762     _destroy_target(old);
763   }
764
765   /* handle IPv6 multicast target */
766   if (interf->multicast6) {
767     old = interf->multicast6;
768     interf->multicast6 = NULL;
769   }
770   else {
771     old = NULL;
772   }
773   if (netaddr_get_address_family(&config->multicast_v6) != AF_UNSPEC) {
774     target = _create_target(interf, &config->multicast_v6, false);
775     if (target == NULL) {
776       OONF_WARN(LOG_RFC5444, "Could not create multicast socket %s for interface %s",
777         netaddr_to_string(&buf, &config->multicast_v6), interf->name);
778       interf->multicast6 = old;
779       old = NULL;
780     }
781     else {
782       interf->multicast6 = target;
783     }
784   }
785   if (old) {
786     _destroy_target(old);
787   }
788 }
789
790 /**
791  * Set/Reset value to overwrite the configured aggregation
792  * interval of a RFC5444 interface
793  * @param interf RFC5444 interface
794  * @param aggregation new aggregation interval, 0 to reset to
795  *   configured value
796  * @return old aggregation interval, 0 if configured value was used
797  */
798 uint64_t
799 oonf_rfc5444_interface_set_aggregation(struct oonf_rfc5444_interface *interf, uint64_t aggregation) {
800   uint64_t old;
801
802   old = interf->overwrite_aggregation_interval;
803   interf->overwrite_aggregation_interval = aggregation;
804   return old;
805 }
806
807 /**
808  * Add an unicast target to a rfc5444 interface
809  * @param interf pointer to interface instance
810  * @param dst pointer to destination IP address
811  * @return pointer to target, NULL if out of memory
812  */
813 struct oonf_rfc5444_target *
814 oonf_rfc5444_add_target(struct oonf_rfc5444_interface *interf, struct netaddr *dst) {
815   struct oonf_rfc5444_target *target;
816 #ifdef OONF_LOG_INFO
817   struct netaddr_str nbuf;
818 #endif
819
820   target = avl_find_element(&interf->_target_tree, dst, target, _node);
821   if (!target) {
822     target = _create_target(interf, dst, true);
823     if (target == NULL) {
824       return NULL;
825     }
826
827     /* hook into interface tree */
828     target->_node.key = &target->dst;
829     avl_insert(&interf->_target_tree, &target->_node);
830   }
831
832   OONF_INFO(LOG_RFC5444, "Add target %s to interface %s on protocol %s (refcount was %d)",
833     netaddr_to_string(&nbuf, dst), interf->name, interf->protocol->name, target->_refcount);
834
835   /* increase interface refcount */
836   interf->_refcount++;
837   return target;
838 }
839
840 /**
841  * Removes an unicast target from a rfc5444 interface
842  * @param target pointer to target instance
843  */
844 void
845 oonf_rfc5444_remove_target(struct oonf_rfc5444_target *target) {
846 #ifdef OONF_LOG_INFO
847   struct netaddr_str nbuf;
848 #endif
849
850   OONF_INFO(LOG_RFC5444, "Remove target %s from interface %s on protocol %s (refcount was %d)",
851     netaddr_to_string(&nbuf, &target->dst), target->interface->name, target->interface->protocol->name,
852     target->_refcount);
853
854   if (target->_refcount > 1) {
855     /* target still in use */
856     target->_refcount--;
857     return;
858   }
859
860   /* remove from protocol tree */
861   avl_remove(&target->interface->_target_tree, &target->_node);
862
863   /* decrease protocol refcount */
864   oonf_rfc5444_remove_interface(target->interface, NULL);
865
866   /* remove target */
867   _destroy_target(target);
868 }
869
870 /**
871  * Send a raw RFC5444 packet to a target
872  * @param target target for the packet data
873  * @param ptr pointer to data
874  * @param len length of data
875  */
876 void
877 oonf_rfc5444_send_target_data(struct oonf_rfc5444_target *target, const void *ptr, size_t len) {
878   union netaddr_socket sock;
879   struct os_interface_listener *interf;
880
881   interf = oonf_rfc5444_get_core_if_listener(target->interface);
882   netaddr_socket_init(&sock, &target->dst, target->interface->protocol->port, interf->data->index);
883
884   _print_packet_to_buffer(LOG_RFC5444_W, &sock, target->interface, ptr, len, "Outgoing RFC5444 packet to",
885     "Error while parsing outgoing RFC5444 packet to");
886
887   if (_block_output) {
888     OONF_DEBUG(LOG_RFC5444, "Output blocked");
889     return;
890   }
891   if (target == target->interface->multicast4 || target == target->interface->multicast6) {
892     oonf_packet_send_managed_multicast(&target->interface->_socket, ptr, len, netaddr_get_address_family(&target->dst));
893   }
894   else {
895     oonf_packet_send_managed(&target->interface->_socket, &sock, ptr, len);
896   }
897 }
898
899 /**
900  * Send a raw RFC5444 packet through an interface to a destination address
901  * @param interf rfc5444 interface
902  * @param dst destination address for packet
903  * @param ptr pointer to data
904  * @param len length of data
905  */
906 void
907 oonf_rfc5444_send_interface_data(
908   struct oonf_rfc5444_interface *interf, const struct netaddr *dst, const void *ptr, size_t len) {
909   union netaddr_socket sock;
910   struct os_interface_listener *os_interf;
911
912   os_interf = oonf_rfc5444_get_core_if_listener(interf);
913   netaddr_socket_init(&sock, dst, interf->protocol->port, os_interf->data->index);
914
915   _print_packet_to_buffer(LOG_RFC5444_W, &sock, interf, ptr, len, "Outgoing RFC5444 packet to",
916     "Error while parsing outgoing RFC5444 packet to");
917
918   if (_block_output) {
919     OONF_DEBUG(LOG_RFC5444, "Output blocked");
920     return;
921   }
922
923   if (netaddr_is_in_subnet(&NETADDR_IPV4_MULTICAST, dst) || netaddr_is_in_subnet(&NETADDR_IPV6_MULTICAST, dst)) {
924     oonf_packet_send_managed_multicast(&interf->_socket, ptr, len, netaddr_get_address_family(dst));
925   }
926   else {
927     oonf_packet_send_managed(&interf->_socket, &sock, ptr, len);
928   }
929 }
930
931 /**
932  * @param target oonf rfc5444 target
933  * @return local socket corresponding to target destination
934  */
935 const union netaddr_socket *
936 oonf_rfc5444_target_get_local_socket(struct oonf_rfc5444_target *target) {
937   int family;
938
939   family = netaddr_get_address_family(&target->dst);
940   return oonf_rfc5444_interface_get_local_socket(target->interface, family);
941 }
942
943 /**
944  * @param rfc5444_if oonf rfc5444 interface
945  * @param af_type address family type
946  * @return local socket corresponding to address family
947  */
948 const union netaddr_socket *
949 oonf_rfc5444_interface_get_local_socket(struct oonf_rfc5444_interface *rfc5444_if, int af_type) {
950   if (af_type == AF_INET) {
951     return &rfc5444_if->_socket.socket_v4.local_socket;
952   }
953   if (af_type == AF_INET6) {
954     return &rfc5444_if->_socket.socket_v6.local_socket;
955   }
956   return NULL;
957 }
958
959 /**
960  * This function can block all output of the RFC5444 code
961  * @param block true to block everything, false to unblock
962  */
963 void
964 oonf_rfc5444_block_output(bool block) {
965   _block_output = block;
966 }
967
968 /**
969  * Create a new rfc5444 target
970  * @param interf rfc5444 interface
971  * @param dst destination ip address
972  * @param unicast true of unicast, false if multicast
973  * @return pointer to target, NULL if out of memory
974  */
975 static struct oonf_rfc5444_target *
976 _create_target(struct oonf_rfc5444_interface *interf, struct netaddr *dst, bool unicast) {
977   static struct oonf_rfc5444_target *target;
978   uint16_t rnd;
979
980   if (os_core_get_random(&rnd, sizeof(rnd))) {
981     OONF_WARN(LOG_RFC5444, "Could not get random data");
982     return NULL;
983   }
984
985   target = oonf_class_malloc(&_target_memcookie);
986   if (target == NULL) {
987     return NULL;
988   }
989
990   /* initialize rfc5444 interfaces */
991   target->rfc5444_target.packet_buffer = target->_packet_buffer;
992   target->rfc5444_target.packet_size = RFC5444_MAX_PACKET_SIZE;
993   target->rfc5444_target.addPacketHeader = _cb_add_seqno;
994   if (unicast) {
995     target->rfc5444_target.sendPacket = _cb_send_unicast_packet;
996   }
997   else {
998     target->rfc5444_target.sendPacket = _cb_send_multicast_packet;
999   }
1000   rfc5444_writer_register_target(&interf->protocol->writer, &target->rfc5444_target);
1001
1002   /* copy socket description */
1003   memcpy(&target->dst, dst, sizeof(target->dst));
1004
1005   /* set interface reference */
1006   target->interface = interf;
1007
1008   /* aggregation timer */
1009   target->_aggregation.class = &_aggregation_timer;
1010
1011   target->_refcount = 1;
1012
1013   /* initialize pktseqno */
1014   target->_pktseqno = rnd;
1015
1016   return target;
1017 }
1018
1019 /**
1020  * Destroy a target and free its resources
1021  * @param target pointer to rfc5444 target
1022  */
1023 static void
1024 _destroy_target(struct oonf_rfc5444_target *target) {
1025   /* cleanup interface */
1026   rfc5444_writer_unregister_target(&target->interface->protocol->writer, &target->rfc5444_target);
1027
1028   /* stop timer */
1029   oonf_timer_stop(&target->_aggregation);
1030
1031   /* free memory */
1032   oonf_class_free(&_target_memcookie, target);
1033 }
1034
1035 /**
1036  * Print a rfc5444 packet to the logging system
1037  * @param sock socket the packet is reffering to
1038  * @param interf pointer to rfc5444 interface
1039  * @param ptr pointer to packet
1040  * @param len length of packet
1041  * @param success text prefix for successful printing
1042  * @param error text prefix when error happens during packet parsing
1043  */
1044 static void
1045 _print_packet_to_buffer(enum oonf_log_source source, union netaddr_socket *sock __attribute__((unused)),
1046   struct oonf_rfc5444_interface *interf __attribute__((unused)), const uint8_t *ptr, size_t len,
1047   const char *success __attribute__((unused)), const char *error __attribute__((unused))) {
1048   enum rfc5444_result result;
1049   struct netaddr_str buf;
1050
1051   if (oonf_log_mask_test(log_global_mask, source, LOG_SEVERITY_DEBUG)) {
1052     abuf_clear(&_printer_buffer);
1053     abuf_hexdump(&_printer_buffer, "", ptr, len);
1054
1055     result = rfc5444_reader_handle_packet(&_printer, ptr, len);
1056     if (result) {
1057       OONF_WARN(source, "%s %s for printing: %s (%d)", error, netaddr_socket_to_string(&buf, sock),
1058         rfc5444_strerror(result), result);
1059       OONF_WARN(source, "packet: %s", abuf_getptr(&_printer_buffer));
1060     }
1061     else {
1062       OONF_DEBUG(source, "%s %s through %s:", success, netaddr_socket_to_string(&buf, sock), interf->name);
1063       OONF_DEBUG(source, "packet: %s", abuf_getptr(&_printer_buffer));
1064     }
1065   }
1066 }
1067
1068 /**
1069  * Handle incoming packet from a socket
1070  * @param sock pointer to packet socket
1071  * @param from originator of incoming packet
1072  * @param length length of incoming packet
1073  */
1074 static void
1075 _cb_receive_data(struct oonf_packet_socket *sock, union netaddr_socket *from, void *ptr, size_t length) {
1076   struct oonf_rfc5444_protocol *protocol;
1077   struct oonf_rfc5444_interface *interf;
1078   enum rfc5444_result result;
1079   struct netaddr source_ip;
1080   struct netaddr_str buf;
1081
1082   interf = sock->config.user;
1083   protocol = interf->protocol;
1084
1085   if (netaddr_from_socket(&source_ip, from)) {
1086     OONF_WARN(LOG_RFC5444, "Could not convert socket to address: %s", netaddr_socket_to_string(&buf, from));
1087     return;
1088   }
1089
1090   protocol->input.src_socket = from;
1091   protocol->input.src_address = &source_ip;
1092   protocol->input.interface = interf;
1093
1094   protocol->input.is_multicast = sock == &interf->_socket.multicast_v4 || sock == &interf->_socket.multicast_v6;
1095
1096   if (strcmp(interf->name, RFC5444_UNICAST_INTERFACE) == 0 &&
1097       (netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, &source_ip) ||
1098         netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &source_ip))) {
1099     OONF_DEBUG(LOG_RFC5444, "Ignore linklocal traffic on generic unicast interface");
1100     return;
1101   }
1102
1103   _print_packet_to_buffer(LOG_RFC5444_R, from, interf, ptr, length, "Incoming RFC5444 packet from",
1104     "Error while parsing incoming RFC5444 packet from");
1105
1106   result = rfc5444_reader_handle_packet(&protocol->reader, ptr, length);
1107   if (result < 0) {
1108     OONF_WARN(LOG_RFC5444, "Error while parsing incoming packet from %s: %s (%d)", netaddr_socket_to_string(&buf, from),
1109       rfc5444_strerror(result), result);
1110     OONF_WARN_HEX(LOG_RFC5444, ptr, length, "%s", abuf_getptr(&_printer_buffer));
1111   }
1112 }
1113
1114 /**
1115  * Callback for sending a multicast packet to a rfc5444 target
1116  * @param writer rfc5444 writer
1117  * @param target rfc5444 target
1118  * @param ptr pointer to outgoing buffer
1119  * @param len length of buffer
1120  */
1121 static void
1122 _cb_send_multicast_packet(
1123   struct rfc5444_writer *writer __attribute__((unused)), struct rfc5444_writer_target *target, void *ptr, size_t len) {
1124   struct oonf_rfc5444_target *t;
1125   struct os_interface_listener *if_listener;
1126   union netaddr_socket sock;
1127
1128   t = container_of(target, struct oonf_rfc5444_target, rfc5444_target);
1129
1130   if_listener = oonf_rfc5444_get_core_if_listener(t->interface);
1131   netaddr_socket_init(&sock, &t->dst, t->interface->protocol->port, if_listener->data->index);
1132
1133   _print_packet_to_buffer(LOG_RFC5444_W, &sock, t->interface, ptr, len, "Outgoing RFC5444 packet to",
1134     "Error while parsing outgoing RFC5444 packet to");
1135
1136   if (_block_output) {
1137     OONF_DEBUG(LOG_RFC5444, "Output blocked");
1138     return;
1139   }
1140   oonf_packet_send_managed_multicast(&t->interface->_socket, ptr, len, netaddr_get_address_family(&t->dst));
1141 }
1142
1143 /**
1144  * Callback for sending an unicast packet to a rfc5444 target
1145  * @param writer rfc5444 writer
1146  * @param target rfc5444 target
1147  * @param ptr pointer to outgoing buffer
1148  * @param len length of buffer
1149  */
1150 static void
1151 _cb_send_unicast_packet(
1152   struct rfc5444_writer *writer __attribute__((unused)), struct rfc5444_writer_target *target, void *ptr, size_t len) {
1153   struct oonf_rfc5444_target *t;
1154   union netaddr_socket sock;
1155   struct os_interface_listener *interf;
1156
1157   t = container_of(target, struct oonf_rfc5444_target, rfc5444_target);
1158
1159   interf = oonf_rfc5444_get_core_if_listener(t->interface);
1160   netaddr_socket_init(&sock, &t->dst, t->interface->protocol->port, interf->data->index);
1161
1162   _print_packet_to_buffer(LOG_RFC5444_W, &sock, t->interface, ptr, len, "Outgoing RFC5444 packet to",
1163     "Error while parsing outgoing RFC5444 packet to");
1164
1165   if (_block_output) {
1166     OONF_DEBUG(LOG_RFC5444, "Output blocked");
1167     return;
1168   }
1169
1170   oonf_packet_send_managed(&t->interface->_socket, &sock, ptr, len);
1171 }
1172
1173 /**
1174  * Handle forwarding of rfc5444 messages
1175  * @param context RFC5444 tlvblock reader context
1176  * @param buffer message to be forwarded
1177  * @param length length of message
1178  */
1179 static void
1180 _cb_forward_message(struct rfc5444_reader_tlvblock_context *context, const uint8_t *buffer, size_t length) {
1181   struct oonf_rfc5444_protocol *protocol;
1182   enum rfc5444_result result;
1183
1184   /* get protocol to use for forwarding message */
1185   protocol = container_of(context->reader, struct oonf_rfc5444_protocol, reader);
1186
1187   /* forward message */
1188   OONF_INFO(LOG_RFC5444, "Forwarding message type %u", context->msg_type);
1189
1190   result = rfc5444_writer_forward_msg(&protocol->writer, context, buffer, length);
1191   if (result != RFC5444_OKAY && result != RFC5444_NO_MSGCREATOR) {
1192     OONF_WARN(LOG_RFC5444, "Error while forwarding message: %s (%d)", rfc5444_strerror(result), result);
1193   }
1194 }
1195
1196 static void
1197 _cb_msggen_notifier(struct rfc5444_writer_target *rfc5444target) {
1198   struct oonf_rfc5444_target *target;
1199   uint64_t interval;
1200
1201   target = container_of(rfc5444target, struct oonf_rfc5444_target, rfc5444_target);
1202   if (!oonf_timer_is_active(&target->_aggregation)) {
1203     interval = target->interface->overwrite_aggregation_interval;
1204     if (!interval) {
1205       interval = target->interface->aggregation_interval;
1206     }
1207
1208     /* activate aggregation timer */
1209     oonf_timer_start(&target->_aggregation, target->interface->aggregation_interval);
1210   }
1211 }
1212
1213 /**
1214  * Selector for outgoing target
1215  * @param writer rfc5444 writer
1216  * @param target rfc5444 target
1217  * @param ptr custom pointer, contains rfc5444 target
1218  * @return true if target corresponds to selection
1219  */
1220 static bool
1221 _cb_single_target_selector(
1222   struct rfc5444_writer *writer __attribute__((unused)), struct rfc5444_writer_target *target, void *ptr) {
1223   struct oonf_rfc5444_target *t = ptr;
1224
1225   return &t->rfc5444_target == target;
1226 }
1227
1228 /**
1229  * Selector for outgoing target
1230  * @param writer rfc5444 writer
1231  * @param rfc5444_target rfc5444 target
1232  * @param ptr custom pointer, contains rfc5444 target
1233  * @return true if target corresponds to selection
1234  */
1235 static bool
1236 _cb_filtered_targets_selector(struct rfc5444_writer *writer, struct rfc5444_writer_target *rfc5444_target, void *ptr) {
1237   rfc5444_writer_targetselector userUseIf;
1238   struct oonf_rfc5444_target *target;
1239 #ifdef OONF_LOG_INFO
1240   struct netaddr_str buf;
1241 #endif
1242
1243   userUseIf = ptr;
1244   target = container_of(rfc5444_target, struct oonf_rfc5444_target, rfc5444_target);
1245
1246   /* check if socket can send data */
1247   if (!oonf_rfc5444_is_target_active(target)) {
1248     return false;
1249   }
1250
1251   /* check if user deselected the target */
1252   if (!userUseIf(writer, rfc5444_target, NULL)) {
1253     return false;
1254   }
1255
1256   /* create message */
1257   OONF_INFO(LOG_RFC5444, "Send message to protocol %s/target %s on interface %s", target->interface->protocol->name,
1258     netaddr_to_string(&buf, &target->dst), target->interface->name);
1259
1260   return true;
1261 }
1262
1263 /**
1264  * Internal memory allocation function for addrblock
1265  * @return pointer to cleared addrblock
1266  */
1267 static struct rfc5444_reader_addrblock_entry *
1268 _alloc_addrblock_entry(void) {
1269   return oonf_class_malloc(&_addrblock_memcookie);
1270 }
1271
1272 /**
1273  * Internal memory allocation function for rfc5444_reader_tlvblock_entry
1274  * @return pointer to cleared rfc5444_reader_tlvblock_entry
1275  */
1276 static struct rfc5444_reader_tlvblock_entry *
1277 _alloc_tlvblock_entry(void) {
1278   return oonf_class_malloc(&_tlvblock_memcookie);
1279 }
1280
1281 /**
1282  * Internal memory allocation function for rfc5444_writer_address
1283  * @return pointer to cleared rfc5444_writer_address
1284  */
1285 static struct rfc5444_writer_address *
1286 _alloc_address_entry(void) {
1287   return oonf_class_malloc(&_address_memcookie);
1288 }
1289
1290 /**
1291  * Internal memory allocation function for rfc5444_writer_addrtlv
1292  * @return pointer to cleared rfc5444_writer_addrtlv
1293  */
1294 static struct rfc5444_writer_addrtlv *
1295 _alloc_addrtlv_entry(void) {
1296   return oonf_class_malloc(&_addrtlv_memcookie);
1297 }
1298
1299 /**
1300  * Free an addrblock entry
1301  * @param addrblock addressblock to be freed
1302  */
1303 static void
1304 _free_addrblock_entry(struct rfc5444_reader_addrblock_entry *addrblock) {
1305   oonf_class_free(&_addrblock_memcookie, addrblock);
1306 }
1307
1308 /**
1309  * Free a tlvblock entry
1310  * @param tlvblock tlvblock to be freed
1311  */
1312 static void
1313 _free_tlvblock_entry(struct rfc5444_reader_tlvblock_entry *tlvblock) {
1314   oonf_class_free(&_tlvblock_memcookie, tlvblock);
1315 }
1316
1317 /**
1318  * Free an address
1319  * @param address address to be freed
1320  */
1321 static void
1322 _free_address_entry(struct rfc5444_writer_address *address) {
1323   oonf_class_free(&_address_memcookie, address);
1324 }
1325
1326 /**
1327  * Free an address tlv entry
1328  * @param addrtlv address tlv entry to be freed
1329  */
1330 static void
1331 _free_addrtlv_entry(struct rfc5444_writer_addrtlv *addrtlv) {
1332   oonf_class_free(&_addrtlv_memcookie, addrtlv);
1333 }
1334
1335 /**
1336  * Callback to add sequence number to outgoing RFC5444 packet
1337  * @param writer pointer to rfc5444 writer
1338  * @param rfc5444_target rfc5444 target where the packet will be sent to
1339  */
1340 static void
1341 _cb_add_seqno(struct rfc5444_writer *writer, struct rfc5444_writer_target *rfc5444_target) {
1342   struct oonf_rfc5444_target *target;
1343   bool seqno;
1344
1345   target = container_of(rfc5444_target, struct oonf_rfc5444_target, rfc5444_target);
1346
1347   seqno = target->_pktseqno_refcount > 0 || target->interface->protocol->_pktseqno_refcount > 0;
1348
1349   rfc5444_writer_set_pkt_header(writer, rfc5444_target, seqno);
1350   if (seqno) {
1351     target->_pktseqno++;
1352     rfc5444_writer_set_pkt_seqno(writer, rfc5444_target, target->_pktseqno);
1353   }
1354 }
1355
1356 /**
1357  * Timer callback for message aggregation
1358  * @param ptr timer instance that fired
1359  */
1360 static void
1361 _cb_aggregation_event(struct oonf_timer_instance *ptr) {
1362   struct oonf_rfc5444_target *target;
1363
1364   target = container_of(ptr, struct oonf_rfc5444_target, _aggregation);
1365
1366   rfc5444_writer_flush(&target->interface->protocol->writer, &target->rfc5444_target, false);
1367 }
1368
1369 /**
1370  * Configuration has changed, handle the changes
1371  */
1372 static void
1373 _cb_cfg_rfc5444_changed(void) {
1374   struct _rfc5444_config config;
1375   int result;
1376
1377   memset(&config, 0, sizeof(config));
1378   result = cfg_schema_tobin(&config, _rfc5444_section.post, _rfc5444_entries, ARRAYSIZE(_rfc5444_entries));
1379   if (result) {
1380     OONF_WARN(LOG_RFC5444, "Could not convert " CFG_RFC5444_SECTION " to binary (%d)", -(result + 1));
1381     return;
1382   }
1383
1384   /* apply values */
1385   oonf_rfc5444_reconfigure_protocol(_rfc5444_protocol, config.port, config.ip_proto);
1386 }
1387
1388 /**
1389  * Configuration has changed, handle the changes
1390  */
1391 static void
1392 _cb_cfg_interface_changed(void) {
1393   struct _rfc5444_if_config config;
1394   struct oonf_rfc5444_interface *interf;
1395   const char *ifname;
1396   char ifbuf[IF_NAMESIZE];
1397   int result;
1398
1399   ifname = cfg_get_phy_if(ifbuf, _interface_section.section_name);
1400
1401   interf = avl_find_element(&_rfc5444_protocol->_interface_tree, ifname, interf, _node);
1402
1403   if (_interface_section.post == NULL) {
1404     /* this section has been removed */
1405     if (interf) {
1406       oonf_rfc5444_remove_interface(interf, NULL);
1407     }
1408     goto interface_changed_cleanup;
1409   }
1410
1411   memset(&config, 0, sizeof(config));
1412   result = cfg_schema_tobin(&config, _interface_section.post, _interface_entries, ARRAYSIZE(_interface_entries));
1413   if (result) {
1414     OONF_WARN(LOG_RFC5444, "Could not convert %s '%s' to binary (%d)", _interface_section.type, ifname, -(result + 1));
1415     goto interface_changed_cleanup;
1416   }
1417
1418   if (_interface_section.pre == NULL) {
1419     interf = oonf_rfc5444_add_interface(_rfc5444_protocol, NULL, ifname);
1420     if (interf == NULL) {
1421       OONF_WARN(LOG_RFC5444, "Could not generate interface '%s' for protocol '%s'", ifname, _rfc5444_protocol->name);
1422       goto interface_changed_cleanup;
1423     }
1424   }
1425
1426   oonf_rfc5444_reconfigure_interface(interf, &config.sock);
1427   interf->aggregation_interval = config.aggregation_interval;
1428
1429   /* fall through */
1430 interface_changed_cleanup:
1431   oonf_packet_free_managed_config(&config.sock);
1432 }
1433
1434 /**
1435  * Interface settings of a rfc5444 interface changed
1436  * @param managed managed socket which interface changed
1437  * @param changed true if socket addresses changed
1438  */
1439 static void
1440 _cb_interface_changed(struct oonf_packet_managed *managed, bool changed) {
1441   struct oonf_rfc5444_interface *interf;
1442   struct oonf_rfc5444_interface_listener *l;
1443
1444   OONF_INFO(LOG_RFC5444, "RFC5444 Interface change event: %s", managed->_managed_config.interface);
1445
1446   interf = container_of(managed, struct oonf_rfc5444_interface, _socket);
1447
1448   if (changed) {
1449     oonf_rfc5444_reconfigure_interface(interf, NULL);
1450   }
1451
1452   list_for_each_element(&interf->_listener, l, _node) {
1453     l->cb_interface_changed(l, changed);
1454   }
1455 }