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