3 * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4 * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
46 #include "common/common_types.h"
47 #include "common/avl.h"
48 #include "common/autobuf.h"
49 #include "core/oonf_logging.h"
51 #include "dlep/dlep_iana.h"
52 #include "dlep/dlep_extension.h"
53 #include "dlep/dlep_reader.h"
54 #include "dlep/dlep_writer.h"
55 #include "dlep/router/dlep_router_interface.h"
56 #include "dlep/router/dlep_router_session.h"
58 #include "dlep/ext_base_proto/proto.h"
59 #include "dlep/ext_base_proto/proto_router.h"
61 static void _cb_init_router(struct dlep_session *);
62 static void _cb_apply_router(struct dlep_session *);
63 static void _cb_cleanup_router(struct dlep_session *);
64 static void _cb_create_peer_discovery(struct oonf_timer_instance *);
66 static int _router_process_peer_offer(struct dlep_extension *, struct dlep_session *);
67 static int _router_process_session_init_ack(struct dlep_extension *, struct dlep_session *);
68 static int _router_process_session_update(struct dlep_extension *, struct dlep_session *);
69 static int _router_process_session_update_ack(struct dlep_extension *, struct dlep_session *);
70 static int _router_process_destination_up(struct dlep_extension *, struct dlep_session *);
71 static int _router_process_destination_up_ack(struct dlep_extension *, struct dlep_session *);
72 static int _router_process_destination_down(struct dlep_extension *, struct dlep_session *);
73 static int _router_process_destination_down_ack(struct dlep_extension *, struct dlep_session *);
74 static int _router_process_destination_update(struct dlep_extension *, struct dlep_session *);
75 static int _router_process_link_char_ack(struct dlep_extension *, struct dlep_session *);
77 static int _router_write_peer_discovery(struct dlep_extension *,
78 struct dlep_session *session, const struct netaddr *);
79 static int _router_write_session_init(struct dlep_extension *,
80 struct dlep_session *session, const struct netaddr *);
82 static struct dlep_extension_implementation _router_signals[] = {
84 .id = DLEP_UDP_PEER_DISCOVERY,
85 .add_tlvs = _router_write_peer_discovery,
88 .id = DLEP_UDP_PEER_OFFER,
89 .process = _router_process_peer_offer,
92 .id = DLEP_SESSION_INITIALIZATION,
93 .add_tlvs = _router_write_session_init,
96 .id = DLEP_SESSION_INITIALIZATION_ACK,
97 .process = _router_process_session_init_ack,
100 .id = DLEP_SESSION_UPDATE,
101 .process = _router_process_session_update,
104 .id = DLEP_SESSION_UPDATE_ACK,
105 .process = _router_process_session_update_ack,
108 .id = DLEP_SESSION_TERMINATION,
109 .process = dlep_base_proto_process_session_termination,
112 .id = DLEP_SESSION_TERMINATION_ACK,
113 .process = dlep_base_proto_process_session_termination_ack,
116 .id = DLEP_DESTINATION_UP,
117 .process = _router_process_destination_up,
120 .id = DLEP_DESTINATION_UP_ACK,
121 .process = _router_process_destination_up_ack,
122 .add_tlvs = dlep_base_proto_write_mac_only,
125 .id = DLEP_DESTINATION_DOWN,
126 .process = _router_process_destination_down,
129 .id = DLEP_DESTINATION_DOWN_ACK,
130 .process = _router_process_destination_down_ack,
131 .add_tlvs = dlep_base_proto_write_mac_only,
134 .id = DLEP_DESTINATION_UPDATE,
135 .process = _router_process_destination_update,
138 .id = DLEP_HEARTBEAT,
139 .process = dlep_base_proto_process_heartbeat,
142 .id = DLEP_LINK_CHARACTERISTICS_ACK,
143 .process = _router_process_link_char_ack,
147 static struct oonf_timer_class _peer_discovery_class = {
148 .name = "dlep peer discovery",
149 .callback = _cb_create_peer_discovery,
152 static struct dlep_extension *_base;
155 * Initialize the routers DLEP base protocol extension
158 dlep_base_proto_router_init(void) {
159 _base = dlep_base_proto_init();
160 dlep_extension_add_processing(_base, false,
161 _router_signals, ARRAYSIZE(_router_signals));
163 oonf_timer_add(&_peer_discovery_class);
165 _base->cb_session_init_router = _cb_init_router;
166 _base->cb_session_apply_router = _cb_apply_router;
167 _base->cb_session_cleanup_router = _cb_cleanup_router;
171 * Callback to initialize the router session
172 * @param session dlep session
175 _cb_init_router(struct dlep_session *session) {
176 if (session->restrict_signal == DLEP_SESSION_INITIALIZATION_ACK) {
178 * we are waiting for a Peer Init Ack,
179 * so we need to send a Peer Init
181 dlep_session_generate_signal(session, DLEP_SESSION_INITIALIZATION, NULL);
182 session->cb_send_buffer(session, 0);
184 session->remote_heartbeat_interval = session->cfg.heartbeat_interval;
185 dlep_base_proto_start_remote_heartbeat(session);
190 * Callback to apply new network settings to a router session
191 * @param session dlep session
194 _cb_apply_router(struct dlep_session *session) {
195 OONF_DEBUG(session->log_source, "Initialize base router session");
196 if (session->restrict_signal == DLEP_UDP_PEER_OFFER) {
198 * we are waiting for a Peer Offer,
199 * so we need to send Peer Discovery messages
201 session->local_event_timer.class = &_peer_discovery_class;
203 OONF_DEBUG(session->log_source, "Activate discovery with interval %"
204 PRIu64, session->cfg.discovery_interval);
206 /* use the "local event" for the discovery timer */
207 oonf_timer_set(&session->local_event_timer,
208 session->cfg.discovery_interval);
213 * Callback to cleanup the router session
214 * @param session dlep session
217 _cb_cleanup_router(struct dlep_session *session) {
218 struct oonf_layer2_net *l2net;
220 l2net = oonf_layer2_net_get(session->l2_listener.name);
222 /* remove DLEP mark from interface */
223 l2net->if_type = OONF_LAYER2_TYPE_UNDEFINED;
224 l2net->if_dlep = false;
226 /* and remove all DLEP data */
227 oonf_layer2_net_remove(l2net, session->l2_origin);
230 dlep_base_proto_stop_timers(session);
234 * Callback to generate regular peer discovery signals
235 * @param ptr timer instance that fired
238 _cb_create_peer_discovery(struct oonf_timer_instance *ptr) {
239 struct dlep_session *session;
241 session = container_of(ptr, struct dlep_session, local_event_timer);
243 OONF_DEBUG(session->log_source, "Generate peer discovery");
245 dlep_session_generate_signal(session, DLEP_UDP_PEER_DISCOVERY, NULL);
246 session->cb_send_buffer(session, AF_INET);
248 dlep_session_generate_signal(session, DLEP_UDP_PEER_DISCOVERY, NULL);
249 session->cb_send_buffer(session, AF_INET6);
253 * Process the peer offer signal
254 * @param ext (this) dlep extension
255 * @param session dlep session
256 * @return -1 if an error happened, 0 otherwise
259 _router_process_peer_offer(
260 struct dlep_extension *ext __attribute__((unused)),
261 struct dlep_session *session) {
262 struct dlep_router_if *router_if;
263 union netaddr_socket local, remote;
264 struct dlep_parser_value *value;
265 const struct os_interface_ip *ip;
266 const struct netaddr *result = NULL;
270 struct os_interface *ifdata;
272 if (session->restrict_signal != DLEP_UDP_PEER_OFFER) {
273 /* ignore unless we are in discovery mode */
277 /* optional peer type tlv */
278 dlep_base_proto_print_peer_type(session);
280 /* we are looking for a good address to respond to */
283 /* remember interface data */
284 ifdata = session->l2_listener.data;
287 value = dlep_session_get_tlv_value(session, DLEP_IPV6_CONPOINT_TLV);
289 if (dlep_reader_ipv6_conpoint_tlv(
290 &addr, &port, &tls, session, value)) {
295 /* TLS not supported at the moment */
297 else if (netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &addr)
299 ip = os_interface_get_prefix_from_dst(&addr, ifdata);
301 result = &ip->address;
302 netaddr_socket_init(&remote, &addr, port, ifdata->index);
305 value = dlep_session_get_next_tlv_value(session, value);
309 value = dlep_session_get_tlv_value(session, DLEP_IPV4_CONPOINT_TLV);
310 while (value && !result) {
311 if (dlep_reader_ipv4_conpoint_tlv(&addr, &port, &tls, session, value)) {
316 /* TLS not supported at the moment */
319 ip = os_interface_get_prefix_from_dst(&addr, ifdata);
321 result = &ip->address;
322 netaddr_socket_init(&remote, &addr, port, ifdata->index);
325 value = dlep_session_get_next_tlv_value(session, value);
328 /* remote address of incoming session */
330 netaddr_from_socket(&addr, &session->remote_socket);
331 ip = os_interface_get_prefix_from_dst(&addr, ifdata);
333 /* no possible way to communicate */
334 OONF_DEBUG(session->log_source,
335 "No matching prefix for incoming connection found");
338 result = &ip->address;
339 netaddr_socket_init(&remote, &addr, port, ifdata->index);
342 /* initialize session */
343 netaddr_socket_init(&local, result, 0, ifdata->index);
345 router_if = dlep_router_get_by_layer2_if(ifdata->name);
346 if (router_if && &router_if->interf.session == session) {
347 dlep_router_add_session(router_if, &local, &remote);
350 /* ignore incoming offer, something is wrong */
355 * Process the peer initialization ack message
356 * @param ext (this) dlep extension
357 * @param session dlep session
358 * @return -1 if an error happened, 0 otherwise
361 _router_process_session_init_ack(
362 struct dlep_extension *ext __attribute__((unused)),
363 struct dlep_session *session) {
364 struct oonf_layer2_net *l2net;
365 struct dlep_parser_value *value;
369 if (session->restrict_signal != DLEP_SESSION_INITIALIZATION_ACK) {
370 /* ignore unless we are in initialization mode */
374 /* mandatory heartbeat tlv */
375 if (dlep_reader_heartbeat_tlv(
376 &session->remote_heartbeat_interval, session, NULL)) {
377 OONF_INFO(session->log_source, "no heartbeat tlv, should not happen!");
381 /* optional extension supported tlv */
382 value = dlep_session_get_tlv_value(session, DLEP_EXTENSIONS_SUPPORTED_TLV);
384 ptr = dlep_session_get_tlv_binary(session, value);
385 if (dlep_session_update_extensions(session, ptr, value->length/2)) {
389 else if (dlep_session_update_extensions(session, NULL, 0)) {
393 l2net = oonf_layer2_net_add(session->l2_listener.name);
398 /* mark interface as DLEP */
399 l2net->if_type = OONF_LAYER2_TYPE_WIRELESS;
400 l2net->if_dlep = true;
402 /* map user data into interface */
403 result = dlep_reader_map_l2neigh_data(l2net->neighdata, session, _base);
405 OONF_INFO(session->log_source, "tlv mapping failed for extension %u: %u",
410 OONF_DEBUG(session->log_source, "Remote heartbeat interval %"PRIu64,
411 session->remote_heartbeat_interval);
413 dlep_base_proto_start_local_heartbeat(session);
414 dlep_base_proto_start_remote_heartbeat(session);
416 dlep_base_proto_print_status(session);
418 session->next_restrict_signal = DLEP_ALL_SIGNALS;
424 * Process the peer update message
425 * @param ext (this) dlep extension
426 * @param session dlep session
427 * @return -1 if an error happened, 0 otherwise
430 _router_process_session_update(
431 struct dlep_extension *ext __attribute__((unused)),
432 struct dlep_session *session) {
433 struct oonf_layer2_net *l2net;
436 l2net = oonf_layer2_net_add(session->l2_listener.name);
441 result = dlep_reader_map_l2neigh_data(l2net->neighdata, session, _base);
443 OONF_INFO(session->log_source, "tlv mapping failed for extension %u: %u",
449 return dlep_session_generate_signal(
450 session, DLEP_SESSION_UPDATE_ACK, NULL);
454 * Process the peer update ack message
455 * @param ext (this) dlep extension
456 * @param session dlep session
457 * @return -1 if an error happened, 0 otherwise
460 _router_process_session_update_ack(
461 struct dlep_extension *ext __attribute__((unused)),
462 struct dlep_session *session) {
463 dlep_base_proto_print_status(session);
468 * Process the destination up message
469 * @param ext (this) dlep extension
470 * @param session dlep session
471 * @return -1 if an error happened, 0 otherwise
474 _router_process_destination_up(
475 struct dlep_extension *ext __attribute__((unused)),
476 struct dlep_session *session) {
477 struct oonf_layer2_net *l2net;
478 struct oonf_layer2_neigh *l2neigh;
482 if (dlep_reader_mac_tlv(&mac, session, NULL)) {
483 OONF_INFO(session->log_source, "mac tlv missing");
487 l2net = oonf_layer2_net_add(session->l2_listener.name);
489 return dlep_session_generate_signal_status(
490 session, DLEP_DESTINATION_UP_ACK, &mac,
491 DLEP_STATUS_REQUEST_DENIED, "Not enough memory");
493 l2neigh = oonf_layer2_neigh_add(l2net, &mac);
495 return dlep_session_generate_signal_status(
496 session, DLEP_DESTINATION_UP_ACK, &mac,
497 DLEP_STATUS_REQUEST_DENIED, "Not enough memory");
500 result = dlep_reader_map_l2neigh_data(l2neigh->data, session, _base);
502 OONF_INFO(session->log_source, "tlv mapping failed for extension %u: %u",
508 return dlep_session_generate_signal(
509 session, DLEP_DESTINATION_UP_ACK, &mac);
513 * Process the destination up ack message
514 * @param ext (this) dlep extension
515 * @param session dlep session
516 * @return -1 if an error happened, 0 otherwise
519 _router_process_destination_up_ack(
520 struct dlep_extension *ext __attribute__((unused)),
521 struct dlep_session *session) {
522 dlep_base_proto_print_status(session);
527 * Process the destination down message
528 * @param ext (this) dlep extension
529 * @param session dlep session
530 * @return -1 if an error happened, 0 otherwise
533 _router_process_destination_down(
534 struct dlep_extension *ext __attribute__((unused)),
535 struct dlep_session *session) {
536 struct oonf_layer2_net *l2net;
537 struct oonf_layer2_neigh *l2neigh;
540 if (dlep_reader_mac_tlv(&mac, session, NULL)) {
544 l2net = oonf_layer2_net_get(session->l2_listener.name);
549 l2neigh = oonf_layer2_neigh_get(l2net, &mac);
554 /* remove layer2 neighbor */
555 oonf_layer2_neigh_remove(l2neigh, session->l2_origin);
558 return dlep_session_generate_signal(
559 session, DLEP_DESTINATION_DOWN_ACK, &mac);
563 * Process the destination down ack message
564 * @param ext (this) dlep extension
565 * @param session dlep session
566 * @return -1 if an error happened, 0 otherwise
569 _router_process_destination_down_ack(
570 struct dlep_extension *ext __attribute__((unused)),
571 struct dlep_session *session) {
572 dlep_base_proto_print_status(session);
577 * Process the destination update message
578 * @param ext (this) dlep extension
579 * @param session dlep session
580 * @return -1 if an error happened, 0 otherwise
583 _router_process_destination_update(
584 struct dlep_extension *ext __attribute__((unused)),
585 struct dlep_session *session) {
586 struct oonf_layer2_net *l2net;
587 struct oonf_layer2_neigh *l2neigh;
591 if (dlep_reader_mac_tlv(&mac, session, NULL)) {
595 l2net = oonf_layer2_net_get(session->l2_listener.name);
600 l2neigh = oonf_layer2_neigh_get(l2net, &mac);
602 /* we did not get the destination up signal */
606 result = dlep_reader_map_l2neigh_data(l2neigh->data, session, _base);
608 OONF_INFO(session->log_source, "tlv mapping failed for extension %u: %u",
617 * Process the link characteristic ack message
618 * @param ext (this) dlep extension
619 * @param session dlep session
620 * @return -1 if an error happened, 0 otherwise
623 _router_process_link_char_ack(
624 struct dlep_extension *ext __attribute__((unused)),
625 struct dlep_session *session) {
626 dlep_base_proto_print_status(session);
631 * Generate a peer discovery signal
632 * @param ext (this) dlep extension
633 * @param session dlep session
634 * @param addr mac address the message should refer to
635 * @return -1 if an error happened, 0 otherwise
638 _router_write_peer_discovery(
639 struct dlep_extension *ext __attribute__((unused)),
640 struct dlep_session *session,
641 const struct netaddr *addr __attribute__((unused))) {
642 if (session->restrict_signal != DLEP_UDP_PEER_OFFER) {
649 * Generate a peer init message
650 * @param ext (this) dlep extension
651 * @param session dlep session
652 * @param addr mac address the message should refer to
653 * @return -1 if an error happened, 0 otherwise
656 _router_write_session_init(
657 struct dlep_extension *ext __attribute__((unused)),
658 struct dlep_session *session,
659 const struct netaddr *addr __attribute__((unused))) {
660 const uint16_t *ext_ids;
663 /* write supported extensions */
664 ext_ids = dlep_extension_get_ids(&ext_count);
666 dlep_writer_add_supported_extensions(
667 &session->writer, ext_ids, ext_count);
670 dlep_writer_add_heartbeat_tlv(&session->writer,
671 session->cfg.heartbeat_interval);
673 /* TODO: report if radio has secured the medium */
674 dlep_writer_add_peer_type_tlv(
675 &session->writer, session->cfg.peer_type, false);