Merge branch 'contiki' into osd
This commit is contained in:
commit
877bf27f5a
12
.travis.yml
12
.travis.yml
|
@ -30,7 +30,7 @@ before_script:
|
||||||
- sudo apt-get -qq install libc6:i386 libgcc1:i386 gcc-4.6-base:i386
|
- sudo apt-get -qq install libc6:i386 libgcc1:i386 gcc-4.6-base:i386
|
||||||
libstdc++5:i386 libstdc++6: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
|
- 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 &&
|
$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/ &&
|
tar xjf arm-2008q3*.tar.bz2 -C /tmp/ &&
|
||||||
|
@ -41,15 +41,16 @@ before_script:
|
||||||
|
|
||||||
## Install mainline ARM toolchain. gcc-arm-none-eabi is available
|
## Install mainline ARM toolchain. gcc-arm-none-eabi is available
|
||||||
## in Ubuntu >= 14.04, but this external PPA is needed for 12.04.
|
## 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 add-apt-repository -y ppa:terry.guo/gcc-arm-embedded &&
|
||||||
sudo apt-get -qq update &&
|
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 ;
|
arm-none-eabi-gcc --version ;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## Download and extract cc26xxware
|
## 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 &&
|
wget http://www.ti.com/lit/sw/swrc296/swrc296.zip &&
|
||||||
unzip swrc296.zip &&
|
unzip swrc296.zip &&
|
||||||
export TI_CC26XXWARE=cc26xxware_2_20_06_14829 ;
|
export TI_CC26XXWARE=cc26xxware_2_20_06_14829 ;
|
||||||
|
@ -110,6 +111,7 @@ env:
|
||||||
- BUILD_TYPE='rpl'
|
- BUILD_TYPE='rpl'
|
||||||
- BUILD_TYPE='rime'
|
- BUILD_TYPE='rime'
|
||||||
- BUILD_TYPE='ipv6'
|
- BUILD_TYPE='ipv6'
|
||||||
|
- BUILD_TYPE='ip64' MAKE_TARGETS='cooja'
|
||||||
- BUILD_TYPE='hello-world'
|
- BUILD_TYPE='hello-world'
|
||||||
- BUILD_TYPE='base'
|
- BUILD_TYPE='base'
|
||||||
# XXX: netperf disabled b/c it's flaky
|
# 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-8051-ports' BUILD_CATEGORY='compile' BUILD_ARCH='8051'
|
||||||
- BUILD_TYPE='compile-arm-apcs-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-apcs'
|
- 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-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='slip-radio' MAKE_TARGETS='cooja'
|
||||||
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
||||||
|
|
|
@ -88,7 +88,7 @@ makestrings(void)
|
||||||
uip_getdraddr(&addr);
|
uip_getdraddr(&addr);
|
||||||
makeaddr(&addr, gateway);
|
makeaddr(&addr, gateway);
|
||||||
|
|
||||||
addrptr = resolv_getserver();
|
addrptr = uip_nameserver_get(0);
|
||||||
if(addrptr != NULL) {
|
if(addrptr != NULL) {
|
||||||
makeaddr(addrptr, dnsserver);
|
makeaddr(addrptr, dnsserver);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ dhcpc_configured(const struct dhcpc_state *s)
|
||||||
uip_sethostaddr(&s->ipaddr);
|
uip_sethostaddr(&s->ipaddr);
|
||||||
uip_setnetmask(&s->netmask);
|
uip_setnetmask(&s->netmask);
|
||||||
uip_setdraddr(&s->default_router);
|
uip_setdraddr(&s->default_router);
|
||||||
resolv_conf(&s->dnsaddr);
|
uip_nameserver_update(&s->dnsaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||||
set_statustext("Configured.");
|
set_statustext("Configured.");
|
||||||
process_post(PROCESS_CURRENT(), SHOWCONFIG, NULL);
|
process_post(PROCESS_CURRENT(), SHOWCONFIG, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ makestrings(void)
|
||||||
makeaddr(&addr, gateway);
|
makeaddr(&addr, gateway);
|
||||||
|
|
||||||
#if UIP_UDP
|
#if UIP_UDP
|
||||||
addrptr = resolv_getserver();
|
addrptr = uip_nameserver_get(0);
|
||||||
if(addrptr != NULL) {
|
if(addrptr != NULL) {
|
||||||
makeaddr(addrptr, dnsserver);
|
makeaddr(addrptr, dnsserver);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ apply_tcpipconfig(void)
|
||||||
#if UIP_UDP
|
#if UIP_UDP
|
||||||
nullterminate(dnsserver);
|
nullterminate(dnsserver);
|
||||||
if(uiplib_ipaddrconv(dnsserver, &addr)) {
|
if(uiplib_ipaddrconv(dnsserver, &addr)) {
|
||||||
resolv_conf(&addr);
|
uip_nameserver_update(&addr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||||
}
|
}
|
||||||
#endif /* UIP_UDP */
|
#endif /* UIP_UDP */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
rest-coap_src = coap-common.c coap-server.c
|
|
||||||
|
|
||||||
APPS += rest-common
|
|
||||||
include $(CONTIKI)/apps/rest-common/Makefile.rest-common
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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_ */
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
|
@ -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_ */
|
|
|
@ -1 +0,0 @@
|
||||||
rest-common_src = rest.c rest-util.c buffer.c static-routing.c
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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_ */
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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_ */
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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_*/
|
|
|
@ -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*/
|
|
|
@ -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_ */
|
|
|
@ -1,4 +0,0 @@
|
||||||
rest-http_src = http-common.c http-server.c
|
|
||||||
|
|
||||||
APPS += rest-common
|
|
||||||
include $(CONTIKI)/apps/rest-common/Makefile.rest-common
|
|
|
@ -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 = ": ";
|
|
|
@ -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_*/
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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_*/
|
|
|
@ -9,7 +9,7 @@ shell_src = shell.c shell-reboot.c shell-vars.c shell-ps.c \
|
||||||
shell_dsc = shell-dsc.c
|
shell_dsc = shell-dsc.c
|
||||||
|
|
||||||
ifeq ($(CONTIKI_WITH_RIME),1)
|
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-ping.c shell-rime-sniff.c shell-rime-netcmd.c \
|
||||||
shell-rime-debug.c shell-rime-debug-runicast.c \
|
shell-rime-debug.c shell-rime-debug-runicast.c \
|
||||||
shell-rime-sendcmd.c shell-download.c shell-rime-neighbors.c \
|
shell-rime-sendcmd.c shell-download.c shell-rime-neighbors.c \
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
|
@ -382,7 +382,6 @@ struct shell_input {
|
||||||
#include "shell-httpd.h"
|
#include "shell-httpd.h"
|
||||||
#include "shell-irc.h"
|
#include "shell-irc.h"
|
||||||
#include "shell-memdebug.h"
|
#include "shell-memdebug.h"
|
||||||
#include "shell-netfile.h"
|
|
||||||
#include "shell-netperf.h"
|
#include "shell-netperf.h"
|
||||||
#include "shell-netstat.h"
|
#include "shell-netstat.h"
|
||||||
#include "shell-ping.h"
|
#include "shell-ping.h"
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "net/ip/uiplib.h"
|
#include "net/ip/uiplib.h"
|
||||||
#include "net/ip/uip-udp-packet.h"
|
#include "net/ip/uip-udp-packet.h"
|
||||||
#include "net/ip/simple-udp.h"
|
#include "net/ip/simple-udp.h"
|
||||||
|
#include "net/ip/uip-nameserver.h"
|
||||||
|
|
||||||
#if NETSTACK_CONF_WITH_IPV6
|
#if NETSTACK_CONF_WITH_IPV6
|
||||||
#include "net/ipv6/uip-icmp6.h"
|
#include "net/ipv6/uip-icmp6.h"
|
||||||
|
|
|
@ -72,14 +72,13 @@ static unsigned char ascii2petscii[128] = {
|
||||||
0x58,0x59,0x5a,0xdb,0xdd,0xdd,0x5e,0xdf,
|
0x58,0x59,0x5a,0xdb,0xdd,0xdd,0x5e,0xdf,
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int i;
|
|
||||||
static unsigned char *ptr;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
petsciiconv_toascii(char *buf, unsigned int len)
|
petsciiconv_toascii(char *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
static char c;
|
unsigned int i;
|
||||||
|
char *ptr;
|
||||||
|
char c;
|
||||||
|
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
for(i = len; i > 0; --i) {
|
for(i = len; i > 0; --i) {
|
||||||
|
@ -108,6 +107,9 @@ petsciiconv_toascii(char *buf, unsigned int len)
|
||||||
void
|
void
|
||||||
petsciiconv_topetscii(char *buf, unsigned int len)
|
petsciiconv_topetscii(char *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
for(i = len; i > 0; --i) {
|
for(i = len; i > 0; --i) {
|
||||||
*ptr = ascii2petscii[*ptr & 0x7f];
|
*ptr = ascii2petscii[*ptr & 0x7f];
|
||||||
|
|
682
core/net/http-socket/http-socket.c
Normal file
682
core/net/http-socket/http-socket.c
Normal 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;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
121
core/net/http-socket/http-socket.h
Normal file
121
core/net/http-socket/http-socket.h
Normal 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 */
|
|
@ -65,6 +65,7 @@
|
||||||
#include "net/ip/tcpip.h"
|
#include "net/ip/tcpip.h"
|
||||||
#include "net/ip/resolv.h"
|
#include "net/ip/resolv.h"
|
||||||
#include "net/ip/uip-udp-packet.h"
|
#include "net/ip/uip-udp-packet.h"
|
||||||
|
#include "net/ip/uip-nameserver.h"
|
||||||
#include "lib/random.h"
|
#include "lib/random.h"
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
|
@ -227,17 +228,6 @@ struct dns_hdr {
|
||||||
uint16_t numextrarr;
|
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. */
|
/** \internal The DNS answer message structure. */
|
||||||
struct dns_answer {
|
struct dns_answer {
|
||||||
/* DNS answer record starts with either a domain name or a pointer
|
/* DNS answer record starts with either a domain name or a pointer
|
||||||
|
@ -269,6 +259,7 @@ struct namemap {
|
||||||
#endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
|
#endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
|
||||||
uip_ipaddr_t ipaddr;
|
uip_ipaddr_t ipaddr;
|
||||||
uint8_t err;
|
uint8_t err;
|
||||||
|
uint8_t server;
|
||||||
#if RESOLV_CONF_SUPPORTS_MDNS
|
#if RESOLV_CONF_SUPPORTS_MDNS
|
||||||
int is_mdns:1, is_probe:1;
|
int is_mdns:1, is_probe:1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -637,6 +628,21 @@ mdns_prep_host_announce_packet(void)
|
||||||
}
|
}
|
||||||
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
|
#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
|
/** \internal
|
||||||
* Runs through the list of names to see if there are any that have
|
* 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.
|
* not yet been queried and, if so, sends out a query.
|
||||||
|
@ -666,6 +672,9 @@ check_entries(void)
|
||||||
if(++namemapptr->retries == RESOLV_CONF_MAX_RETRIES)
|
if(++namemapptr->retries == RESOLV_CONF_MAX_RETRIES)
|
||||||
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
|
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
|
||||||
{
|
{
|
||||||
|
/* 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". */
|
/* STATE_ERROR basically means "not found". */
|
||||||
namemapptr->state = STATE_ERROR;
|
namemapptr->state = STATE_ERROR;
|
||||||
|
|
||||||
|
@ -677,6 +686,7 @@ check_entries(void)
|
||||||
resolv_found(namemapptr->name, NULL);
|
resolv_found(namemapptr->name, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
namemapptr->tmr = namemapptr->retries * namemapptr->retries * 3;
|
namemapptr->tmr = namemapptr->retries * namemapptr->retries * 3;
|
||||||
|
|
||||||
#if RESOLV_CONF_SUPPORTS_MDNS
|
#if RESOLV_CONF_SUPPORTS_MDNS
|
||||||
|
@ -747,7 +757,9 @@ check_entries(void)
|
||||||
} else {
|
} else {
|
||||||
uip_udp_packet_sendto(resolv_conn, uip_appdata,
|
uip_udp_packet_sendto(resolv_conn, uip_appdata,
|
||||||
(query - (uint8_t *) 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,
|
PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
|
||||||
namemapptr->name);
|
namemapptr->name);
|
||||||
|
@ -755,7 +767,8 @@ check_entries(void)
|
||||||
#else /* RESOLV_CONF_SUPPORTS_MDNS */
|
#else /* RESOLV_CONF_SUPPORTS_MDNS */
|
||||||
uip_udp_packet_sendto(resolv_conn, uip_appdata,
|
uip_udp_packet_sendto(resolv_conn, uip_appdata,
|
||||||
(query - (uint8_t *) 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,
|
PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
|
||||||
namemapptr->name);
|
namemapptr->name);
|
||||||
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
|
#endif /* RESOLV_CONF_SUPPORTS_MDNS */
|
||||||
|
@ -774,7 +787,7 @@ newdata(void)
|
||||||
|
|
||||||
static int8_t i;
|
static int8_t i;
|
||||||
|
|
||||||
register struct namemap *namemapptr;
|
register struct namemap *namemapptr = NULL;
|
||||||
|
|
||||||
struct dns_answer *ans;
|
struct dns_answer *ans;
|
||||||
|
|
||||||
|
@ -1041,11 +1054,28 @@ newdata(void)
|
||||||
uip_ipaddr_copy(&namemapptr->ipaddr, (uip_ipaddr_t *) ans->ipaddr);
|
uip_ipaddr_copy(&namemapptr->ipaddr, (uip_ipaddr_t *) ans->ipaddr);
|
||||||
|
|
||||||
resolv_found(namemapptr->name, &namemapptr->ipaddr);
|
resolv_found(namemapptr->name, &namemapptr->ipaddr);
|
||||||
|
break;
|
||||||
|
|
||||||
skip_to_next_answer:
|
skip_to_next_answer:
|
||||||
queryptr = (unsigned char *)skip_name(queryptr) + 10 + uip_htons(ans->len);
|
queryptr = (unsigned char *)skip_name(queryptr) + 10 + uip_htons(ans->len);
|
||||||
--nanswers;
|
--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
|
#if RESOLV_CONF_SUPPORTS_MDNS
|
||||||
|
@ -1405,31 +1435,6 @@ resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr)
|
||||||
return ret;
|
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
|
/** \internal
|
||||||
* Callback function which is called when a hostname is found.
|
* Callback function which is called when a hostname is found.
|
||||||
*
|
*
|
||||||
|
|
|
@ -57,11 +57,6 @@
|
||||||
*/
|
*/
|
||||||
CCIF extern process_event_t resolv_event_found;
|
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 {
|
enum {
|
||||||
/** Hostname is fresh and usable. This response is cached and will eventually
|
/** Hostname is fresh and usable. This response is cached and will eventually
|
||||||
* expire to RESOLV_STATUS_EXPIRED.*/
|
* expire to RESOLV_STATUS_EXPIRED.*/
|
||||||
|
@ -95,6 +90,7 @@ enum {
|
||||||
|
|
||||||
typedef uint8_t resolv_status_t;
|
typedef uint8_t resolv_status_t;
|
||||||
|
|
||||||
|
/* Functions. */
|
||||||
CCIF resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr);
|
CCIF resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr);
|
||||||
|
|
||||||
CCIF void resolv_query(const char *name);
|
CCIF void resolv_query(const char *name);
|
||||||
|
|
|
@ -103,7 +103,7 @@ slipdev_send(void)
|
||||||
ptr = &uip_buf[UIP_LLH_LEN];
|
ptr = &uip_buf[UIP_LLH_LEN];
|
||||||
for(i = 0; i < uip_len; ++i) {
|
for(i = 0; i < uip_len; ++i) {
|
||||||
if(i == UIP_TCPIP_HLEN) {
|
if(i == UIP_TCPIP_HLEN) {
|
||||||
ptr = (char *)uip_appdata;
|
ptr = (uint8_t *)uip_appdata;
|
||||||
}
|
}
|
||||||
c = *ptr++;
|
c = *ptr++;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
static void relisten(struct tcp_socket *s);
|
||||||
|
|
||||||
LIST(socketlist);
|
LIST(socketlist);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
PROCESS(tcp_socket_process, "TCP socket process");
|
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());
|
int len = MIN(s->output_data_max_seg, uip_mss());
|
||||||
|
|
||||||
if(s->output_data_len > 0) {
|
if(s->output_senddata_len > 0) {
|
||||||
len = MIN(s->output_data_len, len);
|
len = MIN(s->output_senddata_len, len);
|
||||||
s->output_data_send_nxt = len;
|
s->output_data_send_nxt = len;
|
||||||
uip_send(s->output_data_ptr, len);
|
uip_send(s->output_data_ptr, len);
|
||||||
}
|
}
|
||||||
|
@ -68,7 +70,7 @@ senddata(struct tcp_socket *s)
|
||||||
static void
|
static void
|
||||||
acked(struct tcp_socket *s)
|
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
|
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||||
outputbuf_lastsent */
|
outputbuf_lastsent */
|
||||||
|
|
||||||
|
@ -81,8 +83,14 @@ acked(struct tcp_socket *s)
|
||||||
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||||
s->output_data_len,
|
s->output_data_len,
|
||||||
s->output_data_send_nxt);
|
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_data_len -= s->output_data_send_nxt;
|
||||||
|
s->output_senddata_len = s->output_data_len;
|
||||||
s->output_data_send_nxt = 0;
|
s->output_data_send_nxt = 0;
|
||||||
|
|
||||||
call_event(s, TCP_SOCKET_DATA_SENT);
|
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||||
|
@ -134,6 +142,11 @@ appcall(void *state)
|
||||||
{
|
{
|
||||||
struct tcp_socket *s = 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()) {
|
if(uip_connected()) {
|
||||||
/* Check if this connection originated in a local listen
|
/* Check if this connection originated in a local listen
|
||||||
socket. We do this by checking the state pointer - if NULL,
|
socket. We do this by checking the state pointer - if NULL,
|
||||||
|
@ -176,8 +189,10 @@ appcall(void *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(uip_aborted()) {
|
if(uip_aborted()) {
|
||||||
|
tcp_markconn(uip_conn, NULL);
|
||||||
call_event(s, TCP_SOCKET_ABORTED);
|
call_event(s, TCP_SOCKET_ABORTED);
|
||||||
relisten(s);
|
relisten(s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
|
@ -203,13 +218,16 @@ appcall(void *state)
|
||||||
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||||
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||||
uip_close();
|
uip_close();
|
||||||
|
s->c = NULL;
|
||||||
tcp_markconn(uip_conn, NULL);
|
tcp_markconn(uip_conn, NULL);
|
||||||
call_event(s, TCP_SOCKET_CLOSED);
|
s->c = NULL;
|
||||||
|
/*call_event(s, TCP_SOCKET_CLOSED);*/
|
||||||
relisten(s);
|
relisten(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(uip_closed()) {
|
if(uip_closed()) {
|
||||||
tcp_markconn(uip_conn, NULL);
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
s->c = NULL;
|
||||||
call_event(s, TCP_SOCKET_CLOSED);
|
call_event(s, TCP_SOCKET_CLOSED);
|
||||||
relisten(s);
|
relisten(s);
|
||||||
}
|
}
|
||||||
|
@ -255,6 +273,7 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||||
s->ptr = ptr;
|
s->ptr = ptr;
|
||||||
s->input_data_ptr = input_databuf;
|
s->input_data_ptr = input_databuf;
|
||||||
s->input_data_maxlen = input_databuf_len;
|
s->input_data_maxlen = input_databuf_len;
|
||||||
|
s->output_data_len = 0;
|
||||||
s->output_data_ptr = output_databuf;
|
s->output_data_ptr = output_databuf;
|
||||||
s->output_data_maxlen = output_databuf_len;
|
s->output_data_maxlen = output_databuf_len;
|
||||||
s->input_callback = input_callback;
|
s->input_callback = input_callback;
|
||||||
|
@ -268,12 +287,15 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
int
|
int
|
||||||
tcp_socket_connect(struct tcp_socket *s,
|
tcp_socket_connect(struct tcp_socket *s,
|
||||||
uip_ipaddr_t *ipaddr,
|
const uip_ipaddr_t *ipaddr,
|
||||||
uint16_t port)
|
uint16_t port)
|
||||||
{
|
{
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if(s->c != NULL) {
|
||||||
|
tcp_markconn(s->c, NULL);
|
||||||
|
}
|
||||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||||
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||||
PROCESS_CONTEXT_END();
|
PROCESS_CONTEXT_END();
|
||||||
|
@ -329,6 +351,11 @@ tcp_socket_send(struct tcp_socket *s,
|
||||||
|
|
||||||
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||||
s->output_data_len += len;
|
s->output_data_len += len;
|
||||||
|
|
||||||
|
if(s->output_senddata_len == 0) {
|
||||||
|
s->output_senddata_len = s->output_data_len;
|
||||||
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -365,3 +392,9 @@ tcp_socket_unregister(struct tcp_socket *s)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_max_sendlen(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
return s->output_data_maxlen - s->output_data_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#ifndef TCP_SOCKET_H
|
#ifndef TCP_SOCKET_H
|
||||||
#define TCP_SOCKET_H
|
#define TCP_SOCKET_H
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
struct tcp_socket;
|
struct tcp_socket;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -95,6 +97,7 @@ struct tcp_socket {
|
||||||
uint16_t output_data_maxlen;
|
uint16_t output_data_maxlen;
|
||||||
uint16_t output_data_len;
|
uint16_t output_data_len;
|
||||||
uint16_t output_data_send_nxt;
|
uint16_t output_data_send_nxt;
|
||||||
|
uint16_t output_senddata_len;
|
||||||
uint16_t output_data_max_seg;
|
uint16_t output_data_max_seg;
|
||||||
|
|
||||||
uint8_t flags;
|
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,
|
int tcp_socket_connect(struct tcp_socket *s,
|
||||||
uip_ipaddr_t *ipaddr,
|
const uip_ipaddr_t *ipaddr,
|
||||||
uint16_t port);
|
uint16_t port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -266,4 +269,19 @@ int tcp_socket_close(struct tcp_socket *s);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int tcp_socket_unregister(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 */
|
#endif /* TCP_SOCKET_H */
|
||||||
|
|
|
@ -228,7 +228,7 @@ packet_input(void)
|
||||||
#if UIP_TCP
|
#if UIP_TCP
|
||||||
#if UIP_ACTIVE_OPEN
|
#if UIP_ACTIVE_OPEN
|
||||||
struct uip_conn *
|
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;
|
struct uip_conn *c;
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ CCIF void tcp_unlisten(uint16_t port);
|
||||||
* memory could not be allocated for the connection.
|
* 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);
|
void *appstate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
236
core/net/ip/uip-nameserver.c
Normal file
236
core/net/ip/uip-nameserver.c
Normal 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 */
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/** @} */
|
101
core/net/ip/uip-nameserver.h
Normal file
101
core/net/ip/uip-nameserver.h
Normal 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_ */
|
||||||
|
/** @} */
|
|
@ -600,7 +600,7 @@ void uip_unlisten(uint16_t port);
|
||||||
* or NULL if no connection could be allocated.
|
* 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))
|
#define uip_ipaddr_copy(dest, src) (*(dest) = *(src))
|
||||||
#endif
|
#endif
|
||||||
#ifndef uip_ip4addr_copy
|
#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
|
#endif
|
||||||
#ifndef uip_ip6addr_copy
|
#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
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
@ -148,6 +149,7 @@ ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr,
|
||||||
m->ip6port == ip6port &&
|
m->ip6port == ip6port &&
|
||||||
uip_ip4addr_cmp(&m->ip4addr, ip4addr) &&
|
uip_ip4addr_cmp(&m->ip4addr, ip4addr) &&
|
||||||
uip_ip6addr_cmp(&m->ip6addr, ip6addr)) {
|
uip_ip6addr_cmp(&m->ip6addr, ip6addr)) {
|
||||||
|
m->ip6to4++;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +168,7 @@ ip64_addrmap_lookup_port(uint16_t mapped_port, uint8_t protocol)
|
||||||
m->protocol, protocol);
|
m->protocol, protocol);
|
||||||
if(m->mapped_port == mapped_port &&
|
if(m->mapped_port == mapped_port &&
|
||||||
m->protocol == protocol) {
|
m->protocol == protocol) {
|
||||||
|
m->ip4to6++;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,6 +207,8 @@ ip64_addrmap_create(const uip_ip6addr_t *ip6addr,
|
||||||
m->ip6port = ip6port;
|
m->ip6port = ip6port;
|
||||||
m->protocol = protocol;
|
m->protocol = protocol;
|
||||||
m->flags = FLAGS_NONE;
|
m->flags = FLAGS_NONE;
|
||||||
|
m->ip6to4 = 1;
|
||||||
|
m->ip4to6 = 0;
|
||||||
timer_set(&m->timer, 0);
|
timer_set(&m->timer, 0);
|
||||||
|
|
||||||
/* Pick a new, unused local port. First make sure that the
|
/* Pick a new, unused local port. First make sure that the
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
@ -40,6 +41,7 @@ struct ip64_addrmap_entry {
|
||||||
struct timer timer;
|
struct timer timer;
|
||||||
uip_ip6addr_t ip6addr;
|
uip_ip6addr_t ip6addr;
|
||||||
uip_ip4addr_t ip4addr;
|
uip_ip4addr_t ip4addr;
|
||||||
|
uint32_t ip6to4, ip4to6;
|
||||||
uint16_t mapped_port;
|
uint16_t mapped_port;
|
||||||
uint16_t ip6port;
|
uint16_t ip6port;
|
||||||
uint16_t ip4port;
|
uint16_t ip4port;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
259
core/net/ip64/ip64-dns64.c
Normal file
259
core/net/ip64/ip64-dns64.c
Normal 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;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
40
core/net/ip64/ip64-dns64.h
Normal file
40
core/net/ip64/ip64-dns64.h
Normal 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_ */
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
@ -58,7 +59,8 @@
|
||||||
#include "ip64-special-ports.h"
|
#include "ip64-special-ports.h"
|
||||||
#include "ip64-eth-interface.h"
|
#include "ip64-eth-interface.h"
|
||||||
#include "ip64-slip-interface.h"
|
#include "ip64-slip-interface.h"
|
||||||
|
#include "ip64-dns64.h"
|
||||||
|
#include "net/ipv6/uip-ds6.h"
|
||||||
#include "ip64-ipv4-dhcp.h"
|
#include "ip64-ipv4-dhcp.h"
|
||||||
#include "contiki-net.h"
|
#include "contiki-net.h"
|
||||||
|
|
||||||
|
@ -172,6 +174,8 @@ static uip_ip4addr_t ipv4_broadcast_addr;
|
||||||
#define TCP_SYN 0x02
|
#define TCP_SYN 0x02
|
||||||
#define TCP_RST 0x04
|
#define TCP_RST 0x04
|
||||||
|
|
||||||
|
#define DNS_PORT 53
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
ip64_init(void)
|
ip64_init(void)
|
||||||
|
@ -434,6 +438,15 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
||||||
case IP_PROTO_UDP:
|
case IP_PROTO_UDP:
|
||||||
PRINTF("ip64_6to4: UDP header\n");
|
PRINTF("ip64_6to4: UDP header\n");
|
||||||
v4hdr->proto = IP_PROTO_UDP;
|
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
|
/* Compute and check the UDP checksum - since we're going to
|
||||||
recompute it ourselves, we must ensure that it was correct in
|
recompute it ourselves, we must ensure that it was correct in
|
||||||
the first place. */
|
the first place. */
|
||||||
|
@ -572,9 +585,18 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
||||||
} else {
|
} else {
|
||||||
ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME);
|
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. */
|
mark them as recyclable. */
|
||||||
if(udphdr->destport == UIP_HTONS(53)) {
|
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
|
||||||
ip64_addrmap_set_recycleble(m);
|
ip64_addrmap_set_recycleble(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -706,6 +728,21 @@ ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4packet_len,
|
||||||
switch(v4hdr->proto) {
|
switch(v4hdr->proto) {
|
||||||
case IP_PROTO_UDP:
|
case IP_PROTO_UDP:
|
||||||
v6hdr->nxthdr = 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;
|
break;
|
||||||
|
|
||||||
case IP_PROTO_TCP:
|
case IP_PROTO_TCP:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
* 3. Neither the name of the copyright holder nor the names of its
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived
|
* contributors may be used to endorse or promote products derived
|
||||||
* from this software without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
|
|
|
@ -262,8 +262,8 @@ uip_over_mesh_send(void)
|
||||||
if(BUF->proto == UIP_PROTO_TCP) {
|
if(BUF->proto == UIP_PROTO_TCP) {
|
||||||
#if NETSTACK_CONF_WITH_RIME
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_ERELIABLE, 1);
|
packetbuf_set_attr(PACKETBUF_ATTR_ERELIABLE, 1);
|
||||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
|
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
|
||||||
|
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||||
/* packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM);*/
|
/* packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,18 +75,9 @@
|
||||||
#include "net/ipv4/uip_arp.h"
|
#include "net/ipv4/uip_arp.h"
|
||||||
#include "net/ip/uip_arch.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"
|
#include "net/ipv4/uip-neighbor.h"
|
||||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Variable definitions. */
|
/* Variable definitions. */
|
||||||
|
|
||||||
|
@ -395,7 +386,7 @@ uip_init(void)
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#if UIP_ACTIVE_OPEN
|
#if UIP_ACTIVE_OPEN
|
||||||
struct uip_conn *
|
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;
|
register struct uip_conn *conn, *cconn;
|
||||||
|
|
||||||
|
@ -1973,6 +1964,4 @@ uip_send(const void *data, int len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
|
||||||
|
|
||||||
/** @}*/
|
/** @}*/
|
||||||
|
|
|
@ -1336,11 +1336,6 @@ send_packet(linkaddr_t *dest)
|
||||||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER,(void*)&uip_lladdr);
|
packetbuf_set_addr(PACKETBUF_ADDR_SENDER,(void*)&uip_lladdr);
|
||||||
#endif
|
#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
|
/* Provide a callback function to receive the result of
|
||||||
a packet transmission. */
|
a packet transmission. */
|
||||||
NETSTACK_LLSEC.send(&packet_sent, NULL);
|
NETSTACK_LLSEC.send(&packet_sent, NULL);
|
||||||
|
@ -1388,6 +1383,7 @@ output(const uip_lladdr_t *localdest)
|
||||||
set_packet_attrs();
|
set_packet_attrs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
#define TCP_FIN 0x01
|
#define TCP_FIN 0x01
|
||||||
#define TCP_ACK 0x10
|
#define TCP_ACK 0x10
|
||||||
#define TCP_CTL 0x3f
|
#define TCP_CTL 0x3f
|
||||||
|
@ -1402,6 +1398,7 @@ output(const uip_lladdr_t *localdest)
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
|
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The destination address will be tagged to each outbound
|
* The destination address will be tagged to each outbound
|
||||||
|
|
|
@ -280,7 +280,7 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
|
||||||
if(r != NULL) {
|
if(r != NULL) {
|
||||||
uip_ipaddr_t *current_nexthop;
|
uip_ipaddr_t *current_nexthop;
|
||||||
current_nexthop = uip_ds6_route_nexthop(r);
|
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! */
|
/* no need to update route - already correct! */
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
#include "net/ipv6/uip-icmp6.h"
|
#include "net/ipv6/uip-icmp6.h"
|
||||||
#include "net/ipv6/uip-nd6.h"
|
#include "net/ipv6/uip-nd6.h"
|
||||||
#include "net/ipv6/uip-ds6.h"
|
#include "net/ipv6/uip-ds6.h"
|
||||||
|
#include "net/ip/uip-nameserver.h"
|
||||||
#include "lib/random.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_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_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_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_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 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
|
#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_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
|
||||||
static uip_ipaddr_t ipaddr;
|
static uip_ipaddr_t ipaddr;
|
||||||
static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
|
static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
|
||||||
#endif
|
#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 */
|
/* create a llao */
|
||||||
static void
|
static void
|
||||||
|
@ -139,7 +144,7 @@ create_llao(uint8_t *llao, uint8_t type) {
|
||||||
|
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NA
|
||||||
static void
|
static void
|
||||||
ns_input(void)
|
ns_input(void)
|
||||||
{
|
{
|
||||||
|
@ -319,7 +324,7 @@ discard:
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
return;
|
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");
|
PRINTF("\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#if UIP_ND6_SEND_NA
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Neighbor Advertisement Processing
|
* Neighbor Advertisement Processing
|
||||||
|
@ -554,7 +560,7 @@ discard:
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif /* UIP_ND6_SEND_NA */
|
||||||
|
|
||||||
#if UIP_CONF_ROUTER
|
#if UIP_CONF_ROUTER
|
||||||
#if UIP_ND6_SEND_RA
|
#if UIP_ND6_SEND_RA
|
||||||
|
@ -715,6 +721,29 @@ uip_nd6_ra_output(uip_ipaddr_t * dest)
|
||||||
|
|
||||||
uip_len += UIP_ND6_OPT_MTU_LEN;
|
uip_len += UIP_ND6_OPT_MTU_LEN;
|
||||||
nd6_opt_offset += 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[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
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],
|
(uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
|
||||||
1, NBR_STALE);
|
1, NBR_STALE);
|
||||||
} else {
|
} 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) {
|
if(nbr->state == NBR_INCOMPLETE) {
|
||||||
nbr->state = NBR_STALE;
|
nbr->state = NBR_STALE;
|
||||||
}
|
}
|
||||||
|
@ -938,6 +967,23 @@ ra_input(void)
|
||||||
/* End of autonomous flag related processing */
|
/* End of autonomous flag related processing */
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
PRINTF("ND option not supported in RA");
|
PRINTF("ND option not supported in RA");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
#define UIP_ND6_MIN_RA_INTERVAL UIP_CONF_ND6_MIN_RA_INTERVAL
|
#define UIP_ND6_MIN_RA_INTERVAL UIP_CONF_ND6_MIN_RA_INTERVAL
|
||||||
#endif
|
#endif
|
||||||
#define UIP_ND6_M_FLAG 0
|
#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_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL
|
||||||
|
|
||||||
#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/
|
#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 */
|
/** \name ND6 option types */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
#define UIP_ND6_OPT_SLLAO 1
|
#define UIP_ND6_OPT_SLLAO 1
|
||||||
|
@ -146,6 +163,8 @@
|
||||||
#define UIP_ND6_OPT_PREFIX_INFO 3
|
#define UIP_ND6_OPT_PREFIX_INFO 3
|
||||||
#define UIP_ND6_OPT_REDIRECTED_HDR 4
|
#define UIP_ND6_OPT_REDIRECTED_HDR 4
|
||||||
#define UIP_ND6_OPT_MTU 5
|
#define UIP_ND6_OPT_MTU 5
|
||||||
|
#define UIP_ND6_OPT_RDNSS 25
|
||||||
|
#define UIP_ND6_OPT_DNSSL 31
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/** \name ND6 option types */
|
/** \name ND6 option types */
|
||||||
|
@ -168,6 +187,8 @@
|
||||||
#define UIP_ND6_OPT_HDR_LEN 2
|
#define UIP_ND6_OPT_HDR_LEN 2
|
||||||
#define UIP_ND6_OPT_PREFIX_INFO_LEN 32
|
#define UIP_ND6_OPT_PREFIX_INFO_LEN 32
|
||||||
#define UIP_ND6_OPT_MTU_LEN 8
|
#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 */
|
/* Length of TLLAO and SLLAO options, it is L2 dependant */
|
||||||
|
@ -290,6 +311,15 @@ typedef struct uip_nd6_opt_mtu {
|
||||||
uint32_t mtu;
|
uint32_t mtu;
|
||||||
} uip_nd6_opt_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 */
|
/** \struct Redirected header option */
|
||||||
typedef struct uip_nd6_opt_redirected_hdr {
|
typedef struct uip_nd6_opt_redirected_hdr {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
|
@ -459,7 +459,7 @@ uip_init(void)
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#if UIP_TCP && UIP_ACTIVE_OPEN
|
#if UIP_TCP && UIP_ACTIVE_OPEN
|
||||||
struct uip_conn *
|
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;
|
register struct uip_conn *conn, *cconn;
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,6 @@ powercycle(struct rtimer *t, void *ptr)
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
static uint8_t packet_seen;
|
static uint8_t packet_seen;
|
||||||
static rtimer_clock_t t0;
|
|
||||||
static uint8_t count;
|
static uint8_t count;
|
||||||
|
|
||||||
#if SYNC_CYCLE_STARTS
|
#if SYNC_CYCLE_STARTS
|
||||||
|
@ -365,7 +364,6 @@ powercycle(struct rtimer *t, void *ptr)
|
||||||
packet_seen = 0;
|
packet_seen = 0;
|
||||||
|
|
||||||
for(count = 0; count < CCA_COUNT_MAX; ++count) {
|
for(count = 0; count < CCA_COUNT_MAX; ++count) {
|
||||||
t0 = RTIMER_NOW();
|
|
||||||
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
|
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
|
||||||
powercycle_turn_radio_on();
|
powercycle_turn_radio_on();
|
||||||
/* Check if a packet is seen in the air. If so, we keep the
|
/* 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;
|
uint8_t got_strobe_ack = 0;
|
||||||
int len;
|
int len;
|
||||||
uint8_t is_broadcast = 0;
|
uint8_t is_broadcast = 0;
|
||||||
uint8_t is_reliable = 0;
|
|
||||||
uint8_t is_known_receiver = 0;
|
uint8_t is_known_receiver = 0;
|
||||||
uint8_t collisions;
|
uint8_t collisions;
|
||||||
int transmit_len;
|
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]);
|
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
|
||||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
#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)) {
|
if(!packetbuf_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED)) {
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
|
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 wt;
|
||||||
rtimer_clock_t txtime;
|
rtimer_clock_t txtime = RTIMER_NOW();
|
||||||
int ret;
|
#if RDC_CONF_HARDWARE_ACK
|
||||||
|
int ret = NETSTACK_RADIO.transmit(transmit_len);
|
||||||
txtime = RTIMER_NOW();
|
#else
|
||||||
ret = NETSTACK_RADIO.transmit(transmit_len);
|
NETSTACK_RADIO.transmit(transmit_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if RDC_CONF_HARDWARE_ACK
|
#if RDC_CONF_HARDWARE_ACK
|
||||||
/* For radios that block in the transmit routine and detect the
|
/* For radios that block in the transmit routine and detect the
|
||||||
|
|
|
@ -373,11 +373,13 @@ send_packet(mac_callback_t sent, void *ptr)
|
||||||
}
|
}
|
||||||
metadata->sent = sent;
|
metadata->sent = sent;
|
||||||
metadata->cptr = ptr;
|
metadata->cptr = ptr;
|
||||||
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||||
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
|
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
|
||||||
list_push(n->queued_packet_list, q);
|
list_push(n->queued_packet_list, q);
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
list_add(n->queued_packet_list, q);
|
list_add(n->queued_packet_list, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -453,8 +453,6 @@ send_packet(void)
|
||||||
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
|
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
|
||||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
||||||
}
|
}
|
||||||
/* is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
|
||||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);*/
|
|
||||||
len = NETSTACK_FRAMER.create();
|
len = NETSTACK_FRAMER.create();
|
||||||
strobe_len = len + sizeof(struct cxmac_hdr);
|
strobe_len = len + sizeof(struct cxmac_hdr);
|
||||||
if(len < 0 || strobe_len > (int)sizeof(strobe)) {
|
if(len < 0 || strobe_len > (int)sizeof(strobe)) {
|
||||||
|
@ -475,7 +473,7 @@ send_packet(void)
|
||||||
return MAC_TX_ERR;
|
return MAC_TX_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WITH_STREAMING
|
#if WITH_STREAMING && PACKETBUF_WITH_PACKET_TYPE
|
||||||
if(is_streaming == 1 &&
|
if(is_streaming == 1 &&
|
||||||
(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||||
&is_streaming_to) ||
|
&is_streaming_to) ||
|
||||||
|
@ -519,7 +517,7 @@ send_packet(void)
|
||||||
wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
|
wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
|
||||||
expected = now + wait - 2 * DEFAULT_ON_TIME;
|
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 */
|
/* Wait until the receiver is expected to be awake */
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
|
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
|
||||||
PACKETBUF_ATTR_PACKET_TYPE_ACK &&
|
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
|
/* If we have received the strobe ACK, and we are sending a packet
|
||||||
that will need an upper layer ACK (as signified by the
|
that will need an upper layer ACK (as signified by the
|
||||||
PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
|
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
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
|
packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
|
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
|
||||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||||
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
packetbuf_attr(PACKETBUF_ATTR_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 */
|
on(); /* Wait for ACK packet */
|
||||||
waiting_for_packet = 1;
|
waiting_for_packet = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -242,8 +242,10 @@ parse(void)
|
||||||
}
|
}
|
||||||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
|
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_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);
|
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
if(frame.fcf.security_enabled) {
|
if(frame.fcf.security_enabled) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ mac_sequence_is_duplicate(void)
|
||||||
for(i = 0; i < MAX_SEQNOS; ++i) {
|
for(i = 0; i < MAX_SEQNOS; ++i) {
|
||||||
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
||||||
&received_seqnos[i].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. */
|
/* Duplicate packet. */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ mac_sequence_register_seqno(void)
|
||||||
for(j = i - 1; j > 0; --j) {
|
for(j = i - 1; j > 0; --j) {
|
||||||
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
|
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,
|
linkaddr_copy(&received_seqnos[0].sender,
|
||||||
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,11 +264,13 @@ send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
|
||||||
static void
|
static void
|
||||||
packet_input(void)
|
packet_input(void)
|
||||||
{
|
{
|
||||||
|
#if NULLRDC_SEND_802154_ACK
|
||||||
int original_datalen;
|
int original_datalen;
|
||||||
uint8_t *original_dataptr;
|
uint8_t *original_dataptr;
|
||||||
|
|
||||||
original_datalen = packetbuf_datalen();
|
original_datalen = packetbuf_datalen();
|
||||||
original_dataptr = packetbuf_dataptr();
|
original_dataptr = packetbuf_dataptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if NULLRDC_802154_AUTOACK
|
#if NULLRDC_802154_AUTOACK
|
||||||
if(packetbuf_datalen() == ACK_LEN) {
|
if(packetbuf_datalen() == ACK_LEN) {
|
||||||
|
@ -294,7 +296,7 @@ packet_input(void)
|
||||||
if(duplicate) {
|
if(duplicate) {
|
||||||
/* Drop the packet. */
|
/* Drop the packet. */
|
||||||
PRINTF("nullrdc: drop duplicate link layer packet %u\n",
|
PRINTF("nullrdc: drop duplicate link layer packet %u\n",
|
||||||
packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
|
packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
|
||||||
} else {
|
} else {
|
||||||
mac_sequence_register_seqno();
|
mac_sequence_register_seqno();
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,9 @@ send_packet(mac_callback_t sent, void *ptr)
|
||||||
params.fcf.frame_type = FRAME802154_DATAFRAME;
|
params.fcf.frame_type = FRAME802154_DATAFRAME;
|
||||||
params.fcf.security_enabled = 0;
|
params.fcf.security_enabled = 0;
|
||||||
params.fcf.frame_pending = 0;
|
params.fcf.frame_pending = 0;
|
||||||
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
|
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
|
||||||
|
#endif
|
||||||
params.fcf.panid_compression = 0;
|
params.fcf.panid_compression = 0;
|
||||||
|
|
||||||
/* Insert IEEE 802.15.4 (2003) version bit. */
|
/* Insert IEEE 802.15.4 (2003) version bit. */
|
||||||
|
|
|
@ -106,10 +106,7 @@ packetbuf_compact(void)
|
||||||
{
|
{
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
if(packetbuf_is_reference()) {
|
if(bufptr > 0) {
|
||||||
memcpy(&packetbuf[PACKETBUF_HDR_SIZE], packetbuf_reference_ptr(),
|
|
||||||
packetbuf_datalen());
|
|
||||||
} else if(bufptr > 0) {
|
|
||||||
len = packetbuf_datalen() + PACKETBUF_HDR_SIZE;
|
len = packetbuf_datalen() + PACKETBUF_HDR_SIZE;
|
||||||
for(i = PACKETBUF_HDR_SIZE; i < len; i++) {
|
for(i = PACKETBUF_HDR_SIZE; i < len; i++) {
|
||||||
packetbuf[i] = packetbuf[bufptr + i];
|
packetbuf[i] = packetbuf[bufptr + i];
|
||||||
|
@ -215,26 +212,6 @@ packetbuf_hdrptr(void)
|
||||||
return (void *)(&packetbuf[hdrptr]);
|
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
|
uint16_t
|
||||||
packetbuf_datalen(void)
|
packetbuf_datalen(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,12 @@
|
||||||
#define PACKETBUF_HDR_SIZE 48
|
#define PACKETBUF_HDR_SIZE 48
|
||||||
#endif
|
#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
|
* \brief Clear and reset the packetbuf
|
||||||
*
|
*
|
||||||
|
@ -181,52 +187,12 @@ uint16_t packetbuf_totlen(void);
|
||||||
*/
|
*/
|
||||||
void packetbuf_set_datalen(uint16_t len);
|
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
|
* \brief Compact the packetbuf
|
||||||
*
|
*
|
||||||
* This function compacts the packetbuf by copying the data
|
* This function compacts the packetbuf by copying the data
|
||||||
* portion of the packetbuf so that becomes consecutive to
|
* portion of the packetbuf so that becomes consecutive to
|
||||||
* the header. It also copies external data that has
|
* the header.
|
||||||
* previously been referenced with packetbuf_reference()
|
|
||||||
* into the packetbuf.
|
|
||||||
*
|
*
|
||||||
* This function is called by the Rime code before a
|
* This function is called by the Rime code before a
|
||||||
* packet is to be sent by a device driver. This assures
|
* 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
|
* This function copies the packetbuf to an external
|
||||||
* buffer. Both the data portion and the header portion of
|
* buffer. Both the data portion and the header portion of
|
||||||
* the packetbuf is copied. If the packetbuf referenced
|
* the packetbuf is copied.
|
||||||
* external data (referenced with packetbuf_reference()) the
|
|
||||||
* external data is copied.
|
|
||||||
*
|
*
|
||||||
* The external buffer to which the packetbuf is to be
|
* The external buffer to which the packetbuf is to be
|
||||||
* copied must be able to accomodate at least
|
* copied must be able to accomodate at least
|
||||||
|
@ -351,10 +315,12 @@ enum {
|
||||||
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
|
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
|
||||||
|
|
||||||
/* Scope 1 attributes: used between two neighbors only. */
|
/* Scope 1 attributes: used between two neighbors only. */
|
||||||
PACKETBUF_ATTR_RELIABLE,
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
PACKETBUF_ATTR_PACKET_ID,
|
|
||||||
PACKETBUF_ATTR_PACKET_TYPE,
|
PACKETBUF_ATTR_PACKET_TYPE,
|
||||||
|
#endif
|
||||||
#if NETSTACK_CONF_WITH_RIME
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
|
PACKETBUF_ATTR_PACKET_ID,
|
||||||
|
PACKETBUF_ATTR_RELIABLE,
|
||||||
PACKETBUF_ATTR_REXMIT,
|
PACKETBUF_ATTR_REXMIT,
|
||||||
PACKETBUF_ATTR_MAX_REXMIT,
|
PACKETBUF_ATTR_MAX_REXMIT,
|
||||||
PACKETBUF_ATTR_NUM_REXMIT,
|
PACKETBUF_ATTR_NUM_REXMIT,
|
||||||
|
|
|
@ -43,18 +43,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "contiki-net.h"
|
#include "contiki-net.h"
|
||||||
|
|
||||||
#if WITH_SWAP
|
#if WITH_SWAP
|
||||||
#include "cfs/cfs.h"
|
#include "cfs/cfs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h> /* for memcpy() */
|
#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
|
/* Structure pointing to a buffer either stored
|
||||||
in RAM or swapped in CFS */
|
in RAM or swapped in CFS */
|
||||||
struct queuebuf {
|
struct queuebuf {
|
||||||
|
@ -83,15 +78,7 @@ struct queuebuf_data {
|
||||||
struct packetbuf_addr addrs[PACKETBUF_NUM_ADDRS];
|
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(bufmem, struct queuebuf, QUEUEBUF_NUM);
|
||||||
MEMB(refbufmem, struct queuebuf_ref, QUEUEBUF_REF_NUM);
|
|
||||||
MEMB(buframmem, struct queuebuf_data, QUEUEBUFRAM_NUM);
|
MEMB(buframmem, struct queuebuf_data, QUEUEBUFRAM_NUM);
|
||||||
|
|
||||||
#if WITH_SWAP
|
#if WITH_SWAP
|
||||||
|
@ -144,7 +131,7 @@ LIST(queuebuf_list);
|
||||||
#endif /* QUEUEBUF_CONF_STATS */
|
#endif /* QUEUEBUF_CONF_STATS */
|
||||||
|
|
||||||
#if QUEUEBUF_STATS
|
#if QUEUEBUF_STATS
|
||||||
uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len;
|
uint8_t queuebuf_len, queuebuf_max_len;
|
||||||
#endif /* QUEUEBUF_STATS */
|
#endif /* QUEUEBUF_STATS */
|
||||||
|
|
||||||
#if WITH_SWAP
|
#if WITH_SWAP
|
||||||
|
@ -301,21 +288,16 @@ queuebuf_init(void)
|
||||||
#endif
|
#endif
|
||||||
memb_init(&buframmem);
|
memb_init(&buframmem);
|
||||||
memb_init(&bufmem);
|
memb_init(&bufmem);
|
||||||
memb_init(&refbufmem);
|
|
||||||
#if QUEUEBUF_STATS
|
#if QUEUEBUF_STATS
|
||||||
queuebuf_max_len = QUEUEBUF_NUM;
|
queuebuf_max_len = 0;
|
||||||
#endif /* QUEUEBUF_STATS */
|
#endif /* QUEUEBUF_STATS */
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
int
|
int
|
||||||
queuebuf_numfree(void)
|
queuebuf_numfree(void)
|
||||||
{
|
{
|
||||||
if(packetbuf_is_reference()) {
|
|
||||||
return memb_numfree(&refbufmem);
|
|
||||||
} else {
|
|
||||||
return memb_numfree(&bufmem);
|
return memb_numfree(&bufmem);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#if QUEUEBUF_DEBUG
|
#if QUEUEBUF_DEBUG
|
||||||
struct queuebuf *
|
struct queuebuf *
|
||||||
|
@ -326,22 +308,7 @@ queuebuf_new_from_packetbuf(void)
|
||||||
#endif /* QUEUEBUF_DEBUG */
|
#endif /* QUEUEBUF_DEBUG */
|
||||||
{
|
{
|
||||||
struct queuebuf *buf;
|
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;
|
struct queuebuf_data *buframptr;
|
||||||
buf = memb_alloc(&bufmem);
|
buf = memb_alloc(&bufmem);
|
||||||
if(buf != NULL) {
|
if(buf != NULL) {
|
||||||
|
@ -387,12 +354,9 @@ queuebuf_new_from_packetbuf(void)
|
||||||
|
|
||||||
#if QUEUEBUF_STATS
|
#if QUEUEBUF_STATS
|
||||||
++queuebuf_len;
|
++queuebuf_len;
|
||||||
PRINTF("queuebuf len %d\n", queuebuf_len);
|
PRINTF("#A q=%d\n", queuebuf_len);
|
||||||
printf("#A q=%d\n", queuebuf_len);
|
if(queuebuf_len > queuebuf_max_len) {
|
||||||
if(queuebuf_len == queuebuf_max_len + 1) {
|
queuebuf_max_len = queuebuf_len;
|
||||||
queuebuf_free(buf);
|
|
||||||
queuebuf_len--;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif /* QUEUEBUF_STATS */
|
#endif /* QUEUEBUF_STATS */
|
||||||
|
|
||||||
|
@ -401,7 +365,6 @@ queuebuf_new_from_packetbuf(void)
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
queuebuf_update_attr_from_packetbuf(struct queuebuf *buf)
|
queuebuf_update_attr_from_packetbuf(struct queuebuf *buf)
|
||||||
|
@ -444,47 +407,30 @@ queuebuf_free(struct queuebuf *buf)
|
||||||
memb_free(&bufmem, buf);
|
memb_free(&bufmem, buf);
|
||||||
#if QUEUEBUF_STATS
|
#if QUEUEBUF_STATS
|
||||||
--queuebuf_len;
|
--queuebuf_len;
|
||||||
printf("#A q=%d\n", queuebuf_len);
|
PRINTF("#A q=%d\n", queuebuf_len);
|
||||||
#endif /* QUEUEBUF_STATS */
|
#endif /* QUEUEBUF_STATS */
|
||||||
#if QUEUEBUF_DEBUG
|
#if QUEUEBUF_DEBUG
|
||||||
list_remove(queuebuf_list, buf);
|
list_remove(queuebuf_list, buf);
|
||||||
#endif /* QUEUEBUF_DEBUG */
|
#endif /* QUEUEBUF_DEBUG */
|
||||||
} else if(memb_inmemb(&refbufmem, buf)) {
|
|
||||||
memb_free(&refbufmem, buf);
|
|
||||||
#if QUEUEBUF_STATS
|
|
||||||
--queuebuf_ref_len;
|
|
||||||
#endif /* QUEUEBUF_STATS */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
queuebuf_to_packetbuf(struct queuebuf *b)
|
queuebuf_to_packetbuf(struct queuebuf *b)
|
||||||
{
|
{
|
||||||
struct queuebuf_ref *r;
|
|
||||||
if(memb_inmemb(&bufmem, b)) {
|
if(memb_inmemb(&bufmem, b)) {
|
||||||
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
||||||
packetbuf_copyfrom(buframptr->data, buframptr->len);
|
packetbuf_copyfrom(buframptr->data, buframptr->len);
|
||||||
packetbuf_attr_copyfrom(buframptr->attrs, buframptr->addrs);
|
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 *
|
void *
|
||||||
queuebuf_dataptr(struct queuebuf *b)
|
queuebuf_dataptr(struct queuebuf *b)
|
||||||
{
|
{
|
||||||
struct queuebuf_ref *r;
|
|
||||||
|
|
||||||
if(memb_inmemb(&bufmem, b)) {
|
if(memb_inmemb(&bufmem, b)) {
|
||||||
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
||||||
return buframptr->data;
|
return buframptr->data;
|
||||||
} else if(memb_inmemb(&refbufmem, b)) {
|
|
||||||
r = (struct queuebuf_ref *)b;
|
|
||||||
return r->ref;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/** @} */
|
|
|
@ -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_ */
|
|
||||||
/** @} */
|
|
||||||
/** @} */
|
|
||||||
|
|
|
@ -195,4 +195,77 @@
|
||||||
#define RPL_PREFERENCE 0
|
#define RPL_PREFERENCE 0
|
||||||
#endif
|
#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 */
|
#endif /* RPL_CONF_H */
|
||||||
|
|
260
core/net/rpl/rpl-dag-root.c
Normal file
260
core/net/rpl/rpl-dag-root.c
Normal 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;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
41
core/net/rpl/rpl-dag-root.h
Normal file
41
core/net/rpl/rpl-dag-root.h
Normal 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_ */
|
|
@ -75,12 +75,37 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Per-parent RPL information */
|
/* Per-parent RPL information */
|
||||||
NBR_TABLE(rpl_parent_t, rpl_parents);
|
NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Allocate instance table. */
|
/* Allocate instance table. */
|
||||||
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
|
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
|
||||||
rpl_instance_t *default_instance;
|
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 *
|
uip_ds6_nbr_t *
|
||||||
rpl_get_nbr(rpl_parent_t *parent)
|
rpl_get_nbr(rpl_parent_t *parent)
|
||||||
|
@ -269,18 +294,28 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
|
||||||
rpl_dag_t *dag;
|
rpl_dag_t *dag;
|
||||||
rpl_instance_t *instance;
|
rpl_instance_t *instance;
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
|
int i;
|
||||||
|
|
||||||
version = RPL_LOLLIPOP_INIT;
|
version = RPL_LOLLIPOP_INIT;
|
||||||
dag = get_dag(instance_id, dag_id);
|
instance = rpl_get_instance(instance_id);
|
||||||
if(dag != NULL) {
|
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;
|
version = dag->version;
|
||||||
RPL_LOLLIPOP_INCREMENT(version);
|
RPL_LOLLIPOP_INCREMENT(version);
|
||||||
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
|
}
|
||||||
if(dag == dag->instance->current_dag) {
|
if(dag == dag->instance->current_dag) {
|
||||||
|
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
|
||||||
dag->instance->current_dag = NULL;
|
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);
|
dag = rpl_alloc_dag(instance_id, dag_id);
|
||||||
if(dag == NULL) {
|
if(dag == NULL) {
|
||||||
|
@ -474,6 +509,9 @@ rpl_alloc_instance(uint8_t instance_id)
|
||||||
instance->instance_id = instance_id;
|
instance->instance_id = instance_id;
|
||||||
instance->def_route = NULL;
|
instance->def_route = NULL;
|
||||||
instance->used = 1;
|
instance->used = 1;
|
||||||
|
#if RPL_WITH_PROBING
|
||||||
|
rpl_schedule_probing(instance);
|
||||||
|
#endif /* RPL_WITH_PROBING */
|
||||||
return instance;
|
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_STAT(rpl_stats.mem_overflows++);
|
||||||
rpl_free_instance(instance);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -517,6 +554,12 @@ rpl_set_default_instance(rpl_instance_t *instance)
|
||||||
default_instance = instance;
|
default_instance = instance;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
rpl_instance_t *
|
||||||
|
rpl_get_default_instance(void)
|
||||||
|
{
|
||||||
|
return default_instance;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rpl_free_instance(rpl_instance_t *instance)
|
rpl_free_instance(rpl_instance_t *instance)
|
||||||
{
|
{
|
||||||
|
@ -534,6 +577,9 @@ rpl_free_instance(rpl_instance_t *instance)
|
||||||
|
|
||||||
rpl_set_default_route(instance, NULL);
|
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->dio_timer);
|
||||||
ctimer_stop(&instance->dao_timer);
|
ctimer_stop(&instance->dao_timer);
|
||||||
ctimer_stop(&instance->dao_lifetime_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_schedule_dao(instance);
|
||||||
}
|
}
|
||||||
rpl_reset_dio_timer(instance);
|
rpl_reset_dio_timer(instance);
|
||||||
|
#if DEBUG
|
||||||
|
rpl_print_neighbor_list();
|
||||||
|
#endif
|
||||||
} else if(best_dag->rank != old_rank) {
|
} else if(best_dag->rank != old_rank) {
|
||||||
PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n",
|
PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n",
|
||||||
(unsigned)old_rank, best_dag->rank);
|
(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, ",
|
PRINTF(", rank %u, min_rank %u, ",
|
||||||
instance->current_dag->rank, instance->current_dag->min_rank);
|
instance->current_dag->rank, instance->current_dag->min_rank);
|
||||||
PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n",
|
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. */
|
/* We have allocated a candidate parent; process the DIO further. */
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,7 @@ rpl_update_header_empty(void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
#if RPL_INSERT_HBH_OPTION
|
||||||
PRINTF("RPL: No hop-by-hop option found, creating it\n");
|
PRINTF("RPL: No hop-by-hop option found, creating it\n");
|
||||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
||||||
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
|
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);
|
set_rpl_opt(uip_ext_opt_offset);
|
||||||
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
|
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,9 +376,11 @@ rpl_invert_header(void)
|
||||||
void
|
void
|
||||||
rpl_insert_header(void)
|
rpl_insert_header(void)
|
||||||
{
|
{
|
||||||
|
#if RPL_INSERT_HBH_OPTION
|
||||||
if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||||
rpl_update_header_empty();
|
rpl_update_header_empty();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -466,8 +466,12 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
|
||||||
|
|
||||||
buffer[pos++] = instance->dtsn_out;
|
buffer[pos++] = instance->dtsn_out;
|
||||||
|
|
||||||
/* always request new DAO to refresh route */
|
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);
|
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||||
|
}
|
||||||
|
|
||||||
/* reserved 2 bytes */
|
/* reserved 2 bytes */
|
||||||
buffer[pos++] = 0; /* flags */
|
buffer[pos++] = 0; /* flags */
|
||||||
|
|
|
@ -313,6 +313,7 @@ rpl_of_t *rpl_find_of(rpl_ocp_t);
|
||||||
void rpl_schedule_dao(rpl_instance_t *);
|
void rpl_schedule_dao(rpl_instance_t *);
|
||||||
void rpl_schedule_dao_immediately(rpl_instance_t *);
|
void rpl_schedule_dao_immediately(rpl_instance_t *);
|
||||||
void rpl_cancel_dao(rpl_instance_t *instance);
|
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_dio_timer(rpl_instance_t *);
|
||||||
void rpl_reset_periodic_timer(void);
|
void rpl_reset_periodic_timer(void);
|
||||||
|
@ -320,4 +321,7 @@ void rpl_reset_periodic_timer(void);
|
||||||
/* Route poisoning. */
|
/* Route poisoning. */
|
||||||
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
|
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
|
||||||
|
|
||||||
|
|
||||||
|
rpl_instance_t *rpl_get_default_instance(void);
|
||||||
|
|
||||||
#endif /* RPL_PRIVATE_H */
|
#endif /* RPL_PRIVATE_H */
|
||||||
|
|
|
@ -166,6 +166,10 @@ handle_dio_timer(void *ptr)
|
||||||
}
|
}
|
||||||
new_dio_interval(instance);
|
new_dio_interval(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
rpl_print_neighbor_list();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
@ -323,5 +327,97 @@ rpl_cancel_dao(rpl_instance_t *instance)
|
||||||
ctimer_stop(&instance->dao_lifetime_timer);
|
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 */
|
||||||
/** @}*/
|
/** @}*/
|
||||||
|
|
|
@ -263,6 +263,7 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
|
||||||
parent->flags |= RPL_PARENT_FLAG_UPDATED;
|
parent->flags |= RPL_PARENT_FLAG_UPDATED;
|
||||||
if(instance->of->neighbor_link_callback != NULL) {
|
if(instance->of->neighbor_link_callback != NULL) {
|
||||||
instance->of->neighbor_link_callback(parent, status, numtx);
|
instance->of->neighbor_link_callback(parent, status, numtx);
|
||||||
|
parent->last_tx_time = clock_time();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ struct rpl_parent {
|
||||||
rpl_metric_container_t mc;
|
rpl_metric_container_t mc;
|
||||||
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
||||||
rpl_rank_t rank;
|
rpl_rank_t rank;
|
||||||
|
clock_time_t last_tx_time;
|
||||||
uint8_t dtsn;
|
uint8_t dtsn;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
};
|
};
|
||||||
|
@ -224,6 +225,9 @@ struct rpl_instance {
|
||||||
uint16_t dio_totrecv;
|
uint16_t dio_totrecv;
|
||||||
#endif /* RPL_CONF_STATS */
|
#endif /* RPL_CONF_STATS */
|
||||||
clock_time_t dio_next_delay; /* delay for completion of dio interval */
|
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 dio_timer;
|
||||||
struct ctimer dao_timer;
|
struct ctimer dao_timer;
|
||||||
struct ctimer dao_lifetime_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);
|
uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr);
|
||||||
void rpl_dag_init(void);
|
void rpl_dag_init(void);
|
||||||
uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent);
|
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
|
* RPL modes
|
||||||
|
|
|
@ -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
|
* function will cause the timer to be stable over time, unlike the
|
||||||
* timer_restart() function.
|
* 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()
|
* \sa timer_restart()
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
|
@ -117,7 +117,7 @@ makestrings(void)
|
||||||
makeaddr(&addr, gateway);
|
makeaddr(&addr, gateway);
|
||||||
|
|
||||||
#if WITH_DNS
|
#if WITH_DNS
|
||||||
addrptr = resolv_getserver();
|
addrptr = uip_nameserver_get(0);
|
||||||
if(addrptr != NULL) {
|
if(addrptr != NULL) {
|
||||||
makeaddr(addrptr, dnsserver);
|
makeaddr(addrptr, dnsserver);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ dhcpc_configured(const struct dhcpc_state *s)
|
||||||
uip_setnetmask(&s->netmask);
|
uip_setnetmask(&s->netmask);
|
||||||
uip_setdraddr(&s->default_router);
|
uip_setdraddr(&s->default_router);
|
||||||
#if WITH_DNS
|
#if WITH_DNS
|
||||||
resolv_conf(&s->dnsaddr);
|
uip_nameserver_update(&s->dnsaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||||
#endif /* WITH_DNS */
|
#endif /* WITH_DNS */
|
||||||
|
|
||||||
set_statustext("Configured.");
|
set_statustext("Configured.");
|
||||||
|
@ -261,7 +261,7 @@ dhcpc_unconfigured(const struct dhcpc_state *s)
|
||||||
uip_setnetmask(&nulladdr);
|
uip_setnetmask(&nulladdr);
|
||||||
uip_setdraddr(&nulladdr);
|
uip_setdraddr(&nulladdr);
|
||||||
#if WITH_DNS
|
#if WITH_DNS
|
||||||
resolv_conf(&nulladdr);
|
uip_nameserver_update(&nulladdr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||||
#endif /* WITH_DNS */
|
#endif /* WITH_DNS */
|
||||||
|
|
||||||
set_statustext("Unconfigured.");
|
set_statustext("Unconfigured.");
|
||||||
|
|
|
@ -105,7 +105,7 @@ config_read(char *filename)
|
||||||
uip_setnetmask(&config.netmask);
|
uip_setnetmask(&config.netmask);
|
||||||
uip_setdraddr(&config.draddr);
|
uip_setdraddr(&config.draddr);
|
||||||
#if WITH_DNS
|
#if WITH_DNS
|
||||||
resolv_conf(&config.resolvaddr);
|
uip_nameserver_update(&config.resolvaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||||
#endif /* WITH_DNS */
|
#endif /* WITH_DNS */
|
||||||
|
|
||||||
return &config.ethernetcfg;
|
return &config.ethernetcfg;
|
||||||
|
|
|
@ -89,7 +89,7 @@ fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
|
||||||
.byte fixup29-fixup28, fixup30-fixup29, fixup31-fixup30
|
.byte fixup29-fixup28, fixup30-fixup29, fixup31-fixup30
|
||||||
.byte fixup32-fixup31, fixup33-fixup32, fixup34-fixup33
|
.byte fixup32-fixup31, fixup33-fixup32, fixup34-fixup33
|
||||||
.byte fixup35-fixup34, fixup36-fixup35, fixup37-fixup36
|
.byte fixup35-fixup34, fixup36-fixup35, fixup37-fixup36
|
||||||
.byte fixup38-fixup37, fixup39-fixup38, fixup40-fixup39
|
.byte fixup38-fixup37, fixup39-fixup38
|
||||||
|
|
||||||
fixups = * - fixup
|
fixups = * - fixup
|
||||||
|
|
||||||
|
@ -272,9 +272,7 @@ fixup22:lda ethdata
|
||||||
bcs :++
|
bcs :++
|
||||||
|
|
||||||
; Yes, skip packet
|
; Yes, skip packet
|
||||||
; Remove and release RX packet from the FIFO
|
jsr releasepacket
|
||||||
lda #%10000000
|
|
||||||
fixup23:sta ethmmucr
|
|
||||||
|
|
||||||
; No packet available
|
; No packet available
|
||||||
lda #$00
|
lda #$00
|
||||||
|
@ -285,7 +283,7 @@ fixup23:sta ethmmucr
|
||||||
; Read bytes into buffer
|
; Read bytes into buffer
|
||||||
: jsr adjustptr
|
: jsr adjustptr
|
||||||
:
|
:
|
||||||
fixup24:lda ethdata
|
fixup23:lda ethdata
|
||||||
sta (ptr),y
|
sta (ptr),y
|
||||||
iny
|
iny
|
||||||
bne :-
|
bne :-
|
||||||
|
@ -294,8 +292,7 @@ fixup24:lda ethdata
|
||||||
bpl :-
|
bpl :-
|
||||||
|
|
||||||
; Remove and release RX packet from the FIFO
|
; Remove and release RX packet from the FIFO
|
||||||
lda #%10000000
|
jsr releasepacket
|
||||||
fixup25:sta ethmmucr
|
|
||||||
|
|
||||||
; Return packet length
|
; Return packet length
|
||||||
lda len
|
lda len
|
||||||
|
@ -313,19 +310,19 @@ send:
|
||||||
; Allocate memory for TX
|
; Allocate memory for TX
|
||||||
txa
|
txa
|
||||||
ora #%00100000
|
ora #%00100000
|
||||||
fixup26:sta ethmmucr
|
fixup24:sta ethmmucr
|
||||||
|
|
||||||
; 8 retries
|
; 8 retries
|
||||||
ldy #$08
|
ldy #$08
|
||||||
|
|
||||||
; Wait for allocation ready
|
; Wait for allocation ready
|
||||||
:
|
:
|
||||||
fixup27:lda ethist
|
fixup25:lda ethist
|
||||||
and #%00001000 ; ALLOC INT
|
and #%00001000 ; ALLOC INT
|
||||||
bne :+
|
bne :+
|
||||||
|
|
||||||
; Shouldn't we do something here to actively free memory,
|
; No space avaliable, skip a received frame
|
||||||
; maybe removing and releasing an RX packet from the FIFO ???
|
jsr releasepacket
|
||||||
|
|
||||||
; And try again
|
; And try again
|
||||||
dey
|
dey
|
||||||
|
@ -335,21 +332,21 @@ fixup27:lda ethist
|
||||||
|
|
||||||
; Acknowledge interrupt, is it necessary ???
|
; Acknowledge interrupt, is it necessary ???
|
||||||
: lda #%00001000
|
: lda #%00001000
|
||||||
fixup28:sta ethack
|
fixup26:sta ethack
|
||||||
|
|
||||||
; Set packet address
|
; Set packet address
|
||||||
fixup29:lda etharr
|
fixup27:lda etharr
|
||||||
fixup30:sta ethpnr
|
fixup28:sta ethpnr
|
||||||
|
|
||||||
lda #$00
|
lda #$00
|
||||||
ldx #%01000000 ; AUTO INCR.
|
ldx #%01000000 ; AUTO INCR.
|
||||||
fixup31:sta ethptr
|
fixup29:sta ethptr
|
||||||
fixup32:stx ethptr+1
|
fixup30:stx ethptr+1
|
||||||
|
|
||||||
; Status written by CSMA
|
; Status written by CSMA
|
||||||
lda #$00
|
lda #$00
|
||||||
fixup33:sta ethdata
|
fixup31:sta ethdata
|
||||||
fixup34:sta ethdata
|
fixup32:sta ethdata
|
||||||
|
|
||||||
; Check packet length parity:
|
; Check packet length parity:
|
||||||
; - Even packet length -> carry set -> add 6 bytes
|
; - Even packet length -> carry set -> add 6 bytes
|
||||||
|
@ -361,10 +358,10 @@ fixup34:sta ethdata
|
||||||
; The packet contains 3 extra words
|
; The packet contains 3 extra words
|
||||||
lda len
|
lda len
|
||||||
adc #$05 ; Actually 5 or 6 depending on carry
|
adc #$05 ; Actually 5 or 6 depending on carry
|
||||||
fixup35:sta ethdata
|
fixup33:sta ethdata
|
||||||
lda len+1
|
lda len+1
|
||||||
adc #$00
|
adc #$00
|
||||||
fixup36:sta ethdata
|
fixup34:sta ethdata
|
||||||
|
|
||||||
; Send the packet
|
; Send the packet
|
||||||
; ---------------
|
; ---------------
|
||||||
|
@ -372,7 +369,7 @@ fixup36:sta ethdata
|
||||||
; Write bytes from buffer
|
; Write bytes from buffer
|
||||||
jsr adjustptr
|
jsr adjustptr
|
||||||
: lda (ptr),y
|
: lda (ptr),y
|
||||||
fixup37:sta ethdata
|
fixup35:sta ethdata
|
||||||
iny
|
iny
|
||||||
bne :-
|
bne :-
|
||||||
inc ptr+1
|
inc ptr+1
|
||||||
|
@ -390,13 +387,13 @@ fixup37:sta ethdata
|
||||||
|
|
||||||
; No
|
; No
|
||||||
: lda #$00
|
: 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
|
; Add packet to FIFO
|
||||||
lda #%11000000 ; ENQUEUE PACKET - transmit packet
|
lda #%11000000 ; ENQUEUE PACKET - transmit packet
|
||||||
fixup40:sta ethmmucr
|
fixup38:sta ethmmucr
|
||||||
clc
|
clc
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
@ -407,6 +404,14 @@ exit:
|
||||||
|
|
||||||
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
||||||
|
|
||||||
|
releasepacket:
|
||||||
|
; Remove and release RX packet from the FIFO
|
||||||
|
lda #%10000000
|
||||||
|
fixup39:sta ethmmucr
|
||||||
|
rts
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------
|
||||||
|
|
||||||
adjustptr:
|
adjustptr:
|
||||||
lda len
|
lda len
|
||||||
ldx len+1
|
ldx len+1
|
||||||
|
|
|
@ -402,14 +402,18 @@ sicslowmac_dataRequest(void)
|
||||||
frame_create_params_t params;
|
frame_create_params_t params;
|
||||||
frame_result_t result;
|
frame_result_t result;
|
||||||
|
|
||||||
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
/* Save the msduHandle in a global variable. */
|
/* Save the msduHandle in a global variable. */
|
||||||
msduHandle = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
|
msduHandle = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Build the FCF. */
|
/* Build the FCF. */
|
||||||
params.fcf.frameType = DATAFRAME;
|
params.fcf.frameType = DATAFRAME;
|
||||||
params.fcf.securityEnabled = false;
|
params.fcf.securityEnabled = false;
|
||||||
params.fcf.framePending = false;
|
params.fcf.framePending = false;
|
||||||
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
params.fcf.ackRequired = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
|
params.fcf.ackRequired = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
|
||||||
|
#endif
|
||||||
params.fcf.panIdCompression = false;
|
params.fcf.panIdCompression = false;
|
||||||
|
|
||||||
/* Insert IEEE 802.15.4 (2003) version bit. */
|
/* Insert IEEE 802.15.4 (2003) version bit. */
|
||||||
|
|
|
@ -1073,8 +1073,10 @@ rf230_transmit(unsigned short payload_len)
|
||||||
|
|
||||||
if (tx_result==RADIO_TX_OK) {
|
if (tx_result==RADIO_TX_OK) {
|
||||||
RIMESTATS_ADD(lltx);
|
RIMESTATS_ADD(lltx);
|
||||||
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE))
|
if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE))
|
||||||
RIMESTATS_ADD(ackrx); //ack was requested and received
|
RIMESTATS_ADD(ackrx); //ack was requested and received
|
||||||
|
#endif
|
||||||
#if RF230_INSERTACK
|
#if RF230_INSERTACK
|
||||||
/* Not PAN broadcast to FFFF, and ACK was requested and received */
|
/* Not PAN broadcast to FFFF, and ACK was requested and received */
|
||||||
if (!((buffer[5]==0xff) && (buffer[6]==0xff)) && (buffer[0]&(1<<6)))
|
if (!((buffer[5]==0xff) && (buffer[6]==0xff)) && (buffer[0]&(1<<6)))
|
||||||
|
|
|
@ -49,8 +49,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RADIO_H
|
#ifndef RF230BB_H_
|
||||||
#define RADIO_H
|
#define RF230BB_H_
|
||||||
/*============================ INCLUDE =======================================*/
|
/*============================ INCLUDE =======================================*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -225,6 +225,6 @@ uint8_t rf230_get_raw_rssi(void);
|
||||||
|
|
||||||
#define rf230_rssi rf230_get_raw_rssi
|
#define rf230_rssi rf230_get_raw_rssi
|
||||||
|
|
||||||
#endif
|
#endif /* RF230BB_H_ */
|
||||||
/** @} */
|
/** @} */
|
||||||
/*EOF*/
|
/*EOF*/
|
||||||
|
|
|
@ -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 += cc2538-rf.c udma.c lpm.c
|
||||||
CONTIKI_CPU_SOURCEFILES += dbg.c ieee-addr.c
|
CONTIKI_CPU_SOURCEFILES += dbg.c ieee-addr.c
|
||||||
CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.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
|
DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c
|
||||||
|
|
||||||
USB_CORE_SOURCEFILES += usb-core.c cdc-acm.c
|
USB_CORE_SOURCEFILES += usb-core.c cdc-acm.c
|
||||||
USB_ARCH_SOURCEFILES += usb-arch.c usb-serial.c cdc-acm-descriptors.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 += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES)
|
||||||
CONTIKI_SOURCEFILES += $(USB_CORE_SOURCEFILES) $(USB_ARCH_SOURCEFILES)
|
CONTIKI_SOURCEFILES += $(USB_CORE_SOURCEFILES) $(USB_ARCH_SOURCEFILES)
|
||||||
|
|
||||||
|
@ -74,7 +82,7 @@ $(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR)
|
||||||
### Compilation rules
|
### Compilation rules
|
||||||
CUSTOM_RULE_LINK=1
|
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)
|
$(TRACE_LD)
|
||||||
$(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
|
$(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
|
||||||
|
|
||||||
|
|
|
@ -96,17 +96,17 @@ clock_init(void)
|
||||||
REG(SYS_CTRL_RCGCGPT) |= SYS_CTRL_RCGCGPT_GPT0;
|
REG(SYS_CTRL_RCGCGPT) |= SYS_CTRL_RCGCGPT_GPT0;
|
||||||
|
|
||||||
/* Make sure GPT0 is off */
|
/* Make sure GPT0 is off */
|
||||||
REG(GPT_0_BASE | GPTIMER_CTL) = 0;
|
REG(GPT_0_BASE + GPTIMER_CTL) = 0;
|
||||||
|
|
||||||
|
|
||||||
/* 16-bit */
|
/* 16-bit */
|
||||||
REG(GPT_0_BASE | GPTIMER_CFG) = 0x04;
|
REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
|
||||||
|
|
||||||
/* One-Shot, Count Down, No Interrupts */
|
/* 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) */
|
/* 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
|
CCIF clock_time_t
|
||||||
|
@ -144,11 +144,11 @@ clock_wait(clock_time_t i)
|
||||||
void
|
void
|
||||||
clock_delay_usec(uint16_t dt)
|
clock_delay_usec(uint16_t dt)
|
||||||
{
|
{
|
||||||
REG(GPT_0_BASE | GPTIMER_TAILR) = dt;
|
REG(GPT_0_BASE + GPTIMER_TAILR) = dt;
|
||||||
REG(GPT_0_BASE | GPTIMER_CTL) |= GPTIMER_CTL_TAEN;
|
REG(GPT_0_BASE + GPTIMER_CTL) |= GPTIMER_CTL_TAEN;
|
||||||
|
|
||||||
/* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
|
/* 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);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,7 +80,6 @@
|
||||||
/* Local RF Flags */
|
/* Local RF Flags */
|
||||||
#define RX_ACTIVE 0x80
|
#define RX_ACTIVE 0x80
|
||||||
#define RF_MUST_RESET 0x40
|
#define RF_MUST_RESET 0x40
|
||||||
#define WAS_OFF 0x10
|
|
||||||
#define RF_ON 0x01
|
#define RF_ON 0x01
|
||||||
|
|
||||||
/* Bit Masks for the last byte in the RX FIFO */
|
/* Bit Masks for the last byte in the RX FIFO */
|
||||||
|
@ -180,6 +179,8 @@ get_channel()
|
||||||
static int8_t
|
static int8_t
|
||||||
set_channel(uint8_t channel)
|
set_channel(uint8_t channel)
|
||||||
{
|
{
|
||||||
|
uint8_t was_on = 0;
|
||||||
|
|
||||||
PRINTF("RF: Set Channel\n");
|
PRINTF("RF: Set Channel\n");
|
||||||
|
|
||||||
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
|
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 */
|
/* Changes to FREQCTRL take effect after the next recalibration */
|
||||||
|
|
||||||
/* If we are off, save state, otherwise switch off and save state */
|
/* If we are off, save state, otherwise switch off and save state */
|
||||||
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) != 0) {
|
||||||
rf_flags |= WAS_OFF;
|
was_on = 1;
|
||||||
} else {
|
|
||||||
rf_flags &= ~WAS_OFF;
|
|
||||||
off();
|
off();
|
||||||
}
|
}
|
||||||
REG(RFCORE_XREG_FREQCTRL) = (CC2538_RF_CHANNEL_MIN
|
REG(RFCORE_XREG_FREQCTRL) = (CC2538_RF_CHANNEL_MIN
|
||||||
+ (channel - CC2538_RF_CHANNEL_MIN) * CC2538_RF_CHANNEL_SPACING);
|
+ (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 */
|
/* 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();
|
on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,10 +243,11 @@ static radio_value_t
|
||||||
get_rssi(void)
|
get_rssi(void)
|
||||||
{
|
{
|
||||||
int8_t rssi;
|
int8_t rssi;
|
||||||
|
uint8_t was_off = 0;
|
||||||
|
|
||||||
/* If we are off, turn on first */
|
/* If we are off, turn on first */
|
||||||
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
||||||
rf_flags |= WAS_OFF;
|
was_off = 1;
|
||||||
on();
|
on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,8 +257,7 @@ get_rssi(void)
|
||||||
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
|
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
|
||||||
|
|
||||||
/* If we were off, turn back off */
|
/* If we were off, turn back off */
|
||||||
if((rf_flags & WAS_OFF) == WAS_OFF) {
|
if(was_off) {
|
||||||
rf_flags &= ~WAS_OFF;
|
|
||||||
off();
|
off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,12 +344,13 @@ static int
|
||||||
channel_clear(void)
|
channel_clear(void)
|
||||||
{
|
{
|
||||||
int cca;
|
int cca;
|
||||||
|
uint8_t was_off = 0;
|
||||||
|
|
||||||
PRINTF("RF: CCA\n");
|
PRINTF("RF: CCA\n");
|
||||||
|
|
||||||
/* If we are off, turn on first */
|
/* If we are off, turn on first */
|
||||||
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
||||||
rf_flags |= WAS_OFF;
|
was_off = 1;
|
||||||
on();
|
on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,8 +364,7 @@ channel_clear(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we were off, turn back off */
|
/* If we were off, turn back off */
|
||||||
if((rf_flags & WAS_OFF) == WAS_OFF) {
|
if(was_off) {
|
||||||
rf_flags &= ~WAS_OFF;
|
|
||||||
off();
|
off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,13 +560,14 @@ transmit(unsigned short transmit_len)
|
||||||
uint8_t counter;
|
uint8_t counter;
|
||||||
int ret = RADIO_TX_ERR;
|
int ret = RADIO_TX_ERR;
|
||||||
rtimer_clock_t t0;
|
rtimer_clock_t t0;
|
||||||
|
uint8_t was_off = 0;
|
||||||
|
|
||||||
PRINTF("RF: Transmit\n");
|
PRINTF("RF: Transmit\n");
|
||||||
|
|
||||||
if(!(rf_flags & RX_ACTIVE)) {
|
if(!(rf_flags & RX_ACTIVE)) {
|
||||||
t0 = RTIMER_NOW();
|
t0 = RTIMER_NOW();
|
||||||
on();
|
on();
|
||||||
rf_flags |= WAS_OFF;
|
was_off = 1;
|
||||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
|
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,8 +609,7 @@ transmit(unsigned short transmit_len)
|
||||||
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
|
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
|
||||||
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
||||||
|
|
||||||
if(rf_flags & WAS_OFF) {
|
if(was_off) {
|
||||||
rf_flags &= ~WAS_OFF;
|
|
||||||
off();
|
off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue