Implement lid_length mechanism into DLEP
[oonf.git] / src-plugins / generic / dlep / dlep_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 <arpa/inet.h>
47
48 #include "common/autobuf.h"
49 #include "common/common_types.h"
50
51 #include "core/oonf_logging.h"
52
53 #include "dlep/dlep_extension.h"
54 #include "dlep/dlep_iana.h"
55 #include "dlep/dlep_writer.h"
56
57 #ifndef _BSD_SOURCE
58 #define _BSD_SOURCE
59 #endif
60 #include <endian.h> /* htobe64 */
61
62 /**
63  * Start to write a new DLEP signal/message into a buffer
64  * @param writer dlep writer
65  * @param signal_type signal/message type
66  */
67 void
68 dlep_writer_start_signal(struct dlep_writer *writer, uint16_t signal_type) {
69   writer->signal_type = signal_type;
70   writer->signal_start = abuf_getlen(writer->out);
71
72   abuf_append_uint16(writer->out, htons(signal_type));
73   abuf_append_uint16(writer->out, 0);
74 }
75
76 /**
77  * Add a TLV to a DLEP writer buffer
78  * @param writer dlep writer
79  * @param type TLV type
80  * @param data pointer to TLV value
81  * @param len length of value, can be 0
82  */
83 void
84 dlep_writer_add_tlv(struct dlep_writer *writer, uint16_t type, const void *data, uint16_t len) {
85   abuf_append_uint16(writer->out, htons(type));
86   abuf_append_uint16(writer->out, htons(len));
87   abuf_memcpy(writer->out, data, len);
88 }
89
90 /**
91  * Add a TLV to a DLEP writer buffer
92  * @param writer dlep writer
93  * @param type TLV type
94  * @param data1 first part of TLV value
95  * @param len1 length of first value
96  * @param data2 second part of TLV value
97  * @param len2 length of second value
98  */
99 void
100 dlep_writer_add_tlv2(
101   struct dlep_writer *writer, uint16_t type, const void *data1, uint16_t len1, const void *data2, uint16_t len2) {
102   abuf_append_uint16(writer->out, htons(type));
103   abuf_append_uint16(writer->out, htons(len1 + len2));
104   abuf_memcpy(writer->out, data1, len1);
105   abuf_memcpy(writer->out, data2, len2);
106 }
107
108 /**
109  * Finish a DLEP signal/message
110  * @param writer dlep writer
111  * @param source logging source for error messages
112  * @return -1 if an error happened, 0 otherwise
113  */
114 int
115 dlep_writer_finish_signal(struct dlep_writer *writer, enum oonf_log_source source) {
116   size_t length;
117   uint16_t tmp16;
118   char *dst;
119
120   if (abuf_has_failed(writer->out)) {
121     OONF_WARN(source, "Could not build signal: %u", writer->signal_type);
122     return -1;
123   }
124
125   length = abuf_getlen(writer->out) - writer->signal_start;
126   if (length > 65535 + 4) {
127     OONF_WARN(
128       source, "Signal %u became too long: %" PRINTF_SIZE_T_SPECIFIER, writer->signal_type, abuf_getlen(writer->out));
129     return -1;
130   }
131
132   /* calculate network ordered size */
133   tmp16 = htons(length - 4);
134
135   /* put it into the signal */
136   dst = abuf_getptr(writer->out);
137   memcpy(&dst[writer->signal_start + 2], &tmp16, sizeof(tmp16));
138
139   OONF_DEBUG_HEX(source, &dst[writer->signal_start], length, "Finished signal %u:", writer->signal_type);
140   return 0;
141 }
142
143 /**
144  * Write a DLEP heartbeat TLV
145  * @param writer dlep writer
146  * @param interval interval length in milliseconds
147  */
148 void
149 dlep_writer_add_heartbeat_tlv(struct dlep_writer *writer, uint64_t interval) {
150   uint32_t value;
151
152   value = htonl(interval);
153
154   dlep_writer_add_tlv(writer, DLEP_HEARTBEAT_INTERVAL_TLV, &value, sizeof(value));
155 }
156
157 /**
158  * Write a DLEP peer type TLV
159  * @param writer dlep writer
160  * @param peer_type ZERO terminated peer type
161  * @param access_control true if radio implements access control, false otherwise
162  */
163 void
164 dlep_writer_add_peer_type_tlv(struct dlep_writer *writer, const char *peer_type, bool access_control) {
165   char flags;
166
167   flags = access_control ? DLEP_PEER_TYPE_SECURED : DLEP_PEER_TYPE_OPEN;
168
169   dlep_writer_add_tlv2(writer, DLEP_PEER_TYPE_TLV, &flags, sizeof(flags), peer_type, strlen(peer_type));
170 }
171
172 /**
173  * Write a DLEP MAC address TLV
174  * @param writer dlep writer
175  * @param mac_lid mac address/LID
176  * @return -1 if address was wrong type, 0 otherwise
177  */
178 int
179 dlep_writer_add_mac_tlv(struct dlep_writer *writer, const struct oonf_layer2_neigh_key *mac_lid) {
180   uint8_t value[8];
181
182   switch (netaddr_get_address_family(&mac_lid->addr)) {
183     case AF_MAC48:
184     case AF_EUI64:
185       break;
186     default:
187       return -1;
188   }
189
190   netaddr_to_binary(value, &mac_lid->addr, 8);
191
192   dlep_writer_add_tlv(writer, DLEP_MAC_ADDRESS_TLV, value, netaddr_get_binlength(&mac_lid->addr));
193   return 0;
194 }
195
196 /**
197  * Write a DLEP Link-ID TLV
198  * @param writer dlep writer
199  * @param mac_lid mac address/LID
200  * @return -1 if address was wrong type, 0 otherwise
201  */
202 int
203 dlep_writer_add_lid_tlv(struct dlep_writer *writer, const struct oonf_layer2_neigh_key *mac_lid) {
204   switch (netaddr_get_address_family(&mac_lid->addr)) {
205     case AF_MAC48:
206     case AF_EUI64:
207       break;
208     default:
209       return -1;
210   }
211
212   dlep_writer_add_tlv(writer, DLEP_LID_TLV, mac_lid->link_id, mac_lid->link_id_length);
213   return 0;
214 }
215
216 /**
217  * Write a DLEP Link-ID length TLV
218  * @param writer dlep writer
219  * @param link_id_length length of link-id
220  * @return -1 if address was wrong type, 0 otherwise
221  */
222 int
223 dlep_writer_add_lid_length_tlv(struct dlep_writer *writer, uint16_t link_id_length) {
224   uint16_t value;
225
226   value = htons(link_id_length);
227   dlep_writer_add_tlv(writer, DLEP_LID_LENGTH_TLV, &value, sizeof(value));
228   return 0;
229 }
230
231 /**
232  * Write a DLEP IPv4/IPv6 address/subnet TLV
233  * @param writer dlep writer
234  * @param ip IPv4 address
235  * @param add true if address should be added, false to remove it
236  */
237 int
238 dlep_writer_add_ip_tlv(struct dlep_writer *writer, const struct netaddr *ip, bool add) {
239   uint8_t value[18];
240
241   value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE;
242   netaddr_to_binary(&value[1], ip, 16);
243
244   switch (netaddr_get_address_family(ip)) {
245     case AF_INET:
246       value[5] = netaddr_get_prefix_length(ip);
247       if (value[5] != 32) {
248         dlep_writer_add_tlv(writer, DLEP_IPV4_SUBNET_TLV, value, 6);
249       }
250       else {
251         dlep_writer_add_tlv(writer, DLEP_IPV4_ADDRESS_TLV, value, 5);
252       }
253       break;
254     case AF_INET6:
255       value[17] = netaddr_get_prefix_length(ip);
256       if (value[17] != 128) {
257         dlep_writer_add_tlv(writer, DLEP_IPV6_SUBNET_TLV, value, 18);
258       }
259       else {
260         dlep_writer_add_tlv(writer, DLEP_IPV6_ADDRESS_TLV, value, 17);
261       }
262       break;
263     default:
264       return -1;
265   }
266   return 0;
267 }
268
269 /**
270  * Write a DLEP IPv4 conpoint TLV
271  * @param writer dlep writer
272  * @param addr IPv4 address
273  * @param port port number
274  * @param tls TLS capability flag
275  */
276 void
277 dlep_writer_add_ipv4_conpoint_tlv(struct dlep_writer *writer, const struct netaddr *addr, uint16_t port, bool tls) {
278   uint8_t value[7];
279
280   if (netaddr_get_address_family(addr) != AF_INET) {
281     return;
282   }
283
284   /* convert port to network byte order */
285   port = htons(port);
286
287   /* copy data into value buffer */
288   value[0] = tls ? DLEP_CONNECTION_TLS : DLEP_CONNECTION_PLAIN;
289   netaddr_to_binary(&value[1], addr, sizeof(value));
290   memcpy(&value[5], &port, sizeof(port));
291
292   dlep_writer_add_tlv(writer, DLEP_IPV4_CONPOINT_TLV, &value, sizeof(value));
293 }
294
295 /**
296  * Write a DLEP IPv6 conpoint TLV
297  * @param writer dlep writer
298  * @param addr IPv6 address
299  * @param port port number
300  * @param tls TLS capability flag
301  */
302 void
303 dlep_writer_add_ipv6_conpoint_tlv(struct dlep_writer *writer, const struct netaddr *addr, uint16_t port, bool tls) {
304   uint8_t value[19];
305
306   if (netaddr_get_address_family(addr) != AF_INET6) {
307     return;
308   }
309
310   /* convert port to network byte order */
311   port = htons(port);
312
313   /* copy data into value buffer */
314   value[0] = tls ? DLEP_CONNECTION_TLS : DLEP_CONNECTION_PLAIN;
315   netaddr_to_binary(&value[1], addr, sizeof(value));
316   memcpy(&value[17], &port, sizeof(port));
317
318   dlep_writer_add_tlv(writer, DLEP_IPV6_CONPOINT_TLV, &value, sizeof(value));
319 }
320
321 /**
322  * Add a DLEP tlv with uint64 value
323  * @param writer dlep writer
324  * @param number value
325  * @param tlv tlv id
326  */
327 void
328 dlep_writer_add_uint64(struct dlep_writer *writer, uint64_t number, enum dlep_tlvs tlv) {
329   uint64_t value;
330
331   value = be64toh(number);
332
333   dlep_writer_add_tlv(writer, tlv, &value, sizeof(value));
334 }
335
336 /**
337  * Add a DLEP tlv with int64 value
338  * @param writer dlep writer
339  * @param number value
340  * @param tlv tlv id
341  */
342 void
343 dlep_writer_add_int64(struct dlep_writer *writer, int64_t number, enum dlep_tlvs tlv) {
344   uint64_t *value = (uint64_t *)(&number);
345
346   *value = htonl(*value);
347
348   dlep_writer_add_tlv(writer, tlv, value, sizeof(*value));
349 }
350
351 /**
352  * Write a DLEP status TLV
353  * @param writer dlep writer
354  * @param status dlep status code
355  * @param text ZERO terminated DLEP status text
356  * @return -1 if status text was too long, 0 otherwise
357  */
358 int
359 dlep_writer_add_status(struct dlep_writer *writer, enum dlep_status status, const char *text) {
360   uint8_t value;
361   size_t txtlen;
362
363   value = status;
364   txtlen = strlen(text);
365   if (txtlen > 65534) {
366     return -1;
367   }
368
369   dlep_writer_add_tlv2(writer, DLEP_STATUS_TLV, &value, sizeof(value), text, txtlen);
370   return 0;
371 }
372
373 /**
374  * Write the supported DLEP extensions TLV
375  * @param writer dlep writer
376  * @param extensions array of supported extensions
377  * @param ext_count number of supported extensions
378  */
379 void
380 dlep_writer_add_supported_extensions(struct dlep_writer *writer, const uint16_t *extensions, uint16_t ext_count) {
381   dlep_writer_add_tlv(writer, DLEP_EXTENSIONS_SUPPORTED_TLV, extensions, ext_count * 2);
382 }
383
384 /**
385  * Write a layer2 data object into a DLEP TLV
386  * @param writer dlep writer
387  * @param data layer2 data
388  * @param tlv tlv id
389  * @param length tlv value length (1,2,4 or 8 bytes)
390  * @return -1 if an error happened, 0 otherwise
391  */
392 int
393 dlep_writer_map_identity(struct dlep_writer *writer, struct oonf_layer2_data *data,
394   const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length) {
395   int64_t l2value64;
396   uint64_t tmp64;
397   uint32_t tmp32;
398   uint16_t tmp16;
399   uint8_t tmp8;
400   void *value;
401
402   if (!oonf_layer2_data_has_value(data)) {
403     /* no data available */
404     return 0;
405   }
406   if (meta->type != oonf_layer2_data_get_type(data)) {
407     /* bad data type */
408     return -1;
409   }
410
411   switch (oonf_layer2_data_get_type(data)) {
412     case OONF_LAYER2_INTEGER_DATA:
413       l2value64 = oonf_layer2_data_get_int64(data, 0);
414       break;
415     case OONF_LAYER2_BOOLEAN_DATA:
416       l2value64 = oonf_layer2_data_get_boolean(data, false) ? 1 : 0;
417       break;
418     default:
419       return -1;
420   }
421
422   switch (length) {
423     case 8:
424       tmp64 = htobe64((uint64_t)l2value64);
425       value = &tmp64;
426       break;
427     case 4:
428       tmp32 = htonl((uint32_t)((int32_t)l2value64));
429       value = &tmp32;
430       break;
431     case 2:
432       tmp16 = htons((uint16_t)((int16_t)l2value64));
433       value = &tmp16;
434       break;
435     case 1:
436       tmp8 = (uint8_t)((int8_t)l2value64);
437       value = &tmp8;
438       break;
439     default:
440       return -1;
441   }
442
443   dlep_writer_add_tlv(writer, tlv, value, length);
444   return 0;
445 }
446
447 /**
448  * Automatically map all predefined metric values of an
449  * extension for layer2 neighbor data from the layer2
450  * database to DLEP TLVs
451  * @param writer dlep writer
452  * @param ext dlep extension
453  * @param data layer2 neighbor data array
454  * @param def layer2 neighbor defaults data array
455  * @return 0 if everything worked fine, negative index
456  *   (minus 1) of the conversion that failed.
457  */
458 int
459 dlep_writer_map_l2neigh_data(
460   struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data, struct oonf_layer2_data *def) {
461   struct dlep_neighbor_mapping *map;
462   struct oonf_layer2_data *ptr;
463   size_t i;
464
465   for (i = 0; i < ext->neigh_mapping_count; i++) {
466     map = &ext->neigh_mapping[i];
467
468     ptr = &data[map->layer2];
469     if (!oonf_layer2_data_has_value(ptr) && def) {
470       ptr = &def[map->layer2];
471     }
472
473     if (map->to_tlv(writer, ptr, oonf_layer2_neigh_metadata_get(map->layer2), map->dlep, map->length)) {
474       return -(i + 1);
475     }
476   }
477   return 0;
478 }
479
480 /**
481  * Automatically map all predefined metric values of an
482  * extension for layer2 network data from the layer2
483  * database to DLEP TLVs
484  * @param writer dlep writer
485  * @param ext dlep extension
486  * @param data layer2 network data array
487  * @return 0 if everything worked fine, negative index
488  *   (minus 1) of the conversion that failed.
489  */
490 int
491 dlep_writer_map_l2net_data(struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data) {
492   struct dlep_network_mapping *map;
493   size_t i;
494
495   for (i = 0; i < ext->if_mapping_count; i++) {
496     map = &ext->if_mapping[i];
497
498     if (map->to_tlv(writer, &data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), map->dlep, map->length)) {
499       return -(i + 1);
500     }
501   }
502   return 0;
503 }