f986aa0ad428b9860e955f83a30232c5d38c95ed
[oonf.git] / src-plugins / generic / dlep / ext_base_proto / proto.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/autobuf.h"
47 #include "common/avl.h"
48 #include "common/common_types.h"
49 #include "subsystems/oonf_timer.h"
50
51 #include "dlep/dlep_extension.h"
52 #include "dlep/dlep_iana.h"
53 #include "dlep/dlep_reader.h"
54 #include "dlep/dlep_writer.h"
55
56 #include "dlep/ext_base_proto/proto.h"
57
58 static void _cb_local_heartbeat(struct oonf_timer_instance *);
59 static void _cb_remote_heartbeat(struct oonf_timer_instance *);
60
61 /* UDP peer discovery */
62
63 /* UDP peer offer */
64 static const uint16_t _peer_offer_tlvs[] = {
65   DLEP_PEER_TYPE_TLV,
66   DLEP_IPV4_CONPOINT_TLV,
67   DLEP_IPV6_CONPOINT_TLV,
68 };
69
70 /* session initialization */
71 static const uint16_t _session_init_tlvs[] = {
72   DLEP_HEARTBEAT_INTERVAL_TLV,
73   DLEP_PEER_TYPE_TLV,
74   DLEP_EXTENSIONS_SUPPORTED_TLV,
75 };
76 static const uint16_t _session_init_mandatory[] = {
77   DLEP_HEARTBEAT_INTERVAL_TLV,
78   DLEP_PEER_TYPE_TLV,
79 };
80
81 /* session initialization ack */
82 static const uint16_t _session_initack_tlvs[] = {
83   DLEP_HEARTBEAT_INTERVAL_TLV,
84   DLEP_STATUS_TLV,
85   DLEP_PEER_TYPE_TLV,
86   DLEP_EXTENSIONS_SUPPORTED_TLV,
87 };
88 static const uint16_t _session_initack_mandatory[] = {
89   DLEP_HEARTBEAT_INTERVAL_TLV,
90   DLEP_STATUS_TLV,
91   DLEP_PEER_TYPE_TLV,
92 };
93
94 /* peer update */
95 static const uint16_t _peer_update_tlvs[] = {
96   DLEP_IPV4_ADDRESS_TLV,
97   DLEP_IPV6_ADDRESS_TLV,
98 };
99 static const uint16_t _peer_update_duplicates[] = {
100   DLEP_IPV4_ADDRESS_TLV,
101   DLEP_IPV6_ADDRESS_TLV,
102 };
103
104 /* peer update ack */
105 static const uint16_t _peer_updateack_tlvs[] = {
106   DLEP_STATUS_TLV,
107 };
108 static const uint16_t _peer_updateack_mandatory[] = {
109   DLEP_STATUS_TLV,
110 };
111
112 /* peer termination */
113 static const uint16_t _peer_termination_tlvs[] = {
114   DLEP_STATUS_TLV,
115 };
116
117 /* peer termination ack */
118 static const uint16_t _peer_terminationack_tlvs[] = {
119   DLEP_STATUS_TLV,
120 };
121
122 /* destination up */
123 static const uint16_t _dst_up_tlvs[] = {
124   DLEP_MAC_ADDRESS_TLV,
125   DLEP_IPV4_ADDRESS_TLV,
126   DLEP_IPV6_ADDRESS_TLV,
127   DLEP_IPV4_SUBNET_TLV,
128   DLEP_IPV6_SUBNET_TLV,
129 };
130 static const uint16_t _dst_up_mandatory[] = {
131   DLEP_MAC_ADDRESS_TLV,
132 };
133 static const uint16_t _dst_up_duplicates[] = {
134   DLEP_IPV4_ADDRESS_TLV,
135   DLEP_IPV6_ADDRESS_TLV,
136   DLEP_IPV4_SUBNET_TLV,
137   DLEP_IPV6_SUBNET_TLV,
138 };
139
140 /* destination up ack */
141 static const uint16_t _dst_up_ack_tlvs[] = {
142   DLEP_MAC_ADDRESS_TLV,
143   DLEP_STATUS_TLV,
144 };
145 static const uint16_t _dst_up_ack_mandatory[] = {
146   DLEP_MAC_ADDRESS_TLV,
147   DLEP_STATUS_TLV,
148 };
149
150 /* destination down */
151 static const uint16_t _dst_down_tlvs[] = {
152   DLEP_MAC_ADDRESS_TLV,
153 };
154 static const uint16_t _dst_down_mandatory[] = {
155   DLEP_MAC_ADDRESS_TLV,
156   DLEP_STATUS_TLV,
157 };
158
159 /* destination down ack */
160 static const uint16_t _dst_down_ack_tlvs[] = {
161   DLEP_MAC_ADDRESS_TLV,
162   DLEP_STATUS_TLV,
163 };
164 static const uint16_t _dst_down_ack_mandatory[] = {
165   DLEP_MAC_ADDRESS_TLV,
166 };
167
168 /* destination update */
169 static const uint16_t _dst_update_tlvs[] = {
170   DLEP_MAC_ADDRESS_TLV,
171   DLEP_IPV4_ADDRESS_TLV,
172   DLEP_IPV6_ADDRESS_TLV,
173   DLEP_IPV4_SUBNET_TLV,
174   DLEP_IPV6_SUBNET_TLV,
175 };
176 static const uint16_t _dst_update_mandatory[] = {
177   DLEP_MAC_ADDRESS_TLV,
178 };
179 static const uint16_t _dst_update_duplicates[] = {
180   DLEP_IPV4_ADDRESS_TLV,
181   DLEP_IPV6_ADDRESS_TLV,
182   DLEP_IPV4_SUBNET_TLV,
183   DLEP_IPV6_SUBNET_TLV,
184 };
185
186 /* link characteristics request */
187 static const uint16_t _linkchar_req_tlvs[] = {
188   DLEP_MAC_ADDRESS_TLV,
189   DLEP_CDRR_TLV,
190   DLEP_CDRT_TLV,
191   DLEP_LATENCY_TLV,
192 };
193 static const uint16_t _linkchar_req_mandatory[] = {
194   DLEP_MAC_ADDRESS_TLV,
195 };
196
197 /* link characteristics ack */
198 static const uint16_t _linkchar_ack_tlvs[] = {
199   DLEP_MAC_ADDRESS_TLV,
200   DLEP_MDRR_TLV,
201   DLEP_MDRT_TLV,
202   DLEP_CDRR_TLV,
203   DLEP_CDRT_TLV,
204   DLEP_LATENCY_TLV,
205   DLEP_RESOURCES_TLV,
206   DLEP_RLQR_TLV,
207   DLEP_RLQT_TLV,
208   DLEP_STATUS_TLV,
209 };
210 static const uint16_t _linkchar_ack_mandatory[] = {
211   DLEP_MAC_ADDRESS_TLV,
212 };
213
214 /* supported signals of this extension */
215 static struct dlep_extension_signal _signals[] = {
216   {
217     .id = DLEP_UDP_PEER_DISCOVERY,
218   },
219   {
220     .id = DLEP_UDP_PEER_OFFER,
221     .supported_tlvs = _peer_offer_tlvs,
222     .supported_tlv_count = ARRAYSIZE(_peer_offer_tlvs),
223   },
224   {
225     .id = DLEP_SESSION_INITIALIZATION,
226     .supported_tlvs = _session_init_tlvs,
227     .supported_tlv_count = ARRAYSIZE(_session_init_tlvs),
228     .mandatory_tlvs = _session_init_mandatory,
229     .mandatory_tlv_count = ARRAYSIZE(_session_init_mandatory),
230   },
231   {
232     .id = DLEP_SESSION_INITIALIZATION_ACK,
233     .supported_tlvs = _session_initack_tlvs,
234     .supported_tlv_count = ARRAYSIZE(_session_initack_tlvs),
235     .mandatory_tlvs = _session_initack_mandatory,
236     .mandatory_tlv_count = ARRAYSIZE(_session_initack_mandatory),
237   },
238   {
239     .id = DLEP_SESSION_UPDATE,
240     .supported_tlvs = _peer_update_tlvs,
241     .supported_tlv_count = ARRAYSIZE(_peer_update_tlvs),
242     .duplicate_tlvs = _peer_update_duplicates,
243     .duplicate_tlv_count = ARRAYSIZE(_peer_update_duplicates),
244   },
245   {
246     .id = DLEP_SESSION_UPDATE_ACK,
247     .supported_tlvs = _peer_updateack_tlvs,
248     .supported_tlv_count = ARRAYSIZE(_peer_updateack_tlvs),
249     .mandatory_tlvs = _peer_updateack_mandatory,
250     .mandatory_tlv_count = ARRAYSIZE(_peer_updateack_mandatory),
251   },
252   {
253     .id = DLEP_SESSION_TERMINATION,
254     .supported_tlvs = _peer_termination_tlvs,
255     .supported_tlv_count = ARRAYSIZE(_peer_termination_tlvs),
256   },
257   {
258     .id = DLEP_SESSION_TERMINATION_ACK,
259     .supported_tlvs = _peer_terminationack_tlvs,
260     .supported_tlv_count = ARRAYSIZE(_peer_terminationack_tlvs),
261   },
262   {
263     .id = DLEP_DESTINATION_UP,
264     .supported_tlvs = _dst_up_tlvs,
265     .supported_tlv_count = ARRAYSIZE(_dst_up_tlvs),
266     .mandatory_tlvs = _dst_up_mandatory,
267     .mandatory_tlv_count = ARRAYSIZE(_dst_up_mandatory),
268     .duplicate_tlvs = _dst_up_duplicates,
269     .duplicate_tlv_count = ARRAYSIZE(_dst_up_duplicates),
270   },
271   {
272     .id = DLEP_DESTINATION_UP_ACK,
273     .supported_tlvs = _dst_up_ack_tlvs,
274     .supported_tlv_count = ARRAYSIZE(_dst_up_ack_tlvs),
275     .mandatory_tlvs = _dst_up_ack_mandatory,
276     .mandatory_tlv_count = ARRAYSIZE(_dst_up_ack_mandatory),
277   },
278   {
279     .id = DLEP_DESTINATION_DOWN,
280     .supported_tlvs = _dst_down_tlvs,
281     .supported_tlv_count = ARRAYSIZE(_dst_down_tlvs),
282     .mandatory_tlvs = _dst_down_mandatory,
283     .mandatory_tlv_count = ARRAYSIZE(_dst_down_mandatory),
284   },
285   {
286     .id = DLEP_DESTINATION_DOWN_ACK,
287     .supported_tlvs = _dst_down_ack_tlvs,
288     .supported_tlv_count = ARRAYSIZE(_dst_down_ack_tlvs),
289     .mandatory_tlvs = _dst_down_ack_mandatory,
290     .mandatory_tlv_count = ARRAYSIZE(_dst_down_ack_mandatory),
291   },
292   {
293     .id = DLEP_DESTINATION_UPDATE,
294     .supported_tlvs = _dst_update_tlvs,
295     .supported_tlv_count = ARRAYSIZE(_dst_update_tlvs),
296     .mandatory_tlvs = _dst_update_mandatory,
297     .mandatory_tlv_count = ARRAYSIZE(_dst_update_mandatory),
298     .duplicate_tlvs = _dst_update_duplicates,
299     .duplicate_tlv_count = ARRAYSIZE(_dst_update_duplicates),
300   },
301   {
302     .id = DLEP_HEARTBEAT,
303   },
304   {
305     .id = DLEP_LINK_CHARACTERISTICS_REQUEST,
306     .supported_tlvs = _linkchar_req_tlvs,
307     .supported_tlv_count = ARRAYSIZE(_linkchar_req_tlvs),
308     .mandatory_tlvs = _linkchar_req_mandatory,
309     .mandatory_tlv_count = ARRAYSIZE(_linkchar_req_mandatory),
310   },
311   {
312     .id = DLEP_LINK_CHARACTERISTICS_ACK,
313     .supported_tlvs = _linkchar_ack_tlvs,
314     .supported_tlv_count = ARRAYSIZE(_linkchar_ack_tlvs),
315     .mandatory_tlvs = _linkchar_ack_mandatory,
316     .mandatory_tlv_count = ARRAYSIZE(_linkchar_ack_mandatory),
317   },
318 };
319
320 /* supported TLVs of this extension */
321 static struct dlep_extension_tlv _tlvs[] = {
322   { DLEP_STATUS_TLV, 1, 65535 },
323   { DLEP_IPV4_CONPOINT_TLV, 5, 7 },
324   { DLEP_IPV6_CONPOINT_TLV, 17, 19 },
325   { DLEP_PEER_TYPE_TLV, 1, 255 },
326   { DLEP_HEARTBEAT_INTERVAL_TLV, 4, 4 },
327   { DLEP_EXTENSIONS_SUPPORTED_TLV, 2, 65534 },
328   { DLEP_MAC_ADDRESS_TLV, 6, 8 },
329   { DLEP_MDRR_TLV, 8, 8 },
330   { DLEP_MDRT_TLV, 8, 8 },
331   { DLEP_CDRR_TLV, 8, 8 },
332   { DLEP_CDRT_TLV, 8, 8 },
333   { DLEP_LATENCY_TLV, 8, 8 },
334   { DLEP_RESOURCES_TLV, 1, 1 },
335   { DLEP_RLQR_TLV, 1, 1 },
336   { DLEP_RLQT_TLV, 1, 1 },
337 };
338
339 static struct dlep_neighbor_mapping _neigh_mappings[] = {
340   {
341     .dlep = DLEP_MDRR_TLV,
342     .layer2 = OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
343     .length = 8,
344     .from_tlv = dlep_reader_map_identity,
345     .to_tlv = dlep_writer_map_identity,
346   },
347   {
348     .dlep = DLEP_MDRT_TLV,
349     .layer2 = OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
350     .length = 8,
351     .from_tlv = dlep_reader_map_identity,
352     .to_tlv = dlep_writer_map_identity,
353   },
354   {
355     .dlep = DLEP_CDRR_TLV,
356     .layer2 = OONF_LAYER2_NEIGH_RX_BITRATE,
357     .length = 8,
358     .from_tlv = dlep_reader_map_identity,
359     .to_tlv = dlep_writer_map_identity,
360   },
361   {
362     .dlep = DLEP_CDRT_TLV,
363     .layer2 = OONF_LAYER2_NEIGH_TX_BITRATE,
364     .length = 8,
365     .from_tlv = dlep_reader_map_identity,
366     .to_tlv = dlep_writer_map_identity,
367   },
368   {
369     .dlep = DLEP_LATENCY_TLV,
370     .layer2 = OONF_LAYER2_NEIGH_LATENCY,
371     .length = 8,
372     .from_tlv = dlep_reader_map_identity,
373     .to_tlv = dlep_writer_map_identity,
374   },
375   {
376     .dlep = DLEP_RESOURCES_TLV,
377     .layer2 = OONF_LAYER2_NEIGH_RESOURCES,
378     .length = 1,
379     .from_tlv = dlep_reader_map_identity,
380     .to_tlv = dlep_writer_map_identity,
381   },
382   {
383     .dlep = DLEP_RLQR_TLV,
384     .layer2 = OONF_LAYER2_NEIGH_RX_RLQ,
385     .length = 1,
386     .from_tlv = dlep_reader_map_identity,
387     .to_tlv = dlep_writer_map_identity,
388   },
389   {
390     .dlep = DLEP_RLQT_TLV,
391     .layer2 = OONF_LAYER2_NEIGH_TX_RLQ,
392     .length = 1,
393     .from_tlv = dlep_reader_map_identity,
394     .to_tlv = dlep_writer_map_identity,
395   },
396 };
397
398 /* DLEP base extension, radio side */
399 static struct dlep_extension _base_proto = {
400   .id = DLEP_EXTENSION_BASE_PROTO,
401   .name = "base",
402
403   .signals = _signals,
404   .signal_count = ARRAYSIZE(_signals),
405   .tlvs = _tlvs,
406   .tlv_count = ARRAYSIZE(_tlvs),
407   .neigh_mapping = _neigh_mappings,
408   .neigh_mapping_count = ARRAYSIZE(_neigh_mappings),
409 };
410
411 static struct oonf_timer_class _local_heartbeat_class = {
412   .name = "dlep local heartbeat",
413   .callback = _cb_local_heartbeat,
414   .periodic = true,
415 };
416 static struct oonf_timer_class _remote_heartbeat_class = {
417   .name = "dlep remote heartbeat",
418   .callback = _cb_remote_heartbeat,
419 };
420
421 /**
422  * Get base protocol DLEP extension
423  * @return this extension
424  */
425 struct dlep_extension *
426 dlep_base_proto_init(void) {
427   dlep_extension_add(&_base_proto);
428   return &_base_proto;
429 }
430
431 /**
432  * Start local heartbeat timer
433  * @param session dlep session
434  */
435 void
436 dlep_base_proto_start_local_heartbeat(struct dlep_session *session) {
437   /* timer for local heartbeat generation */
438   session->local_event_timer.class = &_local_heartbeat_class;
439   oonf_timer_set(&session->local_event_timer, session->cfg.heartbeat_interval);
440 }
441
442 /**
443  * Start remote heartbeat timer
444  * @param session dlep session
445  */
446 void
447 dlep_base_proto_start_remote_heartbeat(struct dlep_session *session) {
448   /* timeout for remote heartbeats */
449   session->remote_heartbeat_timeout.class = &_remote_heartbeat_class;
450   oonf_timer_set(&session->remote_heartbeat_timeout, session->remote_heartbeat_interval * 2);
451 }
452
453 /**
454  * Stop both heartbeat timers
455  * @param session dlep session
456  */
457 void
458 dlep_base_proto_stop_timers(struct dlep_session *session) {
459   OONF_DEBUG(session->log_source, "Cleanup base session");
460   oonf_timer_stop(&session->local_event_timer);
461   oonf_timer_stop(&session->remote_heartbeat_timeout);
462 }
463
464 /**
465  * Print content of the DLEP STATUS TLV to debug
466  * @param session dlep session
467  * @return dlep status
468  */
469 enum dlep_status
470 dlep_base_proto_print_status(struct dlep_session *session)
471 {
472   enum dlep_status status;
473   char text[256];
474
475   if (!dlep_reader_status(&status, text, sizeof(text), session, NULL)) {
476     OONF_DEBUG(session->log_source, "Status %d received: %s", status, text);
477
478     return status;
479   }
480   return DLEP_STATUS_OKAY;
481 }
482
483 /**
484  * Print DLEP peer type to debug
485  * @param session dlep session
486  */
487 void
488 dlep_base_proto_print_peer_type(struct dlep_session *session) {
489   char text[256];
490   bool secure;
491
492   if (!dlep_reader_peer_type(text, sizeof(text), &secure, session, NULL)) {
493     OONF_DEBUG(session->log_source, "Remote peer type (%s): %s", secure ? "secure" : "open", text);
494   }
495 }
496
497 /**
498  * Process a DLEP peer termination message
499  * @param ext (this) dlep extension
500  * @param session dlep session
501  * @return -1 if an error happened, 0 otherwise
502  */
503 int
504 dlep_base_proto_process_session_termination(
505   struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session) {
506   dlep_base_proto_print_status(session);
507
508   session->_peer_state = DLEP_PEER_TERMINATED;
509   return dlep_session_generate_signal(session, DLEP_SESSION_TERMINATION_ACK, NULL);
510 }
511
512 /**
513  * Process a DLEP peer termination ack message
514  * @param ext (this) dlep extension
515  * @param session dlep session
516  * @return -1 if an error happened, 0 otherwise
517  */
518 int
519 dlep_base_proto_process_session_termination_ack(
520   struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session) {
521   session->restrict_signal = DLEP_KILL_SESSION;
522   return 0;
523 }
524
525 /**
526  * Process a DLEP heartbeat message
527  * @param ext (this) dlep extension
528  * @param session dlep session
529  * @return -1 if an error happened, 0 otherwise
530  */
531 int
532 dlep_base_proto_process_heartbeat(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session) {
533   /* just restart the timeout with the same period */
534   oonf_timer_set(&session->remote_heartbeat_timeout, session->remote_heartbeat_interval * 2);
535   return 0;
536 }
537
538 /**
539  * Write the mac address TLV into the DLEP message
540  * @param ext (this) dlep extension
541  * @param session dlep session
542  * @param neigh mac address to write into TLV
543  * @return -1 if an error happened, 0 otherwise
544  */
545 int
546 dlep_base_proto_write_mac_only(
547   struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session, const struct netaddr *neigh) {
548   if (dlep_writer_add_mac_tlv(&session->writer, neigh)) {
549     return -1;
550   }
551   return 0;
552 }
553
554 /**
555  * Callback triggered when to generate a new heartbeat
556  * @param ptr timer instance that fired
557  */
558 static void
559 _cb_local_heartbeat(struct oonf_timer_instance *ptr) {
560   struct dlep_session *session;
561
562   session = container_of(ptr, struct dlep_session, local_event_timer);
563
564   dlep_session_generate_signal(session, DLEP_HEARTBEAT, NULL);
565   session->cb_send_buffer(session, 0);
566 }
567
568 /**
569  * Callback triggered when the remote heartbeat times out
570  * @param ptr timer instance that fired
571  */
572 static void
573 _cb_remote_heartbeat(struct oonf_timer_instance *ptr) {
574   struct dlep_session *session;
575
576   session = container_of(ptr, struct dlep_session, remote_heartbeat_timeout);
577
578   if (session->restrict_signal == DLEP_SESSION_TERMINATION_ACK) {
579     /* peer termination ACK is missing! */
580
581     /* stop local heartbeats */
582     oonf_timer_stop(&session->local_event_timer);
583
584     /* hard-terminate session */
585     if (session->cb_end_session) {
586       session->cb_end_session(session);
587     }
588   }
589   else {
590     /* soft-terminate session (send PEER_TERM) */
591     dlep_session_terminate(session);
592
593     /* set timeout for hard-termination */
594     oonf_timer_set(&session->remote_heartbeat_timeout, session->remote_heartbeat_interval * 2);
595   }
596 }