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       const uint8_t *buffer, size_t len)) {
202   if (forward_target_selector) {
203     _olsrv2_message->forward_target_selector = forward_target_selector;
204   }
205   else {
206     _olsrv2_message->forward_target_selector = nhdp_forwarding_selector;
207   }
208 }
209
210 /**
211  * Send a TC for a specified address family if the originator is set
212  * @param af_type address family type
213  */
214 static void
215 _send_tc(int af_type) {
216   const struct netaddr *originator;
217
218   originator = olsrv2_originator_get(af_type);
219   if (netaddr_get_address_family(originator) == af_type) {
220     OONF_INFO(LOG_OLSRV2_W, "Emit IPv%d TC message.", af_type == AF_INET ? 4 : 6);
221     oonf_rfc5444_send_all(_protocol, RFC7181_MSGTYPE_TC,
222         af_type == AF_INET ? 4 : 16, nhdp_flooding_selector);
223   }
224 }
225
226 /**
227  * Callback for rfc5444 writer to add message header for tc
228  * @param writer
229  * @param message
230  */
231 static int
232 _cb_addMessageHeader(struct rfc5444_writer *writer,
233     struct rfc5444_writer_message *message) {
234   const struct netaddr *orig;
235
236   if (writer->msg_addr_len == 4) {
237     orig = olsrv2_originator_get(AF_INET);
238   }
239   else {
240     orig = olsrv2_originator_get(AF_INET6);
241   }
242
243   /* initialize message header */
244   rfc5444_writer_set_msg_header(writer, message, true, true, true, true);
245   rfc5444_writer_set_msg_originator(writer, message, netaddr_get_binptr(orig));
246   rfc5444_writer_set_msg_hopcount(writer, message, 0);
247   rfc5444_writer_set_msg_hoplimit(writer, message, 255);
248
249   OONF_DEBUG(LOG_OLSRV2_W, "Generate TC");
250   return RFC5444_OKAY;
251 }
252
253 static void
254 _cb_finishMessageHeader(struct rfc5444_writer *writer,
255     struct rfc5444_writer_message *message,
256     struct rfc5444_writer_address *first __attribute__((unused)),
257     struct rfc5444_writer_address *last __attribute__((unused)),
258     bool fragented __attribute__((unused))) {
259   uint16_t seqno;
260
261   seqno = oonf_rfc5444_get_next_message_seqno(_protocol);
262   OONF_DEBUG(LOG_OLSRV2_W, "Set message sequence number to %u", seqno);
263   rfc5444_writer_set_msg_seqno(writer, message, seqno);
264 }
265
266 /**
267  * Callback for rfc5444 writer to add message tlvs to tc
268  * @param writer
269  */
270 static void
271 _cb_addMessageTLVs(struct rfc5444_writer *writer) {
272   uint8_t vtime_encoded, itime_encoded;
273   uint8_t mprtypes[NHDP_MAXIMUM_DOMAINS];
274
275   /* generate validity time and interval time */
276   itime_encoded = rfc5497_timetlv_encode(olsrv2_get_tc_interval());
277   vtime_encoded = rfc5497_timetlv_encode(olsrv2_get_tc_validity());
278
279   /* allocate space for ANSN tlv */
280   rfc5444_writer_allocate_messagetlv(writer, true, 2);
281
282   /* add validity and interval time TLV */
283   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_VALIDITY_TIME, 0,
284       &vtime_encoded, sizeof(vtime_encoded));
285   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_INTERVAL_TIME, 0,
286       &itime_encoded, sizeof(itime_encoded));
287
288   /* generate mprtypes */
289   _mprtypes_size = 0;
290   if (nhdp_domain_get_count() > 1) {
291     _mprtypes_size = nhdp_domain_encode_mprtypes_tlvvalue(mprtypes, sizeof(mprtypes));
292
293     rfc5444_writer_add_messagetlv(writer,
294         DRAFT_MT_MSGTLV_MPR_TYPES, DRAFT_MT_MSGTLV_MPR_TYPES_EXT,
295         mprtypes, _mprtypes_size);
296   }
297
298   /* generate source-specific routing flag */
299   if (os_routing_supports_source_specific(
300       writer->msg_addr_len == 16 ? AF_INET6 : AF_INET)) {
301     rfc5444_writer_add_messagetlv(writer,
302         DRAFT_SSR_MSGTLV_CAPABILITY, DRAFT_SSR_MSGTLV_CAPABILITY_EXT,
303         NULL, 0);
304   }
305 }
306
307 static void
308 _generate_neighbor_metric_tlvs(struct rfc5444_writer *writer,
309     struct rfc5444_writer_address *addr, struct nhdp_neighbor *neigh) {
310   struct nhdp_neighbor_domaindata *neigh_domain;
311   struct nhdp_domain *domain;
312   uint32_t metric_in, metric_out;
313   struct rfc7181_metric_field metric_in_encoded, metric_out_encoded;
314   bool second_tlv;
315
316   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
317     neigh_domain = nhdp_domain_get_neighbordata(domain, neigh);
318
319     /* erase metric values */
320     memset(&metric_in_encoded, 0, sizeof(metric_in_encoded));
321     memset(&metric_out_encoded, 0, sizeof(metric_out_encoded));
322     second_tlv = false;
323
324     if (!nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
325       /* not an MPR, do not mention it in the TC */
326       continue;
327     }
328
329     /* neighbor has selected us as an MPR */
330     OONF_DEBUG(LOG_OLSRV2_W, "Neighbor is chosen by domain %u as MPR", domain->index);
331
332     metric_in = neigh_domain->metric.in;
333     if (metric_in > RFC7181_METRIC_MAX) {
334       /* Metric value does not make sense */
335       continue;
336     }
337     if (rfc7181_metric_encode(&metric_in_encoded, metric_in)) {
338       OONF_DEBUG(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_in);
339       /* invalid incoming metric, do not mention it in the TC */
340       continue;
341     }
342
343     /* set flag for incoming metric */
344     rfc7181_metric_set_flag(&metric_in_encoded, RFC7181_LINKMETRIC_INCOMING_NEIGH);
345
346     metric_out = neigh_domain->metric.out;
347     if (rfc7181_metric_encode(&metric_out_encoded, metric_out)) {
348       OONF_DEBUG(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_in);
349     }
350     else if (memcmp(&metric_in_encoded, &metric_out_encoded, sizeof(metric_in_encoded)) == 0) {
351       /* incoming and outgoing metric are the same */
352       rfc7181_metric_set_flag(&metric_in_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
353     }
354     else if (metric_out <= RFC7181_METRIC_MAX){
355       /* two different link metrics */
356       rfc7181_metric_set_flag(&metric_out_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
357       second_tlv = true;
358     }
359
360     OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x",
361         domain->ext, metric_in_encoded.b[0], metric_in_encoded.b[1]);
362     rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[0],
363         &metric_in_encoded, sizeof(metric_in_encoded), true);
364
365     if (second_tlv) {
366       OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x",
367           domain->ext, metric_out_encoded.b[0], metric_out_encoded.b[1]);
368       rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[1],
369           &metric_out_encoded, sizeof(metric_out_encoded), true);
370     }
371   }
372 }
373
374 /**
375  * Callback for rfc5444 writer to add addresses and addresstlvs to tc
376  * @param writer
377  */
378 static void
379 _cb_addAddresses(struct rfc5444_writer *writer) {
380   struct rfc5444_writer_address *addr;
381   struct nhdp_neighbor *neigh;
382   struct nhdp_naddr *naddr;
383   struct nhdp_domain *domain;
384   struct olsrv2_lan_entry *lan;
385   struct olsrv2_lan_domaindata *lan_data;
386   bool any_advertised;
387   uint8_t nbr_addrtype_value;
388   uint32_t metric_out;
389   struct rfc7181_metric_field metric_out_encoded;
390   uint8_t distance_vector[NHDP_MAXIMUM_DOMAINS];
391   int af_type;
392   enum olsrv2_addrtlv_idx gateway_idx;
393   uint8_t srcprefix[17];
394 #ifdef OONF_LOG_DEBUG_INFO
395   struct netaddr_str nbuf1, nbuf2;
396 #endif
397
398   af_type = writer->msg_addr_len == 4 ? AF_INET : AF_INET6;
399
400   /* iterate over neighbors */
401   list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
402     any_advertised = false;
403
404     if (!neigh->symmetric) {
405       /* do not announce non-symmetric neighbors */
406       continue;
407     }
408
409     /* see if we have been selected as a MPR by this neighbor */
410     list_for_each_element(nhdp_domain_get_list(), domain, _node) {
411       if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
412         /* found one */
413         any_advertised = true;
414         break;
415       }
416     }
417
418     if (!any_advertised) {
419       /* we are not a MPR for this neighbor, so we don't advertise the neighbor */
420       continue;
421     }
422
423     /* iterate over neighbors addresses */
424     avl_for_each_element(&neigh->_neigh_addresses, naddr, _neigh_node) {
425       if (netaddr_get_address_family(&naddr->neigh_addr) != af_type) {
426         /* wrong address family, skip this one */
427         continue;
428       }
429
430       if (!olsrv2_is_nhdp_routable(&naddr->neigh_addr)
431           && netaddr_cmp(&neigh->originator, &naddr->neigh_addr) != 0) {
432         /* do not propagate unroutable addresses in TCs */
433         continue;
434       }
435
436       nbr_addrtype_value = 0;
437
438       if (olsrv2_is_routable(&naddr->neigh_addr)) {
439         nbr_addrtype_value |= RFC7181_NBR_ADDR_TYPE_ROUTABLE;
440       }
441       if (netaddr_cmp(&neigh->originator, &naddr->neigh_addr) == 0) {
442         nbr_addrtype_value |= RFC7181_NBR_ADDR_TYPE_ORIGINATOR;
443       }
444
445       if (nbr_addrtype_value == 0) {
446         /* skip this address */
447         OONF_DEBUG(LOG_OLSRV2_W, "Address %s is neither routable"
448             " nor an originator", netaddr_to_string(&nbuf1, &naddr->neigh_addr));
449         continue;
450       }
451
452       OONF_DEBUG(LOG_OLSRV2_W, "Add address %s to TC",
453           netaddr_to_string(&nbuf1, &naddr->neigh_addr));
454       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
455           &naddr->neigh_addr, false);
456       if (addr == NULL) {
457         OONF_WARN(LOG_OLSRV2_W, "Out of memory error for olsrv2 address");
458         return;
459       }
460
461       /* add neighbor type TLV */
462       OONF_DEBUG(LOG_OLSRV2_W, "Add NBRAddrType TLV with value %u", nbr_addrtype_value);
463       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[IDX_ADDRTLV_NBR_ADDR_TYPE],
464           &nbr_addrtype_value, sizeof(nbr_addrtype_value), false);
465
466       /* add linkmetric TLVs */
467       _generate_neighbor_metric_tlvs(writer, addr, neigh);
468     }
469   }
470
471   /* Iterate over locally attached networks */
472   avl_for_each_element(olsrv2_lan_get_tree(), lan, _node) {
473     if (netaddr_get_address_family(&lan->prefix.dst) != af_type) {
474       /* wrong address family */
475       continue;
476     }
477
478     OONF_DEBUG(LOG_OLSRV2_W, "Add address %s [%s] to TC",
479         netaddr_to_string(&nbuf1, &lan->prefix.dst),
480         netaddr_to_string(&nbuf2, &lan->prefix.src));
481
482     if (netaddr_get_prefix_length(&lan->prefix.dst) > 0
483         || netaddr_get_prefix_length(&lan->prefix.src) == 0) {
484       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
485           &lan->prefix.dst, false);
486
487       if (netaddr_get_prefix_length(&lan->prefix.src) == 0) {
488         gateway_idx = IDX_ADDRTLV_GATEWAY_DSTSPEC;
489       }
490       else {
491         gateway_idx = IDX_ADDRTLV_GATEWAY_SRCSPEC;
492       }
493     }
494     else {
495       addr = rfc5444_writer_add_address(writer, _olsrv2_msgcontent_provider.creator,
496           &lan->prefix.src, false);
497       gateway_idx = IDX_ADDRTLV_GATEWAY_SRCSPEC_DEF;
498     }
499     if (addr == NULL) {
500       OONF_WARN(LOG_OLSRV2_W, "Out of memory error for olsrv2 address");
501       return;
502     }
503
504     /* add Gateway TLV and Metric TLV */
505     memset(distance_vector, 0, sizeof(distance_vector));
506
507     list_for_each_element(nhdp_domain_get_list(), domain, _node) {
508       lan_data = olsrv2_lan_get_domaindata(domain, lan);
509       metric_out = lan_data->outgoing_metric;
510       if (metric_out > RFC7181_METRIC_MAX) {
511         /* metric value does not make sense */
512         continue;
513       }
514
515       if (rfc7181_metric_encode(&metric_out_encoded, metric_out)) {
516         OONF_WARN(LOG_OLSRV2_W, "Encoding of metric %u failed", metric_out);
517         continue;
518       }
519       rfc7181_metric_set_flag(&metric_out_encoded, RFC7181_LINKMETRIC_OUTGOING_NEIGH);
520
521       /* add Metric TLV */
522       OONF_DEBUG(LOG_OLSRV2_W, "Add Linkmetric (ext %u) TLV with value 0x%02x%02x (%u)",
523           domain->ext, metric_out_encoded.b[0], metric_out_encoded.b[1], metric_out);
524       rfc5444_writer_add_addrtlv(writer, addr, &domain->_metric_addrtlvs[0],
525           &metric_out_encoded, sizeof(metric_out_encoded), false);
526
527       OONF_DEBUG(LOG_OLSRV2_W, "Gateway (ext %u) has hopcount cost %u",
528           domain->ext, lan_data->distance);
529       distance_vector[domain->index] = lan_data->distance;
530     }
531
532     /* add Gateway TLV */
533     if (!lan->same_distance) {
534       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[gateway_idx],
535           distance_vector, _mprtypes_size, false);
536     }
537     else {
538       rfc5444_writer_add_addrtlv(writer, addr, &_olsrv2_addrtlvs[gateway_idx],
539           distance_vector, 1, false);
540     }
541
542     if (gateway_idx == IDX_ADDRTLV_GATEWAY_SRCSPEC) {
543       /* add Src Prefix TLV */
544       srcprefix[0] = netaddr_get_prefix_length(&lan->prefix.src);
545       memcpy(&srcprefix[1], netaddr_get_binptr(&lan->prefix.src),
546           netaddr_get_binlength(&lan->prefix.src));
547
548       rfc5444_writer_add_addrtlv(writer, addr,
549           &_olsrv2_addrtlvs[IDX_ADDRTLV_GATEWAY_SRC_PREFIX],
550           srcprefix, 1 + (netaddr_get_prefix_length(&lan->prefix.src) + 7)/8, false);
551     }
552   }
553 }
554
555 /**
556  * Callback triggered when tc is finished.
557  * @param writer
558  * @param start
559  * @param end
560  * @param complete
561  */
562 static void
563 _cb_finishMessageTLVs(struct rfc5444_writer *writer,
564     struct rfc5444_writer_address *start __attribute__((unused)),
565     struct rfc5444_writer_address *end __attribute__((unused)),
566     bool complete) {
567   uint16_t ansn;
568
569   /* get ANSN */
570   ansn = htons(olsrv2_routing_get_ansn());
571
572   rfc5444_writer_set_messagetlv(writer, RFC7181_MSGTLV_CONT_SEQ_NUM,
573       complete ? RFC7181_CONT_SEQ_NUM_COMPLETE : RFC7181_CONT_SEQ_NUM_INCOMPLETE,
574       &ansn, sizeof(ansn));
575 }