Contiki 3.x
radio-uip-uaodv.c
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 #include "radio-uip-uaodv.h"
34 #include "net/ip/uip.h"
35 #include "net/uaodv.h"
36 #include "net/ipv4/uaodv-rt.h"
37 #include "net/ipv4/uaodv-def.h"
38 #include "lib/crc16.h"
39 #include "list.h"
40 #include <string.h>
41 #include <stdio.h>
42 
43 /* Packet buffer size and retransmission settings */
44 #define MAX_BUFFERED_PACKETS 10
45 #define MAX_RETRANSMISSIONS_RREP 16
46 #define MAX_RETRANSMISSIONS_UNICAST 16
47 
48 /* Forward packet (header) */
49 #define FWD_ID "fWd:"
50 #define FWD_ID_LENGTH 4
51 #define FWD_NEXT_IP FWD_ID_LENGTH
52 #define FWD_PACKET_LENGTH (FWD_NEXT_IP + 4)
53 
54 /* Acknowledgement packet */
55 #define ACK_ID "aCk"
56 #define ACK_ID_LENGTH 3
57 #define ACK_CRC ACK_ID_LENGTH
58 #define ACK_PACKET_LENGTH (ACK_ID_LENGTH + 2)
59 #define ACK_TIMEOUT (CLOCK_SECOND / 50) * (random_rand() % 100)
60 
61 enum {
62  EVENT_SEND_ACK
63 };
64 
65 struct buf_packet {
66  struct buf_packet *next;
67  uint8_t data[UIP_BUFSIZE];
68  int len;
69  uint8_t resends;
70  uint8_t acked;
71  uint8_t want_ack;
72  uint16_t crc;
73  uip_ipaddr_t finaldest;
74  struct etimer etimer;
75 };
76 
77 LIST(buf_packet_list);
78 MEMB(buf_packet_mem, struct buf_packet, MAX_BUFFERED_PACKETS);
79 
80 PROCESS(radio_uip_process, "radio uIP uAODV process");
81 
82 static const struct radio_driver *radio;
83 
84 
85 
86 /*---------------------------------------------------------------------------*/
87 static void receiver(const struct radio_driver *d);
88 uint8_t radio_uip_uaodv_send(void);
89 void radio_uip_uaodv_init(const struct radio_driver *d);
90 int radio_uip_handle_ack(uint8_t *buf, int len);
91 uint16_t radio_uip_calc_crc(uint8_t *buf, int len);
92 int radio_uip_buffer_outgoing_packet(uint8_t *buf, int len, uip_ipaddr_t *dest, int max_sends);
93 int radio_uip_is_ack(uint8_t *buf, int len);
94 int radio_uip_uaodv_add_header(uint8_t *buf, int len, uip_ipaddr_t *addr);
95 int radio_uip_uaodv_remove_header(uint8_t *buf, int len);
96 void radio_uip_uaodv_change_header(uint8_t *buf, int len, uip_ipaddr_t *addr);
97 int radio_uip_uaodv_header_exists(uint8_t *buf, int len);
98 int radio_uip_uaodv_is_broadcast(uip_ipaddr_t *addr);
99 int radio_uip_uaodv_fwd_is_broadcast(uint8_t *buf, int len);
100 int radio_uip_uaodv_fwd_is_me(uint8_t *buf, int len);
101 int radio_uip_uaodv_dest_is_me(uint8_t *buf, int len);
102 int radio_uip_uaodv_dest_port(uint8_t *buf, int len);
103 /*---------------------------------------------------------------------------*/
104 
105 /* Main process - handles (re)transmissions and acks */
106 PROCESS_THREAD(radio_uip_process, ev, data)
107 {
108  struct buf_packet *packet;
109 
110  PROCESS_BEGIN();
111 
112  while(1) {
113  PROCESS_YIELD();
114 
115  if(ev == EVENT_SEND_ACK) {
116 
117  /* Prepare and send ack for given 16-bit CRC */
118  uint8_t ackPacket[ACK_PACKET_LENGTH];
119  memcpy(ackPacket, ACK_ID, ACK_ID_LENGTH);
120  ackPacket[ACK_CRC] = ((uint16_t) data >> 8);
121  ackPacket[ACK_CRC+1] = ((uint16_t) data & 0xff);
122  radio->send(ackPacket, ACK_PACKET_LENGTH);
123 
124  } else if(ev == PROCESS_EVENT_TIMER) {
125  /* Locate which packet acknowledgement timed out */
126  for(packet = list_head(buf_packet_list);
127  packet != NULL;
128  packet = packet->next) {
129  if (etimer_expired(&packet->etimer)) {
130 
131  if (packet->acked) {
132  /* Already acked packet, remove silently */
133  list_remove(buf_packet_list, packet);
134  memb_free(&buf_packet_mem, packet);
135 
136  } else if (packet->resends > 0) {
137  /* Resend packet */
138  packet->resends--;
139  etimer_set(&packet->etimer, ACK_TIMEOUT);
140 
141  radio->send(packet->data, packet->len);
142 
143  } else {
144  /* Packet was resent maximum number of times */
145 
146  /* If an ack was expected, flag destination to bad */
147  if (packet->want_ack && !uip_ipaddr_cmp(&packet->finaldest, &uip_broadcast_addr)) {
148  uaodv_bad_dest(&packet->finaldest);
149  }
150 
151  list_remove(buf_packet_list, packet);
152  memb_free(&buf_packet_mem, packet);
153  }
154  }
155  }
156  }
157  }
158  PROCESS_END();
159 }
160 /*---------------------------------------------------------------------------*/
161 static void
162 receiver(const struct radio_driver *d)
163 {
164  uip_len = d->read(&uip_buf[UIP_LLH_LEN], UIP_BUFSIZE - UIP_LLH_LEN);
165  if (uip_len <= 0) {
166  return;
167  }
168 
169  /* Detect and handle acknowledgements */
170  if (radio_uip_is_ack(&uip_buf[UIP_LLH_LEN], uip_len)) {
171  radio_uip_handle_ack(&uip_buf[UIP_LLH_LEN], uip_len);
172  return;
173  }
174 
175  /* If no uAODV header, receive as usual */
176  if (!radio_uip_uaodv_header_exists(&uip_buf[UIP_LLH_LEN], uip_len)) {
177  tcpip_input();
178  return;
179  }
180 
181  /* Drop packet unless we are the uAODV forwarder */
182  if (!radio_uip_uaodv_fwd_is_me(&uip_buf[UIP_LLH_LEN], uip_len)) {
183  return;
184  }
185 
186  {
187  /* Send ack as soon as possible */
188  uint16_t crc;
189  crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len);
190  process_post(&radio_uip_process, EVENT_SEND_ACK, (void*) (uint32_t) crc);
191  }
192 
193  /* Strip header and receive packet */
194  uip_len = radio_uip_uaodv_remove_header(&uip_buf[UIP_LLH_LEN], uip_len);
195  tcpip_input();
196 }
197 /*---------------------------------------------------------------------------*/
198 uint8_t
199 radio_uip_uaodv_send(void)
200 {
201  struct uaodv_rt_entry *route;
202 
203  /* Transmit broadcast packets without header */
204  if (radio_uip_uaodv_is_broadcast(&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->destipaddr)) {
205  return radio_uip_buffer_outgoing_packet(&uip_buf[UIP_LLH_LEN], uip_len, (void*) &uip_broadcast_addr, 1);
206  }
207 
208  /* Transmit uAODV packets with headers but without using route table */
209  if (((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->proto == UIP_PROTO_UDP
210  && radio_uip_uaodv_dest_port(&uip_buf[UIP_LLH_LEN], uip_len) == UIP_HTONS(UAODV_UDPPORT)) {
211  uip_ipaddr_t nexthop;
212  memcpy(&nexthop, &((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->destipaddr, 4);
213 
214  uip_len = radio_uip_uaodv_add_header(
215  &uip_buf[UIP_LLH_LEN],
216  uip_len,
217  &nexthop
218  );
219 
220  /* Buffer packet for persistent transmission */
221  return radio_uip_buffer_outgoing_packet(
222  &uip_buf[UIP_LLH_LEN],
223  uip_len,
224  &((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN + FWD_PACKET_LENGTH])->destipaddr,
225  MAX_RETRANSMISSIONS_RREP);
226  }
227 
228  /* Fetch already prepared uAODV route */
229  route = uaodv_rt_lookup_any((&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->destipaddr));
230  if (route == NULL || route->is_bad) {
231 
232  /* If we are forwarding, notify origin of this bad route */
233  if (tcpip_is_forwarding) {
234  uaodv_bad_dest((&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->destipaddr));
235  }
236 
237  return UIP_FW_DROPPED;
238  }
239 
240  /* Add header and buffer packet for persistent transmission */
241  uip_len = radio_uip_uaodv_add_header(&uip_buf[UIP_LLH_LEN], uip_len, uip_ds6_route_nexthop(route)); /* TODO Correct? */
242  return radio_uip_buffer_outgoing_packet(
243  &uip_buf[UIP_LLH_LEN],
244  uip_len,
245  &route->dest,
246  MAX_RETRANSMISSIONS_UNICAST);
247 }
248 /*---------------------------------------------------------------------------*/
249 void
250 radio_uip_uaodv_init(const struct radio_driver *d)
251 {
252  /* Prepare buffers and start main process */
253  memb_init(&buf_packet_mem);
254  list_init(buf_packet_list);
255  process_start(&radio_uip_process, NULL);
256 
257  radio = d;
258  radio->set_receive_function(receiver);
259  radio->on();
260 }
261 /*---------------------------------------------------------------------------*/
262 uint16_t
263 radio_uip_calc_crc(uint8_t *buf, int len)
264 {
265  uint16_t crcacc = 0xffff;
266  int counter;
267 
268  /* TODO Not effective */
269  for (counter = 0; counter < len; counter++) {
270  crcacc = crc16_add(buf[counter], crcacc);
271  }
272  return crcacc;
273 }
274 /*---------------------------------------------------------------------------*/
275 int
276 radio_uip_buffer_outgoing_packet(uint8_t *buf, int len, uip_ipaddr_t *dest, int max_sends)
277 {
278  struct buf_packet *packet;
279 
280  uint16_t crc;
281 
282  /* Calculate packet's unique CRC */
283  crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len);
284 
285  /* Check if this packet is already being transmitted */
286  for(packet = list_head(buf_packet_list);
287  packet != NULL;
288  packet = packet->next) {
289  if (packet->crc == crc) {
290  return UIP_FW_DROPPED;
291  }
292  }
293 
294  /* Allocate storage memory */
295  packet = (struct buf_packet *)memb_alloc(&buf_packet_mem);
296  if (packet == NULL) {
297  return UIP_FW_DROPPED;
298  }
299 
300  /* Prepare packet buffer */
301  memcpy(packet->data, buf, len);
302  packet->len = len;
303  packet->resends = max_sends;
304  packet->acked = 0;
305  if (packet->resends > 1)
306  packet->want_ack = 1;
307  else
308  packet->want_ack = 0;
309  memcpy(&packet->finaldest, dest, 4);
310  packet->crc = crc;
311 
312  /* Set first transmission to as soon as possible */
313  PROCESS_CONTEXT_BEGIN(&radio_uip_process);
314  etimer_set(&packet->etimer, 0);
315  PROCESS_CONTEXT_END(&radio_uip_process);
316 
317  /* Add to buffered packets list */
318  list_add(buf_packet_list, packet);
319 
320  return UIP_FW_OK;
321 }
322 /*---------------------------------------------------------------------------*/
323 int
324 radio_uip_is_ack(uint8_t *buf, int len)
325 {
326  if (len != ACK_PACKET_LENGTH)
327  return 0;
328 
329  return memcmp(buf, ACK_ID, ACK_ID_LENGTH) == 0;
330 
331 }
332 /*---------------------------------------------------------------------------*/
333 int
334 radio_uip_handle_ack(uint8_t *buf, int len)
335 {
336  struct buf_packet *packet;
337  uint16_t ackCRC;
338 
339  ackCRC = (uint16_t) (buf[ACK_CRC] << 8) + (uint16_t) (0xff&buf[ACK_CRC+1]);
340 
341  /* Locate which packet was acknowledged */
342  for(packet = list_head(buf_packet_list);
343  packet != NULL;
344  packet = packet->next) {
345  if (packet->crc == ackCRC) {
346  /* Signal packet has been acknowledged */
347  packet->acked = 1;
348  return 0;
349  }
350  }
351 
352  return 1;
353 }
354 /*---------------------------------------------------------------------------*/
355 int
356 radio_uip_uaodv_add_header(uint8_t *buf, int len, uip_ipaddr_t *addr)
357 {
358  uint8_t tempbuf[len];
359  memcpy(tempbuf, buf, len);
360  memcpy(&buf[FWD_PACKET_LENGTH], tempbuf, len);
361  memcpy(buf, FWD_ID, FWD_ID_LENGTH);
362  memcpy(&buf[FWD_NEXT_IP], (char*)addr, 4);
363  return FWD_PACKET_LENGTH + len;
364 }
365 /*---------------------------------------------------------------------------*/
366 int
367 radio_uip_uaodv_remove_header(uint8_t *buf, int len)
368 {
369  uint8_t tempbuf[len];
370  memcpy(tempbuf, &buf[FWD_PACKET_LENGTH], len);
371  memcpy(buf, tempbuf, len);
372  return len - FWD_PACKET_LENGTH;
373 }
374 /*---------------------------------------------------------------------------*/
375 void
376 radio_uip_uaodv_change_header(uint8_t *buf, int len, uip_ipaddr_t *addr)
377 {
378  memcpy(&buf[FWD_NEXT_IP], addr, 4);
379 }
380 /*---------------------------------------------------------------------------*/
381 int
382 radio_uip_uaodv_header_exists(uint8_t *buf, int len)
383 {
384  return !memcmp(buf, FWD_ID, FWD_ID_LENGTH);
385 }
386 /*---------------------------------------------------------------------------*/
387 int
388 radio_uip_uaodv_is_broadcast(uip_ipaddr_t *addr)
389 {
390  return uip_ipaddr_cmp(addr, &uip_broadcast_addr);
391 }
392 /*---------------------------------------------------------------------------*/
393 int
394 radio_uip_uaodv_fwd_is_broadcast(uint8_t *buf, int len)
395 {
396  return radio_uip_uaodv_is_broadcast((uip_ipaddr_t*) &buf[FWD_NEXT_IP]);
397 }
398 /*---------------------------------------------------------------------------*/
399 int
400 radio_uip_uaodv_fwd_is_me(uint8_t *buf, int len)
401 {
402  return !memcmp(&buf[FWD_NEXT_IP], &uip_hostaddr, 4);
403 }
404 /*---------------------------------------------------------------------------*/
405 int
406 radio_uip_uaodv_dest_is_me(uint8_t *buf, int len)
407 {
408  return !memcmp((&((struct uip_udpip_hdr *)buf)->destipaddr), &uip_hostaddr, 4);
409 }
410 /*---------------------------------------------------------------------------*/
411 int
412 radio_uip_uaodv_dest_port(uint8_t *buf, int len)
413 {
414  if (len < sizeof(struct uip_udpip_hdr))
415  return -1;
416  return (int) ((struct uip_udpip_hdr *)buf)->destport;
417 }
418 /*---------------------------------------------------------------------------*/
#define UIP_FW_DROPPED
An error message that indicates that a packet that should be forwarded or output was dropped...
Definition: uip-fw.h:171
Linked list manipulation routines.
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:529
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the uIP TCP/IP stack.
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define NULL
The null pointer.
The structure of a device driver for a radio in Contiki.
Definition: radio.h:225
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1238
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
int(* send)(const void *payload, unsigned short payload_len)
Prepare &amp; transmit a packet.
Definition: radio.h:236
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:160
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
int(* on)(void)
Turn the radio on.
Definition: radio.h:252
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define LIST(name)
Declare a linked list.
Definition: list.h:86
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
Routing tables for the micro implementation of the AODV ad hoc routing protocol ...
#define PROCESS_YIELD()
Yield the currently running process.
Definition: process.h:164
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
Definitions for the micro implementation of the AODV ad hoc routing protocol ...
unsigned short crc16_add(unsigned char b, unsigned short acc)
Update an accumulated CRC16 checksum with one byte.
Definition: crc16.c:47
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
Definition: process.h:426
#define UIP_FW_OK
A non-error message that indicates that something went OK.
Definition: uip-fw.h:132
Header file for the CRC16 calculcation
A timer.
Definition: etimer.h:76
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Definition: radio.h:239
#define PROCESS_CONTEXT_END(p)
End a context switch.
Definition: process.h:440