Merge branch 'contiki' into osd

This commit is contained in:
Harald Pichler 2015-05-15 20:48:26 +02:00
commit 877bf27f5a
245 changed files with 8117 additions and 6356 deletions

View file

@ -30,7 +30,7 @@ before_script:
- sudo apt-get -qq install libc6:i386 libgcc1:i386 gcc-4.6-base:i386
libstdc++5:i386 libstdc++6:i386
## Install old APCS ARM toolchain for mc1233x, cc2538 and mbxxx
## Install old APCS ARM toolchain for mc1233x and mbxxx
- if [ ${BUILD_ARCH:-0} = arm-apcs ] ; then
$WGET https://raw.githubusercontent.com/wiki/malvira/libmc1322x/files/arm-2008q3-66-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 &&
tar xjf arm-2008q3*.tar.bz2 -C /tmp/ &&
@ -41,15 +41,16 @@ before_script:
## Install mainline ARM toolchain. gcc-arm-none-eabi is available
## in Ubuntu >= 14.04, but this external PPA is needed for 12.04.
- if [ ${BUILD_ARCH:-0} = arm ] ; then
## Install srecord
- if [ ${BUILD_ARCH:-0} = arm-aapcs ] ; then
sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded &&
sudo apt-get -qq update &&
sudo apt-get -qq install gcc-arm-none-eabi &&
sudo apt-get -qq install gcc-arm-none-eabi srecord &&
arm-none-eabi-gcc --version ;
fi
## Download and extract cc26xxware
- if [ ${BUILD_ARCH:-0} = arm ] ; then
- if [ ${BUILD_ARCH:-0} = arm-aapcs ] ; then
wget http://www.ti.com/lit/sw/swrc296/swrc296.zip &&
unzip swrc296.zip &&
export TI_CC26XXWARE=cc26xxware_2_20_06_14829 ;
@ -110,6 +111,7 @@ env:
- BUILD_TYPE='rpl'
- BUILD_TYPE='rime'
- BUILD_TYPE='ipv6'
- BUILD_TYPE='ip64' MAKE_TARGETS='cooja'
- BUILD_TYPE='hello-world'
- BUILD_TYPE='base'
# XXX: netperf disabled b/c it's flaky
@ -122,6 +124,6 @@ env:
- BUILD_TYPE='compile-8051-ports' BUILD_CATEGORY='compile' BUILD_ARCH='8051'
- BUILD_TYPE='compile-arm-apcs-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-apcs'
- BUILD_TYPE='compile-6502-ports' BUILD_CATEGORY='compile' BUILD_ARCH='6502'
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm'
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-aapcs'
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'

View file

@ -88,7 +88,7 @@ makestrings(void)
uip_getdraddr(&addr);
makeaddr(&addr, gateway);
addrptr = resolv_getserver();
addrptr = uip_nameserver_get(0);
if(addrptr != NULL) {
makeaddr(addrptr, dnsserver);
}
@ -147,7 +147,7 @@ dhcpc_configured(const struct dhcpc_state *s)
uip_sethostaddr(&s->ipaddr);
uip_setnetmask(&s->netmask);
uip_setdraddr(&s->default_router);
resolv_conf(&s->dnsaddr);
uip_nameserver_update(&s->dnsaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
set_statustext("Configured.");
process_post(PROCESS_CURRENT(), SHOWCONFIG, NULL);
}

View file

@ -113,7 +113,7 @@ makestrings(void)
makeaddr(&addr, gateway);
#if UIP_UDP
addrptr = resolv_getserver();
addrptr = uip_nameserver_get(0);
if(addrptr != NULL) {
makeaddr(addrptr, dnsserver);
}
@ -152,7 +152,7 @@ apply_tcpipconfig(void)
#if UIP_UDP
nullterminate(dnsserver);
if(uiplib_ipaddrconv(dnsserver, &addr)) {
resolv_conf(&addr);
uip_nameserver_update(&addr, UIP_NAMESERVER_INFINITE_LIFETIME);
}
#endif /* UIP_UDP */
}

View file

@ -1,4 +0,0 @@
rest-coap_src = coap-common.c coap-server.c
APPS += rest-common
include $(CONTIKI)/apps/rest-common/Makefile.rest-common

View file

@ -1,113 +0,0 @@
/*
* coap-common.c
*
* Created on: Aug 30, 2010
* Author: dogan
*/
#ifdef CONTIKI_TARGET_NETSIM
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#else
#include "contiki.h"
#include "contiki-net.h"
#include <string.h>
#endif
#include "coap-common.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
void init_packet(coap_packet_t* packet)
{
packet->ver = 1;
packet->type = 0;
packet->option_count = 0;
packet->code = 0;
packet->tid = 0;
packet->options = NULL;
packet->url = NULL;
packet->url_len = 0;
packet->query = NULL;
packet->query_len = 0;
packet->payload = NULL;
packet->payload_len = 0;
}
int serialize_packet(coap_packet_t* packet, uint8_t* buffer)
{
int index = 0;
header_option_t* option = NULL;
uint16_t option_delta = 0;
buffer[0] = (packet->ver) << COAP_HEADER_VERSION_POSITION;
buffer[0] |= (packet->type) << COAP_HEADER_TYPE_POSITION;
buffer[0] |= packet->option_count;
buffer[1] = packet->code;
uint16_t temp = uip_htons(packet->tid);
memcpy(
(void*)&buffer[2],
(void*)(&temp),
sizeof(packet->tid));
index += 4;
PRINTF("serialize option_count %u\n", packet->option_count);
/*Options should be sorted beforehand*/
for (option = packet->options ; option ; option = option->next){
uint16_t delta = option->option - option_delta;
if ( !delta ){
PRINTF("WARNING: Delta==Zero\n");
}
buffer[index] = (delta) << COAP_HEADER_OPTION_DELTA_POSITION;
PRINTF("option %u len %u option diff %u option_value addr %x option addr %x next option addr %x", option->option, option->len, option->option - option_delta, (unsigned int) option->value, (unsigned int)option, (unsigned int)option->next);
int i = 0;
for ( ; i < option->len ; i++ ){
PRINTF(" (%u)", option->value[i]);
}
PRINTF("\n");
if (option->len < 0xF){
buffer[index] |= option->len;
index++;
} else{
buffer[index] |= (0xF); //1111
buffer[index + 1] = option->len - (0xF);
index += 2;
}
memcpy((char*)&buffer[index], option->value, option->len);
index += option->len;
option_delta = option->option;
}
if(packet->payload){
memcpy(&buffer[index], packet->payload, packet->payload_len);
index += packet->payload_len;
}
return index;
}

View file

@ -1,144 +0,0 @@
/*
* coap.h
*
* Created on: Aug 25, 2010
* Author: dogan
*/
#ifndef COAP_COMMON_H_
#define COAP_COMMON_H_
#include "contiki-net.h"
/*COAP method types*/
typedef enum {
COAP_GET = 1,
COAP_POST,
COAP_PUT,
COAP_DELETE
} coap_method_t;
typedef enum {
MESSAGE_TYPE_CON,
MESSAGE_TYPE_NON,
MESSAGE_TYPE_ACK,
MESSAGE_TYPE_RST
} message_type;
typedef enum {
OK_200 = 80,
CREATED_201 = 81,
NOT_MODIFIED_304 = 124,
BAD_REQUEST_400 = 160,
NOT_FOUND_404 = 164,
METHOD_NOT_ALLOWED_405 = 165,
UNSUPPORTED_MADIA_TYPE_415 = 175,
INTERNAL_SERVER_ERROR_500 = 200,
BAD_GATEWAY_502 = 202,
GATEWAY_TIMEOUT_504 = 204
} status_code_t;
typedef enum {
Option_Type_Content_Type = 1,
Option_Type_Max_Age = 2,
Option_Type_Etag = 4,
Option_Type_Uri_Authority = 5,
Option_Type_Location = 6,
Option_Type_Uri_Path = 9,
Option_Type_Subscription_Lifetime = 10,
Option_Type_Token = 11,
Option_Type_Block = 13,
Option_Type_Uri_Query = 15
} option_type;
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1,
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_X_BXML = 48,
APPLICATION_FASTINFOSET = 49,
APPLICATION_SOAP_FASTINFOSET = 50,
APPLICATION_JSON = 51
} content_type_t;
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_TYPE_MASK 0x30
#define COAP_HEADER_OPTION_COUNT_MASK 0x0F
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
#define COAP_HEADER_VERSION_POSITION 6
#define COAP_HEADER_TYPE_POSITION 4
#define COAP_HEADER_OPTION_DELTA_POSITION 4
#define REQUEST_BUFFER_SIZE 200
#define DEFAULT_CONTENT_TYPE 0
#define DEFAULT_MAX_AGE 60
#define DEFAULT_URI_AUTHORITY ""
#define DEFAULT_URI_PATH ""
//keep open requests and their xactid
struct header_option_t
{
struct header_option_t* next;
uint16_t option;
uint16_t len;
uint8_t* value;
};
typedef struct header_option_t header_option_t;
struct block_option_t {
uint32_t number;
uint8_t more;
uint8_t size;
};
typedef struct block_option_t block_option_t;
typedef struct
{
uint8_t ver; //2-bits currently set to 1.
uint8_t type; //2-bits Confirmable (0), Non-Confirmable (1), Acknowledgment (2) or Reset (3)
uint8_t option_count; //4-bits
uint8_t code; //8-bits Method or response code
uint16_t tid; //16-bit unsigned integer
header_option_t* options;
char* url; //put it just as a shortcut or else need to parse options everytime to access it.
uint16_t url_len;
char* query;
uint16_t query_len;
uint16_t payload_len;
uint8_t* payload;
uip_ipaddr_t addr;
} coap_packet_t;
/*error definitions*/
typedef enum
{
NO_ERROR,
/*Memory errors*/
MEMORY_ALLOC_ERR,
MEMORY_BOUNDARY_EXCEEDED
} error_t;
int serialize_packet(coap_packet_t* request, uint8_t* buffer);
void init_packet(coap_packet_t* packet);
#endif /* COAP_COMMON_H_ */

View file

@ -1,545 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /*for isxdigit*/
#include "contiki.h"
#include "contiki-net.h"
#include "buffer.h"
#include "coap-server.h"
#include "rest-util.h"
#include "rest.h" /*added for periodic_resource*/
#include "dev/leds.h"
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
#include "static-routing.h"
#endif
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#define MAX_PAYLOAD_LEN 120
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
static struct uip_udp_conn *server_conn;
static uint16_t current_tid;
static service_callback service_cbk = NULL;
void
coap_set_service_callback(service_callback callback)
{
service_cbk = callback;
}
void
parse_message(coap_packet_t* packet, uint8_t* buf, uint16_t size)
{
int processed = 0;
int i = 0;
PRINTF("parse_message size %d-->\n",size);
init_packet(packet);
packet->ver = (buf[0] & COAP_HEADER_VERSION_MASK) >> COAP_HEADER_VERSION_POSITION;
packet->type = (buf[0] & COAP_HEADER_TYPE_MASK) >> COAP_HEADER_TYPE_POSITION;
packet->option_count = buf[0] & COAP_HEADER_OPTION_COUNT_MASK;
packet->code = buf[1];
packet->tid = (buf[2] << 8) + buf[3];
processed += 4;
if (packet->option_count) {
int option_index = 0;
uint8_t option_delta;
uint16_t option_len;
uint8_t* option_buf = buf + processed;
packet->options = (header_option_t*)allocate_buffer(sizeof(header_option_t) * packet->option_count);
if (packet->options) {
header_option_t* current_option = packet->options;
header_option_t* prev_option = NULL;
while(option_index < packet->option_count) {
/*FIXME : put boundary controls*/
option_delta = (option_buf[i] & COAP_HEADER_OPTION_DELTA_MASK) >> COAP_HEADER_OPTION_DELTA_POSITION;
option_len = (option_buf[i] & COAP_HEADER_OPTION_SHORT_LENGTH_MASK);
i++;
if (option_len == 0xf) {
option_len += option_buf[i];
i++;
}
current_option->option = option_delta;
current_option->len = option_len;
current_option->value = option_buf + i;
if (option_index) {
prev_option->next = current_option;
/*This field defines the difference between the option Type of
* this option and the previous option (or zero for the first option)*/
current_option->option += prev_option->option;
}
if (current_option->option == Option_Type_Uri_Path) {
packet->url = (char*)current_option->value;
packet->url_len = current_option->len;
} else if (current_option->option == Option_Type_Uri_Query){
packet->query = (char*)current_option->value;
packet->query_len = current_option->len;
}
PRINTF("OPTION %d %u %s \n", current_option->option, current_option->len, current_option->value);
i += option_len;
option_index++;
prev_option = current_option++;
}
current_option->next = NULL;
} else {
PRINTF("MEMORY ERROR\n"); /*FIXME : add control here*/
return;
}
}
processed += i;
/**/
if (processed < size) {
packet->payload = &buf[processed];
packet->payload_len = size - processed;
}
/*FIXME url is not decoded - is necessary?*/
/*If query is not already provided via Uri_Query option then check URL*/
if (packet->url && !packet->query) {
if ((packet->query = strchr(packet->url, '?'))) {
uint16_t total_url_len = packet->url_len;
/*set query len and update url len so that it does not include query part now*/
packet->url_len = packet->query - packet->url;
packet->query++;
packet->query_len = packet->url + total_url_len - packet->query;
PRINTF("url %s, url_len %u, query %s, query_len %u\n", packet->url, packet->url_len, packet->query, packet->query_len);
}
}
PRINTF("PACKET ver:%d type:%d oc:%d \ncode:%d tid:%u url:%s len:%u payload:%s pay_len %u\n", (int)packet->ver, (int)packet->type, (int)packet->option_count, (int)packet->code, packet->tid, packet->url, packet->url_len, packet->payload, packet->payload_len);
}
int
coap_get_query_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
{
if (packet->query) {
return get_variable(name, packet->query, packet->query_len, output, output_size, 0);
}
return 0;
}
int
coap_get_post_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
{
if (packet->payload) {
return get_variable(name, packet->payload, packet->payload_len, output, output_size, 1);
}
return 0;
}
static header_option_t*
allocate_header_option(uint16_t variable_len)
{
PRINTF("sizeof header_option_t %u variable size %u\n", sizeof(header_option_t), variable_len);
uint8_t* buffer = allocate_buffer(sizeof(header_option_t) + variable_len);
if (buffer){
header_option_t* option = (header_option_t*) buffer;
option->next = NULL;
option->len = 0;
option->value = buffer + sizeof(header_option_t);
return option;
}
return NULL;
}
/*FIXME : does not overwrite the same option yet.*/
int
coap_set_option(coap_packet_t* packet, option_type option_type, uint16_t len, uint8_t* value)
{
PRINTF("coap_set_option len %u\n", len);
header_option_t* option = allocate_header_option(len);
if (option){
option->next = NULL;
option->len = len;
option->option = option_type;
memcpy(option->value, value, len);
header_option_t* option_current = packet->options;
header_option_t* prev = NULL;
while (option_current){
if (option_current->option > option->option){
break;
}
prev = option_current;
option_current = option_current->next;
}
if (!prev){
if (option_current){
option->next = option_current;
}
packet->options = option;
} else{
option->next = option_current;
prev->next = option;
}
packet->option_count++;
PRINTF("option->len %u option->option %u option->value %x next %x\n", option->len, option->option, (unsigned int) option->value, (unsigned int)option->next);
int i = 0;
for ( ; i < option->len ; i++ ){
PRINTF(" (%u)", option->value[i]);
}
PRINTF("\n");
return 1;
}
return 0;
}
header_option_t*
coap_get_option(coap_packet_t* packet, option_type option_type)
{
PRINTF("coap_get_option count: %u--> \n", packet->option_count);
int i = 0;
header_option_t* current_option = packet->options;
for (; i < packet->option_count; current_option = current_option->next, i++) {
PRINTF("Current option: %u\n", current_option->option);
if (current_option->option == option_type){
return current_option;
}
}
return NULL;
}
static void
fill_error_packet(coap_packet_t* packet, int error, uint16_t tid)
{
packet->ver=1;
packet->option_count=0;
packet->url=NULL;
packet->options=NULL;
switch (error){
case MEMORY_ALLOC_ERR:
packet->code=INTERNAL_SERVER_ERROR_500;
packet->tid=tid;
packet->type=MESSAGE_TYPE_ACK;
break;
default:
break;
}
}
static void
init_response(coap_packet_t* request, coap_packet_t* response)
{
init_packet(response);
if(request->type == MESSAGE_TYPE_CON) {
response->code = OK_200;
response->tid = request->tid;
response->type = MESSAGE_TYPE_ACK;
}
}
uint16_t
coap_get_payload(coap_packet_t* packet, uint8_t** payload)
{
if (packet->payload) {
*payload = packet->payload;
return packet->payload_len;
} else {
*payload = NULL;
return 0;
}
}
int
coap_set_payload(coap_packet_t* packet, uint8_t* payload, uint16_t size)
{
packet->payload = copy_to_buffer(payload, size);
if (packet->payload) {
packet->payload_len = size;
return 1;
}
return 0;
}
int
coap_set_header_content_type(coap_packet_t* packet, content_type_t content_type)
{
uint16_t len = 1;
return coap_set_option(packet, Option_Type_Content_Type, len, (uint8_t*) &content_type);
}
content_type_t
coap_get_header_content_type(coap_packet_t* packet)
{
header_option_t* option = coap_get_option(packet, Option_Type_Content_Type);
if (option){
return (uint8_t)(*(option->value));
}
return DEFAULT_CONTENT_TYPE;
}
int
coap_get_header_subscription_lifetime(coap_packet_t* packet, uint32_t* lifetime)
{
PRINTF("coap_get_header_subscription_lifetime --> \n");
header_option_t* option = coap_get_option(packet, Option_Type_Subscription_Lifetime);
if (option){
PRINTF("Subs Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
*lifetime = read_int(option->value, option->len);
return 1;
}
return 0;
}
int
coap_set_header_subscription_lifetime(coap_packet_t* packet, uint32_t lifetime)
{
uint8_t temp[4];
uint16_t len = write_variable_int(temp, lifetime);
return coap_set_option(packet, Option_Type_Subscription_Lifetime, len, temp);
}
int
coap_get_header_block(coap_packet_t* packet, block_option_t* block)
{
uint32_t all_block;
PRINTF("coap_get_header_block --> \n");
header_option_t* option = coap_get_option(packet, Option_Type_Block);
if (option){
PRINTF("Block Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
all_block = read_int(option->value, option->len);
block->number = all_block >> 4;
block->more = (all_block & 0x8) >> 3;
block->size = (all_block & 0x7);
return 1;
}
return 0;
}
int
coap_set_header_block(coap_packet_t* packet, uint32_t number, uint8_t more, uint8_t size)
{
uint8_t temp[4];
size = log_2(size/16);
number = number << 4;
number |= (more << 3) & 0x8;
number |= size & 0x7;
uint16_t len = write_variable_int(temp, number);
PRINTF("number %lu, more %u, size %u block[0] %u block[1] %u block[2] %u block[3] %u\n",
number, (uint16_t)more, (uint16_t)size, (uint16_t)temp[0], (uint16_t)temp[1], (uint16_t)temp[2], (uint16_t)temp[3]);
return coap_set_option(packet, Option_Type_Block, len, temp);
}
int
coap_set_header_uri(coap_packet_t* packet, char* uri)
{
return coap_set_option(packet, Option_Type_Uri_Path, strlen(uri), (uint8_t*) uri);
}
int
coap_set_header_etag(coap_packet_t* packet, uint8_t* etag, uint8_t size)
{
return coap_set_option(packet, Option_Type_Etag, size, etag);
}
void
coap_set_code(coap_packet_t* packet, status_code_t code)
{
packet->code = (uint8_t)code;
}
coap_method_t
coap_get_method(coap_packet_t* packet)
{
return (coap_method_t)packet->code;
}
void
coap_set_method(coap_packet_t* packet, coap_method_t method)
{
packet->code = (uint8_t)method;
}
static void send_request(coap_packet_t* request, struct uip_udp_conn *client_conn)
{
char buf[MAX_PAYLOAD_LEN];
int data_size = 0;
data_size = serialize_packet(request, buf);
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
uip_htons(client_conn->lport), uip_htons(client_conn->rport));
PRINTF("Sending to: ");
PRINT6ADDR(&client_conn->ripaddr);
uip_udp_packet_send(client_conn, buf, data_size);
}
static int
handle_incoming_data(void)
{
int error=NO_ERROR;
char buf[MAX_PAYLOAD_LEN];
PRINTF("uip_datalen received %u \n",(uint16_t)uip_datalen());
char* data = (char *)uip_appdata + uip_ext_len;
uint16_t datalen = uip_datalen() - uip_ext_len;
int data_size = 0;
if (uip_newdata()) {
((char *)data)[datalen] = 0;
PRINTF("Server received: '%s' (port:%u) from ", (char *)data, uip_htons(UIP_UDP_BUF->srcport));
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
parse_message(request, (uint8_t*)data, datalen);
uip_ipaddr_copy(&request->addr, &UIP_IP_BUF->srcipaddr);
if (request->type != MESSAGE_TYPE_ACK) {
coap_packet_t* response = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
init_response(request, response);
if (service_cbk) {
service_cbk(request, response);
}
data_size = serialize_packet(response, buf);
}
delete_buffer();
} else {
PRINTF("Memory Alloc Error\n");
error = MEMORY_ALLOC_ERR;
/*FIXME : Crappy way of accessing TID of the incoming packet, fix it!*/
coap_packet_t error_packet;
fill_error_packet(&error_packet,error, (data[2] << 8) + data[3]);
data_size = serialize_packet(&error_packet, buf);
}
uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
server_conn->rport = UIP_UDP_BUF->srcport;
PRINTF("Responding with message size: %d\n",data_size);
uip_udp_packet_send(server_conn, buf, data_size);
/* Restore server connection to allow data from any node */
memset(&server_conn->ripaddr, 0, sizeof(server_conn->ripaddr));
server_conn->rport = 0;
}
return error;
}
process_event_t resource_changed_event;
void
resource_changed(struct periodic_resource_t* resource)
{
process_post(&coap_server, resource_changed_event, (process_data_t)resource);
}
/*---------------------------------------------------------------------------*/
PROCESS(coap_server, "Coap Server");
PROCESS_THREAD(coap_server, ev, data)
{
PROCESS_BEGIN();
PRINTF("COAP SERVER\n");
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
set_global_address();
configure_routing();
#endif
current_tid = random_rand();
resource_changed_event = process_alloc_event();
/* new connection with remote host */
server_conn = udp_new(NULL, uip_htons(0), NULL);
udp_bind(server_conn, uip_htons(MOTE_SERVER_LISTEN_PORT));
PRINTF("Local/remote port %u/%u\n", uip_htons(server_conn->lport), uip_htons(server_conn->rport));
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
handle_incoming_data();
} else if (ev == resource_changed_event) {
periodic_resource_t* resource = (periodic_resource_t*)data;
PRINTF("resource_changed_event \n");
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
init_packet(request);
coap_set_code(request, COAP_GET);
request->tid = current_tid++;
coap_set_header_subscription_lifetime(request, resource->lifetime);
coap_set_header_uri(request, (char *)resource->resource->url);
if (resource->periodic_request_generator) {
resource->periodic_request_generator(request);
}
if (!resource->client_conn) {
/*FIXME send port is fixed for now to 61616*/
resource->client_conn = udp_new(&resource->addr, uip_htons(61616), NULL);
udp_bind(resource->client_conn, uip_htons(MOTE_CLIENT_LISTEN_PORT));
}
if (resource->client_conn) {
send_request(request, resource->client_conn);
}
delete_buffer();
}
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View file

@ -1,54 +0,0 @@
#ifndef COAPSERVER_H_
#define COAPSERVER_H_
#define COAP_DATA_BUFF_SIZE 300
#include "contiki.h"
#include "coap-common.h"
/*Declare process*/
PROCESS_NAME(coap_server);
#define MOTE_SERVER_LISTEN_PORT 61616
#define MOTE_CLIENT_LISTEN_PORT 61617
void parse_message(coap_packet_t* packet, uint8_t* buf, uint16_t size);
uint16_t coap_get_payload(coap_packet_t* packet, uint8_t** payload);
int coap_set_payload(coap_packet_t* packet, uint8_t* payload, uint16_t size);
content_type_t coap_get_header_content_type(coap_packet_t* packet);
int coap_set_header_content_type(coap_packet_t* packet, content_type_t content_type);
int coap_get_header_subscription_lifetime(coap_packet_t* packet, uint32_t* lifetime);
int coap_set_header_subscription_lifetime(coap_packet_t* packet, uint32_t lifetime);
int coap_get_header_block(coap_packet_t* packet, block_option_t* block);
int coap_set_header_block(coap_packet_t* packet, uint32_t number, uint8_t more, uint8_t size);
int coap_set_header_uri(coap_packet_t* packet, char* uri);
int coap_set_header_etag(coap_packet_t* packet, uint8_t* etag, uint8_t size);
void coap_set_code(coap_packet_t* packet, status_code_t code);
coap_method_t coap_get_method(coap_packet_t* packet);
void coap_set_method(coap_packet_t* packet, coap_method_t method);
int coap_get_query_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size);
int coap_get_post_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size);
header_option_t* coap_get_option(coap_packet_t* packet, option_type option_type);
int coap_set_option(coap_packet_t* packet, option_type option_type, uint16_t len, uint8_t* value);
/*Type definition of the service callback*/
typedef int (*service_callback) (coap_packet_t* request, coap_packet_t* response);
/*
*Setter of the service callback, this callback will be called in case of HTTP request.
*/
void coap_set_service_callback(service_callback callback);
struct periodic_resource_t;
void resource_changed(struct periodic_resource_t* resource);
#endif /* COAPSERVER_H_ */

View file

@ -1 +0,0 @@
rest-common_src = rest.c rest-util.c buffer.c static-routing.c

View file

@ -1,79 +0,0 @@
/*
* buffer.c
*
* Created on: Oct 19, 2010
* Author: dogan
*/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "buffer.h"
uint8_t* data_buffer;
uint16_t buffer_size;
uint16_t buffer_index;
void
delete_buffer(void)
{
if (data_buffer) {
free(data_buffer);
data_buffer = NULL;
buffer_index = 0;
buffer_size = 0;
}
}
uint8_t*
init_buffer(uint16_t size)
{
delete_buffer();
data_buffer = (uint8_t*)malloc(size);
if (data_buffer) {
buffer_size = size;
}
buffer_index = 0;
return data_buffer;
}
uint8_t*
allocate_buffer(uint16_t size)
{
uint8_t* buffer = NULL;
int rem = 0;
/*To get rid of alignment problems, always allocate even size*/
rem = size % 4;
if (rem) {
size+=(4-rem);
}
if (buffer_index + size < buffer_size) {
buffer = data_buffer + buffer_index;
buffer_index += size;
}
return buffer;
}
uint8_t*
copy_to_buffer(void* data, uint16_t len)
{
uint8_t* buffer = allocate_buffer(len);
if (buffer) {
memcpy(buffer, data, len);
}
return buffer;
}
uint8_t*
copy_text_to_buffer(char* text)
{
uint8_t* buffer = allocate_buffer(strlen(text) + 1);
if (buffer) {
strcpy(buffer, text);
}
return buffer;
}

View file

@ -1,17 +0,0 @@
/*
* buffer.h
*
* Created on: Oct 19, 2010
* Author: dogan
*/
#ifndef BUFFER_H_
#define BUFFER_H_
void delete_buffer(void);
uint8_t* init_buffer(uint16_t size);
uint8_t* allocate_buffer(uint16_t size);
uint8_t* copy_to_buffer(void* data, uint16_t len);
uint8_t* copy_text_to_buffer(char* text);
#endif /* BUFFER_H_ */

View file

@ -1,118 +0,0 @@
#include <stddef.h> /*for size_t*/
#include <ctype.h> /*for isxdigit*/
#include <string.h>
#include "contiki-net.h"
/*Copied from mangoose http server*/
size_t
decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form)
{
size_t i, j;
int a, b;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
for (i = j = 0; i < srclen && j < dstlen - 1; i++, j++) {
if (src[i] == '%' &&
isxdigit(* (unsigned char *) (src + i + 1)) &&
isxdigit(* (unsigned char *) (src + i + 2))) {
a = tolower(* (unsigned char *) (src + i + 1));
b = tolower(* (unsigned char *) (src + i + 2));
dst[j] = ((HEXTOI(a) << 4) | HEXTOI(b)) & 0xff;
i += 2;
} else if (is_form && src[i] == '+') {
dst[j] = ' ';
} else {
dst[j] = src[i];
}
}
dst[j] = '\0'; /* Null-terminate the destination */
return ( i == srclen );
}
/*Copied from mangoose http server*/
int
get_variable(const char *name, const char *buffer, size_t buflen, char* output, size_t output_len, int decode_type)
{
const char *start = NULL, *end = NULL, *end_of_value;
size_t var_len = 0;
/*initialize the output buffer first*/
*output = 0;
var_len = strlen(name);
end = buffer + buflen;
for (start = buffer; start + var_len < end; start++){
if ((start == buffer || start[-1] == '&') && start[var_len] == '=' &&
! strncmp(name, start, var_len)) {
/* Point p to variable value */
start += var_len + 1;
/* Point s to the end of the value */
end_of_value = (const char *) memchr(start, '&', end - start);
if (end_of_value == NULL) {
end_of_value = end;
}
return decode(start, end_of_value - start, output, output_len, decode_type);
}
}
return 0;
}
uint32_t
read_int(uint8_t *buf, uint8_t size)
{
uint32_t data = 0;
if (size >= 1 && size <= 4) {
uint8_t *p = (uint8_t *)&data;
memcpy(p + 4 - size, buf, size);
}
return uip_ntohl(data);
}
int
write_int(uint8_t *buf, uint32_t data, uint8_t size)
{
int success = 0;
if (size >= 1 && size <= 4) {
data = uip_htonl(data);
memcpy(buf, ((char*)(&data)) + 4 - size, size);
success = size;
}
return success;
}
int
write_variable_int(uint8_t *buf, uint32_t data)
{
uint8_t size = 4;
if (data <= 0xFF) {
size = 1;
} else if (data <= 0xFFFF) {
size = 2;
} else if (data <= 0xFFFFFF) {
size = 3;
}
return write_int(buf, data, size);
}
uint16_t log_2(uint16_t value)
{
uint16_t result = 0;
do {
value = value >> 1;
result++;
} while (value);
return result ? result - 1 : result;
}

View file

@ -1,20 +0,0 @@
/*
* rest-util.h
*
* Created on: Oct 26, 2010
* Author: dogan
*/
#ifndef RESTUTIL_H_
#define RESTUTIL_H_
size_t decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form);
int get_variable(const char *name, const char *buffer, size_t buflen, char* output, size_t output_len, int decode_type);
uint32_t read_int(uint8_t *buf, uint8_t size);
int write_int(uint8_t *buf, uint32_t data, uint8_t size);
int write_variable_int(uint8_t *buf, uint32_t data);
uint16_t log_2(uint16_t value);
#endif /* RESTUTIL_H_ */

View file

@ -1,333 +0,0 @@
#include "contiki.h"
#include <string.h> /*for string operations in match_addresses*/
#include "rest.h"
#include "buffer.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
/*FIXME it is possible to define some of the rest functions as MACROs rather than functions full of ifdefs.*/
PROCESS_NAME(rest_manager_process);
LIST(restful_services);
LIST(restful_periodic_services);
void
rest_init(void)
{
list_init(restful_services);
#ifdef WITH_COAP
coap_set_service_callback(rest_invoke_restful_service);
#else /*WITH_COAP*/
http_set_service_callback(rest_invoke_restful_service);
#endif /*WITH_COAP*/
/*Start rest framework process*/
process_start(&rest_manager_process, NULL);
}
void
rest_activate_resource(resource_t* resource)
{
/*add it to the restful web service link list*/
list_add(restful_services, resource);
}
void
rest_activate_periodic_resource(periodic_resource_t* periodic_resource)
{
list_add(restful_periodic_services, periodic_resource);
rest_activate_resource(periodic_resource->resource);
}
void
rest_set_user_data(resource_t* resource, void* user_data)
{
resource->user_data = user_data;
}
void*
rest_get_user_data(resource_t* resource)
{
return resource->user_data;
}
void
rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler)
{
resource->pre_handler = pre_handler;
}
void
rest_set_post_handler(resource_t* resource, restful_post_handler post_handler)
{
resource->post_handler = post_handler;
}
list_t
rest_get_resources(void)
{
return restful_services;
}
void
rest_set_response_status(RESPONSE* response, status_code_t status)
{
#ifdef WITH_COAP
coap_set_code(response, status);
#else /*WITH_COAP*/
http_set_status(response, status);
#endif /*WITH_COAP*/
}
#ifdef WITH_COAP
static method_t coap_to_rest_method(coap_method_t method)
{
return (method_t)(1 << (method - 1));
}
static coap_method_t rest_to_coap_method(method_t method)
{
coap_method_t coap_method = COAP_GET;
switch (method) {
case METHOD_GET:
coap_method = COAP_GET;
break;
case METHOD_POST:
coap_method = COAP_POST;
break;
case METHOD_PUT:
coap_method = COAP_PUT;
break;
case METHOD_DELETE:
coap_method = COAP_DELETE;
break;
default:
break;
}
return coap_method;
}
#endif /*WITH_COAP*/
method_t
rest_get_method_type(REQUEST* request)
{
#ifdef WITH_COAP
return coap_to_rest_method(coap_get_method(request));
#else
return (method_t)(request->request_type);
#endif
}
/*Only defined for COAP for now.*/
#ifdef WITH_COAP
void
rest_set_method_type(REQUEST* request, method_t method)
{
coap_set_method(request, rest_to_coap_method(method));
}
#endif /*WITH_COAP*/
void
rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size)
{
#ifdef WITH_COAP
coap_set_payload(response, payload, size);
#else
http_set_res_payload(response, payload, size);
#endif /*WITH_COAP*/
}
/*Only defined for COAP for now.*/
#ifdef WITH_COAP
void
rest_set_request_payload(REQUEST* request, uint8_t* payload, uint16_t size)
{
coap_set_payload(request, payload, size);
}
#endif /*WITH_COAP*/
int
rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
{
#ifdef WITH_COAP
return coap_get_query_variable(request, name, output, output_size);
#else
return http_get_query_variable(request, name, output, output_size);
#endif /*WITH_COAP*/
}
int
rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
{
#ifdef WITH_COAP
return coap_get_post_variable(request, name, output, output_size);
#else
return http_get_post_variable(request, name, output, output_size);
#endif /*WITH_COAP*/
}
content_type_t
rest_get_header_content_type(REQUEST* request)
{
#ifdef WITH_COAP
return coap_get_header_content_type(request);
#else
return http_get_header_content_type(request);
#endif /*WITH_COAP*/
}
int
rest_set_header_content_type(RESPONSE* response, content_type_t content_type)
{
#ifdef WITH_COAP
return coap_set_header_content_type(response, content_type);
#else
return http_set_res_header(response, HTTP_HEADER_NAME_CONTENT_TYPE, http_get_content_type_string(content_type), 1);
#endif /*WITH_COAP*/
}
int
rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size)
{
#ifdef WITH_COAP
return coap_set_header_etag(response, etag, size);
#else
/*FIXME for now etag should be a "/0" ending string for http part*/
char temp_etag[10];
memcpy(temp_etag, etag, size);
temp_etag[size] = 0;
return http_set_res_header(response, HTTP_HEADER_NAME_ETAG, temp_etag, 1);
#endif /*WITH_COAP*/
}
int
rest_invoke_restful_service(REQUEST* request, RESPONSE* response)
{
int found = 0;
const char* url = request->url;
uint16_t url_len = request->url_len;
PRINTF("rest_invoke_restful_service url %s url_len %d -->\n", url, url_len);
resource_t* resource = NULL;
for (resource = (resource_t*)list_head(restful_services); resource; resource = resource->next) {
/*if the web service handles that kind of requests and urls matches*/
if (url && strlen(resource->url) == url_len && strncmp(resource->url, url, url_len) == 0){
found = 1;
method_t method = rest_get_method_type(request);
PRINTF("method %u, resource->methods_to_handle %u\n", (uint16_t)method, resource->methods_to_handle);
if (resource->methods_to_handle & method) {
/*FIXME Need to move somewhere else*/
#ifdef WITH_COAP
uint32_t lifetime = 0;
if (coap_get_header_subscription_lifetime(request, &lifetime)) {
PRINTF("Lifetime %lu\n", lifetime);
periodic_resource_t* periodic_resource = NULL;
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);
periodic_resource;
periodic_resource = periodic_resource->next) {
if (periodic_resource->resource == resource) {
PRINTF("Periodic Resource Found\n");
PRINT6ADDR(&request->addr);
periodic_resource->lifetime = lifetime;
stimer_set(periodic_resource->lifetime_timer, lifetime);
uip_ipaddr_copy(&periodic_resource->addr, &request->addr);
}
}
}
#endif /*WITH_COAP*/
/*call pre handler if it exists*/
if (!resource->pre_handler || resource->pre_handler(request, response)) {
/* call handler function*/
resource->handler(request, response);
/*call post handler if it exists*/
if (resource->post_handler) {
resource->post_handler(request, response);
}
}
} else {
rest_set_response_status(response, METHOD_NOT_ALLOWED_405);
}
break;
}
}
if (!found) {
rest_set_response_status(response, NOT_FOUND_404);
}
return found;
}
PROCESS(rest_manager_process, "Rest Process");
PROCESS_THREAD(rest_manager_process, ev, data)
{
PROCESS_BEGIN();
/*start the coap or http server*/
process_start(SERVER_PROCESS, NULL);
PROCESS_PAUSE();
/*Periodic resources are only available to COAP implementation*/
#if 0
#ifdef WITH_COAP
periodic_resource_t* periodic_resource = NULL;
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services); periodic_resource; periodic_resource = periodic_resource->next) {
if (periodic_resource->period) {
PRINTF("Set timer for Res: %s to %lu\n", periodic_resource->resource->url, periodic_resource->period);
etimer_set(periodic_resource->handler_cb_timer, periodic_resource->period);
}
}
while(1) {
PROCESS_WAIT_EVENT();
if (ev == PROCESS_EVENT_TIMER) {
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);periodic_resource;periodic_resource = periodic_resource->next) {
if (periodic_resource->period && etimer_expired(periodic_resource->handler_cb_timer)) {
PRINTF("Etimer expired for %s (period:%lu life:%lu)\n", periodic_resource->resource->url, periodic_resource->period, periodic_resource->lifetime);
/*call the periodic handler function if exists*/
if (periodic_resource->periodic_handler) {
if ((periodic_resource->periodic_handler)(periodic_resource->resource)) {
PRINTF("RES CHANGE\n");
if (!stimer_expired(periodic_resource->lifetime_timer)) {
PRINTF("TIMER NOT EXPIRED\n");
resource_changed(periodic_resource);
periodic_resource->lifetime = stimer_remaining(periodic_resource->lifetime_timer);
} else {
periodic_resource->lifetime = 0;
}
}
PRINTF("%s lifetime %lu (%lu) expired %d\n", periodic_resource->resource->url, stimer_remaining(periodic_resource->lifetime_timer), periodic_resource->lifetime, stimer_expired(periodic_resource->lifetime_timer));
}
etimer_reset(periodic_resource->handler_cb_timer);
}
}
}
}
#endif /*WITH_COAP*/
#endif
PROCESS_END();
}

View file

@ -1,179 +0,0 @@
#ifndef REST_H_
#define REST_H_
/*includes*/
#include "contiki.h"
#include "contiki-lib.h"
#ifdef WITH_COAP
#include "coap-common.h"
#include "coap-server.h"
#define REQUEST coap_packet_t
#define RESPONSE coap_packet_t
#define SERVER_PROCESS (&coap_server)
#else /*WITH_COAP*/
/*WITH_HTTP*/
#include "http-common.h"
#include "http-server.h"
#define REQUEST http_request_t
#define RESPONSE http_response_t
#define SERVER_PROCESS (&http_server)
#endif /*WITH_COAP*/
struct resource_t;
/*REST method types*/
typedef enum {
METHOD_GET = (1 << 0),
METHOD_POST = (1 << 1),
METHOD_PUT = (1 << 2),
METHOD_DELETE = (1 << 3)
} method_t;
/*Signature of handler functions*/
typedef void (*restful_handler) (REQUEST* request, RESPONSE* response);
typedef int (*restful_pre_handler) (REQUEST* request, RESPONSE* response);
typedef void (*restful_post_handler) (REQUEST* request, RESPONSE* response);
typedef int (*restful_periodic_handler) (struct resource_t* resource);
typedef void (*restful_periodic_request_generator) (REQUEST* request);
/*
* Data structure representing a resource in REST.
*/
struct resource_t {
struct resource_t *next; /*points to next resource defined*/
method_t methods_to_handle; /*handled HTTP methods*/
const char* url; /*handled URL*/
restful_handler handler; /*handler function*/
restful_pre_handler pre_handler; /*to be called before handler, may perform initializations*/
restful_post_handler post_handler; /*to be called after handler, may perform finalizations (cleanup, etc)*/
void* user_data; /*pointer to user specific data*/
};
typedef struct resource_t resource_t;
struct periodic_resource_t {
struct periodic_resource_t *next;
resource_t *resource;
uint32_t period;
struct etimer* handler_cb_timer;
struct stimer* lifetime_timer;
restful_periodic_handler periodic_handler;
restful_periodic_request_generator periodic_request_generator;
uint32_t lifetime;
uip_ipaddr_t addr;
struct uip_udp_conn *client_conn;
};
typedef struct periodic_resource_t periodic_resource_t;
/*
* Macro to define a Resource
* Resources are statically defined for the sake of efficiency and better memory management.
*/
#define RESOURCE(name, methods_to_handle, url) \
void name##_handler(REQUEST*, RESPONSE*); \
resource_t resource_##name = {NULL, methods_to_handle, url, name##_handler, NULL, NULL, NULL}
/*
* Macro to define a Periodic Resource
*/
#define PERIODIC_RESOURCE(name, methods_to_handle, url, period) \
RESOURCE(name, methods_to_handle, url); \
int name##_periodic_handler(resource_t*); \
void name##_periodic_request_generator(REQUEST*); \
struct etimer handler_cb_timer_##name; \
struct stimer lifetime_timer_##name; \
periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period, &handler_cb_timer_##name, &lifetime_timer_##name, name##_periodic_handler, name##_periodic_request_generator, 0}
/*
* Initializes REST framework and starts HTTP or COAP process
*/
void rest_init(void);
/*
* Resources wanted to be accessible should be activated with the following code.
*/
void rest_activate_resource(resource_t* resource);
void rest_activate_periodic_resource(periodic_resource_t* periodic_resource);
/*
* To be called by HTTP/COAP server as a callback function when a new service request appears.
* This function dispatches the corresponding RESTful service.
*/
int rest_invoke_restful_service(REQUEST* request, RESPONSE* response);
/*
* Returns the resource list
*/
list_t rest_get_resources(void);
/*
* Returns query variable in the URL.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size);
/*
* Returns variable in the Post Data/Payload.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size);
method_t rest_get_method_type(REQUEST* request);
void rest_set_method_type(REQUEST* request, method_t method);
/*
* Getter for the request content type
*/
content_type_t rest_get_header_content_type(REQUEST* request);
/*
* Setter for the response content type
*/
int rest_set_header_content_type(RESPONSE* response, content_type_t content_type);
/*
* Setter for the response etag header
*/
int rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size);
/*
* Setter for the status code (200, 201, etc) of the response.
*/
void rest_set_response_status(RESPONSE* response, status_code_t status);
/*
* Setter for the payload of the request and response
*/
void rest_set_request_payload(RESPONSE* response, uint8_t* payload, uint16_t size);
void rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size);
/*
* Getter method for user specific data.
*/
void* rest_get_user_data(resource_t* resource);
/*
* Setter method for user specific data.
*/
void rest_set_user_data(resource_t* resource, void* user_data);
/*
* Sets the pre handler function of the Resource.
* If set, this function will be called just before the original handler function.
* Can be used to setup work before resource handling.
*/
void rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler);
/*
* Sets the post handler function of the Resource.
* If set, this function will be called just after the original handler function.
* Can be used to do cleanup (deallocate memory, etc) after resource handling.
*/
void rest_set_post_handler(resource_t* resource, restful_post_handler post_handler);
#endif /*REST_H_*/

View file

@ -1,71 +0,0 @@
/*
* static-routing.c
*
* Created on: Oct 12, 2010
* Author: dogan
*/
#include "static-routing.h"
#if !defined (CONTIKI_TARGET_MINIMAL_NET) /* Any other targets will be added here (&& ! defined (OTHER))*/
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#if !UIP_CONF_IPV6_RPL
#include "contiki-net.h"
#include "sys/node-id.h"
void set_global_address(void)
{
uip_ipaddr_t ipaddr;
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
}
void configure_routing(void)
{
PRINTF("configure_routing\n");
if (node_id < 10) { /*COOJA*/
/*Go to desktop machine over border router*/
ADD_ROUTE(DESKTOP_MACHINE_ID, COOJA_BORDER_ROUTER_ID);
} else { /*SKY*/
if (node_id < 20) { /*First hops (ids between 10-20)*/
/*Go to desktop machine over border router*/
ADD_ROUTE(DESKTOP_MACHINE_ID, BORDER_ROUTER_ID);
}
switch(node_id) {
case 12:
ADD_ROUTE(22, 22); /*Go to next hop over the local address of next hop*/
break;
case 13:
ADD_ROUTE(23, 23); /*Go to next hop over the local address of next hop*/
break;
case 22:
ADD_ROUTE(0, 12); /*Go to desktop machine over the corresponding first hop*/
break;
case 23:
ADD_ROUTE(0, 13); /*Go to desktop machine over the corresponding first hop*/
break;
default:
break;
}
}
}
#endif /*!UIP_CONF_IPV6_RPL*/
#endif /*CONTIKI_TARGET_MINIMAL_NET*/

View file

@ -1,61 +0,0 @@
/*
* static-routing.h
*
* Created on: Oct 12, 2010
* Author: dogan
*/
#ifndef STATICROUTING_H_
#define STATICROUTING_H_
#if !defined (CONTIKI_TARGET_MINIMAL_NET)
#define NODE_IP(nodeid,type,ipaddr) NODE_##nodeid##_##type(ipaddr)
/*desktop machine*/
#define DESKTOP_MACHINE_ID 0
#define NODE_0_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0x0001)
/*Cooja Nodes*/
#define COOJA_BORDER_ROUTER_ID 1
#define NODE_1_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101)
#define NODE_1_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101)
#define NODE_2_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202)
#define NODE_2_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202)
#define NODE_3_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7403, 0x0003, 0x0303)
#define NODE_3_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7403, 0x0003, 0x0303)
#define NODE_6_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606)
#define NODE_6_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606)
/*real nodes*/
#define BORDER_ROUTER_ID 11
#define NODE_11_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1)
#define NODE_11_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1)
#define NODE_12_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a)
#define NODE_12_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a)
#define NODE_13_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575)
#define NODE_13_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575)
#define NODE_22_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6)
#define NODE_22_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6)
#define NODE_23_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a)
#define NODE_23_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a)
#define ADD_ROUTE(node_global,node_local)\
do{\
uip_ipaddr_t ipaddr_local, ipaddr_global;\
NODE_IP(node_global, GLOBAL, &ipaddr_global);\
NODE_IP(node_local, LOCAL, &ipaddr_local);\
uip_ds6_route_add(&ipaddr_global, 128, &ipaddr_local);\
}while(0)
void set_global_address(void);
void configure_routing(void);
#endif /*CONTIKI_TARGET_MINIMAL_NET*/
#endif /* STATICROUTING_H_ */

View file

@ -1,4 +0,0 @@
rest-http_src = http-common.c http-server.c
APPS += rest-common
include $(CONTIKI)/apps/rest-common/Makefile.rest-common

View file

@ -1,29 +0,0 @@
#include "http-common.h"
/*needed for web services giving all path (http://172.16.79.0/services/light1)
* instead relative (/services/light1) in HTTP request. Ex: Restlet lib.*/
const char* http_string = "http";
/*HTTP method strings*/
const char* http_get_string = "GET";
const char* http_head_string = "HEAD";
const char* http_post_string = "POST";
const char* http_put_string = "PUT";
const char* http_delete_string = "DELETE";
const char* httpv1_1 = "HTTP/1.1";
const char* line_end = "\r\n";
const char* contiki = "Contiki";
const char* close = "close";
/*header names*/
const char* HTTP_HEADER_NAME_CONTENT_TYPE = "Content-Type";
const char* HTTP_HEADER_NAME_CONTENT_LENGTH = "Content-Length";
const char* HTTP_HEADER_NAME_LOCATION = "Location";
const char* HTTP_HEADER_NAME_CONNECTION = "Connection";
const char* HTTP_HEADER_NAME_SERVER = "Server";
const char* HTTP_HEADER_NAME_HOST = "Host";
const char* HTTP_HEADER_NAME_IF_NONE_MATCH = "If-None-Match";
const char* HTTP_HEADER_NAME_ETAG = "ETag";
const char* header_delimiter = ": ";

View file

@ -1,143 +0,0 @@
#ifndef HTTPCOMMON_H_
#define HTTPCOMMON_H_
/*includes*/
#include "contiki.h"
#include "contiki-net.h"
/*current state of the request, waiting: handling request, output: sending response*/
#define STATE_WAITING 0
#define STATE_OUTPUT 1
/*definitions of the line ending characters*/
#define LINE_FEED_CHAR '\n'
#define CARRIAGE_RETURN_CHAR '\r'
/*needed for web services giving all path (http://172.16.79.0/services/light1)
* instead relative (/services/light1) in HTTP request. Ex: Restlet lib. does it*/
extern const char* http_string;
/*HTTP method strings*/
extern const char* http_get_string;
extern const char* http_head_string;
extern const char* http_post_string;
extern const char* http_put_string;
extern const char* http_delete_string;
extern const char* httpv1_1;
extern const char* line_end;
extern const char* contiki;
extern const char* close;
/*header names*/
extern const char* HTTP_HEADER_NAME_CONTENT_TYPE;
extern const char* HTTP_HEADER_NAME_CONTENT_LENGTH;
extern const char* HTTP_HEADER_NAME_LOCATION;
extern const char* HTTP_HEADER_NAME_CONNECTION;
extern const char* HTTP_HEADER_NAME_SERVER;
extern const char* HTTP_HEADER_NAME_HOST;
extern const char* HTTP_HEADER_NAME_IF_NONE_MATCH;
extern const char* HTTP_HEADER_NAME_ETAG;
extern const char* header_delimiter;
/*Configuration parameters*/
#define HTTP_PORT 8080
#define HTTP_DATA_BUFF_SIZE 600
#define INCOMING_DATA_BUFF_SIZE 102 /*100+2, 100 = max url len, 2 = space char+'\0'*/
/*HTTP method types*/
typedef enum {
HTTP_METHOD_GET = (1 << 0),
HTTP_METHOD_POST = (1 << 1),
HTTP_METHOD_PUT = (1 << 2),
HTTP_METHOD_DELETE = (1 << 3)
} http_method_t;
//DY : FIXME right now same enum names with COAP with different values. Will this work fine?
typedef enum {
OK_200 = 200,
CREATED_201 = 201,
NOT_MODIFIED_304 = 304,
BAD_REQUEST_400 = 400,
NOT_FOUND_404 = 404,
METHOD_NOT_ALLOWED_405 = 405,
REQUEST_URI_TOO_LONG_414 = 414,
UNSUPPORTED_MADIA_TYPE_415 = 415,
INTERNAL_SERVER_ERROR_500 = 500,
BAD_GATEWAY_502 = 502,
SERVICE_UNAVAILABLE_503 = 503,
GATEWAY_TIMEOUT_504 = 504
} status_code_t;
typedef enum {
TEXT_PLAIN,
TEXT_XML,
TEXT_CSV,
TEXT_HTML,
APPLICATION_XML,
APPLICATION_EXI,
APPLICATION_JSON,
APPLICATION_LINK_FORMAT,
APPLICATION_WWW_FORM,
UNKNOWN_CONTENT_TYPE
} content_type_t;
/*Header type*/
struct http_header_t {
struct http_header_t* next;
char* name;
char* value;
};
typedef struct http_header_t http_header_t;
/*This structure contains information about the HTTP request.*/
struct http_request_t {
char* url;
uint16_t url_len;
http_method_t request_type; /* GET, POST, etc */
char* query;
uint16_t query_len;
http_header_t* headers;
uint16_t payload_len;
uint8_t* payload;
};
typedef struct http_request_t http_request_t;
/*This structure contains information about the HTTP response.*/
struct http_response_t {
status_code_t status_code;
char* status_string;
http_header_t* headers;
uint16_t payload_len;
uint8_t* payload;
};
typedef struct http_response_t http_response_t;
/*This structure contains information about the TCP Connection.*/
typedef struct {
struct psock sin, sout; /*Protosockets for incoming and outgoing communication*/
struct pt outputpt;
char inputbuf[INCOMING_DATA_BUFF_SIZE]; /*to put incoming data in*/
uint8_t state;
http_request_t request;
http_response_t response;
} connection_state_t;
/*error definitions*/
typedef enum {
HTTP_NO_ERROR,
/*Memory errors*/
HTTP_MEMORY_ALLOC_ERR,
HTTP_MEMORY_BOUNDARY_EXCEEDED,
/*specific errors*/
HTTP_XML_NOT_VALID,
HTTP_SOAP_MESSAGE_NOT_VALID,
HTTP_URL_TOO_LONG,
HTTP_URL_INVALID
} http_error_t;
#endif /*HTTPCOMMON_H_*/

View file

@ -1,653 +0,0 @@
#include <stdio.h>
#include <stdlib.h> /*for atoi*/
#include <string.h>
#include "contiki.h"
#include "http-server.h"
#include "buffer.h"
#include "rest-util.h"
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
#include "static-routing.h"
#endif
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
static void
init_response(http_response_t* response)
{
response->status_code = OK_200;
response->status_string = NULL;
response->headers = NULL;
response->payload = NULL;
response->payload_len = 0;
}
static void
init_request(http_request_t* request)
{
request->request_type = 0;
request->url = NULL;
request->url_len = 0;
request->query = NULL;
request->query_len = 0;
request->headers = NULL;
request->payload = NULL;
request->payload_len = 0;
}
/**
* Initializes the connection state by clearing out the data structures
*/
static void
init_connection(connection_state_t* conn_state)
{
conn_state->state = STATE_WAITING;
init_request(&conn_state->request);
init_response(&conn_state->response);
}
void
http_set_status(http_response_t* response, status_code_t status)
{
response->status_code = status;
}
static http_header_t*
allocate_header(uint16_t variable_len)
{
PRINTF("sizeof http_header_t %u variable size %u\n", sizeof(http_header_t), variable_len);
uint8_t* buffer = allocate_buffer(sizeof(http_header_t) + variable_len);
if (buffer) {
http_header_t* option = (http_header_t*) buffer;
option->next = NULL;
option->name = NULL;
option->value = buffer + sizeof(http_header_t);
return option;
}
return NULL;
}
int
http_set_res_header(http_response_t* response, const char* name, const char* value, int copy)
{
PRINTF("http_set_res_header (copy:%d) %s:%s\n", copy, name, value);
uint16_t size = 0;
http_header_t* current_header = NULL;
http_header_t* head = NULL;
if (copy) {
size += strlen(value) + 1;
}
current_header = allocate_header(size);
if (current_header) {
current_header->name = (char*)name;
if (copy) {
strcpy(current_header->value, value);
} else {
current_header->value = (char*)value;
}
head = response->headers;
response->headers = current_header;
if (head) {
current_header->next = head;
}
return 1;
}
return 0;
}
static const char* is_request_hdr_needed(const char* header_name)
{
const char* header = NULL;
/*FIXME add needed headers here*/
if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_LENGTH) == 0) {
header = HTTP_HEADER_NAME_CONTENT_LENGTH;
} else if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_TYPE) == 0) {
header = HTTP_HEADER_NAME_CONTENT_TYPE;
}
return header;
}
static service_callback service_cbk = NULL;
void
http_set_service_callback(service_callback callback)
{
service_cbk = callback;
}
const char* content_types[] = {
"text/plain",
"text/xml",
"text/csv",
"text/html",
"application/xml",
"application/exi",
"application/json",
"application/link-format",
"application/x-www-form-urlencoded",
};
const char*
http_get_content_type_string(content_type_t content_type)
{
return content_types[content_type];
}
char*
get_default_status_string(status_code_t status_code)
{
char* value = NULL;
switch(status_code) {
case 200:
value = "OK";
break;
case 201:
value = "Created";
break;
case 202:
value = "Accepted";
break;
case 204:
value = "No Content";
break;
case 304:
value = "Not Modified";
break;
case 400:
value = "Bad Request" ;
break;
case 404:
value = "Not Found" ;
break;
case 405:
value = "Method Not Allowed" ;
break;
case 406:
value = "Not Acceptable" ;
break;
case 414:
value = "Request-URI Too Long" ;
break;
case 415:
value = "Unsupported Media Type" ;
break;
case 500:
value = "Internal Server Error" ;
break;
case 501:
value = "Not Implemented" ;
break;
case 503:
value = "Service Unavailable" ;
break;
/*FIXME : will be removed later, put to catch the unhandled statuses.*/
default:
value = "$$BUG$$";
break;
}
return value;
}
int
http_get_query_variable(http_request_t* request, const char *name, char* output, uint16_t output_size)
{
if (request->query) {
return get_variable(name, request->query, request->query_len, output, output_size, 0);
}
return 0;
}
int
http_get_post_variable(http_request_t* request, const char *name, char* output, uint16_t output_size)
{
if (request->payload) {
return get_variable(name, request->payload, request->payload_len, output, output_size, 1);
}
return 0;
}
static int
is_method_handled(connection_state_t* conn_state, const char* method)
{
/*other method types can be added here if needed*/
if(strncmp(method, http_get_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_GET;
} else if (strncmp(method, http_post_string, 4) == 0) {
conn_state->request.request_type = HTTP_METHOD_POST;
} else if (strncmp(method, http_put_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_PUT;
} else if (strncmp(method, http_delete_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_DELETE;
} else {
PRINTF("No Method supported : %s\nstate : %d\n", conn_state->inputbuf, conn_state->state);
return 0;
}
return 1;
}
static int
parse_url(connection_state_t* conn_state, char* url)
{
int error = HTTP_NO_ERROR;
int full_url_path = 0;
/*even for default index.html there is / Ex: GET / HTTP/1.1*/
if (url[0] != '/') {
/*if url is complete (http://...) rather than relative*/
if (strncmp(url, http_string, 4) != 0 ) {
PRINTF("Url not valid : %s \n",url);
error = HTTP_URL_INVALID;
} else {
full_url_path = 1;
}
}
if (error == HTTP_NO_ERROR) {
char* url_buffer = url;
if (full_url_path) {
unsigned char num_of_slash = 0;
do {
url_buffer = strchr( ++url_buffer, '/' );
PRINTF("Buffer : %s %d\n", url_buffer, num_of_slash);
} while (url_buffer && ++num_of_slash < 3);
}
PRINTF("Url found :%s\n", url_buffer);
/*Get rid of the first slash*/
if (url_buffer && ++url_buffer) {
conn_state->request.url = (char*) copy_text_to_buffer(url_buffer);
conn_state->request.url_len = strlen(url_buffer);
if ((conn_state->request.query = strchr(conn_state->request.url, '?'))) {
*(conn_state->request.query++) = 0;
/*update url len - decrease the size of query*/
conn_state->request.url_len = strlen(conn_state->request.url);
conn_state->request.query_len = strlen(conn_state->request.query);
}
PRINTF("url %s, url_len %u, query %s, query_len %u\n", conn_state->request.url, conn_state->request.url_len, conn_state->request.query, conn_state->request.query_len);
/*FIXME url is not decoded - should be done here*/
} else {
error = HTTP_URL_INVALID;
}
}
return error;
}
static int
parse_header(connection_state_t* conn_state, char* inputbuf)
{
PRINTF("parse_header --->\n");
const char* header_name = NULL;
char* delimiter = strchr(inputbuf, ':');
if (delimiter) {
*delimiter++ = 0; /*after increment delimiter will point space char*/
header_name = is_request_hdr_needed(inputbuf);
if (header_name && delimiter) {
char* buffer = delimiter;
if (buffer[0] == ' ') {
buffer++;
}
http_header_t* current_header = NULL;
http_header_t* head = NULL;
current_header = allocate_header(strlen(buffer));
if (current_header) {
current_header->name = (char*)header_name;
strcpy(current_header->value, buffer);
}
head = conn_state->request.headers;
conn_state->request.headers = current_header;
if (head) {
current_header->next = head;
}
return 1;
}
}
return 0;
}
int
http_set_res_payload(http_response_t* response, uint8_t* payload, uint16_t size)
{
response->payload = copy_to_buffer(payload, size);
if (response->payload) {
response->payload_len = size;
return 1;
}
return 0;
}
static const char*
get_header(http_header_t* headers, const char* hdr_name)
{
for (;headers; headers = headers->next) {
if (strcmp(headers->name, hdr_name) == 0) {
return headers->value;
}
}
return NULL;
}
const char* http_get_req_header(http_request_t* request, const char* name)
{
return get_header(request->headers, name);
}
content_type_t http_get_header_content_type(http_request_t* request)
{
const char* content_type_string = http_get_req_header(request, HTTP_HEADER_NAME_CONTENT_TYPE);
if (content_type_string) {
int i = 0;
for(; i < sizeof(content_types)/sizeof(const char*) ; i++) {
if (strcmp(content_types[i], content_type_string)) {
return (content_type_t)i;
}
}
}
return UNKNOWN_CONTENT_TYPE;
}
static
PT_THREAD(handle_request(connection_state_t* conn_state))
{
static int error;
const char* content_len;
PSOCK_BEGIN(&(conn_state->sin));
content_len = NULL;
error = HTTP_NO_ERROR; /*always reinit static variables due to protothreads*/
PRINTF("Request--->\n");
//read method
PSOCK_READTO(&(conn_state->sin), ' ');
if (!is_method_handled(conn_state, conn_state->inputbuf)) {
/*method not handled*/
http_set_status(&conn_state->response, SERVICE_UNAVAILABLE_503);
conn_state->state = STATE_OUTPUT;
} else {
/*read until the end of url*/
PSOCK_READTO(&(conn_state->sin), ' ');
/*-1 is needed since it also includes space char*/
if (conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin)) - 1] != ' ' ) {
error = HTTP_URL_TOO_LONG;
}
conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
PRINTF("Read URL:%s\n", conn_state->inputbuf);
if (error == HTTP_NO_ERROR) {
error = parse_url(conn_state, conn_state->inputbuf);
}
if (error != HTTP_NO_ERROR) {
if (error == HTTP_URL_TOO_LONG) {
http_set_status(&conn_state->response, REQUEST_URI_TOO_LONG_414);
} else {
http_set_status(&conn_state->response, BAD_REQUEST_400);
}
conn_state->state = STATE_OUTPUT;
} else {
/*read until the end of HTTP version - not used yet*/
PSOCK_READTO(&(conn_state->sin), LINE_FEED_CHAR);
PRINTF("After URL:%s\n", conn_state->inputbuf);
/*FIXME : PSOCK_READTO takes just a single delimiter so I read till the end of line
but now it may not fit in the buffer. If PSOCK_READTO would take two delimiters,
we would have read until : and <CR> so it would not be blocked.*/
/*Read the headers and store the necessary ones*/
do {
/*read the next line*/
PSOCK_READTO(&(conn_state->sin), LINE_FEED_CHAR);
conn_state->inputbuf[ PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
/*if headers finished then stop the infinite loop*/
if (conn_state->inputbuf[0] == CARRIAGE_RETURN_CHAR || conn_state->inputbuf[0] == 0) {
PRINTF("Finished Headers!\n\n");
break;
}
parse_header(conn_state, conn_state->inputbuf);
}
while(1);
content_len = get_header(conn_state->request.headers, HTTP_HEADER_NAME_CONTENT_LENGTH);
if (content_len) {
conn_state->request.payload_len = atoi(content_len);
PRINTF("Post Data Size string: %s int: %d\n", content_len, conn_state->request.payload_len);
}
if (conn_state->request.payload_len) {
static uint16_t read_bytes = 0;
/*init the static variable again*/
read_bytes = 0;
conn_state->request.payload = allocate_buffer(conn_state->request.payload_len + 1);
if (conn_state->request.payload) {
do {
PSOCK_READBUF(&(conn_state->sin));
/*null terminate the buffer in case it is a string.*/
conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin))] = 0;
memcpy(conn_state->request.payload + read_bytes, conn_state->inputbuf, PSOCK_DATALEN(&(conn_state->sin)));
read_bytes += PSOCK_DATALEN(&(conn_state->sin));
} while (read_bytes < conn_state->request.payload_len);
conn_state->request.payload[read_bytes++] = 0;
PRINTF("PostData => %s \n", conn_state->request.payload);
} else {
error = HTTP_MEMORY_ALLOC_ERR;
}
}
if (error == HTTP_NO_ERROR) {
if (service_cbk) {
service_cbk(&conn_state->request, &conn_state->response);
}
} else {
PRINTF("Error:%d\n",error);
http_set_status(&conn_state->response, INTERNAL_SERVER_ERROR_500);
}
conn_state->state = STATE_OUTPUT;
}
}
PSOCK_END(&(conn_state->sin));
}
static
PT_THREAD(send_data(connection_state_t* conn_state))
{
uint16_t index;
http_response_t* response;
http_header_t* header;
uint8_t* buffer;
PSOCK_BEGIN(&(conn_state->sout));
PRINTF("send_data -> \n");
index = 0;
response = &conn_state->response;
header = response->headers;
buffer = allocate_buffer(200);
/*FIXME: what is the best solution here to send the data. Right now, if buffer is not allocated, no data is sent!*/
if (buffer) {
index += sprintf(buffer + index, "%s %d %s%s", httpv1_1, response->status_code, response->status_string, line_end);
for (;header;header = header->next) {
PRINTF("header %u \n", (uint16_t)header);
index += sprintf(buffer + index, "%s%s%s%s", header->name, header_delimiter, header->value, line_end);
}
index += sprintf(buffer + index, "%s", line_end);
memcpy(buffer + index, response->payload, response->payload_len);
index += response->payload_len;
PRINTF("Sending Data(size %d): %s \n", index, buffer);
PSOCK_SEND(&(conn_state->sout), buffer, index);
} else {
PRINTF("BUFF ERROR: send_data!\n");
}
PSOCK_END(&(conn_state->sout));
}
static
PT_THREAD(handle_response(connection_state_t* conn_state))
{
PT_BEGIN(&(conn_state->outputpt));
PRINTF("handle_response ->\n");
http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_CONNECTION, close, 0);
http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_SERVER, contiki, 0);
if (!(conn_state->response.status_string)) {
conn_state->response.status_string =
get_default_status_string(conn_state->response.status_code);
}
PT_WAIT_THREAD(&(conn_state->outputpt), send_data(conn_state));
PRINTF("<-- handle_response\n\n\n");
PSOCK_CLOSE(&(conn_state->sout));
PT_END(&(conn_state->outputpt));
}
static void
handle_connection(connection_state_t* conn_state)
{
if (conn_state->state == STATE_WAITING) {
handle_request(conn_state);
}
if (conn_state->state == STATE_OUTPUT) {
handle_response(conn_state);
}
}
PROCESS(http_server, "Httpd Process");
PROCESS_THREAD(http_server, ev, data)
{
connection_state_t *conn_state;
PROCESS_BEGIN();
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
set_global_address();
configure_routing();
#endif /*!UIP_CONF_IPV6_RPL*/
#ifdef CONTIKI_TARGET_SKY
PRINTF("##RF CHANNEL : %d##\n",RF_CHANNEL);
#endif //CONTIKI_TARGET_SKY
tcp_listen(uip_htons(HTTP_PORT));
/*
* We loop for ever, accepting new connections.
*/
while(1) {
PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);
conn_state = (connection_state_t *)data;
if(uip_connected()) {
PRINTF("##Connected##\n");
if(init_buffer(HTTP_DATA_BUFF_SIZE)) {
conn_state = (connection_state_t*)allocate_buffer(sizeof(connection_state_t));
if (conn_state) {
tcp_markconn(uip_conn, conn_state);
/*initialize connection state*/
init_connection(conn_state);
/*-1 is needed to be able to null terminate the strings in the buffer, especially good for debugging (to have null terminated strings)*/
PSOCK_INIT(&(conn_state->sin), (uint8_t*)conn_state->inputbuf, sizeof(conn_state->inputbuf) - 1);
PSOCK_INIT(&(conn_state->sout), (uint8_t*)conn_state->inputbuf, sizeof(conn_state->inputbuf) - 1);
PT_INIT(&(conn_state->outputpt));
handle_connection(conn_state);
} else {
PRINTF("Memory Alloc Error. Aborting!\n");
uip_abort();
}
}
} else if (uip_aborted() || uip_closed() || uip_timedout()) {
if (conn_state) {
delete_buffer();
/*Following 2 lines are needed since this part of code is somehow executed twice so it tries to free the same region twice.
Potential bug in uip*/
conn_state = NULL;
tcp_markconn(uip_conn, conn_state);
}
} else {
handle_connection(conn_state);
}
}
PROCESS_END();
}

View file

@ -1,59 +0,0 @@
#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_
#include "http-common.h"
#include "rest.h"
/*Declare process*/
PROCESS_NAME(http_server);
/*Type definition of the service callback*/
typedef int (*service_callback) (http_request_t* request, http_response_t* response);
/*
*Setter of the service callback, this callback will be called in case of HTTP request.
*/
void http_set_service_callback(service_callback callback);
/*
* Setter for the status code (200, 201, etc) of the response.
*/
void http_set_status(http_response_t* response, status_code_t status);
/*
* Adds the header name and value provided to the response.
* Name of the header should be hardcoded since it is accessed from code segment
* (not copied to buffer) whereas value of the header can be copied
* depending on the relevant parameter. This is needed since some values may be
* generated dynamically (ex: e-tag value)
*/
int http_set_res_header(http_response_t* response, const char* name, const char* value, int copy);
/*
* Returns the value of the header name provided. Return NULL if header does not exist.
*/
const char* http_get_req_header(http_request_t* request, const char* name);
int http_set_res_payload(http_response_t* response, uint8_t* payload, uint16_t size);
/*
* Returns query variable in the URL.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int http_get_query_variable(http_request_t* request, const char *name, char* output, uint16_t output_size);
/*
* Returns variable in the Post Data.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int http_get_post_variable(http_request_t* request, const char *name, char* output, uint16_t output_size);
/*
* Get the header "Content-Type".
*/
const char* http_get_content_type_string(content_type_t content_type);
content_type_t http_get_header_content_type(http_request_t* request);
#endif /*HTTPSERVER_H_*/

View file

@ -9,7 +9,7 @@ shell_src = shell.c shell-reboot.c shell-vars.c shell-ps.c \
shell_dsc = shell-dsc.c
ifeq ($(CONTIKI_WITH_RIME),1)
shell_src += shell-rime.c shell-sendtest.c shell-netfile.c \
shell_src += shell-rime.c shell-sendtest.c \
shell-rime-ping.c shell-rime-sniff.c shell-rime-netcmd.c \
shell-rime-debug.c shell-rime-debug-runicast.c \
shell-rime-sendcmd.c shell-download.c shell-rime-neighbors.c \

View file

@ -1,179 +0,0 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* A brief description of what this file is.
* \author
* Adam Dunkels <adam@sics.se>
*/
#include "contiki.h"
#include "shell-netfile.h"
#include "net/rime/rime.h"
#include "net/rime/rudolph0.h"
#include "dev/leds.h"
#include "cfs/cfs.h"
#include <stdio.h>
#include <string.h>
#define FILENAME_LEN 20
static struct rudolph0_conn rudolph0_conn;
static char filename[FILENAME_LEN];
static int receiving_file;
static struct pt recvnetfilept;
/*---------------------------------------------------------------------------*/
PROCESS(shell_netfile_process, "netfile");
SHELL_COMMAND(netfile_command,
"netfile",
"netfile: send file to entire network",
&shell_netfile_process);
PROCESS(shell_recvnetfile_process, "recvnetfile");
SHELL_COMMAND(recvnetfile_command,
"recvnetfile",
"recvnetfile: receive file from network and print to output",
&shell_recvnetfile_process);
/*---------------------------------------------------------------------------*/
static int
write_chunk_pt(struct rudolph0_conn *c, int offset, int flag,
uint8_t *data, int datalen)
{
PT_BEGIN(&recvnetfilept);
PT_WAIT_UNTIL(&recvnetfilept, receiving_file);
leds_on(LEDS_YELLOW);
leds_on(LEDS_RED);
PT_WAIT_UNTIL(&recvnetfilept, flag == RUDOLPH0_FLAG_NEWFILE);
leds_off(LEDS_RED);
do {
if(datalen > 0) {
shell_output(&recvnetfile_command, data, datalen, "", 0);
/* printf("write_chunk wrote %d bytes at %d\n", datalen, offset);*/
}
PT_YIELD(&recvnetfilept);
} while(flag != RUDOLPH0_FLAG_LASTCHUNK);
shell_output(&recvnetfile_command, data, datalen, "", 0);
/* printf("write_chunk wrote %d bytes at %d\n", datalen, offset);*/
shell_output(&recvnetfile_command, "", 0, "", 0);
leds_off(LEDS_YELLOW);
receiving_file = 0;
process_post(&shell_recvnetfile_process, PROCESS_EVENT_CONTINUE, NULL);
PT_END(&recvnetfilept);
}
static void
write_chunk(struct rudolph0_conn *c, int offset, int flag,
uint8_t *data, int datalen)
{
write_chunk_pt(c, offset, flag, data, datalen);
}
static int
read_chunk(struct rudolph0_conn *c, int offset, uint8_t *to, int maxsize)
{
int ret;
int fd;
fd = cfs_open(filename, CFS_READ);
cfs_seek(fd, offset, CFS_SEEK_SET);
ret = cfs_read(fd, to, maxsize);
/* printf("read_chunk %d bytes at %d, %d\n", ret, offset, (unsigned char)to[0]);*/
cfs_close(fd);
return ret;
}
CC_CONST_FUNCTION static struct rudolph0_callbacks rudolph0_callbacks =
{/*(void (*)(struct rudolph0_conn *, int, int, uint8_t *, int))*/
write_chunk,
read_chunk};
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(shell_netfile_process, ev, data)
{
int fd;
PROCESS_BEGIN();
if(data != NULL) {
rudolph0_send(&rudolph0_conn, CLOCK_SECOND);
strncpy(filename, data, FILENAME_LEN);
fd = cfs_open(filename, CFS_READ);
if(fd < 0) {
shell_output_str(&netfile_command, "netfile: could not open file ", filename);
} else {
cfs_close(fd);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(shell_recvnetfile_process, ev, data)
{
PROCESS_BEGIN();
PT_INIT(&recvnetfilept);
receiving_file = 1;
while(1) {
struct shell_input *input;
PROCESS_WAIT_EVENT();
if(ev == shell_event_input) {
input = data;
if(input->len1 + input->len2 == 0) {
receiving_file = 0;
PROCESS_EXIT();
}
} else if(receiving_file == 0) {
PROCESS_EXIT();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
void
shell_netfile_init(void)
{
receiving_file = 0;
shell_register_command(&netfile_command);
shell_register_command(&recvnetfile_command);
rudolph0_open(&rudolph0_conn, SHELL_RIME_CHANNEL_NETFILE,
&rudolph0_callbacks);
}
/*---------------------------------------------------------------------------*/

View file

@ -382,7 +382,6 @@ struct shell_input {
#include "shell-httpd.h"
#include "shell-irc.h"
#include "shell-memdebug.h"
#include "shell-netfile.h"
#include "shell-netperf.h"
#include "shell-netstat.h"
#include "shell-ping.h"

View file

@ -44,6 +44,7 @@
#include "net/ip/uiplib.h"
#include "net/ip/uip-udp-packet.h"
#include "net/ip/simple-udp.h"
#include "net/ip/uip-nameserver.h"
#if NETSTACK_CONF_WITH_IPV6
#include "net/ipv6/uip-icmp6.h"

View file

@ -72,14 +72,13 @@ static unsigned char ascii2petscii[128] = {
0x58,0x59,0x5a,0xdb,0xdd,0xdd,0x5e,0xdf,
};
static unsigned int i;
static unsigned char *ptr;
/*-----------------------------------------------------------------------------------*/
void
petsciiconv_toascii(char *buf, unsigned int len)
{
static char c;
unsigned int i;
char *ptr;
char c;
ptr = buf;
for(i = len; i > 0; --i) {
@ -108,6 +107,9 @@ petsciiconv_toascii(char *buf, unsigned int len)
void
petsciiconv_topetscii(char *buf, unsigned int len)
{
unsigned int i;
char *ptr;
ptr = buf;
for(i = len; i > 0; --i) {
*ptr = ascii2petscii[*ptr & 0x7f];

View file

@ -0,0 +1,682 @@
/*
* Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "contiki-net.h"
#include "ip64-addr.h"
#include "http-socket.h"
#include <ctype.h>
#include <stdio.h>
#define MAX_PATHLEN 80
#define MAX_HOSTLEN 40
PROCESS(http_socket_process, "HTTP socket process");
LIST(socketlist);
static void removesocket(struct http_socket *s);
/*---------------------------------------------------------------------------*/
static void
call_callback(struct http_socket *s, http_socket_event_t e,
const uint8_t *data, uint16_t datalen)
{
if(s->callback != NULL) {
s->callback(s, s->callbackptr, e,
data, datalen);
}
}
/*---------------------------------------------------------------------------*/
static void
parse_header_init(struct http_socket *s)
{
PT_INIT(&s->headerpt);
}
/*---------------------------------------------------------------------------*/
static int
parse_header_byte(struct http_socket *s, char c)
{
PT_BEGIN(&s->headerpt);
memset(&s->header, -1, sizeof(s->header));
/* Skip the HTTP response */
while(c != ' ') {
PT_YIELD(&s->headerpt);
}
/* Skip the space */
PT_YIELD(&s->headerpt);
/* Read three characters of HTTP status and convert to BCD */
s->header.status_code = 0;
for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) {
s->header.status_code = s->header.status_code << 4 | (c - '0');
PT_YIELD(&s->headerpt);
}
if(s->header.status_code == 0x200 || s->header.status_code == 0x206) {
/* Read headers until data */
while(1) {
/* Skip characters until end of line */
do {
while(c != '\r') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
s->header_chars++;
PT_YIELD(&s->headerpt);
} while(c != '\n');
s->header_chars--;
PT_YIELD(&s->headerpt);
if(s->header_chars == 0) {
/* This was an empty line, i.e. the end of headers */
break;
}
/* Start of line */
s->header_chars = 0;
/* Read header field */
while(c != ' ' && c != '\t' && c != ':' && c != '\r' &&
s->header_chars < sizeof(s->header_field) - 1) {
s->header_field[s->header_chars++] = c;
PT_YIELD(&s->headerpt);
}
s->header_field[s->header_chars] = '\0';
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
if(c == ':') {
/* Skip the colon */
s->header_chars++;
PT_YIELD(&s->headerpt);
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
if(!strcmp(s->header_field, "Content-Length")) {
s->header.content_length = 0;
while(isdigit((int)c)) {
s->header.content_length = s->header.content_length * 10 + c - '0';
s->header_chars++;
PT_YIELD(&s->headerpt);
}
} else if(!strcmp(s->header_field, "Content-Range")) {
/* Skip the bytes-unit token */
while(c != ' ' && c != '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
s->header.content_range.first_byte_pos = 0;
while(isdigit((int)c)) {
s->header.content_range.first_byte_pos =
s->header.content_range.first_byte_pos * 10 + c - '0';
s->header_chars++;
PT_YIELD(&s->headerpt);
}
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
if(c == '-') {
/* Skip the dash */
s->header_chars++;
PT_YIELD(&s->headerpt);
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
s->header.content_range.last_byte_pos = 0;
while(isdigit((int)c)) {
s->header.content_range.last_byte_pos =
s->header.content_range.last_byte_pos * 10 + c - '0';
s->header_chars++;
PT_YIELD(&s->headerpt);
}
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
if(c == '/') {
/* Skip the slash */
s->header_chars++;
PT_YIELD(&s->headerpt);
/* Skip linear white spaces */
while(c == ' ' || c == '\t') {
s->header_chars++;
PT_YIELD(&s->headerpt);
}
if(c != '*') {
s->header.content_range.instance_length = 0;
while(isdigit((int)c)) {
s->header.content_range.instance_length =
s->header.content_range.instance_length * 10 + c - '0';
s->header_chars++;
PT_YIELD(&s->headerpt);
}
}
}
}
}
}
}
/* All headers read, now read data */
call_callback(s, HTTP_SOCKET_HEADER, (void *)&s->header, sizeof(s->header));
/* Should exit the pt here to indicate that all headers have been
read */
PT_EXIT(&s->headerpt);
} else {
if(s->header.status_code == 0x404) {
printf("File not found\n");
} else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) {
printf("File moved (not handled)\n");
}
call_callback(s, HTTP_SOCKET_ERR, (void *)&s->header, sizeof(s->header));
tcp_socket_close(&s->s);
removesocket(s);
PT_EXIT(&s->headerpt);
}
PT_END(&s->headerpt);
}
/*---------------------------------------------------------------------------*/
static int
input_pt(struct http_socket *s,
const uint8_t *inputptr, int inputdatalen)
{
int i;
PT_BEGIN(&s->pt);
/* Parse the header */
s->header_received = 0;
do {
for(i = 0; i < inputdatalen; i++) {
if(!PT_SCHEDULE(parse_header_byte(s, inputptr[i]))) {
s->header_received = 1;
break;
}
}
inputdatalen -= i;
inputptr += i;
if(s->header_received == 0) {
/* If we have not yet received the full header, we wait for the
next packet to arrive. */
PT_YIELD(&s->pt);
}
} while(s->header_received == 0);
s->bodylen = 0;
do {
/* Receive the data */
call_callback(s, HTTP_SOCKET_DATA, inputptr, inputdatalen);
/* Close the connection if the expected content length has been received */
if(s->header.content_length >= 0 && s->bodylen < s->header.content_length) {
s->bodylen += inputdatalen;
if(s->bodylen >= s->header.content_length) {
tcp_socket_close(&s->s);
}
}
PT_YIELD(&s->pt);
} while(inputdatalen > 0);
PT_END(&s->pt);
}
/*---------------------------------------------------------------------------*/
static void
start_timeout_timer(struct http_socket *s)
{
PROCESS_CONTEXT_BEGIN(&http_socket_process);
etimer_set(&s->timeout_timer, HTTP_SOCKET_TIMEOUT);
PROCESS_CONTEXT_END(&http_socket_process);
s->timeout_timer_started = 1;
}
/*---------------------------------------------------------------------------*/
static int
input(struct tcp_socket *tcps, void *ptr,
const uint8_t *inputptr, int inputdatalen)
{
struct http_socket *s = ptr;
input_pt(s, inputptr, inputdatalen);
start_timeout_timer(s);
return 0; /* all data consumed */
}
/*---------------------------------------------------------------------------*/
static int
parse_url(const char *url, char *host, uint16_t *portptr, char *path)
{
const char *urlptr;
int i;
const char *file;
uint16_t port;
if(url == NULL) {
printf("null url\n");
return 0;
}
/* Don't even try to go further if the URL is empty. */
if(strlen(url) == 0) {
printf("empty url\n");
return 0;
}
/* See if the URL starts with http:// and remove it. Otherwise, we
assume it is an implicit http://. */
if(strncmp(url, "http://", strlen("http://")) == 0) {
urlptr = url + strlen("http://");
} else {
urlptr = url;
}
/* Find host part of the URL. */
if(*urlptr == '[') {
/* Handle IPv6 addresses - scan for matching ']' */
urlptr++;
for(i = 0; i < MAX_HOSTLEN; ++i) {
if(*urlptr == ']') {
if(host != NULL) {
host[i] = 0;
}
break;
}
if(host != NULL) {
host[i] = *urlptr;
}
++urlptr;
}
} else {
for(i = 0; i < MAX_HOSTLEN; ++i) {
if(*urlptr == 0 ||
*urlptr == '/' ||
*urlptr == ' ' ||
*urlptr == ':') {
if(host != NULL) {
host[i] = 0;
}
break;
}
if(host != NULL) {
host[i] = *urlptr;
}
++urlptr;
}
}
/* Find the port. Default is 80. */
port = 80;
if(*urlptr == ':') {
port = 0;
do {
++urlptr;
if(*urlptr >= '0' && *urlptr <= '9') {
port = (10 * port) + (*urlptr - '0');
}
} while(*urlptr >= '0' &&
*urlptr <= '9');
}
if(portptr != NULL) {
*portptr = port;
}
/* Find file part of the URL. */
while(*urlptr != '/' && *urlptr != 0) {
++urlptr;
}
if(*urlptr == '/') {
file = urlptr;
} else {
file = "/";
}
if(path != NULL) {
strncpy(path, file, MAX_PATHLEN);
}
return 1;
}
/*---------------------------------------------------------------------------*/
static void
removesocket(struct http_socket *s)
{
etimer_stop(&s->timeout_timer);
s->timeout_timer_started = 0;
list_remove(socketlist, s);
}
/*---------------------------------------------------------------------------*/
static void
event(struct tcp_socket *tcps, void *ptr,
tcp_socket_event_t e)
{
struct http_socket *s = ptr;
char host[MAX_HOSTLEN];
char path[MAX_PATHLEN];
uint16_t port;
char str[42];
int len;
if(e == TCP_SOCKET_CONNECTED) {
printf("Connected\n");
if(parse_url(s->url, host, &port, path)) {
tcp_socket_send_str(tcps, s->postdata != NULL ? "POST " : "GET ");
if(s->proxy_port != 0) {
/* If we are configured to route through a proxy, we should
provide the full URL as the path. */
tcp_socket_send_str(tcps, s->url);
} else {
tcp_socket_send_str(tcps, path);
}
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
tcp_socket_send_str(tcps, "Connection: close\r\n");
tcp_socket_send_str(tcps, "Host: ");
tcp_socket_send_str(tcps, host);
tcp_socket_send_str(tcps, "\r\n");
if(s->postdata != NULL) {
if(s->content_type) {
tcp_socket_send_str(tcps, "Content-Type: ");
tcp_socket_send_str(tcps, s->content_type);
tcp_socket_send_str(tcps, "\r\n");
}
tcp_socket_send_str(tcps, "Content-Length: ");
sprintf(str, "%u", s->postdatalen);
tcp_socket_send_str(tcps, str);
tcp_socket_send_str(tcps, "\r\n");
} else if(s->length || s->pos > 0) {
tcp_socket_send_str(tcps, "Range: bytes=");
if(s->length) {
if(s->pos >= 0) {
sprintf(str, "%llu-%llu", s->pos, s->pos + s->length - 1);
} else {
sprintf(str, "-%llu", s->length);
}
} else {
sprintf(str, "%llu-", s->pos);
}
tcp_socket_send_str(tcps, str);
tcp_socket_send_str(tcps, "\r\n");
}
tcp_socket_send_str(tcps, "\r\n");
if(s->postdata != NULL && s->postdatalen) {
len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
s->postdata += len;
s->postdatalen -= len;
}
}
parse_header_init(s);
} else if(e == TCP_SOCKET_CLOSED) {
call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0);
removesocket(s);
printf("Closed\n");
} else if(e == TCP_SOCKET_TIMEDOUT) {
call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0);
removesocket(s);
printf("Timedout\n");
} else if(e == TCP_SOCKET_ABORTED) {
call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0);
removesocket(s);
printf("Aborted\n");
} else if(e == TCP_SOCKET_DATA_SENT) {
if(s->postdata != NULL && s->postdatalen) {
len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
s->postdata += len;
s->postdatalen -= len;
} else {
start_timeout_timer(s);
}
}
}
/*---------------------------------------------------------------------------*/
static int
start_request(struct http_socket *s)
{
uip_ip4addr_t ip4addr;
uip_ip6addr_t ip6addr;
uip_ip6addr_t *addr;
char host[MAX_HOSTLEN];
char path[MAX_PATHLEN];
uint16_t port;
int ret;
if(parse_url(s->url, host, &port, path)) {
printf("url %s host %s port %d path %s\n",
s->url, host, port, path);
/* Check if we are to route the request through a proxy. */
if(s->proxy_port != 0) {
/* The proxy address should be an IPv6 address. */
uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
port = s->proxy_port;
} else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
/* First check if the host is an IP address. */
if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
ip64_addr_4to6(&ip4addr, &ip6addr);
} else {
/* Try to lookup the hostname. If it fails, we initiate a hostname
lookup. */
ret = resolv_lookup(host, &addr);
if(ret == RESOLV_STATUS_UNCACHED ||
ret == RESOLV_STATUS_EXPIRED) {
resolv_query(host);
puts("Resolving host...");
return HTTP_SOCKET_OK;
}
if(addr != NULL) {
s->did_tcp_connect = 1;
tcp_socket_connect(&s->s, addr, port);
return HTTP_SOCKET_OK;
} else {
return HTTP_SOCKET_ERR;
}
}
}
tcp_socket_connect(&s->s, &ip6addr, port);
return HTTP_SOCKET_OK;
} else {
return HTTP_SOCKET_ERR;
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(http_socket_process, ev, data)
{
PROCESS_BEGIN();
while(1) {
PROCESS_WAIT_EVENT();
if(ev == resolv_event_found && data != NULL) {
struct http_socket *s;
const char *name = data;
/* Either found a hostname, or not. We need to go through the
list of http sockets and figure out to which connection this
reply corresponds, then either restart the HTTP get, or kill
it (if no hostname was found). */
for(s = list_head(socketlist);
s != NULL;
s = list_item_next(s)) {
char host[MAX_HOSTLEN];
if(s->did_tcp_connect) {
/* We already connected, ignored */
} else if(parse_url(s->url, host, NULL, NULL) &&
strcmp(name, host) == 0) {
if(resolv_lookup(name, NULL) == RESOLV_STATUS_CACHED) {
/* Hostname found, restart get. */
start_request(s);
} else {
/* Hostname not found, kill connection. */
call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
removesocket(s);
}
}
}
} else if(ev == PROCESS_EVENT_TIMER) {
struct http_socket *s;
struct etimer *timeout_timer = data;
/*
* A socket time-out has occurred. We need to go through the list of HTTP
* sockets and figure out to which socket this timer event corresponds,
* then close this socket.
*/
for(s = list_head(socketlist);
s != NULL;
s = list_item_next(s)) {
if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
tcp_socket_close(&s->s);
break;
}
}
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
static void
init(void)
{
static uint8_t inited = 0;
if(inited == 0) {
process_start(&http_socket_process, NULL);
list_init(socketlist);
inited = 1;
}
}
/*---------------------------------------------------------------------------*/
void
http_socket_init(struct http_socket *s)
{
init();
uip_create_unspecified(&s->proxy_addr);
s->proxy_port = 0;
}
/*---------------------------------------------------------------------------*/
static void
initialize_socket(struct http_socket *s)
{
s->pos = 0;
s->length = 0;
s->postdata = NULL;
s->postdatalen = 0;
s->timeout_timer_started = 0;
PT_INIT(&s->pt);
tcp_socket_register(&s->s, s,
s->inputbuf, sizeof(s->inputbuf),
s->outputbuf, sizeof(s->outputbuf),
input, event);
}
/*---------------------------------------------------------------------------*/
int
http_socket_get(struct http_socket *s,
const char *url,
int64_t pos,
uint64_t length,
http_socket_callback_t callback,
void *callbackptr)
{
initialize_socket(s);
strncpy(s->url, url, sizeof(s->url));
s->pos = pos;
s->length = length;
s->callback = callback;
s->callbackptr = callbackptr;
s->did_tcp_connect = 0;
list_add(socketlist, s);
return start_request(s);
}
/*---------------------------------------------------------------------------*/
int
http_socket_post(struct http_socket *s,
const char *url,
const void *postdata,
uint16_t postdatalen,
const char *content_type,
http_socket_callback_t callback,
void *callbackptr)
{
initialize_socket(s);
strncpy(s->url, url, sizeof(s->url));
s->postdata = postdata;
s->postdatalen = postdatalen;
s->content_type = content_type;
s->callback = callback;
s->callbackptr = callbackptr;
s->did_tcp_connect = 0;
list_add(socketlist, s);
return start_request(s);
}
/*---------------------------------------------------------------------------*/
int
http_socket_close(struct http_socket *socket)
{
struct http_socket *s;
for(s = list_head(socketlist);
s != NULL;
s = list_item_next(s)) {
if(s == socket) {
tcp_socket_close(&s->s);
removesocket(s);
return 1;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
http_socket_set_proxy(struct http_socket *s,
const uip_ipaddr_t *addr, uint16_t port)
{
uip_ipaddr_copy(&s->proxy_addr, addr);
s->proxy_port = port;
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef HTTP_SOCKET_H
#define HTTP_SOCKET_H
#include "tcp-socket.h"
struct http_socket;
typedef enum {
HTTP_SOCKET_ERR,
HTTP_SOCKET_OK,
HTTP_SOCKET_HEADER,
HTTP_SOCKET_DATA,
HTTP_SOCKET_CLOSED,
HTTP_SOCKET_TIMEDOUT,
HTTP_SOCKET_ABORTED,
HTTP_SOCKET_HOSTNAME_NOT_FOUND,
} http_socket_event_t;
struct http_socket_header {
uint16_t status_code;
int64_t content_length;
struct {
int64_t first_byte_pos;
int64_t last_byte_pos;
int64_t instance_length;
} content_range;
};
typedef void (* http_socket_callback_t)(struct http_socket *s,
void *ptr,
http_socket_event_t ev,
const uint8_t *data,
uint16_t datalen);
#define MAX(n, m) (((n) < (m)) ? (m) : (n))
#define HTTP_SOCKET_INPUTBUFSIZE UIP_TCP_MSS
#define HTTP_SOCKET_OUTPUTBUFSIZE MAX(UIP_TCP_MSS, 128)
#define HTTP_SOCKET_URLLEN 128
#define HTTP_SOCKET_TIMEOUT ((2 * 60 + 30) * CLOCK_SECOND)
struct http_socket {
struct http_socket *next;
struct tcp_socket s;
uip_ipaddr_t proxy_addr;
uint16_t proxy_port;
int64_t pos;
uint64_t length;
const uint8_t *postdata;
uint16_t postdatalen;
http_socket_callback_t callback;
void *callbackptr;
int did_tcp_connect;
char url[HTTP_SOCKET_URLLEN];
uint8_t inputbuf[HTTP_SOCKET_INPUTBUFSIZE];
uint8_t outputbuf[HTTP_SOCKET_OUTPUTBUFSIZE];
struct etimer timeout_timer;
uint8_t timeout_timer_started;
struct pt pt, headerpt;
int header_chars;
char header_field[15];
struct http_socket_header header;
uint8_t header_received;
uint64_t bodylen;
const char *content_type;
};
void http_socket_init(struct http_socket *s);
int http_socket_get(struct http_socket *s, const char *url,
int64_t pos, uint64_t length,
http_socket_callback_t callback,
void *callbackptr);
int http_socket_post(struct http_socket *s, const char *url,
const void *postdata,
uint16_t postdatalen,
const char *content_type,
http_socket_callback_t callback,
void *callbackptr);
int http_socket_close(struct http_socket *socket);
void http_socket_set_proxy(struct http_socket *s,
const uip_ipaddr_t *addr, uint16_t port);
#endif /* HTTP_SOCKET_H */

View file

@ -65,6 +65,7 @@
#include "net/ip/tcpip.h"
#include "net/ip/resolv.h"
#include "net/ip/uip-udp-packet.h"
#include "net/ip/uip-nameserver.h"
#include "lib/random.h"
#ifndef DEBUG
@ -227,17 +228,6 @@ struct dns_hdr {
uint16_t numextrarr;
};
/** These default values for the DNS server are Google's public DNS:
* <https://developers.google.com/speed/public-dns/docs/using>
*/
static uip_ipaddr_t resolv_default_dns_server =
#if NETSTACK_CONF_WITH_IPV6
{ { 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 } };
#else /* NETSTACK_CONF_WITH_IPV6 */
{ { 8, 8, 8, 8 } };
#endif /* NETSTACK_CONF_WITH_IPV6 */
/** \internal The DNS answer message structure. */
struct dns_answer {
/* DNS answer record starts with either a domain name or a pointer
@ -269,6 +259,7 @@ struct namemap {
#endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
uip_ipaddr_t ipaddr;
uint8_t err;
uint8_t server;
#if RESOLV_CONF_SUPPORTS_MDNS
int is_mdns:1, is_probe:1;
#endif
@ -637,6 +628,21 @@ mdns_prep_host_announce_packet(void)
}
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
/*---------------------------------------------------------------------------*/
static char
try_next_server(struct namemap *namemapptr)
{
#if VERBOSE_DEBUG
printf("server %d\n", namemapptr->server);
#endif
namemapptr->server++;
if(uip_nameserver_get(namemapptr->server) != NULL) {
namemapptr->retries = 0;
return 1;
}
namemapptr->server = 0;
return 0;
}
/*---------------------------------------------------------------------------*/
/** \internal
* Runs through the list of names to see if there are any that have
* not yet been queried and, if so, sends out a query.
@ -666,16 +672,20 @@ check_entries(void)
if(++namemapptr->retries == RESOLV_CONF_MAX_RETRIES)
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
{
/* STATE_ERROR basically means "not found". */
namemapptr->state = STATE_ERROR;
/* Try the next server (if possible) before failing. Otherwise
simply mark the entry as failed. */
if(try_next_server(namemapptr) == 0) {
/* STATE_ERROR basically means "not found". */
namemapptr->state = STATE_ERROR;
#if RESOLV_SUPPORTS_RECORD_EXPIRATION
/* Keep the "not found" error valid for 30 seconds */
namemapptr->expiration = clock_seconds() + 30;
/* Keep the "not found" error valid for 30 seconds */
namemapptr->expiration = clock_seconds() + 30;
#endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
resolv_found(namemapptr->name, NULL);
continue;
resolv_found(namemapptr->name, NULL);
continue;
}
}
namemapptr->tmr = namemapptr->retries * namemapptr->retries * 3;
@ -747,7 +757,9 @@ check_entries(void)
} else {
uip_udp_packet_sendto(resolv_conn, uip_appdata,
(query - (uint8_t *) uip_appdata),
&resolv_default_dns_server, UIP_HTONS(DNS_PORT));
(const uip_ipaddr_t *)
uip_nameserver_get(namemapptr->server),
UIP_HTONS(DNS_PORT));
PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
namemapptr->name);
@ -755,7 +767,8 @@ check_entries(void)
#else /* RESOLV_CONF_SUPPORTS_MDNS */
uip_udp_packet_sendto(resolv_conn, uip_appdata,
(query - (uint8_t *) uip_appdata),
&resolv_default_dns_server, UIP_HTONS(DNS_PORT));
uip_nameserver_get(namemapptr->server),
UIP_HTONS(DNS_PORT));
PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
namemapptr->name);
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
@ -774,7 +787,7 @@ newdata(void)
static int8_t i;
register struct namemap *namemapptr;
register struct namemap *namemapptr = NULL;
struct dns_answer *ans;
@ -1041,11 +1054,28 @@ newdata(void)
uip_ipaddr_copy(&namemapptr->ipaddr, (uip_ipaddr_t *) ans->ipaddr);
resolv_found(namemapptr->name, &namemapptr->ipaddr);
break;
skip_to_next_answer:
queryptr = (unsigned char *)skip_name(queryptr) + 10 + uip_htons(ans->len);
--nanswers;
}
/* Got to this point there's no answer, try next nameserver if available
since this one doesn't know the answer */
#if RESOLV_CONF_SUPPORTS_MDNS
if(nanswers == 0 && UIP_UDP_BUF->srcport != UIP_HTONS(MDNS_PORT)
&& hdr->id != 0)
#else
if(nanswers == 0)
#endif
{
if(try_next_server(namemapptr)) {
namemapptr->state = STATE_ASKING;
process_post(&resolv_process, PROCESS_EVENT_TIMER, NULL);
}
}
}
/*---------------------------------------------------------------------------*/
#if RESOLV_CONF_SUPPORTS_MDNS
@ -1405,31 +1435,6 @@ resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr)
return ret;
}
/*---------------------------------------------------------------------------*/
/**
* Obtain the currently configured DNS server.
*
* \return A pointer to a 4-byte representation of the IP address of
* the currently configured DNS server or NULL if no DNS server has
* been configured.
*/
uip_ipaddr_t *
resolv_getserver(void)
{
return &resolv_default_dns_server;
}
/*---------------------------------------------------------------------------*/
/**
* Configure a DNS server.
*
* \param dnsserver A pointer to a 4-byte representation of the IP
* address of the DNS server to be configured.
*/
void
resolv_conf(const uip_ipaddr_t * dnsserver)
{
uip_ipaddr_copy(&resolv_default_dns_server, dnsserver);
}
/*---------------------------------------------------------------------------*/
/** \internal
* Callback function which is called when a hostname is found.
*

View file

@ -57,11 +57,6 @@
*/
CCIF extern process_event_t resolv_event_found;
/* Functions. */
CCIF void resolv_conf(const uip_ipaddr_t * dnsserver);
CCIF uip_ipaddr_t *resolv_getserver(void);
enum {
/** Hostname is fresh and usable. This response is cached and will eventually
* expire to RESOLV_STATUS_EXPIRED.*/
@ -95,6 +90,7 @@ enum {
typedef uint8_t resolv_status_t;
/* Functions. */
CCIF resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr);
CCIF void resolv_query(const char *name);

View file

@ -103,7 +103,7 @@ slipdev_send(void)
ptr = &uip_buf[UIP_LLH_LEN];
for(i = 0; i < uip_len; ++i) {
if(i == UIP_TCPIP_HLEN) {
ptr = (char *)uip_appdata;
ptr = (uint8_t *)uip_appdata;
}
c = *ptr++;
switch(c) {

View file

@ -41,6 +41,8 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static void relisten(struct tcp_socket *s);
LIST(socketlist);
/*---------------------------------------------------------------------------*/
PROCESS(tcp_socket_process, "TCP socket process");
@ -58,8 +60,8 @@ senddata(struct tcp_socket *s)
{
int len = MIN(s->output_data_max_seg, uip_mss());
if(s->output_data_len > 0) {
len = MIN(s->output_data_len, len);
if(s->output_senddata_len > 0) {
len = MIN(s->output_senddata_len, len);
s->output_data_send_nxt = len;
uip_send(s->output_data_ptr, len);
}
@ -68,21 +70,27 @@ senddata(struct tcp_socket *s)
static void
acked(struct tcp_socket *s)
{
if(s->output_data_len > 0) {
if(s->output_senddata_len > 0) {
/* Copy the data in the outputbuf down and update outputbufptr and
outputbuf_lastsent */
if(s->output_data_send_nxt > 0) {
memcpy(&s->output_data_ptr[0],
&s->output_data_ptr[s->output_data_send_nxt],
s->output_data_maxlen - s->output_data_send_nxt);
&s->output_data_ptr[s->output_data_send_nxt],
s->output_data_maxlen - s->output_data_send_nxt);
}
if(s->output_data_len < s->output_data_send_nxt) {
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
s->output_data_len,
s->output_data_send_nxt);
s->output_data_len,
s->output_data_send_nxt);
tcp_markconn(uip_conn, NULL);
uip_abort();
call_event(s, TCP_SOCKET_ABORTED);
relisten(s);
return;
}
s->output_data_len -= s->output_data_send_nxt;
s->output_senddata_len = s->output_data_len;
s->output_data_send_nxt = 0;
call_event(s, TCP_SOCKET_DATA_SENT);
@ -134,6 +142,11 @@ appcall(void *state)
{
struct tcp_socket *s = state;
if(s != NULL && s->c != NULL && s->c != uip_conn) {
/* Safe-guard: this should not happen, as the incoming event relates to
* a previous connection */
return;
}
if(uip_connected()) {
/* Check if this connection originated in a local listen
socket. We do this by checking the state pointer - if NULL,
@ -176,8 +189,10 @@ appcall(void *state)
}
if(uip_aborted()) {
tcp_markconn(uip_conn, NULL);
call_event(s, TCP_SOCKET_ABORTED);
relisten(s);
}
if(s == NULL) {
@ -203,13 +218,16 @@ appcall(void *state)
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
uip_close();
s->c = NULL;
tcp_markconn(uip_conn, NULL);
call_event(s, TCP_SOCKET_CLOSED);
s->c = NULL;
/*call_event(s, TCP_SOCKET_CLOSED);*/
relisten(s);
}
if(uip_closed()) {
tcp_markconn(uip_conn, NULL);
s->c = NULL;
call_event(s, TCP_SOCKET_CLOSED);
relisten(s);
}
@ -255,6 +273,7 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
s->ptr = ptr;
s->input_data_ptr = input_databuf;
s->input_data_maxlen = input_databuf_len;
s->output_data_len = 0;
s->output_data_ptr = output_databuf;
s->output_data_maxlen = output_databuf_len;
s->input_callback = input_callback;
@ -268,12 +287,15 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
/*---------------------------------------------------------------------------*/
int
tcp_socket_connect(struct tcp_socket *s,
uip_ipaddr_t *ipaddr,
uint16_t port)
const uip_ipaddr_t *ipaddr,
uint16_t port)
{
if(s == NULL) {
return -1;
}
if(s->c != NULL) {
tcp_markconn(s->c, NULL);
}
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
s->c = tcp_connect(ipaddr, uip_htons(port), s);
PROCESS_CONTEXT_END();
@ -317,7 +339,7 @@ tcp_socket_unlisten(struct tcp_socket *s)
/*---------------------------------------------------------------------------*/
int
tcp_socket_send(struct tcp_socket *s,
const uint8_t *data, int datalen)
const uint8_t *data, int datalen)
{
int len;
@ -329,6 +351,11 @@ tcp_socket_send(struct tcp_socket *s,
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
s->output_data_len += len;
if(s->output_senddata_len == 0) {
s->output_senddata_len = s->output_data_len;
}
return len;
}
/*---------------------------------------------------------------------------*/
@ -365,3 +392,9 @@ tcp_socket_unregister(struct tcp_socket *s)
return 1;
}
/*---------------------------------------------------------------------------*/
int
tcp_socket_max_sendlen(struct tcp_socket *s)
{
return s->output_data_maxlen - s->output_data_len;
}
/*---------------------------------------------------------------------------*/

View file

@ -32,6 +32,8 @@
#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H
#include "uip.h"
struct tcp_socket;
typedef enum {
@ -95,6 +97,7 @@ struct tcp_socket {
uint16_t output_data_maxlen;
uint16_t output_data_len;
uint16_t output_data_send_nxt;
uint16_t output_senddata_len;
uint16_t output_data_max_seg;
uint8_t flags;
@ -170,7 +173,7 @@ int tcp_socket_register(struct tcp_socket *s, void *ptr,
*
*/
int tcp_socket_connect(struct tcp_socket *s,
uip_ipaddr_t *ipaddr,
const uip_ipaddr_t *ipaddr,
uint16_t port);
/**
@ -266,4 +269,19 @@ int tcp_socket_close(struct tcp_socket *s);
*
*/
int tcp_socket_unregister(struct tcp_socket *s);
/**
* \brief The maximum amount of data that could currently be sent
* \param s A pointer to a TCP socket
* \return The number of bytes available in the output buffer
*
* This function queries the TCP socket and returns the
* number of bytes available in the output buffer. This
* function is used before calling tcp_socket_send() to
* ensure that one application level message can be held
* in the output buffer.
*
*/
int tcp_socket_max_sendlen(struct tcp_socket *s);
#endif /* TCP_SOCKET_H */

View file

@ -228,7 +228,7 @@ packet_input(void)
#if UIP_TCP
#if UIP_ACTIVE_OPEN
struct uip_conn *
tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
{
struct uip_conn *c;

View file

@ -165,7 +165,7 @@ CCIF void tcp_unlisten(uint16_t port);
* memory could not be allocated for the connection.
*
*/
CCIF struct uip_conn *tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port,
CCIF struct uip_conn *tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port,
void *appstate);
/**

View file

@ -0,0 +1,236 @@
/**
* \addtogroup uip6
* @{
*/
/**
* \file
* uIP Name Server interface
* \author Víctor Ariño <victor.arino@tado.com>
*/
/*
* Copyright (c) 2014, tado° GmbH.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
#include "contiki.h"
#include "contiki-net.h"
#include "lib/list.h"
#include "lib/memb.h"
#include <string.h>
/** \brief Nameserver record */
typedef struct uip_nameserver_record {
struct uip_nameserver_record *next;
uip_ipaddr_t ip;
uint32_t added;
uint32_t lifetime;
} uip_nameserver_record;
#if UIP_NAMESERVER_POOL_SIZE > 1
/** \brief Initialization flag */
static uint8_t initialized = 0;
#endif
/** \name List and memory block
* @{
*/
#if UIP_NAMESERVER_POOL_SIZE > 1
LIST(dns);
MEMB(dnsmemb, uip_nameserver_record, UIP_NAMESERVER_POOL_SIZE);
#else /* UIP_NAMESERVER_POOL_SIZE > 1 */
static uip_ipaddr_t serveraddr;
static uint32_t serverlifetime;
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
/** @} */
/** \brief Expiration time in seconds */
#define DNS_EXPIRATION(r) \
(((UIP_NAMESERVER_INFINITE_LIFETIME - r->added) <= r->lifetime) ? \
UIP_NAMESERVER_INFINITE_LIFETIME : r->added + r->lifetime)
/*----------------------------------------------------------------------------*/
/**
* Initialize the module variables
*/
#if UIP_NAMESERVER_POOL_SIZE > 1
static CC_INLINE void
init(void)
{
list_init(dns);
memb_init(&dnsmemb);
initialized = 1;
}
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
/*----------------------------------------------------------------------------*/
void
uip_nameserver_update(uip_ipaddr_t *nameserver, uint32_t lifetime)
{
#if UIP_NAMESERVER_POOL_SIZE > 1
register uip_nameserver_record *e;
if(initialized == 0) {
init();
}
for(e = list_head(dns); e != NULL; e = list_item_next(e)) {
if(uip_ipaddr_cmp(&e->ip, nameserver)) {
break;
/* RFC6106: In case there's no more space, the new servers should replace
* the the eldest ones */
}
}
if(e == NULL) {
if((e = memb_alloc(&dnsmemb)) != NULL) {
list_add(dns, e);
} else {
uip_nameserver_record *p;
for(e = list_head(dns), p = list_head(dns); p != NULL;
p = list_item_next(p)) {
if(DNS_EXPIRATION(p) < DNS_EXPIRATION(e)) {
e = p;
}
}
}
}
/* RFC6106: In case the entry is existing the expiration time must be
* updated. Otherwise, new entries are added. */
if(e != NULL) {
if(lifetime == 0) {
memb_free(&dnsmemb, e);
list_remove(dns, e);
} else {
e->added = clock_seconds();
e->lifetime = lifetime;
uip_ipaddr_copy(&e->ip, nameserver);
}
}
#else /* UIP_NAMESERVER_POOL_SIZE > 1 */
uip_ipaddr_copy(&serveraddr, nameserver);
serverlifetime = lifetime;
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
}
/*----------------------------------------------------------------------------*/
#if UIP_NAMESERVER_POOL_SIZE > 1
/**
* Purge expired records
*/
static void
purge(void)
{
register uip_nameserver_record *e = NULL;
uint32_t time = clock_seconds();
for(e = list_head(dns); e != NULL; e = list_item_next(e)) {
if(DNS_EXPIRATION(e) < time) {
list_remove(dns, e);
memb_free(&dnsmemb, e);
e = list_head(dns);
}
}
}
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
/*----------------------------------------------------------------------------*/
uip_ipaddr_t *
uip_nameserver_get(uint8_t num)
{
#if UIP_NAMESERVER_POOL_SIZE > 1
uint8_t i;
uip_nameserver_record *e = NULL;
if(initialized == 0) {
return NULL;
}
purge();
for(i = 1, e = list_head(dns); e != NULL && i <= num;
i++, e = list_item_next(e)) {
}
if(e != NULL) {
return &e->ip;
}
return NULL;
#else /* UIP_NAMESERVER_POOL_SIZE > 1 */
if(num > 0) {
return NULL;
}
return &serveraddr;
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
}
/*----------------------------------------------------------------------------*/
uint32_t
uip_nameserver_next_expiration(void)
{
#if UIP_NAMESERVER_POOL_SIZE > 1
register uip_nameserver_record *e = NULL;
uint32_t exp = UIP_NAMESERVER_INFINITE_LIFETIME;
uint32_t t;
if(initialized == 0 || list_length(dns) == 0) {
return 0;
}
purge();
for(e = list_head(dns); e != NULL; e = list_item_next(e)) {
t = DNS_EXPIRATION(e);
if(t < exp) {
exp = t;
}
}
return exp;
#else /* UIP_NAMESERVER_POOL_SIZE > 1 */
return serverlifetime;
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
}
/*----------------------------------------------------------------------------*/
uint16_t
uip_nameserver_count(void)
{
#if UIP_NAMESERVER_POOL_SIZE > 1
if(initialized == 0) {
return 0;
}
return list_length(dns);
#else /* UIP_NAMESERVER_POOL_SIZE > 1 */
#if NETSTACK_CONF_WITH_IPV6
if(uip_is_addr_unspecified(&serveraddr)) {
#else /* NETSTACK_CONF_WITH_IPV6 */
if(uip_ipaddr_cmp(&serveraddr, &uip_all_zeroes_addr)) {
#endif /* NETSTACK_CONF_WITH_IPV6 */
return 0;
} else {
return 1;
}
#endif /* UIP_NAMESERVER_POOL_SIZE > 1 */
}
/*----------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,101 @@
/**
* \addtogroup uip6
* @{
*/
/**
* \file
* uIP Name Server interface
* \author Víctor Ariño <victor.arino@tado.com>
*/
/*
* Copyright (c) 2014, tado° GmbH.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
#ifndef UIP_NAMESERVER_H_
#define UIP_NAMESERVER_H_
/**
* \name General
* @{
*/
/** \brief Number of Nameservers to keep */
#ifndef UIP_CONF_NAMESERVER_POOL_SIZE
#define UIP_NAMESERVER_POOL_SIZE 1
#else /* UIP_CONF_NAMESERVER_POOL_SIZE */
#define UIP_NAMESERVER_POOL_SIZE UIP_CONF_NAMESERVER_POOL_SIZE
#endif /* UIP_CONF_NAMESERVER_POOL_SIZE */
/** \brief Infinite Lifetime indicator */
#define UIP_NAMESERVER_INFINITE_LIFETIME 0xFFFFFFFF
/** @} */
/**
* \name Nameserver maintenance
* @{
*/
/**
* \brief Insert or update a nameserver into/from the pool
*
* The list is kept according to the RFC6106, which indicates that new entries
* will replace old ones (with lower lifetime) and existing entries will update
* their lifetimes.
*
* \param nameserver Pointer to the nameserver ip address
* \param lifetime Life time of the given address. Minimum is 0, which is
* considered to remove an entry. Maximum is 0xFFFFFFFF which
* is considered infinite.
*/
void uip_nameserver_update(uip_ipaddr_t *nameserver, uint32_t lifetime);
/**
* \brief Get a Nameserver ip address given in RA
*
* \param num The number of the nameserver to obtain, starting at 0 and going
* up to the pool size.
*/
uip_ipaddr_t *uip_nameserver_get(uint8_t num);
/**
* \brief Get next expiration time
*
* The least expiration time is returned
*/
uint32_t uip_nameserver_next_expiration(void);
/**
* \brief Get the number of recorded name servers
*/
uint16_t uip_nameserver_count(void);
/** @} */
#endif /* UIP_NAMESERVER_H_ */
/** @} */

View file

@ -600,7 +600,7 @@ void uip_unlisten(uint16_t port);
* or NULL if no connection could be allocated.
*
*/
struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, uint16_t port);
struct uip_conn *uip_connect(const uip_ipaddr_t *ripaddr, uint16_t port);
@ -1030,10 +1030,10 @@ struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, uint16_t rport);
#define uip_ipaddr_copy(dest, src) (*(dest) = *(src))
#endif
#ifndef uip_ip4addr_copy
#define uip_ip4addr_copy(dest, src) (*(dest) = *(src))
#define uip_ip4addr_copy(dest, src) (*((uip_ip4addr_t *)dest) = *((uip_ip4addr_t *)src))
#endif
#ifndef uip_ip6addr_copy
#define uip_ip6addr_copy(dest, src) (*(dest) = *(src))
#define uip_ip6addr_copy(dest, src) (*((uip_ip6addr_t *)dest) = *((uip_ip6addr_t *)src))
#endif
/**

View file

@ -1,5 +0,0 @@
The `ip64-addr` module converts between IPv4 addresses and
IPv4-encoded IPv6 addresses. It is used in IPv6 networks that are
attached to the IPv4 world through an `ip64` router. With such a
router, IPv6 nodes in the network can reach IPv4 nodes by using their
IPv6-encoded address.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
@ -148,6 +149,7 @@ ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr,
m->ip6port == ip6port &&
uip_ip4addr_cmp(&m->ip4addr, ip4addr) &&
uip_ip6addr_cmp(&m->ip6addr, ip6addr)) {
m->ip6to4++;
return m;
}
}
@ -166,6 +168,7 @@ ip64_addrmap_lookup_port(uint16_t mapped_port, uint8_t protocol)
m->protocol, protocol);
if(m->mapped_port == mapped_port &&
m->protocol == protocol) {
m->ip4to6++;
return m;
}
}
@ -204,6 +207,8 @@ ip64_addrmap_create(const uip_ip6addr_t *ip6addr,
m->ip6port = ip6port;
m->protocol = protocol;
m->flags = FLAGS_NONE;
m->ip6to4 = 1;
m->ip4to6 = 0;
timer_set(&m->timer, 0);
/* Pick a new, unused local port. First make sure that the

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
@ -40,6 +41,7 @@ struct ip64_addrmap_entry {
struct timer timer;
uip_ip6addr_t ip6addr;
uip_ip4addr_t ip4addr;
uint32_t ip6to4, ip4to6;
uint16_t mapped_port;
uint16_t ip6port;
uint16_t ip4port;

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

259
core/net/ip64/ip64-dns64.c Normal file
View file

@ -0,0 +1,259 @@
/*
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ip64.h"
#include "ip64-addr.h"
#include "ip64-dns64.h"
#include <stdio.h>
#define DEBUG 0
#if DEBUG
#undef PRINTF
#define PRINTF(...) printf(__VA_ARGS__)
#else /* DEBUG */
#define PRINTF(...)
#endif /* DEBUG */
struct dns_hdr {
uint8_t id[2];
uint8_t flags1, flags2;
#define DNS_FLAG1_RESPONSE 0x80
#define DNS_FLAG1_OPCODE_STATUS 0x10
#define DNS_FLAG1_OPCODE_INVERSE 0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01
#define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00
#define DNS_FLAG2_ERR_NAME 0x03
uint8_t numquestions[2];
uint8_t numanswers[2];
uint8_t numauthrr[2];
uint8_t numextrarr[2];
};
#define DNS_QUESTION_TYPE0 0
#define DNS_QUESTION_TYPE1 1
#define DNS_QUESTION_CLASS0 2
#define DNS_QUESTION_CLASS1 3
#define DNS_QUESTION_SIZE 4
struct dns_answer {
/* DNS answer record starts with either a domain name or a pointer
* to a name already present somewhere in the packet. */
uint8_t type[2];
uint8_t class[2];
uint8_t ttl[4];
uint8_t len[2];
union {
uint8_t ip6[16];
uint8_t ip4[4];
} addr;
};
#define DNS_TYPE_A 1
#define DNS_TYPE_AAAA 28
#define DNS_CLASS_IN 1
#define DNS_CLASS_ANY 255
/*---------------------------------------------------------------------------*/
void
ip64_dns64_6to4(const uint8_t *ipv6data, int ipv6datalen,
uint8_t *ipv4data, int ipv4datalen)
{
int i, j;
int qlen;
uint8_t *qdata;
uint8_t *q;
struct dns_hdr *hdr;
hdr = (struct dns_hdr *)ipv4data;
PRINTF("ip64_dns64_6to4 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
PRINTF("ip64_dns64_6to4 flags1: 0x%02x\n", hdr->flags1);
PRINTF("ip64_dns64_6to4 flags2: 0x%02x\n", hdr->flags2);
PRINTF("ip64_dns64_6to4 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
PRINTF("ip64_dns64_6to4 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
PRINTF("ip64_dns64_6to4 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
PRINTF("ip64_dns64_6to4 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
/* Find the DNS question header by scanning through the question
labels. */
qdata = ipv4data + sizeof(struct dns_hdr);
for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
do {
qlen = *qdata;
qdata++;
for(j = 0; j < qlen; j++) {
qdata++;
if(qdata > ipv4data + ipv4datalen) {
PRINTF("ip64_dns64_6to4: packet ended while parsing\n");
return;
}
}
} while(qlen != 0);
q = qdata;
if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
q[DNS_QUESTION_TYPE1] = DNS_TYPE_A;
}
qdata += DNS_QUESTION_SIZE;
}
}
/*---------------------------------------------------------------------------*/
int
ip64_dns64_4to6(const uint8_t *ipv4data, int ipv4datalen,
uint8_t *ipv6data, int ipv6datalen)
{
uint8_t n;
int i, j;
int qlen, len;
const uint8_t *qdata, *adata;
uint8_t *qcopy, *acopy, *lenptr;
uint8_t *q;
struct dns_hdr *hdr;
hdr = (struct dns_hdr *)ipv4data;
PRINTF("ip64_dns64_4to6 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
PRINTF("ip64_dns64_4to6 flags1: 0x%02x\n", hdr->flags1);
PRINTF("ip64_dns64_4to6 flags2: 0x%02x\n", hdr->flags2);
PRINTF("ip64_dns64_4to6 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
PRINTF("ip64_dns64_4to6 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
PRINTF("ip64_dns64_4to6 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
PRINTF("ip64_dns64_4to6 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
/* Find the DNS answer header by scanning through the question
labels. */
qdata = ipv4data + sizeof(struct dns_hdr);
qcopy = ipv6data + sizeof(struct dns_hdr);
for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
do {
qlen = *qdata;
qdata++;
qcopy++;
for(j = 0; j < qlen; j++) {
qdata++;
qcopy++;
if(qdata > ipv4data + ipv4datalen) {
PRINTF("ip64_dns64_4to6: packet ended while parsing\n");
return ipv6datalen;
}
}
} while(qlen != 0);
q = qcopy;
if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
q[DNS_QUESTION_TYPE1] = DNS_TYPE_AAAA;
}
qdata += DNS_QUESTION_SIZE;
qcopy += DNS_QUESTION_SIZE;
}
adata = qdata;
acopy = qcopy;
/* Go through the answers section and update the answers. */
for(i = 0; i < ((hdr->numanswers[0] << 8) + hdr->numanswers[1]); i++) {
n = *adata;
if(n & 0xc0) {
/* Short-hand name format: 2 bytes */
*acopy++ = *adata++;
*acopy++ = *adata++;
} else {
/* Name spelled out */
do {
n = *adata;
adata++;
acopy++;
for(j = 0; j < n; j++) {
*acopy++ = *adata++;
}
} while(n != 0);
}
if(adata[0] == 0 && adata[1] == DNS_TYPE_A) {
/* Update the type field from A to AAAA */
*acopy = *adata;
acopy++;
adata++;
*acopy = DNS_TYPE_AAAA;
acopy++;
adata++;
/* Get the length of the address record. Should be 4. */
lenptr = &acopy[6];
len = (adata[6] << 8) + adata[7];
/* Copy the class, the TTL, and the data length */
memcpy(acopy, adata, 2 + 4 + 2);
acopy += 8;
adata += 8;
if(len == 4) {
uip_ip4addr_t addr;
uip_ipaddr(&addr, adata[0], adata[1], adata[2], adata[3]);
ip64_addr_4to6(&addr, (uip_ip6addr_t *)acopy);
adata += len;
acopy += 16;
lenptr[0] = 0;
lenptr[1] = 16;
ipv6datalen += 12;
} else {
memcpy(acopy, adata, len);
acopy += len;
adata += len;
}
} else {
len = (adata[8] << 8) + adata[9];
/* Copy the type, class, the TTL, and the data length */
memcpy(acopy, adata, 2 + 2 + 4 + 2);
acopy += 10;
adata += 10;
/* Copy the data */
memcpy(acopy, adata, len);
acopy += len;
adata += len;
}
}
return ipv6datalen;
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef IP64_DNS64_H_
#define IP64_DNS64_H_
void ip64_dns64_6to4(const uint8_t *ipv6data, int ipv6datalen,
uint8_t *ipv4data, int ipv4datalen);
int ip64_dns64_4to6(const uint8_t *ipv4data, int ipv4datalen,
uint8_t *ipv6data, int ipv6datalen);
#endif /* IP64_DNS64_H_ */

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
@ -58,7 +59,8 @@
#include "ip64-special-ports.h"
#include "ip64-eth-interface.h"
#include "ip64-slip-interface.h"
#include "ip64-dns64.h"
#include "net/ipv6/uip-ds6.h"
#include "ip64-ipv4-dhcp.h"
#include "contiki-net.h"
@ -172,6 +174,8 @@ static uip_ip4addr_t ipv4_broadcast_addr;
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define DNS_PORT 53
/*---------------------------------------------------------------------------*/
void
ip64_init(void)
@ -434,6 +438,15 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
case IP_PROTO_UDP:
PRINTF("ip64_6to4: UDP header\n");
v4hdr->proto = IP_PROTO_UDP;
/* Check if this is a DNS request. If so, we should rewrite it
with the DNS64 module. */
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
ip64_dns64_6to4((uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
ipv6len - IPV6_HDRLEN - sizeof(struct udp_hdr),
(uint8_t *)udphdr + sizeof(struct udp_hdr),
BUFSIZE - IPV4_HDRLEN - sizeof(struct udp_hdr));
}
/* Compute and check the UDP checksum - since we're going to
recompute it ourselves, we must ensure that it was correct in
the first place. */
@ -572,9 +585,18 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
} else {
ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME);
/* Treat DNS requests specially: since the are one-shot, we
/* Treat UDP packets from the IPv6 network to a multicast
address on the IPv4 network differently: since there is
no way for packets from the IPv4 network to go back to
the IPv6 network on these mappings, we'll mark them as
recyclable. */
if(v4hdr->destipaddr.u8[0] == 224) {
ip64_addrmap_set_recycleble(m);
}
/* Treat DNS requests differently: since the are one-shot, we
mark them as recyclable. */
if(udphdr->destport == UIP_HTONS(53)) {
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
ip64_addrmap_set_recycleble(m);
}
}
@ -706,6 +728,21 @@ ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4packet_len,
switch(v4hdr->proto) {
case IP_PROTO_UDP:
v6hdr->nxthdr = IP_PROTO_UDP;
/* Check if this is a DNS request. If so, we should rewrite it
with the DNS64 module. */
if(udphdr->srcport == UIP_HTONS(DNS_PORT)) {
int len;
len = ip64_dns64_4to6((uint8_t *)v4hdr + IPV4_HDRLEN + sizeof(struct udp_hdr),
ipv4len - IPV4_HDRLEN - sizeof(struct udp_hdr),
(uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
ipv6_packet_len - sizeof(struct udp_hdr));
ipv6_packet_len = len + sizeof(struct udp_hdr);
v6hdr->len[0] = ipv6_packet_len >> 8;
v6hdr->len[1] = ipv6_packet_len & 0xff;
ipv6len = ipv6_packet_len + IPV6_HDRLEN;
}
break;
case IP_PROTO_TCP:

View file

@ -10,6 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.

View file

@ -262,8 +262,8 @@ uip_over_mesh_send(void)
if(BUF->proto == UIP_PROTO_TCP) {
#if NETSTACK_CONF_WITH_RIME
packetbuf_set_attr(PACKETBUF_ATTR_ERELIABLE, 1);
#endif /* NETSTACK_CONF_WITH_RIME */
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
#endif /* NETSTACK_CONF_WITH_RIME */
/* packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM);*/
}

View file

@ -75,18 +75,9 @@
#include "net/ipv4/uip_arp.h"
#include "net/ip/uip_arch.h"
#if !NETSTACK_CONF_WITH_IPV6 /* If NETSTACK_CONF_WITH_IPV6 is defined, we compile the
uip6.c file instead of this one. Therefore
this #ifndef removes the entire compilation
output of the uip.c file */
#if NETSTACK_CONF_WITH_IPV6
#include "net/ipv4/uip-neighbor.h"
#endif /* NETSTACK_CONF_WITH_IPV6 */
#include <string.h>
/*---------------------------------------------------------------------------*/
/* Variable definitions. */
@ -395,7 +386,7 @@ uip_init(void)
/*---------------------------------------------------------------------------*/
#if UIP_ACTIVE_OPEN
struct uip_conn *
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
{
register struct uip_conn *conn, *cconn;
@ -1973,6 +1964,4 @@ uip_send(const void *data, int len)
}
}
/*---------------------------------------------------------------------------*/
#endif /* NETSTACK_CONF_WITH_IPV6 */
/** @}*/

View file

@ -1336,11 +1336,6 @@ send_packet(linkaddr_t *dest)
packetbuf_set_addr(PACKETBUF_ADDR_SENDER,(void*)&uip_lladdr);
#endif
/* Force acknowledge from sender (test hardware autoacks) */
#if SICSLOWPAN_CONF_ACK_ALL
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
#endif
/* Provide a callback function to receive the result of
a packet transmission. */
NETSTACK_LLSEC.send(&packet_sent, NULL);
@ -1388,6 +1383,7 @@ output(const uip_lladdr_t *localdest)
set_packet_attrs();
}
#if PACKETBUF_WITH_PACKET_TYPE
#define TCP_FIN 0x01
#define TCP_ACK 0x10
#define TCP_CTL 0x3f
@ -1402,6 +1398,7 @@ output(const uip_lladdr_t *localdest)
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
}
#endif
/*
* The destination address will be tagged to each outbound

View file

@ -280,7 +280,7 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
if(r != NULL) {
uip_ipaddr_t *current_nexthop;
current_nexthop = uip_ds6_route_nexthop(r);
if(uip_ipaddr_cmp(nexthop, current_nexthop)) {
if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) {
/* no need to update route - already correct! */
return r;
}

View file

@ -72,6 +72,7 @@
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/uip-nd6.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ip/uip-nameserver.h"
#include "lib/random.h"
/*------------------------------------------------------------------*/
@ -112,19 +113,23 @@ void uip_log(char *msg);
#define UIP_ND6_OPT_HDR_BUF ((uip_nd6_opt_hdr *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
#define UIP_ND6_OPT_PREFIX_BUF ((uip_nd6_opt_prefix_info *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
#define UIP_ND6_OPT_MTU_BUF ((uip_nd6_opt_mtu *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
/** @} */
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
static uip_ipaddr_t ipaddr;
static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
#endif
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
/*------------------------------------------------------------------*/
/* create a llao */
static void
@ -139,7 +144,7 @@ create_llao(uint8_t *llao, uint8_t type) {
/*------------------------------------------------------------------*/
#if UIP_ND6_SEND_NA
static void
ns_input(void)
{
@ -319,7 +324,7 @@ discard:
uip_len = 0;
return;
}
#endif /* UIP_ND6_SEND_NA */
/*------------------------------------------------------------------*/
@ -385,6 +390,7 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
PRINTF("\n");
return;
}
#if UIP_ND6_SEND_NA
/*------------------------------------------------------------------*/
/**
* Neighbor Advertisement Processing
@ -554,7 +560,7 @@ discard:
uip_len = 0;
return;
}
#endif /* UIP_ND6_SEND_NA */
#if UIP_CONF_ROUTER
#if UIP_ND6_SEND_RA
@ -715,6 +721,29 @@ uip_nd6_ra_output(uip_ipaddr_t * dest)
uip_len += UIP_ND6_OPT_MTU_LEN;
nd6_opt_offset += UIP_ND6_OPT_MTU_LEN;
#if UIP_ND6_RA_RDNSS
if(uip_nameserver_count() > 0) {
uint8_t i = 0;
uip_ipaddr_t *ip = &UIP_ND6_OPT_RDNSS_BUF->ip;
uip_ipaddr_t *dns = NULL;
UIP_ND6_OPT_RDNSS_BUF->type = UIP_ND6_OPT_RDNSS;
UIP_ND6_OPT_RDNSS_BUF->reserved = 0;
UIP_ND6_OPT_RDNSS_BUF->lifetime = uip_nameserver_next_expiration();
if(UIP_ND6_OPT_RDNSS_BUF->lifetime != UIP_NAMESERVER_INFINITE_LIFETIME) {
UIP_ND6_OPT_RDNSS_BUF->lifetime -= clock_seconds();
}
while((dns = uip_nameserver_get(i)) != NULL) {
uip_ipaddr_copy(ip++, dns);
i++;
}
UIP_ND6_OPT_RDNSS_BUF->len = UIP_ND6_OPT_RDNSS_LEN + (i << 1);
PRINTF("%d nameservers reported\n", i);
uip_len += UIP_ND6_OPT_RDNSS_BUF->len << 3;
nd6_opt_offset += UIP_ND6_OPT_RDNSS_BUF->len << 3;
}
#endif /* UIP_ND6_RA_RDNSS */
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
@ -834,7 +863,7 @@ ra_input(void)
(uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
1, NBR_STALE);
} else {
uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
if(nbr->state == NBR_INCOMPLETE) {
nbr->state = NBR_STALE;
}
@ -938,6 +967,23 @@ ra_input(void)
/* End of autonomous flag related processing */
}
break;
#if UIP_ND6_RA_RDNSS
case UIP_ND6_OPT_RDNSS:
if(UIP_ND6_RA_BUF->flags_reserved & (UIP_ND6_O_FLAG << 6)) {
PRINTF("Processing RDNSS option\n");
uint8_t naddr = (UIP_ND6_OPT_RDNSS_BUF->len - 1) / 2;
uip_ipaddr_t *ip = (uip_ipaddr_t *)(&UIP_ND6_OPT_RDNSS_BUF->ip);
PRINTF("got %d nameservers\n", naddr);
while(naddr-- > 0) {
PRINTF(" nameserver: ");
PRINT6ADDR(ip);
PRINTF(" lifetime: %lx\n", uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime));
uip_nameserver_update(ip, uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime));
ip++;
}
}
break;
#endif /* UIP_ND6_RA_RDNSS */
default:
PRINTF("ND option not supported in RA");
break;

View file

@ -87,7 +87,7 @@
#define UIP_ND6_MIN_RA_INTERVAL UIP_CONF_ND6_MIN_RA_INTERVAL
#endif
#define UIP_ND6_M_FLAG 0
#define UIP_ND6_O_FLAG 0
#define UIP_ND6_O_FLAG (UIP_ND6_RA_RDNSS || UIP_ND6_RA_DNSSL)
#define UIP_ND6_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL
#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/
@ -139,6 +139,23 @@
/** @} */
/** \name RFC 6106 RA DNS Options Constants */
/** @{ */
#ifndef UIP_CONF_ND6_RA_RDNSS
#define UIP_ND6_RA_RDNSS 0
#else
#define UIP_ND6_RA_RDNSS UIP_CONF_ND6_RA_RDNSS
#endif
#ifndef UIP_CONF_ND6_RA_DNSSL
#define UIP_ND6_RA_DNSSL 0
#else
#error Not implemented
#define UIP_ND6_RA_DNSSL UIP_CONF_ND6_RA_DNSSL
#endif
/** @} */
/** \name ND6 option types */
/** @{ */
#define UIP_ND6_OPT_SLLAO 1
@ -146,6 +163,8 @@
#define UIP_ND6_OPT_PREFIX_INFO 3
#define UIP_ND6_OPT_REDIRECTED_HDR 4
#define UIP_ND6_OPT_MTU 5
#define UIP_ND6_OPT_RDNSS 25
#define UIP_ND6_OPT_DNSSL 31
/** @} */
/** \name ND6 option types */
@ -168,6 +187,8 @@
#define UIP_ND6_OPT_HDR_LEN 2
#define UIP_ND6_OPT_PREFIX_INFO_LEN 32
#define UIP_ND6_OPT_MTU_LEN 8
#define UIP_ND6_OPT_RDNSS_LEN 1
#define UIP_ND6_OPT_DNSSL_LEN 1
/* Length of TLLAO and SLLAO options, it is L2 dependant */
@ -290,6 +311,15 @@ typedef struct uip_nd6_opt_mtu {
uint32_t mtu;
} uip_nd6_opt_mtu;
/** \brief ND option RDNSS */
typedef struct uip_nd6_opt_dns {
uint8_t type;
uint8_t len;
uint16_t reserved;
uint32_t lifetime;
uip_ipaddr_t ip;
} uip_nd6_opt_dns;
/** \struct Redirected header option */
typedef struct uip_nd6_opt_redirected_hdr {
uint8_t type;

View file

@ -459,7 +459,7 @@ uip_init(void)
/*---------------------------------------------------------------------------*/
#if UIP_TCP && UIP_ACTIVE_OPEN
struct uip_conn *
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
{
register struct uip_conn *conn, *cconn;

View file

@ -341,7 +341,6 @@ powercycle(struct rtimer *t, void *ptr)
while(1) {
static uint8_t packet_seen;
static rtimer_clock_t t0;
static uint8_t count;
#if SYNC_CYCLE_STARTS
@ -365,7 +364,6 @@ powercycle(struct rtimer *t, void *ptr)
packet_seen = 0;
for(count = 0; count < CCA_COUNT_MAX; ++count) {
t0 = RTIMER_NOW();
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
powercycle_turn_radio_on();
/* Check if a packet is seen in the air. If so, we keep the
@ -501,7 +499,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
uint8_t got_strobe_ack = 0;
int len;
uint8_t is_broadcast = 0;
uint8_t is_reliable = 0;
uint8_t is_known_receiver = 0;
uint8_t collisions;
int transmit_len;
@ -548,11 +545,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
#endif /* NETSTACK_CONF_WITH_IPV6 */
}
is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE)
#if NETSTACK_CONF_WITH_RIME
|| packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)
#endif /* NETSTACK_CONF_WITH_RIME */
;
if(!packetbuf_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED)) {
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
@ -676,11 +668,12 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
{
rtimer_clock_t wt;
rtimer_clock_t txtime;
int ret;
txtime = RTIMER_NOW();
ret = NETSTACK_RADIO.transmit(transmit_len);
rtimer_clock_t txtime = RTIMER_NOW();
#if RDC_CONF_HARDWARE_ACK
int ret = NETSTACK_RADIO.transmit(transmit_len);
#else
NETSTACK_RADIO.transmit(transmit_len);
#endif
#if RDC_CONF_HARDWARE_ACK
/* For radios that block in the transmit routine and detect the

View file

@ -373,11 +373,13 @@ send_packet(mac_callback_t sent, void *ptr)
}
metadata->sent = sent;
metadata->cptr = ptr;
#if PACKETBUF_WITH_PACKET_TYPE
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
list_push(n->queued_packet_list, q);
} else {
} else
#endif
{
list_add(n->queued_packet_list, q);
}

View file

@ -453,8 +453,6 @@ send_packet(void)
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
#endif /* NETSTACK_CONF_WITH_IPV6 */
}
/* is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);*/
len = NETSTACK_FRAMER.create();
strobe_len = len + sizeof(struct cxmac_hdr);
if(len < 0 || strobe_len > (int)sizeof(strobe)) {
@ -475,7 +473,7 @@ send_packet(void)
return MAC_TX_ERR;
}
#if WITH_STREAMING
#if WITH_STREAMING && PACKETBUF_WITH_PACKET_TYPE
if(is_streaming == 1 &&
(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
&is_streaming_to) ||
@ -519,7 +517,7 @@ send_packet(void)
wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
expected = now + wait - 2 * DEFAULT_ON_TIME;
#if WITH_ACK_OPTIMIZATION
#if WITH_ACK_OPTIMIZATION && PACKETBUF_WITH_PACKET_TYPE
/* Wait until the receiver is expected to be awake */
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
PACKETBUF_ATTR_PACKET_TYPE_ACK &&
@ -624,12 +622,16 @@ send_packet(void)
/* If we have received the strobe ACK, and we are sending a packet
that will need an upper layer ACK (as signified by the
PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
if(got_strobe_ack && (
#if NETSTACK_CONF_WITH_RIME
packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
#endif /* NETSTACK_CONF_WITH_RIME */
#if PACKETBUF_WITH_PACKET_TYPE
packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
PACKETBUF_ATTR_PACKET_TYPE_STREAM ||
#endif
0)) {
on(); /* Wait for ACK packet */
waiting_for_packet = 1;
} else {

View file

@ -242,8 +242,10 @@ parse(void)
}
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
/* packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, frame.fcf.ack_required);*/
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
#if NETSTACK_CONF_WITH_RIME
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
#endif
#if LLSEC802154_SECURITY_LEVEL
if(frame.fcf.security_enabled) {

View file

@ -74,7 +74,7 @@ mac_sequence_is_duplicate(void)
for(i = 0; i < MAX_SEQNOS; ++i) {
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
&received_seqnos[i].sender)) {
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno) {
if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno) {
/* Duplicate packet. */
return 1;
}
@ -102,7 +102,7 @@ mac_sequence_register_seqno(void)
for(j = i - 1; j > 0; --j) {
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
}
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
linkaddr_copy(&received_seqnos[0].sender,
packetbuf_addr(PACKETBUF_ADDR_SENDER));
}

View file

@ -264,11 +264,13 @@ send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
static void
packet_input(void)
{
#if NULLRDC_SEND_802154_ACK
int original_datalen;
uint8_t *original_dataptr;
original_datalen = packetbuf_datalen();
original_dataptr = packetbuf_dataptr();
#endif
#if NULLRDC_802154_AUTOACK
if(packetbuf_datalen() == ACK_LEN) {
@ -294,7 +296,7 @@ packet_input(void)
if(duplicate) {
/* Drop the packet. */
PRINTF("nullrdc: drop duplicate link layer packet %u\n",
packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
} else {
mac_sequence_register_seqno();
}

View file

@ -106,7 +106,9 @@ send_packet(mac_callback_t sent, void *ptr)
params.fcf.frame_type = FRAME802154_DATAFRAME;
params.fcf.security_enabled = 0;
params.fcf.frame_pending = 0;
#if NETSTACK_CONF_WITH_RIME
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
#endif
params.fcf.panid_compression = 0;
/* Insert IEEE 802.15.4 (2003) version bit. */

View file

@ -106,10 +106,7 @@ packetbuf_compact(void)
{
int i, len;
if(packetbuf_is_reference()) {
memcpy(&packetbuf[PACKETBUF_HDR_SIZE], packetbuf_reference_ptr(),
packetbuf_datalen());
} else if(bufptr > 0) {
if(bufptr > 0) {
len = packetbuf_datalen() + PACKETBUF_HDR_SIZE;
for(i = PACKETBUF_HDR_SIZE; i < len; i++) {
packetbuf[i] = packetbuf[bufptr + i];
@ -215,26 +212,6 @@ packetbuf_hdrptr(void)
return (void *)(&packetbuf[hdrptr]);
}
/*---------------------------------------------------------------------------*/
void
packetbuf_reference(void *ptr, uint16_t len)
{
packetbuf_clear();
packetbufptr = ptr;
buflen = len;
}
/*---------------------------------------------------------------------------*/
int
packetbuf_is_reference(void)
{
return packetbufptr != &packetbuf[PACKETBUF_HDR_SIZE];
}
/*---------------------------------------------------------------------------*/
void *
packetbuf_reference_ptr(void)
{
return packetbufptr;
}
/*---------------------------------------------------------------------------*/
uint16_t
packetbuf_datalen(void)
{

View file

@ -74,6 +74,12 @@
#define PACKETBUF_HDR_SIZE 48
#endif
#ifdef PACKETBUF_CONF_WITH_PACKET_TYPE
#define PACKETBUF_WITH_PACKET_TYPE PACKETBUF_CONF_WITH_PACKET_TYPE
#else
#define PACKETBUF_WITH_PACKET_TYPE NETSTACK_CONF_WITH_RIME
#endif
/**
* \brief Clear and reset the packetbuf
*
@ -181,52 +187,12 @@ uint16_t packetbuf_totlen(void);
*/
void packetbuf_set_datalen(uint16_t len);
/**
* \brief Point the packetbuf to external data
* \param ptr A pointer to the external data
* \param len The length of the external data
*
* For outbound packets, the packetbuf consists of two
* parts: header and data. This function is used to make
* the packetbuf point to external data. The function also
* specifies the length of the external data that the
* packetbuf references.
*/
void packetbuf_reference(void *ptr, uint16_t len);
/**
* \brief Check if the packetbuf references external data
* \retval Non-zero if the packetbuf references external data, zero otherwise.
*
* For outbound packets, the packetbuf consists of two
* parts: header and data. This function is used to check
* if the packetbuf points to external data that has
* previously been referenced with packetbuf_reference().
*
*/
int packetbuf_is_reference(void);
/**
* \brief Get a pointer to external data referenced by the packetbuf
* \retval A pointer to the external data
*
* For outbound packets, the packetbuf consists of two
* parts: header and data. The data may point to external
* data that has previously been referenced with
* packetbuf_reference(). This function is used to get a
* pointer to the external data.
*
*/
void *packetbuf_reference_ptr(void);
/**
* \brief Compact the packetbuf
*
* This function compacts the packetbuf by copying the data
* portion of the packetbuf so that becomes consecutive to
* the header. It also copies external data that has
* previously been referenced with packetbuf_reference()
* into the packetbuf.
* the header.
*
* This function is called by the Rime code before a
* packet is to be sent by a device driver. This assures
@ -257,9 +223,7 @@ int packetbuf_copyfrom(const void *from, uint16_t len);
*
* This function copies the packetbuf to an external
* buffer. Both the data portion and the header portion of
* the packetbuf is copied. If the packetbuf referenced
* external data (referenced with packetbuf_reference()) the
* external data is copied.
* the packetbuf is copied.
*
* The external buffer to which the packetbuf is to be
* copied must be able to accomodate at least
@ -351,10 +315,12 @@ enum {
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
/* Scope 1 attributes: used between two neighbors only. */
PACKETBUF_ATTR_RELIABLE,
PACKETBUF_ATTR_PACKET_ID,
#if PACKETBUF_WITH_PACKET_TYPE
PACKETBUF_ATTR_PACKET_TYPE,
#endif
#if NETSTACK_CONF_WITH_RIME
PACKETBUF_ATTR_PACKET_ID,
PACKETBUF_ATTR_RELIABLE,
PACKETBUF_ATTR_REXMIT,
PACKETBUF_ATTR_MAX_REXMIT,
PACKETBUF_ATTR_NUM_REXMIT,

View file

@ -43,18 +43,13 @@
*/
#include "contiki-net.h"
#if WITH_SWAP
#include "cfs/cfs.h"
#endif
#include <string.h> /* for memcpy() */
#ifdef QUEUEBUF_CONF_REF_NUM
#define QUEUEBUF_REF_NUM QUEUEBUF_CONF_REF_NUM
#else
#define QUEUEBUF_REF_NUM 2
#endif
/* Structure pointing to a buffer either stored
in RAM or swapped in CFS */
struct queuebuf {
@ -83,15 +78,7 @@ struct queuebuf_data {
struct packetbuf_addr addrs[PACKETBUF_NUM_ADDRS];
};
struct queuebuf_ref {
uint16_t len;
uint8_t *ref;
uint8_t hdr[PACKETBUF_HDR_SIZE];
uint8_t hdrlen;
};
MEMB(bufmem, struct queuebuf, QUEUEBUF_NUM);
MEMB(refbufmem, struct queuebuf_ref, QUEUEBUF_REF_NUM);
MEMB(buframmem, struct queuebuf_data, QUEUEBUFRAM_NUM);
#if WITH_SWAP
@ -144,7 +131,7 @@ LIST(queuebuf_list);
#endif /* QUEUEBUF_CONF_STATS */
#if QUEUEBUF_STATS
uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len;
uint8_t queuebuf_len, queuebuf_max_len;
#endif /* QUEUEBUF_STATS */
#if WITH_SWAP
@ -301,20 +288,15 @@ queuebuf_init(void)
#endif
memb_init(&buframmem);
memb_init(&bufmem);
memb_init(&refbufmem);
#if QUEUEBUF_STATS
queuebuf_max_len = QUEUEBUF_NUM;
queuebuf_max_len = 0;
#endif /* QUEUEBUF_STATS */
}
/*---------------------------------------------------------------------------*/
int
queuebuf_numfree(void)
{
if(packetbuf_is_reference()) {
return memb_numfree(&refbufmem);
} else {
return memb_numfree(&bufmem);
}
return memb_numfree(&bufmem);
}
/*---------------------------------------------------------------------------*/
#if QUEUEBUF_DEBUG
@ -326,81 +308,62 @@ queuebuf_new_from_packetbuf(void)
#endif /* QUEUEBUF_DEBUG */
{
struct queuebuf *buf;
struct queuebuf_ref *rbuf;
if(packetbuf_is_reference()) {
rbuf = memb_alloc(&refbufmem);
if(rbuf != NULL) {
#if QUEUEBUF_STATS
++queuebuf_ref_len;
#endif /* QUEUEBUF_STATS */
rbuf->len = packetbuf_datalen();
rbuf->ref = packetbuf_reference_ptr();
rbuf->hdrlen = packetbuf_copyto_hdr(rbuf->hdr);
} else {
PRINTF("queuebuf_new_from_packetbuf: could not allocate a reference queuebuf\n");
}
return (struct queuebuf *)rbuf;
} else {
struct queuebuf_data *buframptr;
buf = memb_alloc(&bufmem);
if(buf != NULL) {
struct queuebuf_data *buframptr;
buf = memb_alloc(&bufmem);
if(buf != NULL) {
#if QUEUEBUF_DEBUG
list_add(queuebuf_list, buf);
buf->file = file;
buf->line = line;
buf->time = clock_time();
list_add(queuebuf_list, buf);
buf->file = file;
buf->line = line;
buf->time = clock_time();
#endif /* QUEUEBUF_DEBUG */
buf->ram_ptr = memb_alloc(&buframmem);
buf->ram_ptr = memb_alloc(&buframmem);
#if WITH_SWAP
/* If the allocation failed, store the qbuf in swap files */
if(buf->ram_ptr != NULL) {
buf->location = IN_RAM;
buframptr = buf->ram_ptr;
} else {
buf->location = IN_CFS;
buf->swap_id = -1;
tmpdata_qbuf = buf;
buframptr = &tmpdata;
}
/* If the allocation failed, store the qbuf in swap files */
if(buf->ram_ptr != NULL) {
buf->location = IN_RAM;
buframptr = buf->ram_ptr;
} else {
buf->location = IN_CFS;
buf->swap_id = -1;
tmpdata_qbuf = buf;
buframptr = &tmpdata;
}
#else
if(buf->ram_ptr == NULL) {
PRINTF("queuebuf_new_from_packetbuf: could not queuebuf data\n");
if(buf->ram_ptr == NULL) {
PRINTF("queuebuf_new_from_packetbuf: could not queuebuf data\n");
memb_free(&bufmem, buf);
return NULL;
}
buframptr = buf->ram_ptr;
#endif
buframptr->len = packetbuf_copyto(buframptr->data);
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
#if WITH_SWAP
if(buf->location == IN_CFS) {
if(queuebuf_flush_tmpdata() == -1) {
/* We were unable to write the data in the swap */
memb_free(&bufmem, buf);
return NULL;
}
buframptr = buf->ram_ptr;
#endif
buframptr->len = packetbuf_copyto(buframptr->data);
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
#if WITH_SWAP
if(buf->location == IN_CFS) {
if(queuebuf_flush_tmpdata() == -1) {
/* We were unable to write the data in the swap */
memb_free(&bufmem, buf);
return NULL;
}
}
}
#endif
#if QUEUEBUF_STATS
++queuebuf_len;
PRINTF("queuebuf len %d\n", queuebuf_len);
printf("#A q=%d\n", queuebuf_len);
if(queuebuf_len == queuebuf_max_len + 1) {
queuebuf_free(buf);
queuebuf_len--;
return NULL;
}
++queuebuf_len;
PRINTF("#A q=%d\n", queuebuf_len);
if(queuebuf_len > queuebuf_max_len) {
queuebuf_max_len = queuebuf_len;
}
#endif /* QUEUEBUF_STATS */
} else {
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
}
return buf;
} else {
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
}
return buf;
}
/*---------------------------------------------------------------------------*/
void
@ -444,47 +407,30 @@ queuebuf_free(struct queuebuf *buf)
memb_free(&bufmem, buf);
#if QUEUEBUF_STATS
--queuebuf_len;
printf("#A q=%d\n", queuebuf_len);
PRINTF("#A q=%d\n", queuebuf_len);
#endif /* QUEUEBUF_STATS */
#if QUEUEBUF_DEBUG
list_remove(queuebuf_list, buf);
#endif /* QUEUEBUF_DEBUG */
} else if(memb_inmemb(&refbufmem, buf)) {
memb_free(&refbufmem, buf);
#if QUEUEBUF_STATS
--queuebuf_ref_len;
#endif /* QUEUEBUF_STATS */
}
}
/*---------------------------------------------------------------------------*/
void
queuebuf_to_packetbuf(struct queuebuf *b)
{
struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) {
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
packetbuf_copyfrom(buframptr->data, buframptr->len);
packetbuf_attr_copyfrom(buframptr->attrs, buframptr->addrs);
} else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b;
packetbuf_clear();
packetbuf_copyfrom(r->ref, r->len);
packetbuf_hdralloc(r->hdrlen);
memcpy(packetbuf_hdrptr(), r->hdr, r->hdrlen);
}
}
/*---------------------------------------------------------------------------*/
void *
queuebuf_dataptr(struct queuebuf *b)
{
struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) {
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return buframptr->data;
} else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b;
return r->ref;
}
return NULL;
}

View file

@ -1,242 +0,0 @@
/*
* Copyright (c) 2007, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* Rudolph0: a simple block data flooding protocol
* \author
* Adam Dunkels <adam@sics.se>
*/
/**
* \addtogroup rudolph0
* @{
*/
#include <stddef.h> /* for offsetof */
#include "net/rime/rime.h"
#include "net/rime/rudolph0.h"
#define STEADY_TIME CLOCK_SECOND * 2
#define DEFAULT_SEND_INTERVAL CLOCK_SECOND / 2
enum {
TYPE_DATA,
TYPE_NACK,
};
enum {
STATE_RECEIVER,
STATE_SENDER,
};
#define VERSION_LT(a, b) ((signed char)((a) - (b)) < 0)
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
static void
read_new_datapacket(struct rudolph0_conn *c)
{
int len = 0;
if(c->cb->read_chunk) {
len = c->cb->read_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
c->current.data, RUDOLPH0_DATASIZE);
}
c->current.datalen = len;
PRINTF("read_new_datapacket len %d\n", len);
}
/*---------------------------------------------------------------------------*/
static void
send_nack(struct rudolph0_conn *c)
{
struct rudolph0_hdr *hdr;
packetbuf_clear();
packetbuf_hdralloc(sizeof(struct rudolph0_hdr));
hdr = packetbuf_hdrptr();
hdr->type = TYPE_NACK;
hdr->version = c->current.h.version;
hdr->chunk = c->current.h.chunk;
PRINTF("Sending nack for %d:%d\n", hdr->version, hdr->chunk);
polite_send(&c->nackc, c->send_interval / 2, sizeof(struct rudolph0_hdr));
}
/*---------------------------------------------------------------------------*/
static void
sent(struct stbroadcast_conn *stbroadcast)
{
struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
if(c->current.datalen == RUDOLPH0_DATASIZE) {
c->current.h.chunk++;
PRINTF("Sending data chunk %d next time\n", c->current.h.chunk);
read_new_datapacket(c);
} else {
stbroadcast_set_timer(&c->c, STEADY_TIME);
PRINTF("Steady: Sending the same data chunk next time datalen %d, %d\n",
c->current.datalen, RUDOLPH0_DATASIZE);
}
}
/*---------------------------------------------------------------------------*/
static void
recv(struct stbroadcast_conn *stbroadcast)
{
struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
struct rudolph0_datapacket *p = packetbuf_dataptr();
if(p->h.type == TYPE_DATA) {
if(c->current.h.version != p->h.version) {
PRINTF("rudolph0 new version %d\n", p->h.version);
c->current.h.version = p->h.version;
c->current.h.chunk = 0;
c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NEWFILE, p->data, 0);
if(p->h.chunk != 0) {
send_nack(c);
} else {
c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NONE, p->data, p->datalen);
c->current.h.chunk++;
}
} else if(p->h.version == c->current.h.version) {
if(p->h.chunk == c->current.h.chunk) {
PRINTF("received chunk %d\n", p->h.chunk);
if(p->datalen < RUDOLPH0_DATASIZE) {
c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
RUDOLPH0_FLAG_LASTCHUNK, p->data, p->datalen);
} else {
c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
RUDOLPH0_FLAG_NONE, p->data, p->datalen);
}
c->current.h.chunk++;
} else if(p->h.chunk > c->current.h.chunk) {
PRINTF("received chunk %d > %d, sending NACK\n", p->h.chunk, c->current.h.chunk);
send_nack(c);
}
} else { /* p->h.version < c->current.h.version */
/* Ignore packets with old version */
}
}
}
/*---------------------------------------------------------------------------*/
static void
recv_nack(struct polite_conn *polite)
{
struct rudolph0_conn *c = (struct rudolph0_conn *)
((char *)polite - offsetof(struct rudolph0_conn,
nackc));
struct rudolph0_datapacket *p = packetbuf_dataptr();
if(p->h.type == TYPE_NACK && c->state == STATE_SENDER) {
if(p->h.version == c->current.h.version) {
PRINTF("Reseting chunk to %d\n", p->h.chunk);
c->current.h.chunk = p->h.chunk;
} else {
PRINTF("Wrong version, reseting chunk to 0\n");
c->current.h.chunk = 0;
}
read_new_datapacket(c);
stbroadcast_set_timer(&c->c, c->send_interval);
}
}
/*---------------------------------------------------------------------------*/
static const struct polite_callbacks polite = { recv_nack, 0, 0 };
static const struct stbroadcast_callbacks stbroadcast = { recv, sent };
/*---------------------------------------------------------------------------*/
void
rudolph0_open(struct rudolph0_conn *c, uint16_t channel,
const struct rudolph0_callbacks *cb)
{
stbroadcast_open(&c->c, channel, &stbroadcast);
polite_open(&c->nackc, channel + 1, &polite);
c->cb = cb;
c->current.h.version = 0;
c->state = STATE_RECEIVER;
c->send_interval = DEFAULT_SEND_INTERVAL;
}
/*---------------------------------------------------------------------------*/
void
rudolph0_close(struct rudolph0_conn *c)
{
stbroadcast_close(&c->c);
polite_close(&c->nackc);
}
/*---------------------------------------------------------------------------*/
void
rudolph0_send(struct rudolph0_conn *c, clock_time_t send_interval)
{
c->state = STATE_SENDER;
c->current.h.version++;
c->current.h.version++;
c->current.h.chunk = 0;
c->current.h.type = TYPE_DATA;
read_new_datapacket(c);
packetbuf_reference(&c->current, sizeof(struct rudolph0_datapacket));
c->send_interval = send_interval;
stbroadcast_send_stubborn(&c->c, c->send_interval);
}
/*---------------------------------------------------------------------------*/
void
rudolph0_force_restart(struct rudolph0_conn *c)
{
c->current.h.chunk = 0;
send_nack(c);
}
/*---------------------------------------------------------------------------*/
void
rudolph0_stop(struct rudolph0_conn *c)
{
stbroadcast_cancel(&c->c);
}
/*---------------------------------------------------------------------------*/
int
rudolph0_version(struct rudolph0_conn *c)
{
return c->current.h.version;
}
/*---------------------------------------------------------------------------*/
void
rudolph0_set_version(struct rudolph0_conn *c, int version)
{
c->current.h.version = version;
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -1,122 +0,0 @@
/*
* Copyright (c) 2007, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* Header file for the single-hop reliable bulk data transfer module
* \author
* Adam Dunkels <adam@sics.se>
*/
/**
* \addtogroup rime
* @{
*/
/**
* \defgroup rudolph0 Single-hop reliable bulk data transfer (rudolph0)
* @{
*
* The rudolph0 module implements a single-hop reliable bulk data
* transfer mechanism.
*
* \section rudolph0-channels Channels
*
* The rudolph0 module uses 2 channels; one for data packets and one
* for NACK and repair packets.
*
*/
#ifndef RUDOLPH0_H_
#define RUDOLPH0_H_
#include "net/rime/stbroadcast.h"
#include "net/rime/polite.h"
struct rudolph0_conn;
enum {
RUDOLPH0_FLAG_NONE,
RUDOLPH0_FLAG_NEWFILE,
RUDOLPH0_FLAG_LASTCHUNK,
};
struct rudolph0_callbacks {
void (* write_chunk)(struct rudolph0_conn *c, int offset, int flag,
uint8_t *data, int len);
int (* read_chunk)(struct rudolph0_conn *c, int offset, uint8_t *to,
int maxsize);
};
#ifdef RUDOLPH0_CONF_DATASIZE
#define RUDOLPH0_DATASIZE RUDOLPH0_CONF_DATASIZE
#else
#define RUDOLPH0_DATASIZE 64
#endif
struct rudolph0_hdr {
uint8_t type;
uint8_t version;
uint16_t chunk;
};
struct rudolph0_datapacket {
struct rudolph0_hdr h;
uint8_t datalen;
uint8_t data[RUDOLPH0_DATASIZE];
};
struct rudolph0_conn {
struct stbroadcast_conn c;
struct polite_conn nackc;
const struct rudolph0_callbacks *cb;
clock_time_t send_interval;
uint8_t state;
struct rudolph0_datapacket current;
};
void rudolph0_open(struct rudolph0_conn *c, uint16_t channel,
const struct rudolph0_callbacks *cb);
void rudolph0_close(struct rudolph0_conn *c);
void rudolph0_send(struct rudolph0_conn *c, clock_time_t interval);
void rudolph0_stop(struct rudolph0_conn *c);
/* Force the sender to restart sending the file from the start. */
void rudolph0_force_restart(struct rudolph0_conn *c);
void rudolph0_set_version(struct rudolph0_conn *c, int version);
int rudolph0_version(struct rudolph0_conn *c);
#endif /* RUDOLPH0_H_ */
/** @} */
/** @} */

View file

@ -195,4 +195,77 @@
#define RPL_PREFERENCE 0
#endif
/*
* Hop-by-hop option
* This option control the insertion of the RPL Hop-by-Hop extension header
* into packets originating from this node. Incoming Hop-by-hop extension
* header are still processed and forwarded.
*/
#ifdef RPL_CONF_INSERT_HBH_OPTION
#define RPL_INSERT_HBH_OPTION RPL_CONF_INSERT_HBH_OPTION
#else
#define RPL_INSERT_HBH_OPTION 1
#endif
/*
* RPL probing. When enabled, probes will be sent periodically to keep
* parent link estimates up to date.
* */
#ifdef RPL_CONF_WITH_PROBING
#define RPL_WITH_PROBING RPL_CONF_WITH_PROBING
#else
#define RPL_WITH_PROBING 1
#endif
/*
* RPL probing interval.
* */
#ifdef RPL_CONF_PROBING_INTERVAL
#define RPL_PROBING_INTERVAL RPL_CONF_PROBING_INTERVAL
#else
#define RPL_PROBING_INTERVAL (120 * CLOCK_SECOND)
#endif
/*
* RPL probing expiration time.
* */
#ifdef RPL_CONF_PROBING_EXPIRATION_TIME
#define RPL_PROBING_EXPIRATION_TIME RPL_CONF_PROBING_EXPIRATION_TIME
#else
#define RPL_PROBING_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
#endif
/*
* Function used to select the next parent to be probed.
* */
#ifdef RPL_CONF_PROBING_SELECT_FUNC
#define RPL_PROBING_SELECT_FUNC RPL_CONF_PROBING_SELECT_FUNC
#else
#define RPL_PROBING_SELECT_FUNC(dag) get_probing_target((dag))
#endif
/*
* Function used to send RPL probes.
* To probe with DIO, use:
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) dio_output((instance), (addr))
* To probe with DIS, use:
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) dis_output((addr))
* Any other custom probing function is also acceptable.
* */
#ifdef RPL_CONF_PROBING_SEND_FUNC
#define RPL_PROBING_SEND_FUNC RPL_CONF_PROBING_SEND_FUNC
#else
#define RPL_PROBING_SEND_FUNC(instance, addr) dio_output((instance), (addr))
#endif
/*
* Function used to calculate next RPL probing interval
* */
#ifdef RPL_CONF_PROBING_DELAY_FUNC
#define RPL_PROBING_DELAY_FUNC RPL_CONF_PROBING_DELAY_FUNC
#else
#define RPL_PROBING_DELAY_FUNC() ((RPL_PROBING_INTERVAL / 2) \
+ random_rand() % (RPL_PROBING_INTERVAL))
#endif
#endif /* RPL_CONF_H */

260
core/net/rpl/rpl-dag-root.c Normal file
View file

@ -0,0 +1,260 @@
/*
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "contiki.h"
#include "contiki-net.h"
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-dag-root.h"
#include <string.h>
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
static struct uip_ds6_notification n;
static uint8_t to_become_root;
static struct ctimer c;
/*---------------------------------------------------------------------------*/
static const uip_ipaddr_t *
dag_root(void)
{
rpl_dag_t *dag;
dag = rpl_get_any_dag();
if(dag != NULL) {
return &dag->dag_id;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
static const uip_ipaddr_t *
get_global_address(void)
{
int i;
uint8_t state;
uip_ipaddr_t *ipaddr = NULL;
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
state == ADDR_PREFERRED &&
!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
}
}
return ipaddr;
}
/*---------------------------------------------------------------------------*/
static void
create_dag_callback(void *ptr)
{
const uip_ipaddr_t *root, *ipaddr;
root = dag_root();
ipaddr = get_global_address();
if(root == NULL || uip_ipaddr_cmp(root, ipaddr)) {
/* The RPL network we are joining is one that we created, so we
become root. */
if(to_become_root) {
rpl_dag_root_init_dag_immediately();
to_become_root = 0;
}
} else {
rpl_dag_t *dag;
dag = rpl_get_any_dag();
#if DEBUG
printf("Found a network we did not create\n");
printf("version %d grounded %d preference %d used %d joined %d rank %d\n",
dag->version, dag->grounded,
dag->preference, dag->used,
dag->joined, dag->rank);
#endif /* DEBUG */
/* We found a RPL network that we did not create so we just join
it without becoming root. But if the network has an infinite
rank, we assume the network has broken, and we become the new
root of the network. */
if(dag->rank == INFINITE_RANK) {
if(to_become_root) {
rpl_dag_root_init_dag_immediately();
to_become_root = 0;
}
}
/* Try again after the grace period */
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
}
}
/*---------------------------------------------------------------------------*/
static void
route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
int numroutes)
{
if(event == UIP_DS6_NOTIFICATION_DEFRT_ADD) {
if(route != NULL && ipaddr != NULL &&
!uip_is_addr_unspecified(route) &&
!uip_is_addr_unspecified(ipaddr)) {
if(to_become_root) {
ctimer_set(&c, 0, create_dag_callback, NULL);
}
}
}
}
/*---------------------------------------------------------------------------*/
static uip_ipaddr_t *
set_global_address(void)
{
static uip_ipaddr_t ipaddr;
int i;
uint8_t state;
/* Assign a unique local address (RFC4193,
http://tools.ietf.org/html/rfc4193). */
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
printf("IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
printf("\n");
}
}
return &ipaddr;
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init(void)
{
static uint8_t initialized = 0;
if(!initialized) {
to_become_root = 0;
set_global_address();
uip_ds6_notification_add(&n, route_callback);
initialized = 1;
}
}
/*---------------------------------------------------------------------------*/
int
rpl_dag_root_init_dag_immediately(void)
{
struct uip_ds6_addr *root_if;
int i;
uint8_t state;
uip_ipaddr_t *ipaddr = NULL;
rpl_dag_root_init();
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
state == ADDR_PREFERRED &&
!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
}
}
if(ipaddr != NULL) {
root_if = uip_ds6_addr_lookup(ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
uip_ipaddr_t prefix;
rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr);
dag = rpl_get_any_dag();
/* If there are routes in this dag, we remove them all as we are
from now on the new dag root and the old routes are wrong */
rpl_remove_routes(dag);
if(dag->instance != NULL &&
dag->instance->def_route != NULL) {
uip_ds6_defrt_rm(dag->instance->def_route);
dag->instance->def_route = NULL;
}
uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &prefix, 64);
PRINTF("rpl_dag_root_init_dag: created a new RPL dag\n");
return 0;
} else {
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
return -1;
}
} else {
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n");
return -2;
}
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init_dag(void)
{
rpl_dag_root_init();
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
to_become_root = 1;
/* Send a DIS packet to request RPL info from neighbors. */
dis_output(NULL);
}
/*---------------------------------------------------------------------------*/
int
rpl_dag_root_is_root(void)
{
rpl_instance_t *instance;
instance = rpl_get_default_instance();
if(instance == NULL) {
return 0;
}
if(instance->current_dag &&
instance->current_dag->rank == ROOT_RANK(instance)) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef RPL_DAG_ROOT_H_
#define RPL_DAG_ROOT_H_
void rpl_dag_root_init(void);
void rpl_dag_root_init_dag(void);
int rpl_dag_root_init_dag_immediately(void);
int rpl_dag_root_is_root(void);
#endif /* RPL_DAG_ROOT_H_ */

View file

@ -75,12 +75,37 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF};
/*---------------------------------------------------------------------------*/
/* Per-parent RPL information */
NBR_TABLE(rpl_parent_t, rpl_parents);
NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);
/*---------------------------------------------------------------------------*/
/* Allocate instance table. */
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
rpl_instance_t *default_instance;
/*---------------------------------------------------------------------------*/
void
rpl_print_neighbor_list()
{
if(default_instance != NULL && default_instance->current_dag != NULL &&
default_instance->of != NULL && default_instance->of->calculate_rank != NULL) {
int curr_dio_interval = default_instance->dio_intcurrent;
int curr_rank = default_instance->current_dag->rank;
rpl_parent_t *p = nbr_table_head(rpl_parents);
clock_time_t now = clock_time();
printf("RPL: rank %u dioint %u, %u nbr(s)\n", curr_rank, curr_dio_interval, uip_ds6_nbr_num());
while(p != NULL) {
uip_ds6_nbr_t *nbr = rpl_get_nbr(p);
printf("RPL: nbr %3u %5u, %5u => %5u %c (last tx %u min ago)\n",
nbr_table_get_lladdr(rpl_parents, p)->u8[7],
p->rank, nbr ? nbr->link_metric : 0,
default_instance->of->calculate_rank(p, 0),
p == default_instance->current_dag->preferred_parent ? '*' : ' ',
(unsigned)((now - p->last_tx_time) / (60 * CLOCK_SECOND)));
p = nbr_table_next(rpl_parents, p);
}
printf("RPL: end of list\n");
}
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
rpl_get_nbr(rpl_parent_t *parent)
@ -269,17 +294,27 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
rpl_dag_t *dag;
rpl_instance_t *instance;
uint8_t version;
int i;
version = RPL_LOLLIPOP_INIT;
dag = get_dag(instance_id, dag_id);
if(dag != NULL) {
version = dag->version;
RPL_LOLLIPOP_INCREMENT(version);
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
if(dag == dag->instance->current_dag) {
dag->instance->current_dag = NULL;
instance = rpl_get_instance(instance_id);
if(instance != NULL) {
for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
dag = &instance->dag_table[i];
if(dag->used) {
if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
version = dag->version;
RPL_LOLLIPOP_INCREMENT(version);
}
if(dag == dag->instance->current_dag) {
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
dag->instance->current_dag = NULL;
} else {
PRINTF("RPL: Dropping a DAG when setting this node as root");
}
rpl_free_dag(dag);
}
}
rpl_free_dag(dag);
}
dag = rpl_alloc_dag(instance_id, dag_id);
@ -474,6 +509,9 @@ rpl_alloc_instance(uint8_t instance_id)
instance->instance_id = instance_id;
instance->def_route = NULL;
instance->used = 1;
#if RPL_WITH_PROBING
rpl_schedule_probing(instance);
#endif /* RPL_WITH_PROBING */
return instance;
}
}
@ -507,7 +545,6 @@ rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
}
RPL_STAT(rpl_stats.mem_overflows++);
rpl_free_instance(instance);
return NULL;
}
/*---------------------------------------------------------------------------*/
@ -517,6 +554,12 @@ rpl_set_default_instance(rpl_instance_t *instance)
default_instance = instance;
}
/*---------------------------------------------------------------------------*/
rpl_instance_t *
rpl_get_default_instance(void)
{
return default_instance;
}
/*---------------------------------------------------------------------------*/
void
rpl_free_instance(rpl_instance_t *instance)
{
@ -534,6 +577,9 @@ rpl_free_instance(rpl_instance_t *instance)
rpl_set_default_route(instance, NULL);
#if RPL_WITH_PROBING
ctimer_stop(&instance->probing_timer);
#endif /* RPL_WITH_PROBING */
ctimer_stop(&instance->dio_timer);
ctimer_stop(&instance->dao_timer);
ctimer_stop(&instance->dao_lifetime_timer);
@ -729,6 +775,9 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
rpl_schedule_dao(instance);
}
rpl_reset_dio_timer(instance);
#if DEBUG
rpl_print_neighbor_list();
#endif
} else if(best_dag->rank != old_rank) {
PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n",
(unsigned)old_rank, best_dag->rank);
@ -1329,7 +1378,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
PRINTF(", rank %u, min_rank %u, ",
instance->current_dag->rank, instance->current_dag->min_rank);
PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n",
p->rank, -1/*p->mc.obj.etx*/, p->link_metric, instance->mc.obj.etx);
p->rank, -1/*p->mc.obj.etx*/, rpl_get_nbr(p)->link_metric, instance->mc.obj.etx);
/* We have allocated a candidate parent; process the DIO further. */

View file

@ -215,6 +215,7 @@ rpl_update_header_empty(void)
}
break;
default:
#if RPL_INSERT_HBH_OPTION
PRINTF("RPL: No hop-by-hop option found, creating it\n");
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
@ -223,6 +224,7 @@ rpl_update_header_empty(void)
}
set_rpl_opt(uip_ext_opt_offset);
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
#endif
return 0;
}
@ -374,9 +376,11 @@ rpl_invert_header(void)
void
rpl_insert_header(void)
{
#if RPL_INSERT_HBH_OPTION
if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
rpl_update_header_empty();
}
#endif
}
/*---------------------------------------------------------------------------*/

View file

@ -466,8 +466,12 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
buffer[pos++] = instance->dtsn_out;
/* always request new DAO to refresh route */
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
if(uc_addr == NULL) {
/* Request new DAO to refresh route. We do not do this for unicast DIO
* in order to avoid DAO messages after a DIS-DIO update,
* or upon unicast DIO probing. */
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
}
/* reserved 2 bytes */
buffer[pos++] = 0; /* flags */

View file

@ -313,6 +313,7 @@ rpl_of_t *rpl_find_of(rpl_ocp_t);
void rpl_schedule_dao(rpl_instance_t *);
void rpl_schedule_dao_immediately(rpl_instance_t *);
void rpl_cancel_dao(rpl_instance_t *instance);
void rpl_schedule_probing(rpl_instance_t *instance);
void rpl_reset_dio_timer(rpl_instance_t *);
void rpl_reset_periodic_timer(void);
@ -320,4 +321,7 @@ void rpl_reset_periodic_timer(void);
/* Route poisoning. */
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
rpl_instance_t *rpl_get_default_instance(void);
#endif /* RPL_PRIVATE_H */

View file

@ -166,6 +166,10 @@ handle_dio_timer(void *ptr)
}
new_dio_interval(instance);
}
#if DEBUG
rpl_print_neighbor_list();
#endif
}
/*---------------------------------------------------------------------------*/
void
@ -323,5 +327,97 @@ rpl_cancel_dao(rpl_instance_t *instance)
ctimer_stop(&instance->dao_lifetime_timer);
}
/*---------------------------------------------------------------------------*/
#if RPL_WITH_PROBING
static rpl_parent_t *
get_probing_target(rpl_dag_t *dag)
{
/* Returns the next probing target. The current implementation probes the current
* preferred parent if we have not updated its link for RPL_PROBING_EXPIRATION_TIME.
* Otherwise, it picks at random between:
* (1) selecting the best parent not updated for RPL_PROBING_EXPIRATION_TIME
* (2) selecting the least recently updated parent
*/
rpl_parent_t *p;
rpl_parent_t *probing_target = NULL;
rpl_rank_t probing_target_rank = INFINITE_RANK;
/* min_last_tx is the clock time RPL_PROBING_EXPIRATION_TIME in the past */
clock_time_t min_last_tx = clock_time();
min_last_tx = min_last_tx > 2 * RPL_PROBING_EXPIRATION_TIME
? min_last_tx - RPL_PROBING_EXPIRATION_TIME : 1;
if(dag == NULL ||
dag->instance == NULL ||
dag->preferred_parent == NULL) {
return NULL;
}
/* Our preferred parent needs probing */
if(dag->preferred_parent->last_tx_time < min_last_tx) {
probing_target = dag->preferred_parent;
}
/* With 50% probability: probe best parent not updated for RPL_PROBING_EXPIRATION_TIME */
if(probing_target == NULL && (random_rand() % 2) == 0) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->dag == dag && p->last_tx_time < min_last_tx) {
/* p is in our dag and needs probing */
rpl_rank_t p_rank = dag->instance->of->calculate_rank(p, 0);
if(probing_target == NULL
|| p_rank < probing_target_rank) {
probing_target = p;
probing_target_rank = p_rank;
}
}
p = nbr_table_next(rpl_parents, p);
}
}
/* The default probing target is the least recently updated parent */
if(probing_target == NULL) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->dag == dag) {
if(probing_target == NULL
|| p->last_tx_time < probing_target->last_tx_time) {
probing_target = p;
}
}
p = nbr_table_next(rpl_parents, p);
}
}
return probing_target;
}
/*---------------------------------------------------------------------------*/
static void
handle_probing_timer(void *ptr)
{
rpl_instance_t *instance = (rpl_instance_t *)ptr;
rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(instance->current_dag);
/* Perform probing */
if(probing_target != NULL && rpl_get_parent_ipaddr(probing_target) != NULL) {
PRINTF("RPL: probing %3u\n",
nbr_table_get_lladdr(rpl_parents, probing_target)->u8[7]);
/* Send probe, e.g. unicast DIO or DIS */
RPL_PROBING_SEND_FUNC(instance, rpl_get_parent_ipaddr(probing_target));
}
/* Schedule next probing */
rpl_schedule_probing(instance);
#if DEBUG
rpl_print_neighbor_list();
#endif
}
/*---------------------------------------------------------------------------*/
void
rpl_schedule_probing(rpl_instance_t *instance)
{
ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(),
handle_probing_timer, instance);
}
#endif /* RPL_WITH_PROBING */
/** @}*/

View file

@ -263,6 +263,7 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
parent->flags |= RPL_PARENT_FLAG_UPDATED;
if(instance->of->neighbor_link_callback != NULL) {
instance->of->neighbor_link_callback(parent, status, numtx);
parent->last_tx_time = clock_time();
}
}
}

View file

@ -114,6 +114,7 @@ struct rpl_parent {
rpl_metric_container_t mc;
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
rpl_rank_t rank;
clock_time_t last_tx_time;
uint8_t dtsn;
uint8_t flags;
};
@ -224,6 +225,9 @@ struct rpl_instance {
uint16_t dio_totrecv;
#endif /* RPL_CONF_STATS */
clock_time_t dio_next_delay; /* delay for completion of dio interval */
#if RPL_WITH_PROBING
struct ctimer probing_timer;
#endif /* RPL_WITH_PROBING */
struct ctimer dio_timer;
struct ctimer dao_timer;
struct ctimer dao_lifetime_timer;
@ -251,6 +255,10 @@ rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr);
void rpl_dag_init(void);
uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent);
void rpl_print_neighbor_list();
/* Per-parent RPL information */
NBR_TABLE_DECLARE(rpl_parents);
/**
* RPL modes

View file

@ -76,8 +76,9 @@ timer_set(struct timer *t, clock_time_t interval)
* function will cause the timer to be stable over time, unlike the
* timer_restart() function.
*
* \param t A pointer to the timer.
* \note Must not be executed before timer expired
*
* \param t A pointer to the timer.
* \sa timer_restart()
*/
void

View file

@ -117,7 +117,7 @@ makestrings(void)
makeaddr(&addr, gateway);
#if WITH_DNS
addrptr = resolv_getserver();
addrptr = uip_nameserver_get(0);
if(addrptr != NULL) {
makeaddr(addrptr, dnsserver);
}
@ -245,7 +245,7 @@ dhcpc_configured(const struct dhcpc_state *s)
uip_setnetmask(&s->netmask);
uip_setdraddr(&s->default_router);
#if WITH_DNS
resolv_conf(&s->dnsaddr);
uip_nameserver_update(&s->dnsaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
#endif /* WITH_DNS */
set_statustext("Configured.");
@ -261,7 +261,7 @@ dhcpc_unconfigured(const struct dhcpc_state *s)
uip_setnetmask(&nulladdr);
uip_setdraddr(&nulladdr);
#if WITH_DNS
resolv_conf(&nulladdr);
uip_nameserver_update(&nulladdr, UIP_NAMESERVER_INFINITE_LIFETIME);
#endif /* WITH_DNS */
set_statustext("Unconfigured.");

View file

@ -105,7 +105,7 @@ config_read(char *filename)
uip_setnetmask(&config.netmask);
uip_setdraddr(&config.draddr);
#if WITH_DNS
resolv_conf(&config.resolvaddr);
uip_nameserver_update(&config.resolvaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
#endif /* WITH_DNS */
return &config.ethernetcfg;

View file

@ -89,7 +89,7 @@ fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
.byte fixup29-fixup28, fixup30-fixup29, fixup31-fixup30
.byte fixup32-fixup31, fixup33-fixup32, fixup34-fixup33
.byte fixup35-fixup34, fixup36-fixup35, fixup37-fixup36
.byte fixup38-fixup37, fixup39-fixup38, fixup40-fixup39
.byte fixup38-fixup37, fixup39-fixup38
fixups = * - fixup
@ -272,9 +272,7 @@ fixup22:lda ethdata
bcs :++
; Yes, skip packet
; Remove and release RX packet from the FIFO
lda #%10000000
fixup23:sta ethmmucr
jsr releasepacket
; No packet available
lda #$00
@ -285,7 +283,7 @@ fixup23:sta ethmmucr
; Read bytes into buffer
: jsr adjustptr
:
fixup24:lda ethdata
fixup23:lda ethdata
sta (ptr),y
iny
bne :-
@ -294,8 +292,7 @@ fixup24:lda ethdata
bpl :-
; Remove and release RX packet from the FIFO
lda #%10000000
fixup25:sta ethmmucr
jsr releasepacket
; Return packet length
lda len
@ -313,19 +310,19 @@ send:
; Allocate memory for TX
txa
ora #%00100000
fixup26:sta ethmmucr
fixup24:sta ethmmucr
; 8 retries
ldy #$08
; Wait for allocation ready
:
fixup27:lda ethist
fixup25:lda ethist
and #%00001000 ; ALLOC INT
bne :+
; Shouldn't we do something here to actively free memory,
; maybe removing and releasing an RX packet from the FIFO ???
; No space avaliable, skip a received frame
jsr releasepacket
; And try again
dey
@ -335,21 +332,21 @@ fixup27:lda ethist
; Acknowledge interrupt, is it necessary ???
: lda #%00001000
fixup28:sta ethack
fixup26:sta ethack
; Set packet address
fixup29:lda etharr
fixup30:sta ethpnr
fixup27:lda etharr
fixup28:sta ethpnr
lda #$00
ldx #%01000000 ; AUTO INCR.
fixup31:sta ethptr
fixup32:stx ethptr+1
fixup29:sta ethptr
fixup30:stx ethptr+1
; Status written by CSMA
lda #$00
fixup33:sta ethdata
fixup34:sta ethdata
fixup31:sta ethdata
fixup32:sta ethdata
; Check packet length parity:
; - Even packet length -> carry set -> add 6 bytes
@ -361,10 +358,10 @@ fixup34:sta ethdata
; The packet contains 3 extra words
lda len
adc #$05 ; Actually 5 or 6 depending on carry
fixup35:sta ethdata
fixup33:sta ethdata
lda len+1
adc #$00
fixup36:sta ethdata
fixup34:sta ethdata
; Send the packet
; ---------------
@ -372,7 +369,7 @@ fixup36:sta ethdata
; Write bytes from buffer
jsr adjustptr
: lda (ptr),y
fixup37:sta ethdata
fixup35:sta ethdata
iny
bne :-
inc ptr+1
@ -390,13 +387,13 @@ fixup37:sta ethdata
; No
: lda #$00
fixup38:sta ethdata ; Fill byte
fixup36:sta ethdata ; Fill byte
:
fixup39:sta ethdata ; Control byte
fixup37:sta ethdata ; Control byte
; Add packet to FIFO
lda #%11000000 ; ENQUEUE PACKET - transmit packet
fixup40:sta ethmmucr
fixup38:sta ethmmucr
clc
rts
@ -407,6 +404,14 @@ exit:
;---------------------------------------------------------------------
releasepacket:
; Remove and release RX packet from the FIFO
lda #%10000000
fixup39:sta ethmmucr
rts
;---------------------------------------------------------------------
adjustptr:
lda len
ldx len+1

View file

@ -402,14 +402,18 @@ sicslowmac_dataRequest(void)
frame_create_params_t params;
frame_result_t result;
#if NETSTACK_CONF_WITH_RIME
/* Save the msduHandle in a global variable. */
msduHandle = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
#endif
/* Build the FCF. */
params.fcf.frameType = DATAFRAME;
params.fcf.securityEnabled = false;
params.fcf.framePending = false;
#if NETSTACK_CONF_WITH_RIME
params.fcf.ackRequired = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
#endif
params.fcf.panIdCompression = false;
/* Insert IEEE 802.15.4 (2003) version bit. */

View file

@ -1073,8 +1073,10 @@ rf230_transmit(unsigned short payload_len)
if (tx_result==RADIO_TX_OK) {
RIMESTATS_ADD(lltx);
#if NETSTACK_CONF_WITH_RIME
if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE))
RIMESTATS_ADD(ackrx); //ack was requested and received
#endif
#if RF230_INSERTACK
/* Not PAN broadcast to FFFF, and ACK was requested and received */
if (!((buffer[5]==0xff) && (buffer[6]==0xff)) && (buffer[0]&(1<<6)))

View file

@ -49,8 +49,8 @@
*
*/
#ifndef RADIO_H
#define RADIO_H
#ifndef RF230BB_H_
#define RF230BB_H_
/*============================ INCLUDE =======================================*/
#include <stdint.h>
#include <stdbool.h>
@ -225,6 +225,6 @@ uint8_t rf230_get_raw_rssi(void);
#define rf230_rssi rf230_get_raw_rssi
#endif
#endif /* RF230BB_H_ */
/** @} */
/*EOF*/

View file

@ -52,12 +52,20 @@ CONTIKI_CPU_SOURCEFILES += nvic.c cpu.c sys-ctrl.c gpio.c ioc.c spi.c adc.c
CONTIKI_CPU_SOURCEFILES += cc2538-rf.c udma.c lpm.c
CONTIKI_CPU_SOURCEFILES += dbg.c ieee-addr.c
CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c
CONTIKI_CPU_SOURCEFILES += i2c.c cc2538-temp-sensor.c vdd3-sensor.c
DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c
USB_CORE_SOURCEFILES += usb-core.c cdc-acm.c
USB_ARCH_SOURCEFILES += usb-arch.c usb-serial.c cdc-acm-descriptors.c
ifneq ($(TARGET_START_SOURCEFILES),)
CPU_START_SOURCEFILES = TARGET_START_SOURCEFILES
else
CPU_START_SOURCEFILES = startup-gcc.c
endif
CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}}
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES)
CONTIKI_SOURCEFILES += $(USB_CORE_SOURCEFILES) $(USB_ARCH_SOURCEFILES)
@ -74,7 +82,7 @@ $(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR)
### Compilation rules
CUSTOM_RULE_LINK=1
%.elf: $(TARGET_STARTFILES) %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a $(LDSCRIPT)
%.elf: $(CPU_STARTFILES) %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a $(LDSCRIPT)
$(TRACE_LD)
$(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@

View file

@ -96,17 +96,17 @@ clock_init(void)
REG(SYS_CTRL_RCGCGPT) |= SYS_CTRL_RCGCGPT_GPT0;
/* Make sure GPT0 is off */
REG(GPT_0_BASE | GPTIMER_CTL) = 0;
REG(GPT_0_BASE + GPTIMER_CTL) = 0;
/* 16-bit */
REG(GPT_0_BASE | GPTIMER_CFG) = 0x04;
REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
/* One-Shot, Count Down, No Interrupts */
REG(GPT_0_BASE | GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
/* Prescale by 16 (thus, value 15 in TAPR) */
REG(GPT_0_BASE | GPTIMER_TAPR) = 0x0F;
REG(GPT_0_BASE + GPTIMER_TAPR) = 0x0F;
}
/*---------------------------------------------------------------------------*/
CCIF clock_time_t
@ -144,11 +144,11 @@ clock_wait(clock_time_t i)
void
clock_delay_usec(uint16_t dt)
{
REG(GPT_0_BASE | GPTIMER_TAILR) = dt;
REG(GPT_0_BASE | GPTIMER_CTL) |= GPTIMER_CTL_TAEN;
REG(GPT_0_BASE + GPTIMER_TAILR) = dt;
REG(GPT_0_BASE + GPTIMER_CTL) |= GPTIMER_CTL_TAEN;
/* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
while(REG(GPT_0_BASE | GPTIMER_CTL) & GPTIMER_CTL_TAEN);
while(REG(GPT_0_BASE + GPTIMER_CTL) & GPTIMER_CTL_TAEN);
}
/*---------------------------------------------------------------------------*/
/**

View file

@ -80,7 +80,6 @@
/* Local RF Flags */
#define RX_ACTIVE 0x80
#define RF_MUST_RESET 0x40
#define WAS_OFF 0x10
#define RF_ON 0x01
/* Bit Masks for the last byte in the RX FIFO */
@ -180,6 +179,8 @@ get_channel()
static int8_t
set_channel(uint8_t channel)
{
uint8_t was_on = 0;
PRINTF("RF: Set Channel\n");
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
@ -189,16 +190,14 @@ set_channel(uint8_t channel)
/* Changes to FREQCTRL take effect after the next recalibration */
/* If we are off, save state, otherwise switch off and save state */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
rf_flags |= WAS_OFF;
} else {
rf_flags &= ~WAS_OFF;
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) != 0) {
was_on = 1;
off();
}
REG(RFCORE_XREG_FREQCTRL) = (CC2538_RF_CHANNEL_MIN
+ (channel - CC2538_RF_CHANNEL_MIN) * CC2538_RF_CHANNEL_SPACING);
/* switch radio back on only if radio was on before - otherwise will turn on radio foor sleepy nodes */
if((rf_flags & WAS_OFF) != WAS_OFF) {
if(was_on) {
on();
}
@ -244,10 +243,11 @@ static radio_value_t
get_rssi(void)
{
int8_t rssi;
uint8_t was_off = 0;
/* If we are off, turn on first */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
rf_flags |= WAS_OFF;
was_off = 1;
on();
}
@ -257,8 +257,7 @@ get_rssi(void)
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
/* If we were off, turn back off */
if((rf_flags & WAS_OFF) == WAS_OFF) {
rf_flags &= ~WAS_OFF;
if(was_off) {
off();
}
@ -345,12 +344,13 @@ static int
channel_clear(void)
{
int cca;
uint8_t was_off = 0;
PRINTF("RF: CCA\n");
/* If we are off, turn on first */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
rf_flags |= WAS_OFF;
was_off = 1;
on();
}
@ -364,8 +364,7 @@ channel_clear(void)
}
/* If we were off, turn back off */
if((rf_flags & WAS_OFF) == WAS_OFF) {
rf_flags &= ~WAS_OFF;
if(was_off) {
off();
}
@ -561,13 +560,14 @@ transmit(unsigned short transmit_len)
uint8_t counter;
int ret = RADIO_TX_ERR;
rtimer_clock_t t0;
uint8_t was_off = 0;
PRINTF("RF: Transmit\n");
if(!(rf_flags & RX_ACTIVE)) {
t0 = RTIMER_NOW();
on();
rf_flags |= WAS_OFF;
was_off = 1;
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
}
@ -609,8 +609,7 @@ transmit(unsigned short transmit_len)
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
if(rf_flags & WAS_OFF) {
rf_flags &= ~WAS_OFF;
if(was_off) {
off();
}

Some files were not shown because too many files have changed in this diff Show more