Merge pull request #19 in FKIEA/oonf-os from develop to master
[oonf.git] / src / 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 <oonf/libcommon/autobuf.h>
49 #include <oonf/oonf.h>
50
51 #include <oonf/libcore/oonf_logging.h>
52
53 #include <oonf/generic/dlep/dlep_extension.h>
54 #include <oonf/generic/dlep/dlep_iana.h>
55 #include <oonf/generic/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 if length is greater than zero
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   if (mac_lid->link_id_length > 0) {
205     dlep_writer_add_tlv(writer, DLEP_LID_TLV, mac_lid->link_id, mac_lid->link_id_length);
206   }
207   return 0;
208 }
209
210 /**
211  * Write a DLEP Link-ID length TLV
212  * @param writer dlep writer
213  * @param link_id_length length of link-id
214  * @return -1 if address was wrong type, 0 otherwise
215  */
216 int
217 dlep_writer_add_lid_length_tlv(struct dlep_writer *writer, uint16_t link_id_length) {
218   uint16_t value;
219
220   value = htons(link_id_length);
221   dlep_writer_add_tlv(writer, DLEP_LID_LENGTH_TLV, &value, sizeof(value));
222   return 0;
223 }
224
225 /**
226  * Write a DLEP IPv4/IPv6 address/subnet TLV
227  * @param writer dlep writer
228  * @param ip IPv4 address
229  * @param add true if address should be added, false to remove it
230  */
231 int
232 dlep_writer_add_ip_tlv(struct dlep_writer *writer, const struct netaddr *ip, bool add) {
233   uint8_t value[18];
234
235   value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE;
236   netaddr_to_binary(&value[1], ip, 16);
237
238   switch (netaddr_get_address_family(ip)) {
239     case AF_INET:
240       value[5] = netaddr_get_prefix_length(ip);
241       if (value[5] != 32) {
242         dlep_writer_add_tlv(writer, DLEP_IPV4_SUBNET_TLV, value, 6);
243       }
244       else {
245         dlep_writer_add_tlv(writer, DLEP_IPV4_ADDRESS_TLV, value, 5);
246       }
247       break;
248     case AF_INET6:
249       value[17] = netaddr_get_prefix_length(ip);
250       if (value[17] != 128) {
251         dlep_writer_add_tlv(writer, DLEP_IPV6_SUBNET_TLV, value, 18);
252       }
253       else {
254         dlep_writer_add_tlv(writer, DLEP_IPV6_ADDRESS_TLV, value, 17);
255       }
256       break;
257     default:
258       return -1;
259   }
260   return 0;
261 }
262
263 /**
264  * Write a DLEP IPv4 conpoint TLV
265  * @param writer dlep writer
266  * @param addr IPv4 address
267  * @param port port number
268  * @param tls TLS capability flag
269  */
270 void
271 dlep_writer_add_ipv4_conpoint_tlv(struct dlep_writer *writer, const struct netaddr *addr, uint16_t port, bool tls) {
272   uint8_t value[7];
273
274   if (netaddr_get_address_family(addr) != AF_INET) {
275     return;
276   }
277
278   /* convert port to network byte order */
279   port = htons(port);
280
281   /* copy data into value buffer */
282   value[0] = tls ? DLEP_CONNECTION_TLS : DLEP_CONNECTION_PLAIN;
283   netaddr_to_binary(&value[1], addr, sizeof(value));
284   memcpy(&value[5], &port, sizeof(port));
285
286   dlep_writer_add_tlv(writer, DLEP_IPV4_CONPOINT_TLV, &value, sizeof(value));
287 }
288
289 /**
290  * Write a DLEP IPv6 conpoint TLV
291  * @param writer dlep writer
292  * @param addr IPv6 address
293  * @param port port number
294  * @param tls TLS capability flag
295  */
296 void
297 dlep_writer_add_ipv6_conpoint_tlv(struct dlep_writer *writer, const struct netaddr *addr, uint16_t port, bool tls) {
298   uint8_t value[19];
299
300   if (netaddr_get_address_family(addr) != AF_INET6) {
301     return;
302   }
303
304   /* convert port to network byte order */
305   port = htons(port);
306
307   /* copy data into value buffer */
308   value[0] = tls ? DLEP_CONNECTION_TLS : DLEP_CONNECTION_PLAIN;
309   netaddr_to_binary(&value[1], addr, sizeof(value));
310   memcpy(&value[17], &port, sizeof(port));
311
312   dlep_writer_add_tlv(writer, DLEP_IPV6_CONPOINT_TLV, &value, sizeof(value));
313 }
314
315 /**
316  * Add a DLEP tlv with uint64 value
317  * @param writer dlep writer
318  * @param number value
319  * @param tlv tlv id
320  */
321 void
322 dlep_writer_add_uint64(struct dlep_writer *writer, uint64_t number, enum dlep_tlvs tlv) {
323   uint64_t value;
324
325   value = be64toh(number);
326
327   dlep_writer_add_tlv(writer, tlv, &value, sizeof(value));
328 }
329
330 /**
331  * Add a DLEP tlv with int64 value
332  * @param writer dlep writer
333  * @param number value
334  * @param tlv tlv id
335  */
336 void
337 dlep_writer_add_int64(struct dlep_writer *writer, int64_t number, enum dlep_tlvs tlv) {
338   uint64_t *value = (uint64_t *)(&number);
339
340   *value = htonl(*value);
341
342   dlep_writer_add_tlv(writer, tlv, value, sizeof(*value));
343 }
344
345 /**
346  * Write a DLEP status TLV
347  * @param writer dlep writer
348  * @param status dlep status code
349  * @param text ZERO terminated DLEP status text
350  * @return -1 if status text was too long, 0 otherwise
351  */
352 int
353 dlep_writer_add_status(struct dlep_writer *writer, enum dlep_status status, const char *text) {
354   uint8_t value;
355   size_t txtlen;
356
357   value = status;
358   txtlen = strlen(text);
359   if (txtlen > 65534) {
360     return -1;
361   }
362
363   dlep_writer_add_tlv2(writer, DLEP_STATUS_TLV, &value, sizeof(value), text, txtlen);
364   return 0;
365 }
366
367 /**
368  * Write the supported DLEP extensions TLV
369  * @param writer dlep writer
370  * @param extensions array of supported extensions
371  * @param ext_count number of supported extensions
372  */
373 void
374 dlep_writer_add_supported_extensions(struct dlep_writer *writer, const uint16_t *extensions, uint16_t ext_count) {
375   dlep_writer_add_tlv(writer, DLEP_EXTENSIONS_SUPPORTED_TLV, extensions, ext_count * 2);
376 }
377
378 /**
379  * Write a layer2 data object into a DLEP TLV
380  * @param writer dlep writer
381  * @param data layer2 data
382  * @param tlv tlv id
383  * @param length tlv value length (1,2,4 or 8 bytes)
384  * @return -1 if an error happened, 0 otherwise
385  */
386 int
387 dlep_writer_map_identity(struct dlep_writer *writer, struct oonf_layer2_data *data,
388   const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling) {
389   int64_t l2value64;
390   uint64_t tmp64;
391   uint32_t tmp32;
392   uint16_t tmp16;
393   uint8_t tmp8;
394   void *value;
395
396   if (!oonf_layer2_data_has_value(data)) {
397     /* no data available */
398     return 0;
399   }
400   if (meta->type != oonf_layer2_data_get_type(data)) {
401     /* bad data type */
402     return -1;
403   }
404
405   switch (oonf_layer2_data_get_type(data)) {
406     case OONF_LAYER2_INTEGER_DATA:
407       l2value64 = oonf_layer2_data_get_int64(data, scaling, 0);
408       break;
409     case OONF_LAYER2_BOOLEAN_DATA:
410       l2value64 = oonf_layer2_data_get_boolean(data, false) ? 1 : 0;
411       break;
412     default:
413       return -1;
414   }
415
416   switch (length) {
417     case 8:
418       tmp64 = htobe64((uint64_t)l2value64);
419       value = &tmp64;
420       break;
421     case 4:
422       tmp32 = htonl((uint32_t)((int32_t)l2value64));
423       value = &tmp32;
424       break;
425     case 2:
426       tmp16 = htons((uint16_t)((int16_t)l2value64));
427       value = &tmp16;
428       break;
429     case 1:
430       tmp8 = (uint8_t)((int8_t)l2value64);
431       value = &tmp8;
432       break;
433     default:
434       return -1;
435   }
436
437   dlep_writer_add_tlv(writer, tlv, value, length);
438   return 0;
439 }
440
441 /**
442  * Automatically map all predefined metric values of an
443  * extension for layer2 neighbor data from the layer2
444  * database to DLEP TLVs
445  * @param writer dlep writer
446  * @param ext dlep extension
447  * @param data layer2 neighbor data array
448  * @param def layer2 neighbor defaults data array
449  * @return 0 if everything worked fine, negative index
450  *   (minus 1) of the conversion that failed.
451  */
452 int
453 dlep_writer_map_l2neigh_data(
454   struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data, struct oonf_layer2_data *def) {
455   struct dlep_neighbor_mapping *map;
456   struct oonf_layer2_data *ptr;
457   size_t i;
458
459   for (i = 0; i < ext->neigh_mapping_count; i++) {
460     map = &ext->neigh_mapping[i];
461
462     ptr = &data[map->layer2];
463     if (!oonf_layer2_data_has_value(ptr) && def) {
464       ptr = &def[map->layer2];
465     }
466
467     if (map->to_tlv(writer, ptr, oonf_layer2_neigh_metadata_get(map->layer2), map->dlep, map->length, map->scaling)) {
468       return -(i + 1);
469     }
470   }
471   return 0;
472 }
473
474 /**
475  * Automatically map all predefined metric values of an
476  * extension for layer2 network data from the layer2
477  * database to DLEP TLVs
478  * @param writer dlep writer
479  * @param ext dlep extension
480  * @param data layer2 network data array
481  * @return 0 if everything worked fine, negative index
482  *   (minus 1) of the conversion that failed.
483  */
484 int
485 dlep_writer_map_l2net_data(struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data) {
486   struct dlep_network_mapping *map;
487   size_t i;
488
489   for (i = 0; i < ext->if_mapping_count; i++) {
490     map = &ext->if_mapping[i];
491
492     if (map->to_tlv(writer, &data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), map->dlep, map->length, map->scaling)) {
493       return -(i + 1);
494     }
495   }
496   return 0;
497 }