Keep statistics of logged warnings
[oonf.git] / src-plugins / olsrv2 / olsrv2 / olsrv2_writer.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 "common/avl.h"
47 #include "common/common_types.h"
48 #include "common/list.h"
49 #include "common/netaddr.h"
50 #include "core/oonf_logging.h"
51 #include "subsystems/oonf_class.h"
52 #include "subsystems/oonf_rfc5444.h"
53
54 #include "nhdp/nhdp_interfaces.h"
55 #include "nhdp/nhdp_db.h"
56 #include "nhdp/nhdp_domain.h"
57
58 #include "olsrv2/olsrv2.h"
59 #include "olsrv2/olsrv2_internal.h"
60 #include "olsrv2/olsrv2_lan.h"
61 #include "olsrv2/olsrv2_originator.h"
62 #include "olsrv2/olsrv2_writer.h"
63
64 /* constants */
65
66 /**
67  * olsrv2 index values for address tlvs
68  */
69 enum olsrv2_addrtlv_idx {
70   /*! index of neighbor address tlv */
71   IDX_ADDRTLV_NBR_ADDR_TYPE,
72
73   /*! index of destination specific gateway tlv */
74   IDX_ADDRTLV_GATEWAY_DSTSPEC,
75
76   /*! index of source specific gateway tlv */
77   IDX_ADDRTLV_GATEWAY_SRCSPEC,
78
79   /*! index of source specific default gateway tlv */
80   IDX_ADDRTLV_GATEWAY_SRCSPEC_DEF,
81
82   /*! index of source prefix tlv */
83   IDX_ADDRTLV_GATEWAY_SRC_PREFIX,
84 };
85
86 /* Prototypes */
87 static void _send_tc(int af_type);
88 #if 0
89 static bool _cb_tc_interface_selector(struct rfc5444_writer *,
90     struct rfc5444_writer_target *rfc5444_target, void *ptr);
91 #endif
92
93 static int _cb_addMessageHeader(
94     struct rfc5444_writer *, struct rfc5444_writer_message *);
95 static void _cb_finishMessageHeader(struct rfc5444_writer *, struct rfc5444_writer_message *,
96     struct rfc5444_writer_address *, struct rfc5444_writer_address *, bool);
97
98 static void _cb_addMessageTLVs(struct rfc5444_writer *);
99 static void _cb_addAddresses(struct rfc5444_writer *);
100 static void _cb_finishMessageTLVs(struct rfc5444_writer *,
101   struct rfc5444_writer_address *start,
102   struct rfc5444_writer_address *end, bool complete);
103
104 /* definition of NHDP writer */
105 static struct rfc5444_writer_message *_olsrv2_message = NULL;
106
107 static struct rfc5444_writer_content_provider _olsrv2_msgcontent_provider = {
108   .msg_type = RFC7181_MSGTYPE_TC,
109   .addMessageTLVs = _cb_addMessageTLVs,
110   .addAddresses = _cb_addAddresses,
111   .finishMessageTLVs = _cb_finishMessageTLVs,
112 };
113
114 static struct rfc5444_writer_tlvtype _olsrv2_addrtlvs[] = {
115   [IDX_ADDRTLV_NBR_ADDR_TYPE]       = { .type = RFC7181_ADDRTLV_NBR_ADDR_TYPE },
116   [IDX_ADDRTLV_GATEWAY_DSTSPEC]     = {
117       .type = RFC7181_ADDRTLV_GATEWAY, .exttype = RFC7181_DSTSPEC_GATEWAY },
118   [IDX_ADDRTLV_GATEWAY_SRCSPEC]     = {
119       .type = RFC7181_ADDRTLV_GATEWAY, .exttype = RFC7181_SRCSPEC_GATEWAY },
120   [IDX_ADDRTLV_GATEWAY_SRCSPEC_DEF] = {
121       .type = RFC7181_ADDRTLV_GATEWAY, .exttype = RFC7181_SRCSPEC_DEF_GATEWAY },
122   [IDX_ADDRTLV_GATEWAY_SRC_PREFIX] = {
123       .type = SRCSPEC_GW_ADDRTLV_SRC_PREFIX },
124 };
125
126 static struct oonf_rfc5444_protocol *_protocol;
127
128 static bool _cleanedup = false;
129 static size_t _mprtypes_size;
130
131 /**
132  * initialize olsrv2 writer
133  * @param protocol rfc5444 protocol
134  * @return -1 if an error happened, 0 otherwise
135  */
136 int
137 olsrv2_writer_init(struct oonf_rfc5444_protocol *protocol) {
138   _protocol = protocol;
139
140   _olsrv2_message = rfc5444_writer_register_message(
141       &_protocol->writer, RFC7181_MSGTYPE_TC, false);
142   if (_olsrv2_message == NULL) {
143     OONF_WARN(LOG_OLSRV2, "Could not register OLSRV2 TC message");
144     return -1;
145   }
146
147   _olsrv2_message->addMessageHeader = _cb_addMessageHeader;
148   _olsrv2_message->finishMessageHeader = _cb_finishMessageHeader;
149   _olsrv2_message->forward_target_selector = nhdp_forwarding_selector;
150
151   if (rfc5444_writer_register_msgcontentprovider(
152       &_protocol->writer, &_olsrv2_msgcontent_provider,
153       _olsrv2_addrtlvs, ARRAYSIZE(_olsrv2_addrtlvs))) {
154
155     OONF_WARN(LOG_OLSRV2, "Count not register OLSRV2 msg contentprovider");
156     rfc5444_writer_unregister_message(&_protocol->writer, _olsrv2_message);
157     return -1;
158   }
159
160   return 0;
161 }
162
163 /**
164  * Cleanup olsrv2 writer
165  */
166 void
167 olsrv2_writer_cleanup(void) {
168   _cleanedup = true;
169
170   /* remove pbb writer */
171   rfc5444_writer_unregister_content_provider(
172       &_protocol->writer, &_olsrv2_msgcontent_provider,
173       _olsrv2_addrtlvs, ARRAYSIZE(_olsrv2_addrtlvs));
174   rfc5444_writer_unregister_message(&_protocol->writer, _olsrv2_message);
175 }
176
177 /**
178  * Send a new TC message over all relevant interfaces
179  */
180 void
181 olsrv2_writer_send_tc(void) {
182   if (_cleanedup) {
183     /* do not send more TCs during shutdown */
184     return;
185   }
186
187   _send_tc(AF_INET);
188   _send_tc(AF_INET6);
189 }
190
191 /**
192  * Set a new forwarding selector for OLSRv2 TC messages
193  * @param forward_target_selector pointer to forwarding selector
194  *   callback, NULL for NHDP dualstack forwarding selector
195  */
196 void
197 olsrv2_writer_set_forwarding_selector(
198     bool (*forward_target_selector)(struct rfc5444_writer_target *,
199       struct rfc5444_reader_tlvblock_context *context)) {
200   if (forward_target_selector) {
201     _olsrv2_message->forward_target_selector = forward_target_selector;
202   }
203   else {
204     _olsrv2_message->forward_target_selector = nhdp_forwarding_selector;
205   }
206 }
207
208 /**
209  * Send a TC for a specified address family if the originator is set
210  * @param af_type address family type
211  */
212 static void
213 _send_tc(int af_type) {
214   const struct netaddr *originator;
215
216   originator = olsrv2_originator_get(af_type);
217   if (netaddr_get_address_family(originator) == af_type) {
218     OONF_INFO(LOG_OLSRV2_W, "Emit IPv%d TC message.", af_type == AF_INET ? 4 : 6);
219     oonf_rfc5444_send_all(_protocol, RFC7181_MSGTYPE_TC,
220         af_type == AF_INET ? 4 : 16, nhdp_flooding_selector);
221   }
222 }
223
224 /**
225  * Callback for rfc5444 writer to add message header for tc
226  * @param writer
227  * @param message
228  */
229 static int
230 _cb_addMessageHeader(struct rfc5444_writer *writer,
231     struct rfc5444_writer_message *message) {
232   const struct netaddr *orig;
233
234   if (writer->msg_addr_len == 4) {
235     orig = olsrv2_originator_get(AF_INET);
236   }
237   else {
238     orig = olsrv2_originator_get(AF_INET6);
239   }
240
241   /* initialize message header */
242   rfc5444_writer_set_msg_header(writer, message, true, true, true, true);
243   rfc5444_writer_set_msg_originator(writer, message, netaddr_get_binptr(orig));
244   rfc5444_writer_set_msg_hopcount(writer, message, 0);
245   rfc5444_writer_set_msg_hoplimit(writer, message, 255);
246
247   OONF_DEBUG(LOG_OLSRV2_W, "Generate TC");
248   return RFC5444_OKAY;
249 }
250
251 static void
252 _cb_finishMessageHeader(struct rfc5444_writer *writer,
253     struct rfc5444_writer_message *message,
254     struct rfc5444_writer_address *first __attribute__((unused)),
255     struct rfc5444_writer_address *last __attribute__((unused)),
256     bool fragented __attribute__((unused))) {
257   uint16_t seqno;
258
259   seqno = oonf_rfc5444_get_next_message_seqno(_protocol);
260   OONF_DEBUG(LOG_OLSRV2_W, "Set message sequence number to %u", seqno);
261   rfc5444_writer_set_msg_seqno(writer, message, seqno);
262 }
263
264 /**
265  * Callback for rfc5444 writer to add message tlvs to tc
266  * @param writer
267  */
268 static void
269 _cb_addMessageTLVs(struct rfc5444_writer *writer) {
270   uint8_t vtime_encoded, itime_encoded;
271   uint8_t mprtypes[NHDP_MAXIMUM_DOMAINS];
272
273   /* generate validity time and interval time */
274   itime_encoded = rfc5497_timetlv_encode(olsrv2_get_tc_interval());
275   vtime_encoded = rfc5497_timetlv_encode(olsrv2_get_tc_validity());
276
277   /* allocate space for ANSN tlv */
278   rfc5444_writer_allocate_messagetlv(writer, true, 2);
279
280   /* add validity and interval time TLV */
281   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_VALIDITY_TIME, 0,
282       &vtime_encoded, sizeof(vtime_encoded));
283   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_INTERVAL_TIME, 0,
284       &itime_encoded, sizeof(itime_encoded));
285
286   /* generate mprtypes */
287   _mprtypes_size = 0;
288   if (nhdp_domain_get_count() > 1) {
289     _mprtypes_size = nhdp_domain_encode_mprtypes_tlvvalue(mprtypes, sizeof(mprtypes));
290
291     rfc5444_writer_add_messagetlv(writer,
292         DRAFT_MT_MSGTLV_MPR_TYPES, DRAFT_MT_MSGTLV_MPR_TYPES_EXT,
293         mprtypes, _mprtypes_size);
294   }
295
296   /* generate source-specific routing flag */
297   if (os_routing_supports_source_specific(
298       writer->msg_addr_len == 16 ? AF_INET6 : AF_INET)) {
299     rfc5444_writer_add_messagetlv(writer,
300         DRAFT_SSR_MSGTLV_CAPABILITY, DRAFT_SSR_MSGTLV_CAPABILITY_EXT,
301         NULL, 0);
302   }
303 }
304
305 static void
306 _generate_neighbor_metric_tlvs(struct rfc5444_writer *writer,
307     struct rfc5444_writer_address *addr, struct nhdp_neighbor *neigh) {
308   struct nhdp_neighbor_domaindata *neigh_domain;
309   struct nhdp_domain *domain;
310   uint32_t metric_in, metric_out;
311   struct rfc7181_metric_field metric_in_encoded, metric_out_encoded;
312   bool second_tlv;
313
314   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
315     neigh_domain = nhdp_domain_get_neighbordata(domain, neigh);
316
317     /* erase metric values */
318     memset(&metric_in_encoded, 0, sizeof(metric_in_encoded));
319     memset(&metric_out_encoded, 0, sizeof(metric_out_encoded));
320     second_tlv = false;
321
322     if (!nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
323       /* not an MPR, do not mention it in the TC */
324       continue;
325     }
326
327     /* neighbor has selected us as an MPR */
328     OONF_DEBUG(LOG_OLSRV2_W, "Neighbor is chosen by domain %u as MPR", domain->index);
329
330     metric_in = neigh_domain->metric.in;
331     if (metric_in > RFC7181_METRIC_MAX) {
332       /* Metric value does not make sense */
333       continue;
334     }
335     if (rfc7181_metric_encode(&metric_in_encoded, metric_in)) {
336       OONF_DEBUG(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_in);
337       /* invalid incoming metric, do not mention it in the TC */
338       continue;
339     }
340
341     /* set flag for incoming metric */
342     rfc7181_metric_set_flag(&metric_in_encoded, RFC7181_LINKMETRIC_INCOMING_NEIGH);
343
344     metric_out = neigh_domain->metric.out;
345     if (rfc7181_metric_encode(&metric_out_encoded, metric_out)) {
346       OONF_DEBUG(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_in);
347     }
348     else if (memcmp(&metric_in_encoded, &metric_out_encoded, sizeof(metric_in_encoded)) == 0) {
349       /* incoming and outgoing metric are the same */
350       rfc7181_metric_set_flag(&metric_in_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
351     }
352     else if (metric_out <= RFC7181_METRIC_MAX){
353       /* two different link metrics */
354       rfc7181_metric_set_flag(&metric_out_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
355       second_tlv = true;
356     }
357
358     OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x",
359         domain->ext, metric_in_encoded.b[0], metric_in_encoded.b[1]);
360     rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[0],
361         &metric_in_encoded, sizeof(metric_in_encoded), true);
362
363     if (second_tlv) {
364       OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x",
365           domain->ext, metric_out_encoded.b[0], metric_out_encoded.b[1]);
366       rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[1],
367           &metric_out_encoded, sizeof(metric_out_encoded), true);
368     }
369   }
370 }
371
372 /**
373  * Callback for rfc5444 writer to add addresses and addresstlvs to tc
374  * @param writer
375  */
376 static void
377 _cb_addAddresses(struct rfc5444_writer *writer) {
378   struct rfc5444_writer_address *addr;
379   struct nhdp_neighbor *neigh;
380   struct nhdp_naddr *naddr;
381   struct nhdp_domain *domain;
382   struct olsrv2_lan_entry *lan;
383   struct olsrv2_lan_domaindata *lan_data;
384   bool any_advertised;
385   uint8_t nbr_addrtype_value;
386   uint32_t metric_out;
387   struct rfc7181_metric_field metric_out_encoded;
388   uint8_t distance_vector[NHDP_MAXIMUM_DOMAINS];
389   int af_type;
390   enum olsrv2_addrtlv_idx gateway_idx;
391   uint8_t srcprefix[17];
392 #ifdef OONF_LOG_DEBUG_INFO
393   struct netaddr_str nbuf1, nbuf2;
394 #endif
395
396   af_type = writer->msg_addr_len == 4 ? AF_INET : AF_INET6;
397
398   /* iterate over neighbors */
399   list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
400     any_advertised = false;
401
402     if (!neigh->symmetric) {
403       /* do not announce non-symmetric neighbors */
404       continue;
405     }
406
407     /* see if we have been selected as a MPR by this neighbor */
408     list_for_each_element(nhdp_domain_get_list(), domain, _node) {
409       if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
410         /* found one */
411         any_advertised = true;
412         break;
413       }
414     }
415
416     if (!any_advertised) {
417       /* we are not a MPR for this neighbor, so we don't advertise the neighbor */
418       continue;
419     }
420
421     /* iterate over neighbors addresses */
422     avl_for_each_element(&neigh->_neigh_addresses, naddr, _neigh_node) {
423       if (netaddr_get_address_family(&naddr->neigh_addr) != af_type) {
424         /* wrong address family, skip this one */
425         continue;
426       }
427
428       if (!olsrv2_is_nhdp_routable(&naddr->neigh_addr)
429           && netaddr_cmp(&neigh->originator, &naddr->neigh_addr) != 0) {
430         /* do not propagate unroutable addresses in TCs */
431         continue;
432       }
433
434       nbr_addrtype_value = 0;
435
436       if (olsrv2_is_routable(&naddr->neigh_addr)) {
437         nbr_addrtype_value |= RFC7181_NBR_ADDR_TYPE_ROUTABLE;
438       }
439       if (netaddr_cmp(&neigh->originator, &naddr->neigh_addr) == 0) {
440         nbr_addrtype_value |= RFC7181_NBR_ADDR_TYPE_ORIGINATOR;
441       }
442
443       if (nbr_addrtype_value == 0) {
444         /* skip this address */
445         OONF_DEBUG(LOG_OLSRV2_W, "Address %s is neither routable"
446             " nor an originator", netaddr_to_string(&nbuf1, &naddr->neigh_addr));
447         continue;
448       }
449
450       OONF_DEBUG(LOG_OLSRV2_W, "Add address %s to TC",
451           netaddr_to_string(&nbuf1, &naddr->neigh_addr));
452       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
453           &naddr->neigh_addr, false);
454       if (addr == NULL) {
455         OONF_WARN(LOG_OLSRV2_W, "Out of memory error for olsrv2 address");
456         return;
457       }
458
459       /* add neighbor type TLV */
460       OONF_DEBUG(LOG_OLSRV2_W, "Add NBRAddrType TLV with value %u", nbr_addrtype_value);
461       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[IDX_ADDRTLV_NBR_ADDR_TYPE],
462           &nbr_addrtype_value, sizeof(nbr_addrtype_value), false);
463
464       /* add linkmetric TLVs */
465       _generate_neighbor_metric_tlvs(writer, addr, neigh);
466     }
467   }
468
469   /* Iterate over locally attached networks */
470   avl_for_each_element(olsrv2_lan_get_tree(), lan, _node) {
471     if (netaddr_get_address_family(&lan->prefix.dst) != af_type) {
472       /* wrong address family */
473       continue;
474     }
475
476     OONF_DEBUG(LOG_OLSRV2_W, "Add address %s [%s] to TC",
477         netaddr_to_string(&nbuf1, &lan->prefix.dst),
478         netaddr_to_string(&nbuf2, &lan->prefix.src));
479
480     if (netaddr_get_prefix_length(&lan->prefix.dst) > 0
481         || netaddr_get_prefix_length(&lan->prefix.src) == 0) {
482       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
483           &lan->prefix.dst, false);
484
485       if (netaddr_get_prefix_length(&lan->prefix.src) == 0) {
486         gateway_idx = IDX_ADDRTLV_GATEWAY_DSTSPEC;
487       }
488       else {
489         gateway_idx = IDX_ADDRTLV_GATEWAY_SRCSPEC;
490       }
491     }
492     else {
493       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
494           &lan->prefix.src, false);
495       gateway_idx = IDX_ADDRTLV_GATEWAY_SRCSPEC_DEF;
496     }
497     if (addr == NULL) {
498       OONF_WARN(LOG_OLSRV2_W, "Out of memory error for olsrv2 address");
499       return;
500     }
501
502     /* add Gateway TLV and Metric TLV */
503     memset(distance_vector, 0, sizeof(distance_vector));
504
505     list_for_each_element(nhdp_domain_get_list(), domain, _node) {
506       lan_data = olsrv2_lan_get_domaindata(domain, lan);
507       metric_out = lan_data->outgoing_metric;
508       if (metric_out > RFC7181_METRIC_MAX) {
509         /* metric value does not make sense */
510         continue;
511       }
512
513       if (rfc7181_metric_encode(&metric_out_encoded, metric_out)) {
514         OONF_WARN(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_out);
515         continue;
516       }
517       rfc7181_metric_set_flag(&metric_out_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
518
519       /* add Metric TLV */
520       OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x (%u)",
521           domain->ext, metric_out_encoded.b[0], metric_out_encoded.b[1], metric_out);
522       rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[0],
523           &metric_out_encoded, sizeof(metric_out_encoded), false);
524
525       OONF_DEBUG(LOG_OLSRV2_W, "Gateway (ext %u) has hopcount cost %u",
526           domain->ext, lan_data->distance);
527       distance_vector[domain->index] = lan_data->distance;
528     }
529
530     /* add Gateway TLV */
531     if (!lan->same_distance) {
532       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[gateway_idx],
533           distance_vector, _mprtypes_size, false);
534     }
535     else {
536       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[gateway_idx],
537           distance_vector, 1, false);
538     }
539
540     if (gateway_idx == IDX_ADDRTLV_GATEWAY_SRCSPEC) {
541       /* add Src Prefix TLV */
542       srcprefix[0] = netaddr_get_prefix_length(&lan->prefix.src);
543       memcpy(&srcprefix[1], netaddr_get_binptr(&lan->prefix.src),
544           netaddr_get_binlength(&lan->prefix.src));
545
546       rfc5444_writer_add_addrtlv(writer, addr,
547           &_olsrv2_addrtlvs[IDX_ADDRTLV_GATEWAY_SRC_PREFIX],
548           srcprefix, 1 + (netaddr_get_prefix_length(&lan->prefix.src) + 7)/8, false);
549     }
550   }
551 }
552
553 /**
554  * Callback triggered when tc is finished.
555  * @param writer
556  * @param start
557  * @param end
558  * @param complete
559  */
560 static void
561 _cb_finishMessageTLVs(struct rfc5444_writer *writer,
562     struct rfc5444_writer_address *start __attribute__((unused)),
563     struct rfc5444_writer_address *end __attribute__((unused)),
564     bool complete) {
565   uint16_t ansn;
566
567   /* get ANSN */
568   ansn = htons(olsrv2_update_ansn(false));
569
570   rfc5444_writer_set_messagetlv(writer, RFC7181_MSGTLV_CONT_SEQ_NUM,
571       complete ? RFC7181_CONT_SEQ_NUM_COMPLETE : RFC7181_CONT_SEQ_NUM_INCOMPLETE,
572       &ansn, sizeof(ansn));
573 }