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