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