Fix handling of lid-length TLV in DLEP session ACK
[oonf.git] / src-plugins / generic / dlep / dlep_reader.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/common_types.h"
47 #include "common/netaddr.h"
48
49 #include "dlep/dlep_extension.h"
50 #include "dlep/dlep_reader.h"
51 #include "dlep/dlep_session.h"
52
53 /**
54  * Parse a heartbeat TLV
55  * @param interval pointer to storage for heartbeat interval
56  * @param session dlep session
57  * @param value dlep value to parse, NULL for using the first
58  *   DLEP_HEARTBEAT_INTERVAL_TLV value
59  * @return -1 if an error happened, 0 otherwise
60  */
61 int
62 dlep_reader_heartbeat_tlv(uint64_t *interval, struct dlep_session *session, struct dlep_parser_value *value) {
63   uint32_t tmp;
64   const uint8_t *ptr;
65
66   if (!value) {
67     value = dlep_session_get_tlv_value(session, DLEP_HEARTBEAT_INTERVAL_TLV);
68     if (!value) {
69       return -1;
70     }
71   }
72
73   ptr = dlep_session_get_tlv_binary(session, value);
74   memcpy(&tmp, ptr, sizeof(tmp));
75   *interval = ntohl(tmp);
76   return 0;
77 }
78
79 /**
80  * Parse a DLEP peer type TLV
81  * @param text pointer to buffer for peer type
82  * @param text_length length of buffer for peer type
83  * @param secured_medium set to true if medium is secured, false otherwise
84  * @param session dlep session
85  * @param value dlep value to parse, NULL for using the first
86  *   DLEP_PEER_TYPE_TLV value
87  * @return -1 if an error happened, 0 otherwise
88  */
89 int
90 dlep_reader_peer_type(
91   char *text, size_t text_length, bool *secured_medium, struct dlep_session *session, struct dlep_parser_value *value) {
92   const uint8_t *ptr;
93
94   if (!value) {
95     value = dlep_session_get_tlv_value(session, DLEP_PEER_TYPE_TLV);
96     if (!value) {
97       return -1;
98     }
99   }
100   if (value->length == 0) {
101     return -1;
102   }
103
104   ptr = dlep_session_get_tlv_binary(session, value);
105
106   *secured_medium = (ptr[0] & DLEP_PEER_TYPE_SECURED) != 0;
107
108   if (value->length > 1 && text_length > 0) {
109     /* generate a 0 terminated copy of the text */
110     if (text_length - 1u > value->length - 1u) {
111       memcpy(text, &ptr[1], value->length - 1u);
112       text[value->length - 1u] = 0;
113     }
114     else {
115       memcpy(text, &ptr[1], text_length - 2u);
116       text[text_length - 2u] = 0;
117     }
118   }
119   return 0;
120 }
121
122 /**
123  * Parse a DLEP mac address TLV
124  * @param key pointer to link-id storage
125  * @param session dlep session
126  * @param value dlep value to parse, NULL for using the first
127  *   DLEP_MAC_ADDRESS_TLV value
128  * @return -1 if an error happened, 0 otherwise
129  */
130 int
131 dlep_reader_mac_tlv(struct oonf_layer2_neigh_key *key, struct dlep_session *session, struct dlep_parser_value *value) {
132   const uint8_t *ptr;
133
134   if (!value) {
135     value = dlep_session_get_tlv_value(session, DLEP_MAC_ADDRESS_TLV);
136     if (!value) {
137       return -1;
138     }
139   }
140
141   ptr = dlep_session_get_tlv_binary(session, value);
142   return netaddr_from_binary(&key->addr, ptr, value->length, 0);
143 }
144
145 /**
146  * Parse a DLEP link-id TLV
147  * @param key pointer to link-id storage
148  * @param session dlep session
149  * @param value dlep value to parse, NULL for using the first
150  *   DLEP_LID_TLV value
151  * @return -1 if an error happened, 0 otherwise
152  */
153 int
154 dlep_reader_lid_tlv(struct oonf_layer2_neigh_key *key, struct dlep_session *session, struct dlep_parser_value *value) {
155   const uint8_t *ptr;
156
157   if (!value) {
158     value = dlep_session_get_tlv_value(session, DLEP_LID_TLV);
159     if (!value) {
160       return -1;
161     }
162   }
163
164   ptr = dlep_session_get_tlv_binary(session, value);
165   memcpy(key->link_id, ptr, value->length);
166   key->link_id_length = value->length;
167   return 0;
168 }
169
170 /**
171  * Parse a DLEP link-id length TLV
172  * @param length pointer to link-id length storage
173  * @param session dlep session
174  * @param value dlep value to parse, NULL for using the first
175  *   DLEP_LID_TLV value
176  * @return -1 if an error happened, 0 otherwise
177  */
178 int
179 dlep_reader_lid_length_tlv(uint16_t *length, struct dlep_session *session, struct dlep_parser_value *value) {
180   const uint8_t *ptr;
181   uint16_t tmp16;
182   if (!value) {
183     value = dlep_session_get_tlv_value(session, DLEP_LID_LENGTH_TLV);
184     if (!value) {
185       return -1;
186     }
187   }
188
189   ptr = dlep_session_get_tlv_binary(session, value);
190   memcpy(&tmp16, ptr, sizeof(tmp16));
191   *length = ntohs(tmp16);
192
193   return 0;
194 }
195
196 /**
197  * Parse DLEP IPv4 address TLV
198  * @param ipv4 pointer to address storage
199  * @param add pointer to boolean for flag storage
200  * @param session dlep session
201  * @param value dlep value to parse, NULL for using the first
202  *   DLEP_IPV4_ADDRESS_TLV value
203  * @return -1 if an error happened, 0 otherwise
204  */
205 int
206 dlep_reader_ipv4_tlv(struct netaddr *ipv4, bool *add, struct dlep_session *session, struct dlep_parser_value *value) {
207   const uint8_t *ptr;
208
209   if (!value) {
210     value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
211     if (!value) {
212       return -1;
213     }
214   }
215
216   ptr = dlep_session_get_tlv_binary(session, value);
217   *add = (ptr[0] & DLEP_IP_ADD) == DLEP_IP_ADD;
218   return netaddr_from_binary(ipv4, &ptr[1], 4, AF_INET);
219 }
220
221 /**
222  * Parse DLEP IPv6 address TLV
223  * @param ipv6 pointer to address storage
224  * @param add pointer to boolean for flag storage
225  * @param session dlep session
226  * @param value dlep value to parse, NULL for using the first
227  *   DLEP_IPV6_ADDRESS_TLV value
228  * @return -1 if an error happened, 0 otherwise
229  */
230 int
231 dlep_reader_ipv6_tlv(struct netaddr *ipv6, bool *add, struct dlep_session *session, struct dlep_parser_value *value) {
232   const uint8_t *ptr;
233
234   if (!value) {
235     value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
236     if (!value) {
237       return -1;
238     }
239   }
240
241   ptr = dlep_session_get_tlv_binary(session, value);
242   *add = (ptr[0] & DLEP_IP_ADD) == DLEP_IP_ADD;
243   return netaddr_from_binary(ipv6, &ptr[1], 16, AF_INET6);
244 }
245
246 /**
247  * Parse DLEP IPv4 subnet TLV
248  * @param ipv4 pointer to address storage
249  * @param add pointer to boolean for flag storage
250  * @param session dlep session
251  * @param value dlep value to parse, NULL for using the first
252  *   DLEP_IPV4_SUBNET_TLV value
253  * @return -1 if an error happened, 0 otherwise
254  */
255 int
256 dlep_reader_ipv4_subnet_tlv(
257   struct netaddr *ipv4, bool *add, struct dlep_session *session, struct dlep_parser_value *value) {
258   const uint8_t *ptr;
259
260   if (!value) {
261     value = dlep_session_get_tlv_value(session, DLEP_IPV4_SUBNET_TLV);
262     if (!value) {
263       return -1;
264     }
265   }
266
267   ptr = dlep_session_get_tlv_binary(session, value);
268   *add = (ptr[0] & DLEP_IP_ADD) == DLEP_IP_ADD;
269   return netaddr_from_binary_prefix(ipv4, &ptr[1], 4, AF_INET, ptr[5]);
270 }
271
272 /**
273  * Parse DLEP IPv6 subnet TLV
274  * @param ipv6 pointer to address storage
275  * @param add pointer to boolean for flag storage
276  * @param session dlep session
277  * @param value dlep value to parse, NULL for using the first
278  *   DLEP_IPV6_SUBNET_TLV value
279  * @return -1 if an error happened, 0 otherwise
280  */
281 int
282 dlep_reader_ipv6_subnet_tlv(
283   struct netaddr *ipv6, bool *add, struct dlep_session *session, struct dlep_parser_value *value) {
284   const uint8_t *ptr;
285
286   if (!value) {
287     value = dlep_session_get_tlv_value(session, DLEP_IPV6_SUBNET_TLV);
288     if (!value) {
289       return -1;
290     }
291   }
292
293   ptr = dlep_session_get_tlv_binary(session, value);
294   *add = (ptr[0] & DLEP_IP_ADD) == DLEP_IP_ADD;
295   return netaddr_from_binary_prefix(ipv6, &ptr[1], 16, AF_INET6, ptr[17]);
296 }
297
298 /**
299  * Parse a DLEP IPv4 conpoint TLV
300  * @param addr pointer to address storage
301  * @param port pointer to port storage
302  * @param tls pointer to storage for TLV flag
303  * @param session dlep session
304  * @param value dlep value to parse, NULL for using the first
305  *   DLEP_IPv4_CONPOINT_TLV value
306  * @return -1 if an error happened, 0 otherwise
307  */
308 int
309 dlep_reader_ipv4_conpoint_tlv(
310   struct netaddr *addr, uint16_t *port, bool *tls, struct dlep_session *session, struct dlep_parser_value *value) {
311   uint16_t tmp;
312   const uint8_t *ptr;
313
314   if (!value) {
315     value = dlep_session_get_tlv_value(session, DLEP_IPV4_CONPOINT_TLV);
316     if (!value) {
317       return -1;
318     }
319   }
320
321   if (value->length != 5 && value->length != 7) {
322     return -1;
323   }
324
325   ptr = dlep_session_get_tlv_binary(session, value);
326
327   /* handle TLS flag */
328   *tls = (ptr[0] & DLEP_CONNECTION_TLS) == DLEP_CONNECTION_TLS;
329
330   /* handle port */
331   if (value->length == 7) {
332     memcpy(&tmp, &ptr[5], sizeof(tmp));
333     *port = ntohs(tmp);
334   }
335   else {
336     *port = DLEP_PORT;
337   }
338
339   /* handle IP */
340   return netaddr_from_binary(addr, &ptr[1], 4, AF_INET);
341 }
342
343 /**
344  * Parse a DLEP IPv6 conpoint TLV
345  * @param addr pointer to address storage
346  * @param port pointer to port storage
347  * @param tls pointer to storage for TLV flag
348  * @param session dlep session
349  * @param value dlep value to parse, NULL for using the first
350  *   DLEP_IPv6_CONPOINT_TLV value
351  * @return -1 if an error happened, 0 otherwise
352  */
353 int
354 dlep_reader_ipv6_conpoint_tlv(
355   struct netaddr *addr, uint16_t *port, bool *tls, struct dlep_session *session, struct dlep_parser_value *value) {
356   uint16_t tmp;
357   const uint8_t *ptr;
358
359   if (!value) {
360     value = dlep_session_get_tlv_value(session, DLEP_IPV6_CONPOINT_TLV);
361     if (!value) {
362       return -1;
363     }
364   }
365
366   if (value->length != 17 && value->length != 19) {
367     return -1;
368   }
369
370   ptr = dlep_session_get_tlv_binary(session, value);
371
372   /* handle TLS flag */
373   *tls = (ptr[0] & DLEP_CONNECTION_TLS) == DLEP_CONNECTION_TLS;
374
375   /* handle port */
376   if (value->length == 19) {
377     memcpy(&tmp, &ptr[17], sizeof(tmp));
378     *port = ntohs(tmp);
379   }
380   else {
381     *port = DLEP_PORT;
382   }
383
384   /* handle IP */
385   return netaddr_from_binary(addr, &ptr[1], 16, AF_INET6);
386 }
387
388 /**
389  * Parse a generic uint64 value TLV
390  * @param number storage for uint64 value
391  * @param tlv_id tlv_id to parse
392  * @param session dlep session
393  * @param value dlep value to parse, NULL for using the first
394  *   tlv_id TLV value
395  * @return -1 if an error happened, 0 otherwise
396  */
397 int
398 dlep_reader_uint64(uint64_t *number, uint16_t tlv_id, struct dlep_session *session, struct dlep_parser_value *value) {
399   uint64_t tmp;
400   const uint8_t *ptr;
401
402   if (!value) {
403     value = dlep_session_get_tlv_value(session, tlv_id);
404     if (!value) {
405       return -1;
406     }
407   }
408
409   ptr = dlep_session_get_tlv_binary(session, value);
410   memcpy(&tmp, ptr, sizeof(tmp));
411   *number = be64toh(tmp);
412   return 0;
413 }
414
415 /**
416  * Parse a generic int64 value TLV
417  * @param number storage for int64 value
418  * @param tlv_id tlv_id to parse
419  * @param session dlep session
420  * @param value dlep value to parse, NULL for using the first
421  *   tlv_id TLV value
422  * @return -1 if an error happened, 0 otherwise
423  */
424 int
425 dlep_reader_int64(int64_t *number, uint16_t tlv_id, struct dlep_session *session, struct dlep_parser_value *value) {
426   uint64_t tmp;
427   const uint8_t *ptr;
428
429   if (!value) {
430     value = dlep_session_get_tlv_value(session, tlv_id);
431     if (!value) {
432       return -1;
433     }
434   }
435
436   ptr = dlep_session_get_tlv_binary(session, value);
437   memcpy(&tmp, ptr, sizeof(tmp));
438   *number = (int64_t)(be64toh(tmp));
439   return 0;
440 }
441
442 /**
443  * Parse a DLEP status TLV
444  * @param status pointer to store status
445  * @param text pointer to store text status
446  * @param text_length length of text status buffer
447  * @param session dlep session
448  * @param value dlep value to parse, NULL for using the first
449  *   DLEP_STATUS_TLV value
450  * @return -1 if an error happened, 0 otherwise
451  */
452 int
453 dlep_reader_status(enum dlep_status *status, char *text, size_t text_length, struct dlep_session *session,
454   struct dlep_parser_value *value) {
455   const uint8_t *ptr;
456
457   if (!value) {
458     value = dlep_session_get_tlv_value(session, DLEP_STATUS_TLV);
459     if (!value) {
460       return -1;
461     }
462   }
463
464   ptr = dlep_session_get_tlv_binary(session, value);
465   *status = ptr[0];
466
467   if (value->length > 1 && text_length > 0) {
468     /* generate a 0 terminated copy of the text */
469     if (text_length >= value->length) {
470       memcpy(text, &ptr[1], value->length - 1);
471       text[value->length - 1] = 0;
472     }
473     else {
474       memcpy(text, &ptr[1], text_length - 1);
475       text[text_length - 1] = 0;
476     }
477   }
478   else if (text_length) {
479     *text = 0;
480   }
481   return 0;
482 }
483
484 /**
485  * Parse a metric TLV and copy it into a layer2 data object
486  * @param data pointer to layer2 data object
487  * @param meta metadata description for data
488  * @param session dlep session
489  * @param dlep_tlv DLEP TLV id
490  * @return -1 if an error happened, 0 otherwise
491  */
492 int
493 dlep_reader_map_identity(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
494   struct dlep_session *session, uint16_t dlep_tlv) {
495   struct dlep_parser_value *value;
496   int64_t l2value;
497   uint64_t tmp64;
498   uint32_t tmp32;
499   uint16_t tmp16;
500   uint8_t tmp8;
501   const uint8_t *dlepvalue;
502
503   value = dlep_session_get_tlv_value(session, dlep_tlv);
504   if (value) {
505     dlepvalue = dlep_parser_get_tlv_binary(&session->parser, value);
506
507     switch (value->length) {
508       case 8:
509         memcpy(&tmp64, dlepvalue, 8);
510         l2value = (int64_t)be64toh(tmp64);
511         break;
512       case 4:
513         memcpy(&tmp32, dlepvalue, 4);
514         l2value = (int32_t)ntohl(tmp32);
515         break;
516       case 2:
517         memcpy(&tmp16, dlepvalue, 2);
518         l2value = (int16_t)ntohs(tmp16);
519         break;
520       case 1:
521         memcpy(&tmp8, dlepvalue, 1);
522         l2value = (int8_t)tmp8;
523         break;
524       default:
525         return -1;
526     }
527
528     switch (meta->type) {
529       case OONF_LAYER2_INTEGER_DATA:
530         oonf_layer2_data_set_int64(data, session->l2_origin, l2value);
531         break;
532       case OONF_LAYER2_BOOLEAN_DATA:
533         oonf_layer2_data_set_bool(data, session->l2_origin, l2value != 0);
534         break;
535       default:
536         return -1;
537     }
538   }
539   return 0;
540 }
541
542 /**
543  * Automatically map all predefined metric values of an
544  * extension for layer2 neighbor data from DLEP TLVs to
545  * the layer2 database
546  * @param data layer2 neighbor data array
547  * @param session dlep session
548  * @param ext dlep extension
549  * @return 0 if everything worked fine, negative index
550  *   (minus 1) of the conversion that failed.
551  */
552 int
553 dlep_reader_map_l2neigh_data(struct oonf_layer2_data *data, struct dlep_session *session, struct dlep_extension *ext) {
554   struct dlep_neighbor_mapping *map;
555   size_t i;
556
557   for (i = 0; i < ext->neigh_mapping_count; i++) {
558     map = &ext->neigh_mapping[i];
559
560     if (map->from_tlv(&data[map->layer2], oonf_layer2_neigh_metadata_get(map->layer2), session, map->dlep)) {
561       return -(i + 1);
562     }
563   }
564   return 0;
565 }
566
567 /**
568  * Automatically map all predefined metric values of an
569  * extension for layer2 network data from DLEP TLVs to
570  * the layer2 database
571  * @param data layer2 network data array
572  * @param session dlep session
573  * @param ext dlep extension
574  * @return 0 if everything worked fine, negative index
575  *   (minus 1) of the conversion that failed.
576  */
577 int
578 dlep_reader_map_l2net_data(struct oonf_layer2_data *data, struct dlep_session *session, struct dlep_extension *ext) {
579   struct dlep_network_mapping *map;
580   size_t i;
581
582   for (i = 0; i < ext->if_mapping_count; i++) {
583     map = &ext->if_mapping[i];
584
585     if (map->from_tlv(&data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), session, map->dlep)) {
586       return -(i + 1);
587     }
588   }
589   return 0;
590 }