diff --git a/platform/cooja/net/radio-uip-uaodv.c b/platform/cooja/net/radio-uip-uaodv.c index 895d589c7..cb409cd77 100644 --- a/platform/cooja/net/radio-uip-uaodv.c +++ b/platform/cooja/net/radio-uip-uaodv.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * @(#)$Id: radio-uip-uaodv.c,v 1.1 2007/05/19 14:25:43 fros4943 Exp $ + * @(#)$Id: radio-uip-uaodv.c,v 1.2 2007/07/11 15:23:42 fros4943 Exp $ */ #include "radio-uip-uaodv.h" @@ -40,18 +40,56 @@ #include #include -static const struct radio_driver *radio; +#define UNICAST_ACKED 1 /* Define to acknowledge unicast packets */ +#define BAD_REPLY_ON_NO_ROUTE 0 /* TODO */ #define uip_udp_sender() (&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->srcipaddr) -#define HEADER_ID_LENGTH strlen(uniqueID) +#define HEADER_ID_LENGTH strlen(uniqueFwdHeader) #define HEADER_NEXT_FWD HEADER_ID_LENGTH #define HEADER_LENGTH HEADER_NEXT_FWD + 4 -static char* uniqueID = "fWd:"; + +#if UNICAST_ACKED + +#include "lib/crc16.h" +#include "list.h" + +enum { + EVENT_SEND_ACK +}; + +struct bufferedPacket { + struct bufferedPacket *next; + u8_t data[UIP_BUFSIZE]; + int len; + u8_t resends; + u8_t acked; + u16_t crc; + struct etimer etimer; +}; + +LIST(bufferedPackets); +MEMB(bufferedPacketsMEMB, struct bufferedPacket, 10); + +PROCESS(radio_uip_ack_process, "radio uIP uAODV ack process"); +#endif + +static const char* uniqueFwdHeader = "fWd:"; +#if UNICAST_ACKED +static const char* uniqueAckHeader = "aCk"; +#define ACK_HEADER_LENGTH 3 +#define ACK_LENGTH ACK_HEADER_LENGTH + 2 +#endif +static const struct radio_driver *radio; static struct uaodv_rt_entry *route; + /*---------------------------------------------------------------------------*/ +#if UNICAST_ACKED +int radio_uip_wait_for_ack(u8_t *buf, int len); +int radio_uip_is_ack(u8_t *buf, int len); +#endif int radio_uip_uaodv_add_header(u8_t *buf, int len, uip_ipaddr_t *addr); int radio_uip_uaodv_remove_header(u8_t *buf, int len); void radio_uip_uaodv_change_header(u8_t *buf, int len, uip_ipaddr_t *addr); @@ -62,6 +100,61 @@ int radio_uip_uaodv_fwd_is_me(u8_t *buf, int len); int radio_uip_uaodv_dest_is_me(u8_t *buf, int len); int radio_uip_uaodv_dest_port(u8_t *buf, int len); /*---------------------------------------------------------------------------*/ + +#if UNICAST_ACKED +PROCESS_THREAD(radio_uip_ack_process, ev, data) +{ + struct bufferedPacket *bufPacket; + + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD(); + + /* We should either send an ack, or resend a packet */ + if(ev == EVENT_SEND_ACK) { + char ackPacket[ACK_LENGTH]; + + /* Prepare and send ack */ + memcpy(ackPacket, uniqueAckHeader, ACK_HEADER_LENGTH); + memcpy(&ackPacket[ACK_HEADER_LENGTH], &data, 2); + radio->send(ackPacket, ACK_LENGTH); + + } else if(ev == PROCESS_EVENT_TIMER) { + + /* Locate which packet acknowledgement timed out */ + for(bufPacket = list_head(bufferedPackets); + bufPacket != NULL; + bufPacket = bufPacket->next) { + if (etimer_expired(&bufPacket->etimer)) { + + if (bufPacket->acked) { + /* This packet was already acknowledged! */ + list_remove(bufferedPackets, bufPacket); + memb_free(&bufferedPacketsMEMB, bufPacket); + } else if (bufPacket->resends < 3) { + /* Resend packet a number of times */ + bufPacket->resends++; + + /* TODO Compress packets? */ + radio->send(bufPacket->data, bufPacket->len); + etimer_restart(&bufPacket->etimer); + } else { + /* Too many resends, give up */ + list_remove(bufferedPackets, bufPacket); + memb_free(&bufferedPacketsMEMB, bufPacket); + /* TODO: Report non-delivered packet */ + } + } + } + } + + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +#endif + static void receiver(const struct radio_driver *d) { @@ -69,8 +162,29 @@ receiver(const struct radio_driver *d) if (uip_len <= 0) { return; } + +#if UNICAST_ACKED + /* Detect and parse acknowledgements */ + if (radio_uip_is_ack(&uip_buf[UIP_LLH_LEN], uip_len)) { + radio_uip_handle_ack(&uip_buf[UIP_LLH_LEN], uip_len); + return; + } +#endif + +#if UNICAST_ACKED + /* uAODV RREP and RERR messages should be acked as soon as possible */ + if (radio_uip_uaodv_dest_is_me(&uip_buf[UIP_LLH_LEN], uip_len) && + radio_uip_uaodv_dest_port(&uip_buf[UIP_LLH_LEN], uip_len) == HTONS(UAODV_UDPPORT)) { + struct uaodv_msg *m = (struct uaodv_msg *)&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if (m->type == UAODV_RREP_TYPE || m->type == UAODV_RERR_TYPE) { + u16_t crc; + crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len); + process_post(&radio_uip_ack_process, EVENT_SEND_ACK, crc); + } + } +#endif - /* If no uAODV header, receive as usual */ + /* If no uAODV header, receive as usual (compatibility) */ if (!radio_uip_uaodv_header_exists(&uip_buf[UIP_LLH_LEN], uip_len)) { uip_len = hc_inflate(&uip_buf[UIP_LLH_LEN], uip_len); tcpip_input(); @@ -92,7 +206,17 @@ receiver(const struct radio_driver *d) } /* If we are final destination, strip header and receive */ - if (radio_uip_uaodv_dest_is_me(&uip_buf[UIP_LLH_LEN], uip_len)) { + if (radio_uip_uaodv_dest_is_me(&uip_buf[UIP_LLH_LEN + HEADER_LENGTH], uip_len)) { + +#if UNICAST_ACKED + { + /* Unicast packets should be acked as soon as possible */ + u16_t crc; + crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len); + process_post(&radio_uip_ack_process, EVENT_SEND_ACK, crc); + } +#endif + uip_len = radio_uip_uaodv_remove_header(&uip_buf[UIP_LLH_LEN], uip_len); uip_len = hc_inflate(&uip_buf[UIP_LLH_LEN], uip_len); tcpip_input(); @@ -104,21 +228,51 @@ receiver(const struct radio_driver *d) /* TODO Assuming uAODV already knows a path */ route = uaodv_rt_lookup((&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN + HEADER_LENGTH])->destipaddr)); if (route != NULL) { + +#if UNICAST_ACKED + { + /* Ack last forwarder as soon as possible */ + u16_t crc; + crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len); + process_post(&radio_uip_ack_process, EVENT_SEND_ACK, crc); + } +#endif + radio_uip_uaodv_change_header(&uip_buf[UIP_LLH_LEN], uip_len, &route->nexthop); + +#if UNICAST_ACKED + /* Wait for ack from next forwarded */ + radio_uip_wait_for_ack(&uip_buf[UIP_LLH_LEN], uip_len); +#endif + d->send(&uip_buf[UIP_LLH_LEN], uip_len); + +#if BAD_REPLY_ON_NO_ROUTE + } else { + NOT IMPLEMENTED +#endif } - } /*---------------------------------------------------------------------------*/ u8_t radio_uip_uaodv_send(void) { - /* uAODV process messages should be sent as usual */ + /* uAODV RREQ messages should be sent as usual */ if (radio_uip_uaodv_dest_port(&uip_buf[UIP_LLH_LEN], uip_len) == HTONS(UAODV_UDPPORT)) { + struct uaodv_msg *m = (struct uaodv_msg *)&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if (m->type == UAODV_RREQ_TYPE) { + uip_len = hc_compress(&uip_buf[UIP_LLH_LEN], uip_len); + return radio->send(&uip_buf[UIP_LLH_LEN], uip_len); + } + + /* uAODV RREP and RERR messages should be acked */ +#if UNICAST_ACKED + radio_uip_wait_for_ack(&uip_buf[UIP_LLH_LEN], uip_len); +#endif uip_len = hc_compress(&uip_buf[UIP_LLH_LEN], uip_len); return radio->send(&uip_buf[UIP_LLH_LEN], uip_len); } - + if (radio_uip_uaodv_is_broadcast(uip_udp_sender())) { uip_len = hc_compress(&uip_buf[UIP_LLH_LEN], uip_len); @@ -131,6 +285,11 @@ radio_uip_uaodv_send(void) route = uaodv_rt_lookup((&((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->destipaddr)); if (route == NULL) return UIP_FW_NOROUTE; uip_len = radio_uip_uaodv_add_header(&uip_buf[UIP_LLH_LEN], uip_len, &route->nexthop); /* TODO Correct? */ + +#if UNICAST_ACKED + /* We expect to get an ack for this unicast packet */ + radio_uip_wait_for_ack(&uip_buf[UIP_LLH_LEN], uip_len); +#endif } return radio->send(&uip_buf[UIP_LLH_LEN], uip_len); @@ -139,15 +298,95 @@ radio_uip_uaodv_send(void) void radio_uip_uaodv_init(const struct radio_driver *d) { +#if UNICAST_ACKED + memb_init(&bufferedPacketsMEMB); + list_init(bufferedPackets); + process_start(&radio_uip_ack_process, NULL); +#endif + radio = d; radio->set_receive_function(receiver); - radio->on();} + radio->on(); +} +#if UNICAST_ACKED +/*---------------------------------------------------------------------------*/ +u16_t +radio_uip_calc_crc(u8_t *buf, int len) +{ + u16_t crcacc = 0xffff; + int counter; + + for (counter = 0; counter < len; counter++) { + crcacc = crc16_add(buf[counter], crcacc); + } + return crcacc; +} +/*---------------------------------------------------------------------------*/ +int +radio_uip_wait_for_ack(u8_t *buf, int len) +{ + struct bufferedPacket *bufPacket; + + /* Allocate storage memory */ + bufPacket = (struct bufferedPacket *)memb_alloc(&bufferedPacketsMEMB); + if (bufPacket == NULL) { + return 1; + } + + /* Store packet specific data and set timer */ + memcpy(bufPacket->data, buf, len); + bufPacket->len = len; + bufPacket->resends = 0; + bufPacket->acked = 0; + bufPacket->crc = radio_uip_calc_crc(&uip_buf[UIP_LLH_LEN], uip_len); + PROCESS_CONTEXT_BEGIN(&radio_uip_ack_process); + etimer_set(&bufPacket->etimer, CLOCK_SECOND * 1); + PROCESS_CONTEXT_END(&radio_uip_ack_process); + + /* Add to list for later reference */ + list_add(bufferedPackets, bufPacket); + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +radio_uip_is_ack(u8_t *buf, int len) +{ + struct bufferedPacket *bufPacket; + + if (uip_len != ACK_LENGTH) + return 0; + + return strncmp(buf, uniqueAckHeader, ACK_HEADER_LENGTH) == 0; +} +/*---------------------------------------------------------------------------*/ +int +radio_uip_handle_ack(u8_t *buf, int len) +{ + struct bufferedPacket *bufPacket; + u16_t ackCRC; + + memcpy(&ackCRC, &buf[ACK_HEADER_LENGTH], 2); + + /* Locate which packet was acknowledged */ + for(bufPacket = list_head(bufferedPackets); + bufPacket != NULL; + bufPacket = bufPacket->next) { + if (bufPacket->crc == ackCRC) { + /* Signal packet has been acknowledged */ + bufPacket->acked = 1; + return 0; + } + } + return 1; +} +#endif /*---------------------------------------------------------------------------*/ int radio_uip_uaodv_add_header(u8_t *buf, int len, uip_ipaddr_t *addr) { memcpy(&buf[HEADER_LENGTH], buf, len); - memcpy(buf, uniqueID, HEADER_ID_LENGTH); + memcpy(buf, uniqueFwdHeader, HEADER_ID_LENGTH); memcpy(&buf[HEADER_NEXT_FWD], (char*)addr, 4); return HEADER_LENGTH + len; } @@ -169,7 +408,7 @@ radio_uip_uaodv_change_header(u8_t *buf, int len, uip_ipaddr_t *addr) int radio_uip_uaodv_header_exists(u8_t *buf, int len) { - return !memcmp(buf, uniqueID, HEADER_ID_LENGTH); + return !memcmp(buf, uniqueFwdHeader, HEADER_ID_LENGTH); } /*---------------------------------------------------------------------------*/ int @@ -193,12 +432,14 @@ radio_uip_uaodv_fwd_is_me(u8_t *buf, int len) int radio_uip_uaodv_dest_is_me(u8_t *buf, int len) { - return !memcmp((&((struct uip_udpip_hdr *)&buf[HEADER_LENGTH])->destipaddr), &uip_hostaddr, 4); + return !memcmp((&((struct uip_udpip_hdr *)buf)->destipaddr), &uip_hostaddr, 4); } /*---------------------------------------------------------------------------*/ int radio_uip_uaodv_dest_port(u8_t *buf, int len) { + if (len < sizeof(struct uip_udpip_hdr)) + return -1; return (int) ((struct uip_udpip_hdr *)buf)->destport; } /*---------------------------------------------------------------------------*/