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