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