1/********************************************************************* 2 PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved. 3 See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. 4 5 . 6 7 Author: Daniele Lacamera <daniele.lacamera@altran.com> 8 *********************************************************************/ 9#include <pico_stack.h> 10#include <pico_tree.h> 11#include <pico_socket.h> 12#include <pico_aodv.h> 13#include <pico_device.h> 14 15#include <pico_ipv4.h> 16#ifdef PICO_SUPPORT_IPV4 17 18#ifdef DEBUG_AODV 19 #define pico_aodv_dbg dbg 20#else 21 #define pico_aodv_dbg(...) do {} while(0) 22#endif 23 24#define AODV_MAX_PKT (64) 25static const struct pico_ip4 HOST_NETMASK = { 26 0xffffffff 27}; 28static struct pico_ip4 all_bcast = { 29 .addr = 0xFFFFFFFFu 30}; 31 32static const struct pico_ip4 ANY_HOST = { 33 0x0 34}; 35 36static uint32_t pico_aodv_local_id = 0; 37static int aodv_node_compare(void *ka, void *kb) 38{ 39 struct pico_aodv_node *a = ka, *b = kb; 40 if (a->dest.ip4.addr < b->dest.ip4.addr) 41 return -1; 42 43 if (b->dest.ip4.addr < a->dest.ip4.addr) 44 return 1; 45 46 return 0; 47} 48 49static int aodv_dev_cmp(void *ka, void *kb) 50{ 51 struct pico_device *a = ka, *b = kb; 52 if (a->hash < b->hash) 53 return -1; 54 55 if (a->hash > b->hash) 56 return 1; 57 58 return 0; 59} 60 61static PICO_TREE_DECLARE(aodv_nodes, aodv_node_compare); 62static PICO_TREE_DECLARE(aodv_devices, aodv_dev_cmp); 63 64static struct pico_socket *aodv_socket = NULL; 65 66static struct pico_aodv_node *get_node_by_addr(const union pico_address *addr) 67{ 68 struct pico_aodv_node search; 69 memcpy(&search.dest, addr, sizeof(union pico_address)); 70 return pico_tree_findKey(&aodv_nodes, &search); 71 72} 73 74static void pico_aodv_set_dev(struct pico_device *dev) 75{ 76 pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dev)); 77} 78 79 80static int aodv_peer_refresh(struct pico_aodv_node *node, uint32_t seq) 81{ 82 if ((0 == (node->flags & PICO_AODV_NODE_SYNC)) || (pico_seq_compare(seq, node->dseq) > 0)) { 83 node->dseq = seq; 84 node->flags |= PICO_AODV_NODE_SYNC; 85 node->last_seen = PICO_TIME_MS(); 86 return 0; 87 } 88 89 return -1; 90} 91 92static void aodv_elect_route(struct pico_aodv_node *node, union pico_address *gw, uint8_t metric, struct pico_device *dev) 93{ 94 metric++; 95 if (!(PICO_AODV_ACTIVE(node)) || metric < node->metric) { 96 pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); 97 if (!gw) { 98 pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, ANY_HOST, 1, pico_ipv4_link_by_dev(dev)); 99 node->metric = 1; 100 } else { 101 node->metric = metric; 102 pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, gw->ip4, metric, NULL); 103 } 104 } 105} 106 107static struct pico_aodv_node *aodv_peer_new(const union pico_address *addr) 108{ 109 struct pico_aodv_node *node = PICO_ZALLOC(sizeof(struct pico_aodv_node)); 110 if (!node) 111 return NULL; 112 113 memcpy(&node->dest, addr, sizeof(union pico_address)); 114 115 if (pico_tree_insert(&aodv_nodes, node)) { 116 PICO_FREE(node); 117 return NULL; 118 } 119 120 return node; 121} 122 123 124static struct pico_aodv_node *aodv_peer_eval(union pico_address *addr, uint32_t seq, int valid_seq) 125{ 126 struct pico_aodv_node *node = NULL; 127 node = get_node_by_addr(addr); 128 if (!node) { 129 node = aodv_peer_new(addr); 130 } 131 132 if (!valid_seq) 133 return node; 134 135 if (node && (aodv_peer_refresh(node, long_be(seq)) == 0)) 136 return node; 137 138 return NULL; 139} 140 141static void aodv_forward(void *pkt, struct pico_msginfo *info, int reply) 142{ 143 struct pico_aodv_node *orig; 144 union pico_address orig_addr; 145 struct pico_tree_node *index; 146 struct pico_device *dev; 147 pico_time now; 148 int size; 149 150 pico_aodv_dbg("Forwarding %s packet\n", reply ? "REPLY" : "REQUEST"); 151 152 if (reply) { 153 struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *)pkt; 154 orig_addr.ip4.addr = rep->dest; 155 rep->hop_count++; 156 pico_aodv_dbg("RREP hop count: %d\n", rep->hop_count); 157 size = sizeof(struct pico_aodv_rrep); 158 } else { 159 struct pico_aodv_rreq *req = (struct pico_aodv_rreq *)pkt; 160 orig_addr.ip4.addr = req->orig; 161 req->hop_count++; 162 size = sizeof(struct pico_aodv_rreq); 163 } 164 165 orig = get_node_by_addr(&orig_addr); 166 if (!orig) 167 orig = aodv_peer_new(&orig_addr); 168 169 if (!orig) 170 return; 171 172 now = PICO_TIME_MS(); 173 174 pico_aodv_dbg("Forwarding %s: last fwd_time: %lu now: %lu ttl: %d ==== \n", reply ? "REPLY" : "REQUEST", orig->fwd_time, now, info->ttl); 175 if (((orig->fwd_time == 0) || ((now - orig->fwd_time) > AODV_NODE_TRAVERSAL_TIME)) && (--info->ttl > 0)) { 176 orig->fwd_time = now; 177 info->dev = NULL; 178 pico_tree_foreach(index, &aodv_devices){ 179 dev = index->keyValue; 180 pico_aodv_set_dev(dev); 181 pico_socket_sendto_extended(aodv_socket, pkt, size, &all_bcast, short_be(PICO_AODV_PORT), info); 182 pico_aodv_dbg("Forwarding %s: complete! ==== \n", reply ? "REPLY" : "REQUEST"); 183 } 184 } 185} 186 187static uint32_t aodv_lifetime(struct pico_aodv_node *node) 188{ 189 uint32_t lifetime; 190 pico_time now = PICO_TIME_MS(); 191 if (!node->last_seen) 192 node->last_seen = now; 193 194 if ((now - node->last_seen) > AODV_ACTIVE_ROUTE_TIMEOUT) 195 return 0; 196 197 lifetime = AODV_ACTIVE_ROUTE_TIMEOUT - (uint32_t)(now - node->last_seen); 198 return lifetime; 199} 200 201static void aodv_send_reply(struct pico_aodv_node *node, struct pico_aodv_rreq *req, int node_is_local, struct pico_msginfo *info) 202{ 203 struct pico_aodv_rrep reply; 204 union pico_address dest; 205 union pico_address oaddr; 206 struct pico_aodv_node *orig; 207 oaddr.ip4.addr = req->orig; 208 orig = get_node_by_addr(&oaddr); 209 reply.type = AODV_TYPE_RREP; 210 reply.dest = req->dest; 211 reply.dseq = req->dseq; 212 reply.orig = req->orig; 213 if (!orig) 214 return; 215 216 reply.hop_count = (uint8_t)(orig->metric - 1u); 217 218 219 dest.ip4.addr = 0xFFFFFFFF; /* wide broadcast */ 220 221 if (short_be(req->req_flags) & AODV_RREQ_FLAG_G) { 222 dest.ip4.addr = req->orig; 223 } else { 224 pico_aodv_set_dev(info->dev); 225 } 226 227 if (node_is_local) { 228 reply.lifetime = long_be(AODV_MY_ROUTE_TIMEOUT); 229 reply.dseq = long_be(++pico_aodv_local_id); 230 pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); 231 } else if (((short_be(req->req_flags) & AODV_RREQ_FLAG_D) == 0) && (node->flags & PICO_AODV_NODE_SYNC)) { 232 reply.lifetime = long_be(aodv_lifetime(node)); 233 reply.dseq = long_be(node->dseq); 234 pico_aodv_dbg("Generating RREP for node %x, id=%x\n", reply.dest, reply.dseq); 235 pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); 236 } 237 238 pico_aodv_dbg("no rrep generated.\n"); 239} 240 241/* Parser functions */ 242 243static int aodv_send_req(struct pico_aodv_node *node); 244 245static void aodv_reverse_path_discover(pico_time now, void *arg) 246{ 247 struct pico_aodv_node *origin = (struct pico_aodv_node *)arg; 248 (void)now; 249 pico_aodv_dbg("Sending G RREQ to ORIGIN (metric = %d).\n", origin->metric); 250 origin->ring_ttl = origin->metric; 251 aodv_send_req(origin); 252} 253 254static void aodv_recv_valid_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req, struct pico_msginfo *info) 255{ 256 struct pico_device *dev; 257 dev = pico_ipv4_link_find(&node->dest.ip4); 258 pico_aodv_dbg("Valid req.\n"); 259 if (dev || PICO_AODV_ACTIVE(node)) { 260 /* if destination is ourselves, or we have a possible route: Send reply. */ 261 aodv_send_reply(node, req, dev != NULL, info); 262 if (dev) { 263 /* if really for us, we need to build the return route. Initiate a gratuitous request. */ 264 union pico_address origin_addr; 265 struct pico_aodv_node *origin; 266 origin_addr.ip4.addr = req->orig; 267 origin = get_node_by_addr(&origin_addr); 268 if (origin) { 269 origin->flags |= PICO_AODV_NODE_ROUTE_DOWN; 270 if (!pico_timer_add(AODV_PATH_DISCOVERY_TIME, aodv_reverse_path_discover, origin)) { 271 pico_aodv_dbg("AODV: Failed to start path discovery timer\n"); 272 } 273 } 274 } 275 276 pico_aodv_dbg("Replied.\n"); 277 } else { 278 /* destination unknown. Evaluate forwarding. */ 279 pico_aodv_dbg(" == Forwarding == .\n"); 280 aodv_forward(req, info, 0); 281 } 282} 283 284 285static void aodv_parse_rreq(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) 286{ 287 struct pico_aodv_rreq *req = (struct pico_aodv_rreq *) buf; 288 struct pico_aodv_node *node = NULL; 289 struct pico_device *dev; 290 union pico_address orig, dest; 291 (void)from; 292 if (len != (int)sizeof(struct pico_aodv_rreq)) 293 return; 294 295 orig.ip4.addr = req->orig; 296 dev = pico_ipv4_link_find(&orig.ip4); 297 if (dev) { 298 pico_aodv_dbg("RREQ <-- myself\n"); 299 return; 300 } 301 302 node = aodv_peer_eval(&orig, req->oseq, 1); 303 if (!node) { 304 pico_aodv_dbg("RREQ: Neighbor is not valid. oseq=%d\n", long_be(req->oseq)); 305 return; 306 } 307 308 if (req->hop_count > 0) 309 aodv_elect_route(node, from, req->hop_count, msginfo->dev); 310 else 311 aodv_elect_route(node, NULL, 0, msginfo->dev); 312 313 dest.ip4.addr = req->dest; 314 node = aodv_peer_eval(&dest, req->dseq, !(req->req_flags & short_be(AODV_RREQ_FLAG_U))); 315 if (!node) { 316 node = aodv_peer_new(&dest); 317 pico_aodv_dbg("RREQ: New peer! %08x\n", dest.ip4.addr); 318 } 319 320 if (!node) 321 return; 322 323 aodv_recv_valid_rreq(node, req, msginfo); 324} 325 326static void aodv_parse_rrep(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) 327{ 328 struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *) buf; 329 struct pico_aodv_node *node = NULL; 330 union pico_address dest; 331 union pico_address orig; 332 struct pico_device *dev = NULL; 333 if (len != (int)sizeof(struct pico_aodv_rrep)) 334 return; 335 336 dest.ip4.addr = rep->dest; 337 orig.ip4.addr = rep->orig; 338 dev = pico_ipv4_link_find(&dest.ip4); 339 340 if (dev) /* Our reply packet got rebounced, no useful information here, no need to fwd. */ 341 return; 342 343 pico_aodv_dbg("::::::::::::: Parsing RREP for node %08x\n", rep->dest); 344 node = aodv_peer_eval(&dest, rep->dseq, 1); 345 if (node) { 346 pico_aodv_dbg("::::::::::::: Node found. Electing route and forwarding.\n"); 347 dest.ip4.addr = node->dest.ip4.addr; 348 if (rep->hop_count > 0) 349 aodv_elect_route(node, from, rep->hop_count, msginfo->dev); 350 else 351 aodv_elect_route(node, NULL, 0, msginfo->dev); 352 353 /* If we are the final destination for the reply (orig), no need to forward. */ 354 if (pico_ipv4_link_find(&orig.ip4)) { 355 node->flags |= PICO_AODV_NODE_ROUTE_UP; 356 } else { 357 aodv_forward(rep, msginfo, 1); 358 } 359 } 360} 361 362static void aodv_parse_rerr(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) 363{ 364 if ((uint32_t)len < sizeof(struct pico_aodv_rerr) || 365 (((uint32_t)len - sizeof(struct pico_aodv_rerr)) % sizeof(struct pico_aodv_unreachable)) > 0) 366 return; 367 368 (void)from; 369 (void)buf; 370 (void)len; 371 (void)msginfo; 372 /* TODO: invalidate routes. This only makes sense if we are using HELLO messages. */ 373} 374 375static void aodv_parse_rack(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) 376{ 377 if (len != (int)sizeof(struct pico_aodv_rack)) 378 return; 379 380 (void)from; 381 (void)buf; 382 (void)len; 383 (void)msginfo; 384} 385 386struct aodv_parser_s { 387 void (*call)(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo); 388}; 389 390static struct aodv_parser_s aodv_parser[5] = { 391 {.call = NULL}, 392 {.call = aodv_parse_rreq }, 393 {.call = aodv_parse_rrep }, 394 {.call = aodv_parse_rerr }, 395 {.call = aodv_parse_rack } 396}; 397 398 399static void pico_aodv_parse(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) 400{ 401 struct pico_aodv_node *node; 402 uint8_t hopcount = 0; 403 if ((buf[0] < 1) || (buf[0] > 4)) { 404 /* Type is invalid. Discard silently. */ 405 return; 406 } 407 408 if (buf[0] == AODV_TYPE_RREQ) { 409 hopcount = ((struct pico_aodv_rreq *)buf)->hop_count; 410 } 411 412 if (buf[0] == AODV_TYPE_RREP) { 413 hopcount = ((struct pico_aodv_rrep *)buf)->hop_count; 414 } 415 416 node = aodv_peer_eval(from, 0, 0); 417 if (!node) 418 node = aodv_peer_new(from); 419 420 if (node && (hopcount == 0)) { 421 aodv_elect_route(node, NULL, hopcount, msginfo->dev); 422 } 423 424 pico_aodv_dbg("Received AODV packet, ttl = %d\n", msginfo->ttl); 425 aodv_parser[buf[0]].call(from, buf, len, msginfo); 426} 427 428static void pico_aodv_socket_callback(uint16_t ev, struct pico_socket *s) 429{ 430 static uint8_t aodv_pkt[AODV_MAX_PKT]; 431 static union pico_address from; 432 static struct pico_msginfo msginfo; 433 uint16_t sport; 434 int r; 435 if (s != aodv_socket) 436 return; 437 438 if (ev & PICO_SOCK_EV_RD) { 439 r = pico_socket_recvfrom_extended(s, aodv_pkt, AODV_MAX_PKT, &from, &sport, &msginfo); 440 if (r <= 0) 441 return; 442 443 pico_aodv_dbg("Received AODV packet: %d bytes \n", r); 444 445 pico_aodv_parse(&from, aodv_pkt, r, &msginfo); 446 } 447} 448 449static void aodv_make_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req) 450{ 451 memset(req, 0, sizeof(struct pico_aodv_rreq)); 452 req->type = AODV_TYPE_RREQ; 453 454 if (0 == (node->flags & PICO_AODV_NODE_SYNC)) { 455 req->req_flags |= short_be(AODV_RREQ_FLAG_U); /* no known dseq, mark as U */ 456 req->dseq = 0; /* Unknown */ 457 } else { 458 req->dseq = long_be(node->dseq); 459 req->req_flags |= short_be(AODV_RREQ_FLAG_G); /* RFC3561 $6.3: we SHOULD set G flag as originators */ 460 } 461 462 /* Hop count = 0; */ 463 req->rreq_id = long_be(++pico_aodv_local_id); 464 req->dest = node->dest.ip4.addr; 465 req->oseq = long_be(pico_aodv_local_id); 466} 467 468static void aodv_retrans_rreq(pico_time now, void *arg) 469{ 470 struct pico_aodv_node *node = (struct pico_aodv_node *)arg; 471 struct pico_device *dev; 472 struct pico_tree_node *index; 473 static struct pico_aodv_rreq rreq; 474 struct pico_ipv4_link *ip4l = NULL; 475 struct pico_msginfo info = { 476 .dev = NULL, .tos = 0, .ttl = AODV_TTL_START 477 }; 478 (void)now; 479 480 memset(&rreq, 0, sizeof(rreq)); 481 482 if (node->flags & PICO_AODV_NODE_ROUTE_UP) { 483 pico_aodv_dbg("------------------------------------------------------ Node %08x already active.\n", node->dest.ip4.addr); 484 return; 485 } 486 487 if (node->ring_ttl > AODV_TTL_THRESHOLD) { 488 node->ring_ttl = AODV_NET_DIAMETER; 489 pico_aodv_dbg("----------- DIAMETER reached.\n"); 490 } 491 492 493 if (node->rreq_retry > AODV_RREQ_RETRIES) { 494 node->rreq_retry = 0; 495 node->ring_ttl = 0; 496 pico_aodv_dbg("Node is unreachable.\n"); 497 node->flags &= (uint16_t)(~PICO_AODV_NODE_ROUTE_DOWN); 498 return; 499 } 500 501 if (node->ring_ttl == AODV_NET_DIAMETER) { 502 node->rreq_retry++; 503 pico_aodv_dbg("Retry #%d\n", node->rreq_retry); 504 } 505 506 aodv_make_rreq(node, &rreq); 507 info.ttl = (uint8_t)node->ring_ttl; 508 pico_tree_foreach(index, &aodv_devices){ 509 dev = index->keyValue; 510 pico_aodv_set_dev(dev); 511 ip4l = pico_ipv4_link_by_dev(dev); 512 if (ip4l) { 513 rreq.orig = ip4l->address.addr; 514 pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); 515 } 516 } 517 if (node->ring_ttl < AODV_NET_DIAMETER) 518 node->ring_ttl = (uint8_t)(node->ring_ttl + AODV_TTL_INCREMENT); 519 520 if (!pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(node->ring_ttl), aodv_retrans_rreq, node)) { 521 pico_aodv_dbg("AODV: Failed to start retransmission timer\n"); 522 } 523} 524 525static int aodv_send_req(struct pico_aodv_node *node) 526{ 527 struct pico_device *dev; 528 struct pico_tree_node *index; 529 static struct pico_aodv_rreq rreq; 530 int n = 0; 531 struct pico_ipv4_link *ip4l = NULL; 532 struct pico_msginfo info = { 533 .dev = NULL, .tos = 0, .ttl = AODV_TTL_START 534 }; 535 memset(&rreq, 0, sizeof(rreq)); 536 537 if (PICO_AODV_ACTIVE(node)) 538 return 0; 539 540 node->flags |= PICO_AODV_NODE_REQUESTING; 541 542 if (pico_tree_empty(&aodv_devices)) 543 return n; 544 545 if (!aodv_socket) { 546 pico_err = PICO_ERR_EINVAL; 547 return -1; 548 } 549 550 if (node->flags & PICO_AODV_NODE_ROUTE_DOWN) { 551 info.ttl = node->metric; 552 } 553 554 aodv_make_rreq(node, &rreq); 555 pico_tree_foreach(index, &aodv_devices) { 556 dev = index->keyValue; 557 pico_aodv_set_dev(dev); 558 ip4l = pico_ipv4_link_by_dev(dev); 559 if (ip4l) { 560 rreq.orig = ip4l->address.addr; 561 pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); 562 n++; 563 } 564 } 565 if (!pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(1), aodv_retrans_rreq, node)) { 566 pico_aodv_dbg("AODV: Failed to start retransmission timer\n"); 567 return -1; 568 } 569 return n; 570} 571 572static void pico_aodv_expired(struct pico_aodv_node *node) 573{ 574 node->flags |= PICO_AODV_NODE_UNREACH; 575 node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_UP); 576 node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_DOWN); 577 pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); 578 node->ring_ttl = 0; 579 /* TODO: send err */ 580 581} 582 583static void pico_aodv_collector(pico_time now, void *arg) 584{ 585 struct pico_tree_node *index; 586 struct pico_aodv_node *node; 587 (void)arg; 588 (void)now; 589 pico_tree_foreach(index, &aodv_nodes){ 590 node = index->keyValue; 591 if (PICO_AODV_ACTIVE(node)) { 592 uint32_t lifetime = aodv_lifetime(node); 593 if (lifetime == 0) 594 pico_aodv_expired(node); 595 } 596 } 597 if (!pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL)) { 598 pico_aodv_dbg("AODV: Failed to start collector timer\n"); 599 /* TODO what to do now? garbage collection will not be restarted, leading to memory leaks */ 600 } 601} 602 603MOCKABLE int pico_aodv_init(void) 604{ 605 struct pico_ip4 any = { 606 0 607 }; 608 uint16_t port = short_be(PICO_AODV_PORT); 609 if (aodv_socket) { 610 pico_err = PICO_ERR_EADDRINUSE; 611 return -1; 612 } 613 614 aodv_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, pico_aodv_socket_callback); 615 if (!aodv_socket) 616 return -1; 617 618 if (pico_socket_bind(aodv_socket, &any, &port) != 0) { 619 uint16_t err = pico_err; 620 pico_socket_close(aodv_socket); 621 pico_err = err; 622 aodv_socket = NULL; 623 return -1; 624 } 625 626 pico_aodv_local_id = pico_rand(); 627 if (!pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL)) { 628 pico_aodv_dbg("AODV: Failed to start collector timer\n"); 629 pico_socket_close(aodv_socket); 630 aodv_socket = NULL; 631 return -1; 632 } 633 return 0; 634} 635 636 637int pico_aodv_add(struct pico_device *dev) 638{ 639 return (pico_tree_insert(&aodv_devices, dev)) ? (0) : (-1); 640} 641 642void pico_aodv_refresh(const union pico_address *addr) 643{ 644 struct pico_aodv_node *node = get_node_by_addr(addr); 645 if (node) { 646 node->last_seen = PICO_TIME_MS(); 647 } 648} 649 650int pico_aodv_lookup(const union pico_address *addr) 651{ 652 struct pico_aodv_node *node = get_node_by_addr(addr); 653 if (!node) 654 node = aodv_peer_new(addr); 655 656 if (!node) 657 return -1; 658 659 if ((node->flags & PICO_AODV_NODE_ROUTE_UP) || (node->flags & PICO_AODV_NODE_ROUTE_DOWN)) 660 return 0; 661 662 if (node->ring_ttl < AODV_TTL_START) { 663 node->ring_ttl = AODV_TTL_START; 664 aodv_send_req(node); 665 return 0; 666 } 667 668 pico_err = PICO_ERR_EINVAL; 669 return -1; 670} 671 672#else 673 674int pico_aodv_init(void) 675{ 676 return -1; 677} 678 679int pico_aodv_add(struct pico_device *dev) 680{ 681 (void)dev; 682 return -1; 683} 684 685int pico_aodv_lookup(const union pico_address *addr) 686{ 687 (void)addr; 688 return -1; 689} 690 691void pico_aodv_refresh(const union pico_address *addr) 692{ 693 (void)addr; 694} 695 696#endif 697