Merge pull request #1003 from adamdunkels/pr/http-socket-dns64-tcp-socket
New HTTP socket, DNS64, IP64 Cooja tests
This commit is contained in:
commit
44af0fa66b
|
@ -110,6 +110,7 @@ env:
|
|||
- BUILD_TYPE='rpl'
|
||||
- BUILD_TYPE='rime'
|
||||
- BUILD_TYPE='ipv6'
|
||||
- BUILD_TYPE='ip64' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='hello-world'
|
||||
- BUILD_TYPE='base'
|
||||
# XXX: netperf disabled b/c it's flaky
|
||||
|
|
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 */
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static void relisten(struct tcp_socket *s);
|
||||
|
||||
LIST(socketlist);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(tcp_socket_process, "TCP socket process");
|
||||
|
@ -58,8 +60,8 @@ senddata(struct tcp_socket *s)
|
|||
{
|
||||
int len = MIN(s->output_data_max_seg, uip_mss());
|
||||
|
||||
if(s->output_data_len > 0) {
|
||||
len = MIN(s->output_data_len, len);
|
||||
if(s->output_senddata_len > 0) {
|
||||
len = MIN(s->output_senddata_len, len);
|
||||
s->output_data_send_nxt = len;
|
||||
uip_send(s->output_data_ptr, len);
|
||||
}
|
||||
|
@ -68,7 +70,7 @@ senddata(struct tcp_socket *s)
|
|||
static void
|
||||
acked(struct tcp_socket *s)
|
||||
{
|
||||
if(s->output_data_len > 0) {
|
||||
if(s->output_senddata_len > 0) {
|
||||
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||
outputbuf_lastsent */
|
||||
|
||||
|
@ -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",
|
||||
s->output_data_len,
|
||||
s->output_data_send_nxt);
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
uip_abort();
|
||||
call_event(s, TCP_SOCKET_ABORTED);
|
||||
relisten(s);
|
||||
return;
|
||||
}
|
||||
s->output_data_len -= s->output_data_send_nxt;
|
||||
s->output_senddata_len = s->output_data_len;
|
||||
s->output_data_send_nxt = 0;
|
||||
|
||||
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||
|
@ -134,6 +142,11 @@ appcall(void *state)
|
|||
{
|
||||
struct tcp_socket *s = state;
|
||||
|
||||
if(s != NULL && s->c != NULL && s->c != uip_conn) {
|
||||
/* Safe-guard: this should not happen, as the incoming event relates to
|
||||
* a previous connection */
|
||||
return;
|
||||
}
|
||||
if(uip_connected()) {
|
||||
/* Check if this connection originated in a local listen
|
||||
socket. We do this by checking the state pointer - if NULL,
|
||||
|
@ -176,8 +189,10 @@ appcall(void *state)
|
|||
}
|
||||
|
||||
if(uip_aborted()) {
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_ABORTED);
|
||||
relisten(s);
|
||||
|
||||
}
|
||||
|
||||
if(s == NULL) {
|
||||
|
@ -203,13 +218,16 @@ appcall(void *state)
|
|||
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||
uip_close();
|
||||
s->c = NULL;
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
s->c = NULL;
|
||||
/*call_event(s, TCP_SOCKET_CLOSED);*/
|
||||
relisten(s);
|
||||
}
|
||||
|
||||
if(uip_closed()) {
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
s->c = NULL;
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
relisten(s);
|
||||
}
|
||||
|
@ -255,6 +273,7 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
s->ptr = ptr;
|
||||
s->input_data_ptr = input_databuf;
|
||||
s->input_data_maxlen = input_databuf_len;
|
||||
s->output_data_len = 0;
|
||||
s->output_data_ptr = output_databuf;
|
||||
s->output_data_maxlen = output_databuf_len;
|
||||
s->input_callback = input_callback;
|
||||
|
@ -268,12 +287,15 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
const uip_ipaddr_t *ipaddr,
|
||||
uint16_t port)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if(s->c != NULL) {
|
||||
tcp_markconn(s->c, NULL);
|
||||
}
|
||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||
PROCESS_CONTEXT_END();
|
||||
|
@ -329,6 +351,11 @@ tcp_socket_send(struct tcp_socket *s,
|
|||
|
||||
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||
s->output_data_len += len;
|
||||
|
||||
if(s->output_senddata_len == 0) {
|
||||
s->output_senddata_len = s->output_data_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -365,3 +392,9 @@ tcp_socket_unregister(struct tcp_socket *s)
|
|||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_max_sendlen(struct tcp_socket *s)
|
||||
{
|
||||
return s->output_data_maxlen - s->output_data_len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#ifndef TCP_SOCKET_H
|
||||
#define TCP_SOCKET_H
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
struct tcp_socket;
|
||||
|
||||
typedef enum {
|
||||
|
@ -95,6 +97,7 @@ struct tcp_socket {
|
|||
uint16_t output_data_maxlen;
|
||||
uint16_t output_data_len;
|
||||
uint16_t output_data_send_nxt;
|
||||
uint16_t output_senddata_len;
|
||||
uint16_t output_data_max_seg;
|
||||
|
||||
uint8_t flags;
|
||||
|
@ -170,7 +173,7 @@ int tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
*
|
||||
*/
|
||||
int tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
const uip_ipaddr_t *ipaddr,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
|
@ -266,4 +269,19 @@ int tcp_socket_close(struct tcp_socket *s);
|
|||
*
|
||||
*/
|
||||
int tcp_socket_unregister(struct tcp_socket *s);
|
||||
|
||||
/**
|
||||
* \brief The maximum amount of data that could currently be sent
|
||||
* \param s A pointer to a TCP socket
|
||||
* \return The number of bytes available in the output buffer
|
||||
*
|
||||
* This function queries the TCP socket and returns the
|
||||
* number of bytes available in the output buffer. This
|
||||
* function is used before calling tcp_socket_send() to
|
||||
* ensure that one application level message can be held
|
||||
* in the output buffer.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_max_sendlen(struct tcp_socket *s);
|
||||
|
||||
#endif /* TCP_SOCKET_H */
|
||||
|
|
|
@ -228,7 +228,7 @@ packet_input(void)
|
|||
#if UIP_TCP
|
||||
#if UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
|
||||
tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
|
||||
{
|
||||
struct uip_conn *c;
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ CCIF void tcp_unlisten(uint16_t port);
|
|||
* memory could not be allocated for the connection.
|
||||
*
|
||||
*/
|
||||
CCIF struct uip_conn *tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port,
|
||||
CCIF struct uip_conn *tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port,
|
||||
void *appstate);
|
||||
|
||||
/**
|
||||
|
|
|
@ -600,7 +600,7 @@ void uip_unlisten(uint16_t port);
|
|||
* or NULL if no connection could be allocated.
|
||||
*
|
||||
*/
|
||||
struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, uint16_t port);
|
||||
struct uip_conn *uip_connect(const uip_ipaddr_t *ripaddr, uint16_t port);
|
||||
|
||||
|
||||
|
||||
|
@ -1030,10 +1030,10 @@ struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, uint16_t rport);
|
|||
#define uip_ipaddr_copy(dest, src) (*(dest) = *(src))
|
||||
#endif
|
||||
#ifndef uip_ip4addr_copy
|
||||
#define uip_ip4addr_copy(dest, src) (*(dest) = *(src))
|
||||
#define uip_ip4addr_copy(dest, src) (*((uip_ip4addr_t *)dest) = *((uip_ip4addr_t *)src))
|
||||
#endif
|
||||
#ifndef uip_ip6addr_copy
|
||||
#define uip_ip6addr_copy(dest, src) (*(dest) = *(src))
|
||||
#define uip_ip6addr_copy(dest, src) (*((uip_ip6addr_t *)dest) = *((uip_ip6addr_t *)src))
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -148,6 +149,7 @@ ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr,
|
|||
m->ip6port == ip6port &&
|
||||
uip_ip4addr_cmp(&m->ip4addr, ip4addr) &&
|
||||
uip_ip6addr_cmp(&m->ip6addr, ip6addr)) {
|
||||
m->ip6to4++;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +168,7 @@ ip64_addrmap_lookup_port(uint16_t mapped_port, uint8_t protocol)
|
|||
m->protocol, protocol);
|
||||
if(m->mapped_port == mapped_port &&
|
||||
m->protocol == protocol) {
|
||||
m->ip4to6++;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +207,8 @@ ip64_addrmap_create(const uip_ip6addr_t *ip6addr,
|
|||
m->ip6port = ip6port;
|
||||
m->protocol = protocol;
|
||||
m->flags = FLAGS_NONE;
|
||||
m->ip6to4 = 1;
|
||||
m->ip4to6 = 0;
|
||||
timer_set(&m->timer, 0);
|
||||
|
||||
/* Pick a new, unused local port. First make sure that the
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -40,6 +41,7 @@ struct ip64_addrmap_entry {
|
|||
struct timer timer;
|
||||
uip_ip6addr_t ip6addr;
|
||||
uip_ip4addr_t ip4addr;
|
||||
uint32_t ip6to4, ip4to6;
|
||||
uint16_t mapped_port;
|
||||
uint16_t ip6port;
|
||||
uint16_t ip4port;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
259
core/net/ip64/ip64-dns64.c
Normal file
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
|
||||
* 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.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -58,7 +59,8 @@
|
|||
#include "ip64-special-ports.h"
|
||||
#include "ip64-eth-interface.h"
|
||||
#include "ip64-slip-interface.h"
|
||||
|
||||
#include "ip64-dns64.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "ip64-ipv4-dhcp.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
|
@ -172,6 +174,8 @@ static uip_ip4addr_t ipv4_broadcast_addr;
|
|||
#define TCP_SYN 0x02
|
||||
#define TCP_RST 0x04
|
||||
|
||||
#define DNS_PORT 53
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ip64_init(void)
|
||||
|
@ -434,6 +438,15 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
|||
case IP_PROTO_UDP:
|
||||
PRINTF("ip64_6to4: UDP header\n");
|
||||
v4hdr->proto = IP_PROTO_UDP;
|
||||
|
||||
/* Check if this is a DNS request. If so, we should rewrite it
|
||||
with the DNS64 module. */
|
||||
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
|
||||
ip64_dns64_6to4((uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv6len - IPV6_HDRLEN - sizeof(struct udp_hdr),
|
||||
(uint8_t *)udphdr + sizeof(struct udp_hdr),
|
||||
BUFSIZE - IPV4_HDRLEN - sizeof(struct udp_hdr));
|
||||
}
|
||||
/* Compute and check the UDP checksum - since we're going to
|
||||
recompute it ourselves, we must ensure that it was correct in
|
||||
the first place. */
|
||||
|
@ -572,9 +585,18 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
|||
} else {
|
||||
ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME);
|
||||
|
||||
/* Treat DNS requests specially: since the are one-shot, we
|
||||
/* Treat UDP packets from the IPv6 network to a multicast
|
||||
address on the IPv4 network differently: since there is
|
||||
no way for packets from the IPv4 network to go back to
|
||||
the IPv6 network on these mappings, we'll mark them as
|
||||
recyclable. */
|
||||
if(v4hdr->destipaddr.u8[0] == 224) {
|
||||
ip64_addrmap_set_recycleble(m);
|
||||
}
|
||||
|
||||
/* Treat DNS requests differently: since the are one-shot, we
|
||||
mark them as recyclable. */
|
||||
if(udphdr->destport == UIP_HTONS(53)) {
|
||||
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
|
||||
ip64_addrmap_set_recycleble(m);
|
||||
}
|
||||
}
|
||||
|
@ -706,6 +728,21 @@ ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4packet_len,
|
|||
switch(v4hdr->proto) {
|
||||
case IP_PROTO_UDP:
|
||||
v6hdr->nxthdr = IP_PROTO_UDP;
|
||||
/* Check if this is a DNS request. If so, we should rewrite it
|
||||
with the DNS64 module. */
|
||||
if(udphdr->srcport == UIP_HTONS(DNS_PORT)) {
|
||||
int len;
|
||||
|
||||
len = ip64_dns64_4to6((uint8_t *)v4hdr + IPV4_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv4len - IPV4_HDRLEN - sizeof(struct udp_hdr),
|
||||
(uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv6_packet_len - sizeof(struct udp_hdr));
|
||||
ipv6_packet_len = len + sizeof(struct udp_hdr);
|
||||
v6hdr->len[0] = ipv6_packet_len >> 8;
|
||||
v6hdr->len[1] = ipv6_packet_len & 0xff;
|
||||
ipv6len = ipv6_packet_len + IPV6_HDRLEN;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IP_PROTO_TCP:
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -386,7 +386,7 @@ uip_init(void)
|
|||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
{
|
||||
register struct uip_conn *conn, *cconn;
|
||||
|
||||
|
|
|
@ -459,7 +459,7 @@ uip_init(void)
|
|||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_TCP && UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
{
|
||||
register struct uip_conn *conn, *cconn;
|
||||
|
||||
|
|
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_ */
|
|
@ -516,6 +516,12 @@ rpl_set_default_instance(rpl_instance_t *instance)
|
|||
default_instance = instance;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_instance_t *
|
||||
rpl_get_default_instance(void)
|
||||
{
|
||||
return default_instance;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_free_instance(rpl_instance_t *instance)
|
||||
{
|
||||
|
|
|
@ -320,4 +320,7 @@ void rpl_reset_periodic_timer(void);
|
|||
/* Route poisoning. */
|
||||
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
|
||||
|
||||
|
||||
rpl_instance_t *rpl_get_default_instance(void);
|
||||
|
||||
#endif /* RPL_PRIVATE_H */
|
||||
|
|
7
examples/http-socket/Makefile
Normal file
7
examples/http-socket/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
all: http-example
|
||||
CONTIKI=../..
|
||||
MODULES += core/net/http-socket
|
||||
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
||||
|
62
examples/http-socket/http-example.c
Normal file
62
examples/http-socket/http-example.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "contiki-net.h"
|
||||
#include "http-socket.h"
|
||||
#include "ip64-addr.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static struct http_socket s;
|
||||
static int bytes_received = 0;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(http_example_process, "HTTP Example");
|
||||
AUTOSTART_PROCESSES(&http_example_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
callback(struct http_socket *s, void *ptr,
|
||||
http_socket_event_t e,
|
||||
const uint8_t *data, uint16_t datalen)
|
||||
{
|
||||
if(e == HTTP_SOCKET_ERR) {
|
||||
printf("HTTP socket error\n");
|
||||
} else if(e == HTTP_SOCKET_TIMEDOUT) {
|
||||
printf("HTTP socket error: timed out\n");
|
||||
} else if(e == HTTP_SOCKET_ABORTED) {
|
||||
printf("HTTP socket error: aborted\n");
|
||||
} else if(e == HTTP_SOCKET_HOSTNAME_NOT_FOUND) {
|
||||
printf("HTTP socket error: hostname not found\n");
|
||||
} else if(e == HTTP_SOCKET_CLOSED) {
|
||||
printf("HTTP socket closed, %d bytes received\n", bytes_received);
|
||||
} else if(e == HTTP_SOCKET_DATA) {
|
||||
bytes_received += datalen;
|
||||
printf("HTTP socket received %d bytes of data\n", datalen);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(http_example_process, ev, data)
|
||||
{
|
||||
static struct etimer et;
|
||||
uip_ip4addr_t ip4addr;
|
||||
uip_ip6addr_t ip6addr;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
uip_ipaddr(&ip4addr, 8,8,8,8);
|
||||
ip64_addr_4to6(&ip4addr, &ip6addr);
|
||||
uip_nameserver_update(&ip6addr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||
|
||||
etimer_set(&et, CLOCK_SECOND * 60);
|
||||
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
|
||||
|
||||
http_socket_init(&s);
|
||||
http_socket_get(&s, "http://www.contiki-os.org/", 0, 0,
|
||||
callback, NULL);
|
||||
|
||||
etimer_set(&et, CLOCK_SECOND);
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
|
||||
etimer_reset(&et);
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
5
examples/ip64-router/Makefile
Normal file
5
examples/ip64-router/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
all: ip64-router
|
||||
CONTIKI=../..
|
||||
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
27
examples/ip64-router/ip64-router.c
Normal file
27
examples/ip64-router/ip64-router.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "ip64.h"
|
||||
#include "net/netstack.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(router_node_process, "Router node");
|
||||
AUTOSTART_PROCESSES(&router_node_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(router_node_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
/* Set us up as a RPL root node. */
|
||||
rpl_dag_root_init_dag();
|
||||
|
||||
/* Initialize the IP64 module so we'll start translating packets */
|
||||
ip64_init();
|
||||
|
||||
/* ... and do nothing more. */
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
0
examples/ip64-router/project-conf.h
Normal file
0
examples/ip64-router/project-conf.h
Normal file
15
platform/cooja-ip64/Makefile.cooja-ip64
Normal file
15
platform/cooja-ip64/Makefile.cooja-ip64
Normal file
|
@ -0,0 +1,15 @@
|
|||
COOJAPLATFORMDIR=$(CONTIKI)/platform/cooja
|
||||
|
||||
MODULES += core/net/ip64
|
||||
include $(COOJAPLATFORMDIR)/Makefile.cooja
|
||||
|
||||
vpath %.c $(COOJAPLATFORMDIR) $(COOJAPLATFORMDIR)/dev \
|
||||
$(COOJAPLATFORMDIR)/net $(COOJAPLATFORMDIR)/lib \
|
||||
$(COOJAPLATFORMDIR)/sys $(COOJAPLATFORMDIR)/cfs
|
||||
CFLAGS += -I $(COOJAPLATFORMDIR)
|
||||
|
||||
CFLAGS += -DWITH_IP64=1 -DWITH_LARGE_BUFFER_SIZE=1
|
||||
CFLAGS += -DINCLUDE_SUBPLATFORM_CONF=1
|
||||
|
||||
%.cooja: %.cooja-ip64
|
||||
cp $< $@
|
50
platform/cooja-ip64/Makefile.customrules-cooja-ip64
Normal file
50
platform/cooja-ip64/Makefile.customrules-cooja-ip64
Normal file
|
@ -0,0 +1,50 @@
|
|||
### Define custom targets
|
||||
|
||||
REDEF_PRINTF=1 # Redefine functions to enable printf()s inside Cooja
|
||||
|
||||
# NB: Assumes ARCHIVE was not overridden and is in $(OBJECTDIR)
|
||||
$(ARCHIVE): $(CONTIKI_OBJECTFILES) | $(OBJECTDIR)
|
||||
${subst obj_cooja/,$(OBJECTDIR)/,$(AR_COMMAND_1)} $^ $(AR_COMMAND_2)
|
||||
|
||||
# NB: Assumes JNILIB was not overridden and is in $(OBJECTDIR)
|
||||
$(JNILIB): $(CONTIKI_APP_OBJ) $(MAIN_OBJ) $(PROJECT_OBJECTFILES) $(ARCHIVE) | $(OBJECTDIR)
|
||||
ifdef SYMBOLS
|
||||
@echo Generating symbols
|
||||
# Recreate symbols file and relink with final memory layout (twice)
|
||||
${CONTIKI}/tools/make-symbols-nm $(JNILIB)
|
||||
$(CC) $(CFLAGS) -c symbols.c -o $(OBJECTDIR)/symbols.o
|
||||
$(LINK_COMMAND_1) $^ $(LINK_COMMAND_2)
|
||||
${CONTIKI}/tools/make-symbols-nm $(JNILIB)
|
||||
$(CC) $(CFLAGS) -c symbols.c -o $(OBJECTDIR)/symbols.o
|
||||
endif ## SYMBOLS
|
||||
ifdef REDEF_PRINTF
|
||||
@echo Redefining printf
|
||||
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym printf=log_printf $(OBJ); )
|
||||
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym puts=log_puts $(OBJ); )
|
||||
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym putchar=log_putchar $(OBJ); )
|
||||
endif ## REDEF_PRINTF
|
||||
${subst .cooja,.$(TARGET),${subst obj_cooja/,$(OBJECTDIR)/,$(LINK_COMMAND_1)}} $^ $(LINK_COMMAND_2)
|
||||
|
||||
.PHONY: $(CONTIKI_APP).$(TARGET)
|
||||
$(CONTIKI_APP).$(TARGET): $(JNILIB)
|
||||
cp $(JNILIB) $@
|
||||
rm $(CONTIKI_APP_OBJ)
|
||||
|
||||
mkdir -p obj_cooja
|
||||
@-cp obj_cooja-ip64/$(LIBNAME).map obj_cooja/$(LIBNAME).map && echo Placed a copy of the map file at obj_cooja/$(LIBNAME).map
|
||||
|
||||
cp obj_cooja-ip64/$(LIBNAME).cooja-ip64 obj_cooja/$(LIBNAME).cooja
|
||||
@echo Placed a copy of the shared library at obj_cooja/$(LIBNAME).cooja
|
||||
|
||||
cp $@ $(CONTIKI_APP).cooja
|
||||
@echo Placed a copy of the shared library at $(CONTIKI_APP).cooja
|
||||
|
||||
# Trickiness: GNU make matches this against the file base name.
|
||||
# Assume that the directory part is the standard location.
|
||||
mtype%.o: contiki-cooja-ip64-main.o | $(OBJECTDIR)
|
||||
mv contiki-cooja-ip64-main.o $@
|
||||
|
||||
symbols.c:
|
||||
# Create initial symbol files if not existing
|
||||
cp ${CONTIKI}/tools/empty-symbols.c symbols.c
|
||||
cp ${CONTIKI}/tools/empty-symbols.h symbols.h
|
425
platform/cooja-ip64/contiki-cooja-ip64-main.c
Normal file
425
platform/cooja-ip64/contiki-cooja-ip64-main.c
Normal file
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* COOJA Contiki mote main file.
|
||||
* \author
|
||||
* Fredrik Osterlind <fros@sics.se>
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "contiki.h"
|
||||
|
||||
#include "sys/clock.h"
|
||||
#include "sys/etimer.h"
|
||||
#include "sys/cooja_mt.h"
|
||||
#include "sys/autostart.h"
|
||||
|
||||
#include "lib/random.h"
|
||||
#include "lib/simEnvChange.h"
|
||||
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/netstack.h"
|
||||
#include "net/ip/uip-nameserver.h"
|
||||
|
||||
#include "dev/serial-line.h"
|
||||
#include "dev/cooja-radio.h"
|
||||
#include "dev/button-sensor.h"
|
||||
#include "dev/pir-sensor.h"
|
||||
#include "dev/vib-sensor.h"
|
||||
|
||||
#include "sys/node-id.h"
|
||||
|
||||
#include "ip64.h"
|
||||
#include "dev/slip.h"
|
||||
|
||||
/* JNI-defined functions, depends on the environment variable CLASSNAME */
|
||||
#ifndef CLASSNAME
|
||||
#error CLASSNAME is undefined, required by contiki-cooja-main.c
|
||||
#endif /* CLASSNAME */
|
||||
#define COOJA__QUOTEME(a,b,c) COOJA_QUOTEME(a,b,c)
|
||||
#define COOJA_QUOTEME(a,b,c) a##b##c
|
||||
#define COOJA_JNI_PATH Java_org_contikios_cooja_corecomm_
|
||||
#define Java_org_contikios_cooja_corecomm_CLASSNAME_init COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_init)
|
||||
#define Java_org_contikios_cooja_corecomm_CLASSNAME_getMemory COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_getMemory)
|
||||
#define Java_org_contikios_cooja_corecomm_CLASSNAME_setMemory COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_setMemory)
|
||||
#define Java_org_contikios_cooja_corecomm_CLASSNAME_tick COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_tick)
|
||||
#define Java_org_contikios_cooja_corecomm_CLASSNAME_setReferenceAddress COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_setReferenceAddress)
|
||||
|
||||
#include "net/ip/uip.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#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])
|
||||
|
||||
/* Simulation mote interfaces */
|
||||
SIM_INTERFACE_NAME(moteid_interface);
|
||||
SIM_INTERFACE_NAME(vib_interface);
|
||||
SIM_INTERFACE_NAME(rs232_interface);
|
||||
SIM_INTERFACE_NAME(simlog_interface);
|
||||
SIM_INTERFACE_NAME(beep_interface);
|
||||
SIM_INTERFACE_NAME(radio_interface);
|
||||
SIM_INTERFACE_NAME(button_interface);
|
||||
SIM_INTERFACE_NAME(pir_interface);
|
||||
SIM_INTERFACE_NAME(clock_interface);
|
||||
SIM_INTERFACE_NAME(leds_interface);
|
||||
SIM_INTERFACE_NAME(cfs_interface);
|
||||
SIM_INTERFACES(&vib_interface, &moteid_interface, &rs232_interface, &simlog_interface, &beep_interface, &radio_interface, &button_interface, &pir_interface, &clock_interface, &leds_interface, &cfs_interface);
|
||||
/* Example: manually add mote interfaces */
|
||||
//SIM_INTERFACE_NAME(dummy_interface);
|
||||
//SIM_INTERFACES(..., &dummy_interface);
|
||||
|
||||
/* Sensors */
|
||||
SENSORS(&button_sensor, &pir_sensor, &vib_sensor);
|
||||
|
||||
/*
|
||||
* referenceVar is used for comparing absolute and process relative memory.
|
||||
* (this must not be static due to memory locations)
|
||||
*/
|
||||
long referenceVar;
|
||||
|
||||
/*
|
||||
* Contiki and rtimer threads.
|
||||
*/
|
||||
static struct cooja_mt_thread rtimer_thread;
|
||||
static struct cooja_mt_thread process_run_thread;
|
||||
|
||||
#define MIN(a, b) ( (a)<(b) ? (a) : (b) )
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
print_processes(struct process * const processes[])
|
||||
{
|
||||
/* const struct process * const * p = processes;*/
|
||||
printf("Starting");
|
||||
while(*processes != NULL) {
|
||||
printf(" '%s'", (*processes)->name);
|
||||
processes++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
rtimer_thread_loop(void *data)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
rtimer_arch_check();
|
||||
|
||||
/* Return to COOJA */
|
||||
cooja_mt_yield();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_mac_addr(void)
|
||||
{
|
||||
linkaddr_t addr;
|
||||
int i;
|
||||
|
||||
memset(&addr, 0, sizeof(linkaddr_t));
|
||||
for(i = 0; i < sizeof(uip_lladdr.addr); i += 2) {
|
||||
addr.u8[i + 1] = node_id & 0xff;
|
||||
addr.u8[i + 0] = node_id >> 8;
|
||||
}
|
||||
linkaddr_set_node_addr(&addr);
|
||||
printf("MAC address ");
|
||||
for(i = 0; i < sizeof(addr.u8) - 1; i++) {
|
||||
printf("%d.", addr.u8[i]);
|
||||
}
|
||||
printf("%d\n", addr.u8[i]);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
contiki_init(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t addr[sizeof(uip_lladdr.addr)];
|
||||
uip_ipaddr_t ipaddr;
|
||||
uip_ds6_addr_t *lladdr;
|
||||
uip_ip4addr_t ipv4addr, netmask;
|
||||
|
||||
/* Start process handler */
|
||||
process_init();
|
||||
|
||||
/* Start Contiki processes */
|
||||
process_start(&etimer_process, NULL);
|
||||
process_start(&sensors_process, NULL);
|
||||
ctimer_init();
|
||||
|
||||
/* Print startup information */
|
||||
printf(CONTIKI_VERSION_STRING " started. ");
|
||||
if(node_id > 0) {
|
||||
printf("Node id is set to %u.\n", node_id);
|
||||
} else {
|
||||
printf("Node id is not set.\n");
|
||||
}
|
||||
|
||||
set_mac_addr();
|
||||
|
||||
queuebuf_init();
|
||||
|
||||
/* Initialize communication stack */
|
||||
netstack_init();
|
||||
printf("%s/%s/%s, channel check rate %lu Hz\n",
|
||||
NETSTACK_NETWORK.name, NETSTACK_MAC.name, NETSTACK_RDC.name,
|
||||
CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval() == 0 ? 1:
|
||||
NETSTACK_RDC.channel_check_interval()));
|
||||
|
||||
/* IPv6 CONFIGURATION */
|
||||
|
||||
|
||||
for(i = 0; i < sizeof(uip_lladdr.addr); i += 2) {
|
||||
addr[i + 1] = node_id & 0xff;
|
||||
addr[i + 0] = node_id >> 8;
|
||||
}
|
||||
linkaddr_copy(addr, &linkaddr_node_addr);
|
||||
memcpy(&uip_lladdr.addr, addr, sizeof(uip_lladdr.addr));
|
||||
|
||||
process_start(&tcpip_process, NULL);
|
||||
|
||||
printf("Tentative link-local IPv6 address ");
|
||||
|
||||
lladdr = uip_ds6_get_link_local(-1);
|
||||
for(i = 0; i < 7; ++i) {
|
||||
printf("%02x%02x:", lladdr->ipaddr.u8[i * 2],
|
||||
lladdr->ipaddr.u8[i * 2 + 1]);
|
||||
}
|
||||
printf("%02x%02x\n", lladdr->ipaddr.u8[14],
|
||||
lladdr->ipaddr.u8[15]);
|
||||
|
||||
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_TENTATIVE);
|
||||
printf("Tentative global IPv6 address ");
|
||||
for(i = 0; i < 7; ++i) {
|
||||
printf("%02x%02x:",
|
||||
ipaddr.u8[i * 2], ipaddr.u8[i * 2 + 1]);
|
||||
}
|
||||
printf("%02x%02x\n",
|
||||
ipaddr.u8[7 * 2], ipaddr.u8[7 * 2 + 1]);
|
||||
|
||||
/* Start serial process */
|
||||
serial_line_init();
|
||||
|
||||
/* Start autostart processes (defined in Contiki application) */
|
||||
print_processes(autostart_processes);
|
||||
autostart_start(autostart_processes);
|
||||
|
||||
/* Start the SLIP */
|
||||
printf("Initiating SLIP with IP address is 172.16.0.2.\n");
|
||||
|
||||
uip_ipaddr(&ipv4addr, 172, 16, 0, 2);
|
||||
uip_ipaddr(&netmask, 255, 255, 255, 0);
|
||||
ip64_set_ipv4_address(&ipv4addr, &netmask);
|
||||
|
||||
rs232_set_input(slip_input_byte);
|
||||
log_set_putchar_with_slip(1);
|
||||
|
||||
uip_ip4addr_t ip4addr;
|
||||
uip_ip6addr_t ip6addr;
|
||||
|
||||
uip_ipaddr(&ip4addr, 8,8,8,8);
|
||||
ip64_addr_4to6(&ip4addr, &ip6addr);
|
||||
|
||||
uip_nameserver_update((uip_ipaddr_t *)&ip6addr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
process_run_thread_loop(void *data)
|
||||
{
|
||||
/* Yield once during bootup */
|
||||
simProcessRunValue = 1;
|
||||
cooja_mt_yield();
|
||||
|
||||
contiki_init();
|
||||
|
||||
while(1) {
|
||||
simProcessRunValue = process_run();
|
||||
while(simProcessRunValue-- > 0) {
|
||||
process_run();
|
||||
}
|
||||
simProcessRunValue = process_nevents();
|
||||
|
||||
/* Check if we must stay awake */
|
||||
if(simDontFallAsleep) {
|
||||
simDontFallAsleep = 0;
|
||||
simProcessRunValue = 1;
|
||||
}
|
||||
|
||||
/* Return to COOJA */
|
||||
cooja_mt_yield();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialize a mote by starting processes etc.
|
||||
*
|
||||
* This function initializes a mote by starting certain
|
||||
* processes and setting up the environment.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_contikios_cooja_corecomm_CLASSNAME_init(JNIEnv *env, jobject obj)
|
||||
{
|
||||
/* Create rtimers and Contiki threads */
|
||||
cooja_mt_start(&rtimer_thread, &rtimer_thread_loop, NULL);
|
||||
cooja_mt_start(&process_run_thread, &process_run_thread_loop, NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Get a segment from the process memory.
|
||||
* \param start Start address of segment
|
||||
* \param length Size of memory segment
|
||||
* \return Java byte array containing a copy of memory segment.
|
||||
*
|
||||
* Fetches a memory segment from the process memory starting at
|
||||
* (start), with size (length). This function does not perform
|
||||
* ANY error checking, and the process may crash if addresses are
|
||||
* not available/readable.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_contikios_cooja_corecomm_CLASSNAME_getMemory(JNIEnv *env, jobject obj, jint rel_addr, jint length, jbyteArray mem_arr)
|
||||
{
|
||||
(*env)->SetByteArrayRegion(
|
||||
env,
|
||||
mem_arr,
|
||||
0,
|
||||
(size_t) length,
|
||||
(jbyte *) (((long)rel_addr) + referenceVar)
|
||||
);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Replace a segment of the process memory with given byte array.
|
||||
* \param start Start address of segment
|
||||
* \param length Size of memory segment
|
||||
* \param mem_arr Byte array contaning new memory
|
||||
*
|
||||
* Replaces a process memory segment with given byte array.
|
||||
* This function does not perform ANY error checking, and the
|
||||
* process may crash if addresses are not available/writable.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_contikios_cooja_corecomm_CLASSNAME_setMemory(JNIEnv *env, jobject obj, jint rel_addr, jint length, jbyteArray mem_arr)
|
||||
{
|
||||
jbyte *mem = (*env)->GetByteArrayElements(env, mem_arr, 0);
|
||||
memcpy((char *)(((long)rel_addr) + referenceVar),
|
||||
mem,
|
||||
length);
|
||||
(*env)->ReleaseByteArrayElements(env, mem_arr, mem, 0);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Let mote execute one "block" of code (tick mote).
|
||||
*
|
||||
* Let mote defined by the active contiki processes and current
|
||||
* process memory execute some program code. This code must not block
|
||||
* or else this function will never return. A typical contiki
|
||||
* process will return when it executes PROCESS_WAIT..() statements.
|
||||
*
|
||||
* Before the control is left to contiki processes, any messages
|
||||
* from the Java part are handled. These may for example be
|
||||
* incoming network data. After the contiki processes return control,
|
||||
* messages to the Java part are also handled (those which may need
|
||||
* special attention).
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_contikios_cooja_corecomm_CLASSNAME_tick(JNIEnv *env, jobject obj)
|
||||
{
|
||||
clock_time_t nextEtimer;
|
||||
rtimer_clock_t nextRtimer;
|
||||
|
||||
simProcessRunValue = 0;
|
||||
|
||||
/* Let all simulation interfaces act first */
|
||||
doActionsBeforeTick();
|
||||
|
||||
/* Poll etimer process */
|
||||
if(etimer_pending()) {
|
||||
etimer_request_poll();
|
||||
}
|
||||
|
||||
/* Let rtimers run.
|
||||
* Sets simProcessRunValue */
|
||||
cooja_mt_exec(&rtimer_thread);
|
||||
|
||||
if(simProcessRunValue == 0) {
|
||||
/* Rtimers done: Let Contiki handle a few events.
|
||||
* Sets simProcessRunValue */
|
||||
cooja_mt_exec(&process_run_thread);
|
||||
}
|
||||
|
||||
/* Let all simulation interfaces act before returning to java */
|
||||
doActionsAfterTick();
|
||||
|
||||
/* Do we have any pending timers */
|
||||
simEtimerPending = etimer_pending() || rtimer_arch_pending();
|
||||
if(!simEtimerPending) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save nearest expiration time */
|
||||
nextEtimer = etimer_next_expiration_time() - (clock_time_t) simCurrentTime;
|
||||
nextRtimer = rtimer_arch_next() - (rtimer_clock_t) simCurrentTime;
|
||||
if(etimer_pending() && rtimer_arch_pending()) {
|
||||
simNextExpirationTime = MIN(nextEtimer, nextRtimer);
|
||||
} else if(etimer_pending()) {
|
||||
simNextExpirationTime = nextEtimer;
|
||||
} else if(rtimer_arch_pending()) {
|
||||
simNextExpirationTime = nextRtimer;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Set the relative memory address of the reference variable.
|
||||
* \return Relative memory address.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_contikios_cooja_corecomm_CLASSNAME_setReferenceAddress(JNIEnv *env, jobject obj, jint addr)
|
||||
{
|
||||
referenceVar = (((long)&referenceVar) - ((long)addr));
|
||||
}
|
45
platform/cooja-ip64/ip64-conf.h
Normal file
45
platform/cooja-ip64/ip64-conf.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2012-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 IP64_CONF_H
|
||||
#define IP64_CONF_H
|
||||
|
||||
#undef UIP_FALLBACK_INTERFACE
|
||||
#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface
|
||||
|
||||
#include "ip64-slip-interface.h"
|
||||
#include "ip64-null-driver.h"
|
||||
|
||||
#define IP64_CONF_UIP_FALLBACK_INTERFACE_SLIP 1
|
||||
#define IP64_CONF_UIP_FALLBACK_INTERFACE ip64_slip_interface
|
||||
#define IP64_CONF_INPUT ip64_slip_interface_input
|
||||
#define IP64_CONF_ETH_DRIVER ip64_null_driver
|
||||
|
||||
#endif /* IP64_CONF_H */
|
54
platform/cooja-ip64/subplatform-conf.h
Normal file
54
platform/cooja-ip64/subplatform-conf.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 __PLATFORM_CONF_H__
|
||||
#define __PLATFORM_CONF_H__
|
||||
|
||||
#if WITH_IP64
|
||||
#define WITH_SLIP 1
|
||||
#ifndef UIP_FALLBACK_INTERFACE
|
||||
#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface
|
||||
#endif
|
||||
#endif /* WITH_IP64 */
|
||||
|
||||
#ifndef UIP_CONF_ND6_RA_RDNSS
|
||||
#define UIP_CONF_ND6_RA_RDNSS 1
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_ND6_SEND_RA
|
||||
#define UIP_CONF_ND6_SEND_RA 1
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_ROUTER
|
||||
#define UIP_CONF_ROUTER 1
|
||||
#endif
|
||||
|
||||
#endif /* __PLATFORM_CONF_H__ */
|
|
@ -37,7 +37,7 @@ endif ## QUICKSTART
|
|||
#MAIN_SRC = $(OBJECTDIR)/$(LIBNAME).c
|
||||
MAIN_OBJ = $(OBJECTDIR)/$(LIBNAME).o
|
||||
ARCHIVE = $(OBJECTDIR)/$(LIBNAME).a
|
||||
JNILIB = $(OBJECTDIR)/$(LIBNAME).cooja
|
||||
JNILIB = $(OBJECTDIR)/$(LIBNAME).$(TARGET)
|
||||
CONTIKI_APP_OBJ = $(CONTIKI_APP).co
|
||||
|
||||
### COOJA platform sources
|
||||
|
@ -75,7 +75,7 @@ CFLAGSNO = $(EXTRA_CC_ARGS) -Wall -g -I/usr/local/include -DCLASSNAME=$(CLASSNAM
|
|||
CFLAGS += $(CFLAGSNO)
|
||||
|
||||
MODULES += core/net core/net/mac \
|
||||
core/net/llsec
|
||||
core/net/llsec core/net/ip64-addr
|
||||
|
||||
## Copied from Makefile.include, since Cooja overrides CFLAGS et al
|
||||
HAS_STACK = 0
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#ifndef CONTIKI_CONF_H_
|
||||
#define CONTIKI_CONF_H_
|
||||
|
||||
#ifdef INCLUDE_SUBPLATFORM_CONF
|
||||
#include "subplatform-conf.h"
|
||||
#endif /* INCLUDE_SUBPLATFORM_CONF */
|
||||
|
||||
#define PROFILE_CONF_ON 0
|
||||
#define ENERGEST_CONF_ON 0
|
||||
#define LOG_CONF_ENABLED 1
|
||||
|
@ -135,9 +139,17 @@
|
|||
|
||||
#define TCPIP_CONF_ANNOTATE_TRANSMISSIONS 1
|
||||
|
||||
#ifndef UIP_CONF_ND6_SEND_RA
|
||||
#define UIP_CONF_ND6_SEND_RA 0
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_ND6_REACHABLE_TIME
|
||||
#define UIP_CONF_ND6_REACHABLE_TIME 600000
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_ND6_RETRANS_TIMER
|
||||
#define UIP_CONF_ND6_RETRANS_TIMER 10000
|
||||
#endif
|
||||
|
||||
#define LINKADDR_CONF_SIZE 8
|
||||
#define UIP_CONF_NETIF_MAX_ADDRESSES 3
|
||||
|
@ -149,9 +161,6 @@
|
|||
#define UIP_CONF_IPV6_REASSEMBLY 0
|
||||
#define UIP_CONF_NETIF_MAX_ADDRESSES 3
|
||||
#define UIP_CONF_IP_FORWARD 0
|
||||
#ifndef UIP_CONF_BUFFER_SIZE
|
||||
#define UIP_CONF_BUFFER_SIZE 240
|
||||
#endif
|
||||
|
||||
#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_COMPRESSION_HC06
|
||||
#ifndef SICSLOWPAN_CONF_FRAG
|
||||
|
@ -168,7 +177,9 @@
|
|||
|
||||
#define PACKETBUF_CONF_ATTRS_INLINE 1
|
||||
|
||||
#ifndef QUEUEBUF_CONF_NUM
|
||||
#define QUEUEBUF_CONF_NUM 16
|
||||
#endif
|
||||
|
||||
#define CC_CONF_REGISTER_ARGS 1
|
||||
#define CC_CONF_FUNCTION_POINTER_ARGS 1
|
||||
|
@ -202,12 +213,6 @@ typedef unsigned long rtimer_clock_t;
|
|||
|
||||
#define UIP_CONF_DHCP_LIGHT
|
||||
#define UIP_CONF_LLH_LEN 0
|
||||
#ifndef UIP_CONF_RECEIVE_WINDOW
|
||||
#define UIP_CONF_RECEIVE_WINDOW 48
|
||||
#endif
|
||||
#ifndef UIP_CONF_TCP_MSS
|
||||
#define UIP_CONF_TCP_MSS 48
|
||||
#endif
|
||||
#define UIP_CONF_MAX_CONNECTIONS 4
|
||||
#define UIP_CONF_MAX_LISTENPORTS 8
|
||||
#define UIP_CONF_UDP_CONNS 12
|
||||
|
@ -230,10 +235,27 @@ typedef unsigned long rtimer_clock_t;
|
|||
|
||||
#define CFS_CONF_OFFSET_TYPE long
|
||||
|
||||
#ifndef UIP_CONF_BUFFER_SIZE
|
||||
#define UIP_CONF_BUFFER_SIZE 1600
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_TCP_MSS
|
||||
#define UIP_CONF_TCP_MSS (UIP_CONF_BUFFER_SIZE - 70)
|
||||
#endif
|
||||
|
||||
#ifndef UIP_CONF_RECEIVE_WINDOW
|
||||
#define UIP_CONF_RECEIVE_WINDOW (UIP_CONF_BUFFER_SIZE - 70)
|
||||
#endif
|
||||
|
||||
#define RF_CHANNEL 26
|
||||
#define IEEE802154_CONF_PANID 0xABCD
|
||||
#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125
|
||||
|
||||
/* include the project config */
|
||||
/* PROJECT_CONF_H might be defined in the project Makefile */
|
||||
#ifdef PROJECT_CONF_H
|
||||
#include PROJECT_CONF_H
|
||||
#endif /* PROJECT_CONF_H */
|
||||
|
||||
|
||||
#endif /* CONTIKI_CONF_H_ */
|
||||
|
|
|
@ -42,4 +42,4 @@ CURSES_LIBS ?= -lncurses
|
|||
|
||||
TARGET_LIBFILES += $(CURSES_LIBS)
|
||||
|
||||
MODULES+=core/net core/net/mac core/ctk core/net/llsec
|
||||
MODULES+=core/net core/net/mac core/ctk core/net/llsec core/net/ip64-addr/
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
205
|
||||
209
|
||||
|
||||
|
|
245
regression-tests/20-ip64/01-cooja-ip64-http-socket.csc
Normal file
245
regression-tests/20-ip64/01-cooja-ip64-http-socket.csc
Normal file
|
@ -0,0 +1,245 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<simconf>
|
||||
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||
<simulation>
|
||||
<title>My simulation</title>
|
||||
<speedlimit>1.0</speedlimit>
|
||||
<randomseed>generated</randomseed>
|
||||
<motedelay_us>1000000</motedelay_us>
|
||||
<radiomedium>
|
||||
org.contikios.cooja.radiomediums.UDGM
|
||||
<transmitting_range>50.0</transmitting_range>
|
||||
<interference_range>100.0</interference_range>
|
||||
<success_ratio_tx>1.0</success_ratio_tx>
|
||||
<success_ratio_rx>1.0</success_ratio_rx>
|
||||
</radiomedium>
|
||||
<events>
|
||||
<logoutput>40000</logoutput>
|
||||
</events>
|
||||
<motetype>
|
||||
org.contikios.cooja.contikimote.ContikiMoteType
|
||||
<identifier>mtype503</identifier>
|
||||
<description>ip64-router/ip64-router.c TARGET=cooja-ip64</description>
|
||||
<source>[CONTIKI_DIR]/examples/ip64-router/ip64-router.c</source>
|
||||
<commands>make ip64-router.cooja-ip64 TARGET=cooja-ip64</commands>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Battery</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiVib</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiMoteID</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRS232</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiBeeper</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiIPAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRadio</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiButton</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiPIR</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiClock</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiLED</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiCFS</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||
<symbols>false</symbols>
|
||||
</motetype>
|
||||
<motetype>
|
||||
org.contikios.cooja.contikimote.ContikiMoteType
|
||||
<identifier>mtype555</identifier>
|
||||
<description>examples/http-socket/http-example.c</description>
|
||||
<source>[CONTIKI_DIR]/examples/http-socket/http-example.c</source>
|
||||
<commands>make http-example.cooja TARGET=cooja</commands>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Battery</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiVib</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiMoteID</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRS232</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiBeeper</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiIPAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRadio</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiButton</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiPIR</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiClock</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiLED</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiCFS</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||
<symbols>false</symbols>
|
||||
</motetype>
|
||||
<mote>
|
||||
<interface_config>
|
||||
org.contikios.cooja.interfaces.Position
|
||||
<x>55.719691912311305</x>
|
||||
<y>37.8697579181178</y>
|
||||
<z>0.0</z>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.contikimote.interfaces.ContikiMoteID
|
||||
<id>1</id>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.contikimote.interfaces.ContikiRadio
|
||||
<bitrate>250.0</bitrate>
|
||||
</interface_config>
|
||||
<motetype_identifier>mtype503</motetype_identifier>
|
||||
</mote>
|
||||
<mote>
|
||||
<interface_config>
|
||||
org.contikios.cooja.interfaces.Position
|
||||
<x>65.60514720922419</x>
|
||||
<y>33.88871867406431</y>
|
||||
<z>0.0</z>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.contikimote.interfaces.ContikiMoteID
|
||||
<id>2</id>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.contikimote.interfaces.ContikiRadio
|
||||
<bitrate>250.0</bitrate>
|
||||
</interface_config>
|
||||
<motetype_identifier>mtype555</motetype_identifier>
|
||||
</mote>
|
||||
</simulation>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.SimControl
|
||||
<width>280</width>
|
||||
<z>1</z>
|
||||
<height>160</height>
|
||||
<location_x>606</location_x>
|
||||
<location_y>15</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.Visualizer
|
||||
<plugin_config>
|
||||
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||
<skin>org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin</skin>
|
||||
<skin>org.contikios.cooja.plugins.skins.LEDVisualizerSkin</skin>
|
||||
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||
<viewport>8.230641272440463 0.0 0.0 8.230641272440463 -395.6087959411366 -239.69239249818943</viewport>
|
||||
</plugin_config>
|
||||
<width>219</width>
|
||||
<z>3</z>
|
||||
<height>171</height>
|
||||
<location_x>29</location_x>
|
||||
<location_y>27</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.LogListener
|
||||
<plugin_config>
|
||||
<filter />
|
||||
<formatted_time />
|
||||
<coloring />
|
||||
</plugin_config>
|
||||
<width>888</width>
|
||||
<z>2</z>
|
||||
<height>603</height>
|
||||
<location_x>34</location_x>
|
||||
<location_y>307</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.ScriptRunner
|
||||
<plugin_config>
|
||||
<script>/* conf */
|
||||
var travis = java.lang.System.getenv().get("TRAVIS");
|
||||
if (travis == null) {
|
||||
/* Instant Contiki */
|
||||
CMD_TUNNEL = "echo '-vj' > ~/.slirprc && make Connect.class && java Connect 'nc localhost 60001' 'script -t -f -c slirp'";
|
||||
CMD_PING = "ping -c 5 8.8.8.8";
|
||||
CMD_DIR = "../../wpcapslip";
|
||||
} else {
|
||||
/* Travis */
|
||||
CMD_TUNNEL = "cd $TRAVIS_BUILD_DIR/tools/wpcapslip && sudo apt-get install slirp && echo '-vj' > ~/.slirprc && make Connect.class && java Connect 'nc localhost 60001' 'script -t -f -c slirp'";
|
||||
CMD_PING = "ping -c 5 8.8.8.8";
|
||||
CMD_DIR = ".";
|
||||
}
|
||||

|
||||
/* delay */
|
||||
GENERATE_MSG(1000, "continue");
|
||||
YIELD_THEN_WAIT_UNTIL(msg.equals("continue"));
|
||||

|
||||
/* realtime speed */
|
||||
sim.setSpeedLimit(1.0);
|
||||

|
||||
/* tunnel interface */
|
||||
log.log("opening tunnel interface: " + CMD_TUNNEL + "\n");
|
||||
launcher = new java.lang.ProcessBuilder["(java.lang.String[])"](['sh','-c',CMD_TUNNEL]);
|
||||
launcher.directory(new java.io.File(CMD_DIR));
|
||||
launcher.redirectErrorStream(true);
|
||||
tunProcess = launcher.start();
|
||||
tunRunnable = new Object();
|
||||
tunRunnable.run = function() {
|
||||
var stdIn = new java.io.BufferedReader(new java.io.InputStreamReader(tunProcess.getInputStream()));
|
||||
while ((line = stdIn.readLine()) != null) {
|
||||
if (line != null && !line.trim().equals("")) {
|
||||
log.log("TUN> " + line + "\n");
|
||||
}
|
||||
}
|
||||
tunProcess.destroy();
|
||||
}
|
||||
new java.lang.Thread(new java.lang.Runnable(tunRunnable)).start();
|
||||

|
||||
GENERATE_MSG(2000, "continue");
|
||||
YIELD_THEN_WAIT_UNTIL(msg.equals("continue"));
|
||||

|
||||
/* ping */
|
||||
log.log("pinging: " + CMD_PING + "\n");
|
||||
launcher = new java.lang.ProcessBuilder["(java.lang.String[])"](['sh','-c',CMD_PING]);
|
||||
launcher.directory(new java.io.File(CMD_DIR));
|
||||
launcher.redirectErrorStream(true);
|
||||
tunProcess = launcher.start();
|
||||
tunRunnable = new Object();
|
||||
tunRunnable.run = function() {
|
||||
var stdIn = new java.io.BufferedReader(new java.io.InputStreamReader(tunProcess.getInputStream()));
|
||||
while ((line = stdIn.readLine()) != null) {
|
||||
if (line != null && !line.trim().equals("")) {
|
||||
log.log("PING> " + line + "\n");
|
||||
}
|
||||
}
|
||||
tunProcess.destroy();
|
||||
}
|
||||
new java.lang.Thread(new java.lang.Runnable(tunRunnable)).start();
|
||||

|
||||
GENERATE_MSG(2000000, "stop");
|
||||
while(!msg.equals("stop")) {
|
||||
if (!msg.startsWith("#L")) {
|
||||
log.log(mote + ": " + msg + "\n");
|
||||
}
|
||||
if (id == 2 && msg.startsWith("HTTP socket closed")) {
|
||||
if (msg.split(' ')[3] > 0) {
|
||||
log.testOK();
|
||||
} else {
|
||||
log.testFailed(); 
|
||||
}
|
||||
}
|
||||
YIELD();
|
||||
}
|
||||
log.testFailed();</script>
|
||||
<active>true</active>
|
||||
</plugin_config>
|
||||
<width>960</width>
|
||||
<z>0</z>
|
||||
<height>682</height>
|
||||
<location_x>528</location_x>
|
||||
<location_y>192</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.serialsocket.SerialSocketServer
|
||||
<mote_arg>0</mote_arg>
|
||||
<plugin_config>
|
||||
<port>60001</port>
|
||||
<bound>true</bound>
|
||||
</plugin_config>
|
||||
<width>362</width>
|
||||
<z>4</z>
|
||||
<height>116</height>
|
||||
<location_x>234</location_x>
|
||||
<location_y>101</location_y>
|
||||
</plugin>
|
||||
</simconf>
|
||||
|
1
regression-tests/20-ip64/Makefile
Normal file
1
regression-tests/20-ip64/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
include ../Makefile.simulation-test
|
193
tools/wpcapslip/Connect.java
Normal file
193
tools/wpcapslip/Connect.java
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class Connect {
|
||||
private static Process cmd1Process;
|
||||
private static Process cmd2Process;
|
||||
private static BufferedOutputStream cmd1Out = null;
|
||||
private static BufferedOutputStream cmd2Out = null;
|
||||
|
||||
private static final int BUFSIZE = 512;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 2) {
|
||||
System.err.println("Usage: " + Connect.class.getName() + " [cmd1] [cmd2]");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/* Command 1 */
|
||||
String cmd1 = args[0];
|
||||
System.out.println("> " + cmd1);
|
||||
cmd1Process = Runtime.getRuntime().exec(cmd1, null, new File("."));
|
||||
final DataInputStream cmd1Input = new DataInputStream(
|
||||
cmd1Process.getInputStream());
|
||||
final BufferedReader cmd1Err = new BufferedReader(
|
||||
new InputStreamReader(cmd1Process.getErrorStream()));
|
||||
cmd1Out = new BufferedOutputStream(cmd1Process.getOutputStream());
|
||||
Thread readInput = new Thread(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
int numRead = 0;
|
||||
byte[] buf = new byte[BUFSIZE];
|
||||
try {
|
||||
while (true) {
|
||||
numRead = cmd1Input.read(buf, 0, BUFSIZE);
|
||||
if (numRead > 0 && cmd2Out != null) {
|
||||
/* System.err.println("1>2 " + numRead); */
|
||||
cmd2Out.write(buf, 0, numRead);
|
||||
cmd2Out.flush();
|
||||
}
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String exitVal = "?";
|
||||
try {
|
||||
if (cmd1Process != null) {
|
||||
exitVal = "" + cmd1Process.exitValue();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
exitVal = "!";
|
||||
}
|
||||
System.out.println("cmd1 terminated: " + exitVal);
|
||||
exit();
|
||||
}
|
||||
}, "read stdout cmd1");
|
||||
Thread readError = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
String line;
|
||||
try {
|
||||
while ((line = cmd1Err.readLine()) != null) {
|
||||
System.err.println("cmd1 err: " + line);
|
||||
}
|
||||
cmd1Err.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
System.err.println("cmd1 terminated.");
|
||||
exit();
|
||||
}
|
||||
}, "read error cmd1");
|
||||
readInput.start();
|
||||
readError.start();
|
||||
|
||||
/* Command 2 */
|
||||
String cmd2 = args[1];
|
||||
System.err.println("> " + cmd2);
|
||||
cmd2Process = Runtime.getRuntime().exec(cmd2, null, new File("."));
|
||||
final DataInputStream cmd2Input = new DataInputStream(
|
||||
cmd2Process.getInputStream());
|
||||
final BufferedReader cmd2Err = new BufferedReader(
|
||||
new InputStreamReader(cmd2Process.getErrorStream()));
|
||||
cmd2Out = new BufferedOutputStream(cmd2Process.getOutputStream());
|
||||
readInput = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
int numRead = 0;
|
||||
byte[] buf = new byte[BUFSIZE];
|
||||
try {
|
||||
while (true) {
|
||||
numRead = cmd2Input.read(buf, 0, BUFSIZE);
|
||||
if (numRead > 0 && cmd1Out != null) {
|
||||
/* System.err.println("2>1 " + numRead); */
|
||||
cmd1Out.write(buf, 0, numRead);
|
||||
cmd1Out.flush();
|
||||
}
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String exitVal = "?";
|
||||
try {
|
||||
if (cmd2Process != null) {
|
||||
exitVal = "" + cmd2Process.exitValue();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
exitVal = "!";
|
||||
}
|
||||
System.out.println("cmd2 terminated: " + exitVal);
|
||||
exit();
|
||||
}
|
||||
}, "read stdout cmd2");
|
||||
readError = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
String line;
|
||||
try {
|
||||
while ((line = cmd2Err.readLine()) != null) {
|
||||
System.err.println("cmd2 err: " + line);
|
||||
}
|
||||
cmd2Err.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
System.err.println("cmd2 terminated.");
|
||||
exit();
|
||||
}
|
||||
}, "read error cmd2");
|
||||
readInput.start();
|
||||
readError.start();
|
||||
|
||||
while (true) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
private static void exit() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
try {
|
||||
if (cmd1Process != null) {
|
||||
cmd1Process.destroy();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
if (cmd2Process != null) {
|
||||
cmd2Process.destroy();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
System.err.flush();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
}
|
115
tools/wpcapslip/ConnectSocket.java
Normal file
115
tools/wpcapslip/ConnectSocket.java
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
public class ConnectSocket {
|
||||
private static BufferedOutputStream stdoutOutput = null;
|
||||
private static BufferedOutputStream networkServerOutput = null;
|
||||
|
||||
private static final int BUFSIZE = 512;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 2) {
|
||||
System.err.println("Usage: " + ConnectSocket.class.getName() + " [server ip] [server port]");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/* Stdin */
|
||||
final BufferedInputStream stdinInput = new BufferedInputStream(new DataInputStream(System.in));
|
||||
stdoutOutput = new BufferedOutputStream(System.out);
|
||||
Thread readInput = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
int numRead = 0;
|
||||
byte[] buf = new byte[BUFSIZE];
|
||||
try {
|
||||
while (true) {
|
||||
numRead = stdinInput.read(buf, 0, BUFSIZE);
|
||||
if (numRead > 0 && networkServerOutput != null) {
|
||||
/* System.err.println("1>2 " + numRead); */
|
||||
|
||||
networkServerOutput.write(buf, 0, numRead);
|
||||
networkServerOutput.flush();
|
||||
}
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}, "read stdin");
|
||||
readInput.start();
|
||||
|
||||
/* Network server */
|
||||
Socket networkServer = new Socket(args[0], Integer.parseInt(args[1]));
|
||||
final BufferedInputStream networkServerInput = new BufferedInputStream(new DataInputStream(networkServer.getInputStream()));
|
||||
networkServerOutput = new BufferedOutputStream(networkServer.getOutputStream());
|
||||
readInput = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
int numRead = 0;
|
||||
byte[] buf = new byte[BUFSIZE];
|
||||
try {
|
||||
while (true) {
|
||||
numRead = networkServerInput.read(buf, 0, BUFSIZE);
|
||||
if (numRead > 0 && stdoutOutput != null) {
|
||||
/* System.err.println("2>1 " + numRead); */
|
||||
stdoutOutput.write(buf, 0, numRead);
|
||||
stdoutOutput.flush();
|
||||
}
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}, "read network server");
|
||||
readInput.start();
|
||||
|
||||
while (true) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
private static void exit() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
System.err.flush();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,21 @@
|
|||
CONTIKI=../..
|
||||
|
||||
CFLAGS=-Wall -Werror -I$(CONTIKI)/core -I.
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -I$(CONTIKI)/core -I.
|
||||
|
||||
all: wpcapslip
|
||||
all: wpcapslip wpcapstdio Connect.class ConnectSocket.class
|
||||
|
||||
%.class: %.java
|
||||
javac $*.java
|
||||
|
||||
vpath %.c $(CONTIKI)/core/net
|
||||
|
||||
wpcapslip: wpcapslip.o wpcap.o tcpdump.o
|
||||
|
||||
wpcapstdio: wpcapstdio.o wpcap.o tcpdump.o
|
||||
|
||||
%: %.o
|
||||
$(CC) $(LDFLAGS) $^ /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.class *.exe *.o
|
40
tools/wpcapslip/net/tcpdump.h
Normal file
40
tools/wpcapslip/net/tcpdump.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*
|
||||
*/
|
||||
#ifndef __TCPDUMP_H__
|
||||
#define __TCPDUMP_H__
|
||||
|
||||
#include "net/ip/uip.h"
|
||||
|
||||
int tcpdump_format(uint8_t *packet, uint16_t packetlen,
|
||||
char *printbuf, uint16_t printbuflen);
|
||||
|
||||
#endif /* __TCPDUMP_H__ */
|
289
tools/wpcapslip/tcpdump.c
Normal file
289
tools/wpcapslip/tcpdump.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contiki-net.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct ip_hdr {
|
||||
/* IP header. */
|
||||
uint8_t vhl,
|
||||
tos,
|
||||
len[2],
|
||||
ipid[2],
|
||||
ipoffset[2],
|
||||
ttl,
|
||||
proto;
|
||||
uint16_t ipchksum;
|
||||
uint8_t srcipaddr[4],
|
||||
destipaddr[4];
|
||||
};
|
||||
|
||||
#define TCP_FIN 0x01
|
||||
#define TCP_SYN 0x02
|
||||
#define TCP_RST 0x04
|
||||
#define TCP_PSH 0x08
|
||||
#define TCP_ACK 0x10
|
||||
#define TCP_URG 0x20
|
||||
#define TCP_CTL 0x3f
|
||||
|
||||
struct tcpip_hdr {
|
||||
/* IP header. */
|
||||
uint8_t vhl,
|
||||
tos,
|
||||
len[2],
|
||||
ipid[2],
|
||||
ipoffset[2],
|
||||
ttl,
|
||||
proto;
|
||||
uint16_t ipchksum;
|
||||
uint8_t srcipaddr[4],
|
||||
destipaddr[4];
|
||||
/* TCP header. */
|
||||
uint16_t srcport,
|
||||
destport;
|
||||
uint8_t seqno[4],
|
||||
ackno[4],
|
||||
tcpoffset,
|
||||
flags,
|
||||
wnd[2];
|
||||
uint16_t tcpchksum;
|
||||
uint8_t urgp[2];
|
||||
uint8_t optdata[4];
|
||||
};
|
||||
|
||||
#define ICMP_ECHO_REPLY 0
|
||||
#define ICMP_ECHO 8
|
||||
|
||||
struct icmpip_hdr {
|
||||
/* IP header. */
|
||||
uint8_t vhl,
|
||||
tos,
|
||||
len[2],
|
||||
ipid[2],
|
||||
ipoffset[2],
|
||||
ttl,
|
||||
proto;
|
||||
uint16_t ipchksum;
|
||||
uint8_t srcipaddr[4],
|
||||
destipaddr[4];
|
||||
/* The ICMP and IP headers. */
|
||||
/* ICMP (echo) header. */
|
||||
uint8_t type, icode;
|
||||
uint16_t icmpchksum;
|
||||
uint16_t id, seqno;
|
||||
};
|
||||
|
||||
|
||||
/* The UDP and IP headers. */
|
||||
struct udpip_hdr {
|
||||
/* IP header. */
|
||||
uint8_t vhl,
|
||||
tos,
|
||||
len[2],
|
||||
ipid[2],
|
||||
ipoffset[2],
|
||||
ttl,
|
||||
proto;
|
||||
uint16_t ipchksum;
|
||||
uint8_t srcipaddr[4],
|
||||
destipaddr[4];
|
||||
|
||||
/* UDP header. */
|
||||
uint16_t srcport,
|
||||
destport;
|
||||
uint16_t udplen;
|
||||
uint16_t udpchksum;
|
||||
};
|
||||
|
||||
#define ETHBUF ((struct eth_hdr *)&packet[0])
|
||||
#define IPBUF ((struct ip_hdr *)&packet[0])
|
||||
#define UDPBUF ((struct udpip_hdr *)&packet[0])
|
||||
#define ICMPBUF ((struct icmpip_hdr *)&packet[0])
|
||||
#define TCPBUF ((struct tcpip_hdr *)&packet[0])
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
tcpflags(unsigned char flags, char *flagsstr)
|
||||
{
|
||||
if(flags & TCP_FIN) {
|
||||
*flagsstr++ = 'F';
|
||||
}
|
||||
if(flags & TCP_SYN) {
|
||||
*flagsstr++ = 'S';
|
||||
}
|
||||
if(flags & TCP_RST) {
|
||||
*flagsstr++ = 'R';
|
||||
}
|
||||
if(flags & TCP_ACK) {
|
||||
*flagsstr++ = 'A';
|
||||
}
|
||||
if(flags & TCP_URG) {
|
||||
*flagsstr++ = 'U';
|
||||
}
|
||||
|
||||
*flagsstr = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static char * CC_FASTCALL
|
||||
n(uint16_t num, char *ptr)
|
||||
{
|
||||
uint16_t d;
|
||||
uint8_t a, f;
|
||||
|
||||
if(num == 0) {
|
||||
*ptr = '0';
|
||||
return ptr + 1;
|
||||
} else {
|
||||
f = 0;
|
||||
for(d = 10000; d >= 1; d /= 10) {
|
||||
a = (num / d) % 10;
|
||||
if(f == 1 || a > 0) {
|
||||
*ptr = a + '0';
|
||||
++ptr;
|
||||
f = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static char * CC_FASTCALL
|
||||
d(char *ptr)
|
||||
{
|
||||
*ptr = '.';
|
||||
return ptr + 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static char * CC_FASTCALL
|
||||
s(char *str, char *ptr)
|
||||
{
|
||||
strcpy(ptr, str);
|
||||
return ptr + strlen(str);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcpdump_format(uint8_t *packet, uint16_t packetlen,
|
||||
char *buf, uint16_t buflen)
|
||||
{
|
||||
char flags[8];
|
||||
if(IPBUF->proto == UIP_PROTO_ICMP) {
|
||||
if(ICMPBUF->type == ICMP_ECHO) {
|
||||
return s(" ping",
|
||||
n(IPBUF->destipaddr[3], d(
|
||||
n(IPBUF->destipaddr[2], d(
|
||||
n(IPBUF->destipaddr[1], d(
|
||||
n(IPBUF->destipaddr[0],
|
||||
s(" ",
|
||||
n(IPBUF->srcipaddr[3], d(
|
||||
n(IPBUF->srcipaddr[2], d(
|
||||
n(IPBUF->srcipaddr[1], d(
|
||||
n(IPBUF->srcipaddr[0],
|
||||
buf)))))))))))))))) - buf;
|
||||
|
||||
/* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d ping",
|
||||
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
|
||||
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
|
||||
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
|
||||
IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
|
||||
} else if(ICMPBUF->type == ICMP_ECHO_REPLY) {
|
||||
return s(" pong",
|
||||
n(IPBUF->destipaddr[3], d(
|
||||
n(IPBUF->destipaddr[2], d(
|
||||
n(IPBUF->destipaddr[1], d(
|
||||
n(IPBUF->destipaddr[0],
|
||||
s(" ",
|
||||
n(IPBUF->srcipaddr[3], d(
|
||||
n(IPBUF->srcipaddr[2], d(
|
||||
n(IPBUF->srcipaddr[1], d(
|
||||
n(IPBUF->srcipaddr[0],
|
||||
buf)))))))))))))))) - buf;
|
||||
/* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d pong",
|
||||
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
|
||||
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
|
||||
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
|
||||
IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
|
||||
}
|
||||
} else if(IPBUF->proto == UIP_PROTO_UDP) {
|
||||
return s(" UDP",
|
||||
n(uip_htons(UDPBUF->destport), d(
|
||||
n(IPBUF->destipaddr[3], d(
|
||||
n(IPBUF->destipaddr[2], d(
|
||||
n(IPBUF->destipaddr[1], d(
|
||||
n(IPBUF->destipaddr[0],
|
||||
s(" ",
|
||||
n(uip_htons(UDPBUF->srcport), d(
|
||||
n(IPBUF->srcipaddr[3], d(
|
||||
n(IPBUF->srcipaddr[2], d(
|
||||
n(IPBUF->srcipaddr[1], d(
|
||||
n(IPBUF->srcipaddr[0],
|
||||
buf)))))))))))))))))))) - buf;
|
||||
/* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d UDP",
|
||||
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
|
||||
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
|
||||
uip_htons(UDPBUF->srcport),
|
||||
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
|
||||
IPBUF->destipaddr[2], IPBUF->destipaddr[3],
|
||||
uip_htons(UDPBUF->destport));*/
|
||||
} else if(IPBUF->proto == UIP_PROTO_TCP) {
|
||||
tcpflags(TCPBUF->flags, flags);
|
||||
return s(flags,
|
||||
s(" ",
|
||||
n(uip_htons(TCPBUF->destport), d(
|
||||
n(IPBUF->destipaddr[3], d(
|
||||
n(IPBUF->destipaddr[2], d(
|
||||
n(IPBUF->destipaddr[1], d(
|
||||
n(IPBUF->destipaddr[0],
|
||||
s(" ",
|
||||
n(uip_htons(TCPBUF->srcport), d(
|
||||
n(IPBUF->srcipaddr[3], d(
|
||||
n(IPBUF->srcipaddr[2], d(
|
||||
n(IPBUF->srcipaddr[1], d(
|
||||
n(IPBUF->srcipaddr[0],
|
||||
buf))))))))))))))))))))) - buf;
|
||||
/* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d %s",
|
||||
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
|
||||
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
|
||||
uip_htons(TCPBUF->srcport),
|
||||
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
|
||||
IPBUF->destipaddr[2], IPBUF->destipaddr[3],
|
||||
uip_htons(TCPBUF->destport),
|
||||
flags); */
|
||||
} else {
|
||||
strcpy(buf, "Unrecognized protocol");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -58,7 +58,6 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
@ -69,7 +68,7 @@
|
|||
#define PROGRESS(x)
|
||||
|
||||
|
||||
static void raw_send(void *buf, int len);
|
||||
void raw_send(void *buf, int len);
|
||||
|
||||
struct pcap;
|
||||
|
||||
|
@ -150,7 +149,7 @@ struct arp_entry {
|
|||
struct uip_eth_addr ethaddr;
|
||||
uint8_t time;
|
||||
};
|
||||
static struct uip_eth_addr uip_lladdr = {{0,0,0,0,0,0}};
|
||||
struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
|
||||
static const uip_ipaddr_t all_zeroes_addr = { { 0x0, /* rest is 0 */ } };
|
||||
static const struct uip_eth_addr broadcast_ethaddr =
|
||||
{{0xff,0xff,0xff,0xff,0xff,0xff}};
|
||||
|
@ -164,18 +163,20 @@ static int arptime;
|
|||
|
||||
static int logging;
|
||||
|
||||
uip_lladdr_t uip_lladdr;
|
||||
|
||||
static void
|
||||
log_message(char *msg1, char *msg2)
|
||||
{
|
||||
if(logging) {
|
||||
printf("Log: %s %s\n", msg1, msg2);
|
||||
fprintf(stderr, "Log: %s %s\n", msg1, msg2);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
error_exit(char *msg1)
|
||||
{
|
||||
printf("error_exit: %s", msg1);
|
||||
fprintf(stderr, "error_exit: %s", msg1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -263,7 +264,7 @@ set_ethaddr(struct in_addr addr)
|
|||
log_message("set_ethaddr: with address: ", inet_ntoa(adapter_addr));
|
||||
|
||||
if(adapter_addr.s_addr == addr.s_addr) {
|
||||
printf("Using local network interface with address %s\n",
|
||||
fprintf(stderr, "Using local network interface with address %s\n",
|
||||
inet_ntoa(adapter_addr));
|
||||
if(adapters->PhysicalAddressLength != 6) {
|
||||
error_exit("ip addr specified on cmdline does not belong to an ethernet card\n");
|
||||
|
@ -292,12 +293,12 @@ print_packet(unsigned char *buf, int len)
|
|||
int i;
|
||||
|
||||
for(i = 0; i < len; ++i) {
|
||||
printf("0x%02x, ", buf[i]);
|
||||
fprintf(stderr, "0x%02x, ", buf[i]);
|
||||
if(i % 8 == 7) {
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
fprintf(stderr, "\n\n");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -399,7 +400,7 @@ arp_out(struct ethip_hdr *iphdr, int len)
|
|||
int i;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
/* Find the destination IP address in the ARP table and construct
|
||||
the Ethernet header. If the destination IP addres isn't on the
|
||||
local network, we use the default router's IP address instead.
|
||||
|
@ -439,8 +440,8 @@ arp_out(struct ethip_hdr *iphdr, int len)
|
|||
|
||||
memset(arphdr->ethhdr.dest.addr, 0xff, 6);
|
||||
memset(arphdr->dhwaddr.addr, 0x00, 6);
|
||||
memcpy(arphdr->ethhdr.src.addr, uip_lladdr.addr, 6);
|
||||
memcpy(arphdr->shwaddr.addr, uip_lladdr.addr, 6);
|
||||
memcpy(arphdr->ethhdr.src.addr, uip_ethaddr.addr, 6);
|
||||
memcpy(arphdr->shwaddr.addr, uip_ethaddr.addr, 6);
|
||||
|
||||
uip_ipaddr_copy(&arphdr->dipaddr, &ipaddr);
|
||||
uip_ipaddr_copy(&arphdr->sipaddr, &netaddr);
|
||||
|
@ -476,14 +477,14 @@ do_arp(void *buf, int len)
|
|||
if(hdr->ethhdr.type == UIP_HTONS(UIP_ETHTYPE_ARP)) {
|
||||
if(hdr->opcode == UIP_HTONS(ARP_REQUEST)) {
|
||||
/* Check if the ARP is for our network */
|
||||
/* printf("ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n",
|
||||
/* fprintf(stderr, "ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n",
|
||||
uip_ipaddr_to_quad(&hdr->dipaddr),
|
||||
uip_ipaddr_to_quad(&netaddr),
|
||||
uip_ipaddr_to_quad(&netmask));*/
|
||||
if(uip_ipaddr_maskcmp(&hdr->dipaddr, &netaddr, &netmask)) {
|
||||
uip_ipaddr_t tmpaddr;
|
||||
|
||||
/* printf("ARP for us.\n");*/
|
||||
/* fprintf(stderr, "ARP for us.\n");*/
|
||||
uip_arp_update(&hdr->sipaddr, &hdr->shwaddr);
|
||||
|
||||
hdr->opcode = UIP_HTONS(ARP_REPLY);
|
||||
|
@ -521,8 +522,8 @@ cleanup(void)
|
|||
char buf[1024];
|
||||
|
||||
snprintf(buf, sizeof(buf), "route delete %d.%d.%d.%d",
|
||||
uip_ipaddr_to_quad(&ifaddr));
|
||||
printf("%s\n", buf);
|
||||
uip_ipaddr_to_quad(&netaddr));
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
system(buf);
|
||||
}
|
||||
|
||||
|
@ -551,7 +552,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
|
|||
tmpaddr = inet_addr(slipnetmask);
|
||||
memcpy(&netmask.u16[0], &tmpaddr, sizeof(tmpaddr));
|
||||
|
||||
printf("Network address %d.%d.%d.%d/%d.%d.%d.%d\n",
|
||||
fprintf(stderr, "Network address %d.%d.%d.%d/%d.%d.%d.%d\n",
|
||||
uip_ipaddr_to_quad(&netaddr),
|
||||
uip_ipaddr_to_quad(&netmask));
|
||||
|
||||
|
@ -559,7 +560,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
|
|||
uip_ipaddr_to_quad(&netaddr),
|
||||
uip_ipaddr_to_quad(&netmask),
|
||||
uip_ipaddr_to_quad(&ifaddr));
|
||||
printf("%s\n", buf);
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
system(buf);
|
||||
signal(SIGTERM, remove_route);
|
||||
|
||||
|
@ -593,7 +594,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
|
|||
if(ret > 0) {
|
||||
/* print_packet(buf, ret);*/
|
||||
if(do_arp(buf, ret)) {
|
||||
printf("IP packet\n");
|
||||
fprintf(stderr, "IP packet\n");
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
|
@ -602,17 +603,16 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
wpcap_poll(char **buf)
|
||||
wpcap_poll(char **buf, int eth)
|
||||
{
|
||||
struct pcap_pkthdr *packet_header;
|
||||
unsigned char *packet;
|
||||
int len;
|
||||
int ret;
|
||||
char *buf2;
|
||||
|
||||
switch(pcap_next_ex(pcap, &packet_header, &packet)) {
|
||||
case -1:
|
||||
error_exit("error on poll\n");
|
||||
case 0:
|
||||
ret = pcap_next_ex(pcap, &packet_header, &packet);
|
||||
if (ret != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -622,13 +622,20 @@ wpcap_poll(char **buf)
|
|||
|
||||
CopyMemory(*buf, packet, packet_header->caplen);
|
||||
len = packet_header->caplen;
|
||||
/* printf("len %d\n", len);*/
|
||||
|
||||
if(eth) {
|
||||
/* poll requested us to return the raw ethernet packet */
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
buf2 = do_arp(*buf, len);
|
||||
if(buf2 == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
len = len - (buf2 - *buf);
|
||||
*buf = buf2;
|
||||
/*fprintf(stderr, "wpcap_poll() %d\n", len);*/
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
@ -644,7 +651,7 @@ wpcap_send(void *buf, int len)
|
|||
raw_send(buf2, len);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
void
|
||||
raw_send(void *buf, int len)
|
||||
{
|
||||
/* printf("sending len %d\n", len);*/
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
@ -75,6 +73,18 @@ static int should_print = 0;
|
|||
|
||||
#define IP_HLEN 20
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
uip_htons(uint16_t val)
|
||||
{
|
||||
return UIP_HTONS(val);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint32_t
|
||||
uip_htonl(uint32_t val)
|
||||
{
|
||||
return UIP_HTONL(val);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
print_packet(uint8_t *packet, int len)
|
||||
|
@ -289,8 +299,9 @@ serial_to_wpcap(FILE *inslip)
|
|||
*/
|
||||
#define DEBUG_LINE_MARKER '\r'
|
||||
int ecode;
|
||||
|
||||
ecode = check_ip(&uip.iphdr, inbufptr);
|
||||
if(ecode < 0 && inbufptr == 8 && strncmp(uip.inbuf, "=IPA", 4) == 0) {
|
||||
if(ecode < 0 && inbufptr == 8 && strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) {
|
||||
static struct in_addr ipa;
|
||||
|
||||
inbufptr = 0;
|
||||
|
@ -902,7 +913,7 @@ main(int argc, char **argv)
|
|||
if(iphdr->ip_id != last_id) {
|
||||
last_id = iphdr->ip_id;
|
||||
/* printf("------ wpcap_poll ret %d\n", ret);*/
|
||||
print_packet(pbuf, ret);
|
||||
print_packet((uint8_t*)pbuf, ret);
|
||||
write_to_serial(slipfd, pbuf, ret);
|
||||
slip_flushbuf(slipfd);
|
||||
sigalarm_reset();
|
||||
|
|
597
tools/wpcapslip/wpcapstdio.c
Normal file
597
tools/wpcapslip/wpcapstdio.c
Normal file
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Thingsquare, 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 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.
|
||||
*
|
||||
* Author: Fredrik Osterlind <fredrik@thingsquare.com>
|
||||
* Based on wpcapslip.c by : Oliver Schmidt <ol.sc@web.de>
|
||||
*/
|
||||
|
||||
/* This is a stripped-down version of wpcapslip: Instead of reading from and writing
|
||||
* to a serial port, this program just reads and writes to stdin/stdout. To
|
||||
* achieve the same functionality as wpcapslip, this program can hence be connected
|
||||
* to serialdump. But, in contrast to wpcapslip, this program can easily be connected
|
||||
* to networked or simulated serial ports. -- Fredrik, 2012 */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __CYGWIN__
|
||||
#include <alloca.h>
|
||||
#else /* __CYGWIN__ */
|
||||
#include <malloc.h>
|
||||
#endif /* __CYGWIN__ */
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <err.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define PROGRESS(x)
|
||||
|
||||
void wpcap_start(char *ethifaddr, char *netaddr, char *netmask, int logging);
|
||||
|
||||
void wpcap_send(void *buf, int len);
|
||||
void raw_send(void *buf, int len);
|
||||
|
||||
uint16_t wpcap_poll(char **buf, int eth);
|
||||
|
||||
#include "net/tcpdump.h"
|
||||
static int should_print = 0;
|
||||
|
||||
static int send_eth = 0; /* Sends ethernet frames or IP packets */
|
||||
|
||||
#define IP_HLEN 20
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
uip_htons(uint16_t val)
|
||||
{
|
||||
return UIP_HTONS(val);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint32_t
|
||||
uip_htonl(uint32_t val)
|
||||
{
|
||||
return UIP_HTONL(val);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
print_packet(char* prefix, uint8_t *packet, int len)
|
||||
{
|
||||
char buf[2000];
|
||||
if(should_print) {
|
||||
tcpdump_format(packet, len, buf, sizeof(buf));
|
||||
fprintf(stderr, "%s: %s\n", prefix, buf);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void cleanup(void);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
sigcleanup(int signo)
|
||||
{
|
||||
fprintf(stderr, "signal %d\n", signo);
|
||||
exit(0); /* exit(0) will call cleanup() */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define SLIP_END 0300
|
||||
#define SLIP_ESC 0333
|
||||
#define SLIP_ESC_END 0334
|
||||
#define SLIP_ESC_ESC 0335
|
||||
|
||||
struct ip {
|
||||
u_int8_t ip_vhl; /* version and header length */
|
||||
#define IP_V4 0x40
|
||||
#define IP_V 0xf0
|
||||
#define IP_HL 0x0f
|
||||
u_int8_t ip_tos; /* type of service */
|
||||
u_int16_t ip_len; /* total length */
|
||||
u_int16_t ip_id; /* identification */
|
||||
u_int16_t ip_off; /* fragment offset field */
|
||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||
#define IP_DF 0x4000 /* dont fragment flag */
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||
u_int8_t ip_ttl; /* time to live */
|
||||
u_int8_t ip_p; /* protocol */
|
||||
u_int16_t ip_sum; /* checksum */
|
||||
u_int32_t ip_src, ip_dst; /* source and dest address */
|
||||
u_int16_t uh_sport; /* source port */
|
||||
u_int16_t uh_dport; /* destination port */
|
||||
u_int16_t uh_ulen; /* udp length */
|
||||
u_int16_t uh_sum; /* udp checksum */
|
||||
};
|
||||
|
||||
static int ip_id, last_id;
|
||||
|
||||
int
|
||||
ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
||||
|
||||
int
|
||||
ssystem(const char *fmt, ...)
|
||||
{
|
||||
char cmd[128];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(cmd, sizeof(cmd), fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "%s\n", cmd);
|
||||
fflush(stderr);
|
||||
return system(cmd);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
is_sensible_string(const unsigned char *s, int len)
|
||||
{
|
||||
int i;
|
||||
for(i = 1; i < len; i++) {
|
||||
if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
|
||||
continue;
|
||||
} else if(s[i] < ' ' || '~' < s[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
u_int16_t
|
||||
ip4sum(u_int16_t sum, const void *_p, u_int16_t len)
|
||||
{
|
||||
u_int16_t t;
|
||||
const u_int8_t *p = _p;
|
||||
const u_int8_t *end = p + len;
|
||||
|
||||
while(p < (end - 1)) {
|
||||
t = (p[0] << 8) + p[1];
|
||||
sum += t;
|
||||
if(sum < t)
|
||||
sum++;
|
||||
p += 2;
|
||||
}
|
||||
if(p < end) {
|
||||
t = (p[0] << 8) + 0;
|
||||
sum += t;
|
||||
if(sum < t)
|
||||
sum++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
chksum(const void *p, uint16_t len)
|
||||
{
|
||||
uint16_t sum = ip4sum(0, p, len);
|
||||
return (sum == 0) ? 0xffff : uip_htons(sum);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
check_ip(const struct ip *ip, unsigned ip_len)
|
||||
{
|
||||
u_int16_t sum, ip_hl;
|
||||
|
||||
if(send_eth) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check IP version and length. */
|
||||
if((ip->ip_vhl & IP_V) != IP_V4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(uip_ntohs(ip->ip_len) > ip_len) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(uip_ntohs(ip->ip_len) < ip_len) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Check IP header. */
|
||||
ip_hl = 4 * (ip->ip_vhl & IP_HL);
|
||||
sum = ip4sum(0, ip, ip_hl);
|
||||
if(sum != 0xffff && sum != 0x0) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
if(ip->ip_p == 6 || ip->ip_p == 17) { /* Check TCP or UDP header. */
|
||||
u_int16_t tcp_len = ip_len - ip_hl;
|
||||
|
||||
/* Sum pseudoheader. */
|
||||
sum = ip->ip_p + tcp_len; /* proto and len, no carry */
|
||||
sum = ip4sum(sum, &ip->ip_src, 8); /* src and dst */
|
||||
|
||||
/* Sum TCP/UDP header and data. */
|
||||
sum = ip4sum(sum, (u_int8_t*)ip + ip_hl, tcp_len);
|
||||
|
||||
/* Failed checksum test? */
|
||||
if(sum != 0xffff && sum != 0x0) {
|
||||
if(ip->ip_p == 6) { /* TCP == 6 */
|
||||
return -5;
|
||||
} else { /* UDP */
|
||||
/* Deal with disabled UDP checksums. */
|
||||
if(ip->uh_sum != 0) {
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(ip->ip_p == 1) { /* ICMP */
|
||||
u_int16_t icmp_len = ip_len - ip_hl;
|
||||
|
||||
sum = ip4sum(0, (u_int8_t*)ip + ip_hl, icmp_len);
|
||||
if(sum != 0xffff && sum != 0x0) {
|
||||
return -7;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Read a single character from stdin. When we have a full packet, write it to
|
||||
* the network interface.
|
||||
*/
|
||||
void
|
||||
serial_to_wpcap(void)
|
||||
{
|
||||
static union {
|
||||
unsigned char inbuf[2000];
|
||||
struct ip iphdr;
|
||||
} uip;
|
||||
static int inbufptr = 0;
|
||||
|
||||
int ret;
|
||||
unsigned char c;
|
||||
|
||||
if(inbufptr >= sizeof(uip.inbuf)) {
|
||||
inbufptr = 0;
|
||||
return;
|
||||
}
|
||||
ret = read(STDIN_FILENO, &c, 1);
|
||||
|
||||
if(ret <= 0) {
|
||||
err(1, "serial_to_wpcap: read");
|
||||
inbufptr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case SLIP_END:
|
||||
if(inbufptr > 0) {
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
#define DEBUG_LINE_MARKER '\r'
|
||||
int ecode;
|
||||
|
||||
ecode = check_ip(&uip.iphdr, inbufptr);
|
||||
if(ecode < 0 && inbufptr == 8
|
||||
&& strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) {
|
||||
static struct in_addr ipa;
|
||||
|
||||
inbufptr = 0;
|
||||
if(memcmp(&ipa, &uip.inbuf[4], sizeof(ipa)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&ipa, &uip.inbuf[4], sizeof(ipa));
|
||||
break;
|
||||
} else if(ecode < 0) {
|
||||
/*
|
||||
* If sensible ASCII string, print it as debug info!
|
||||
*/
|
||||
/* printf("----------------------------------\n");*/
|
||||
if(uip.inbuf[0] == DEBUG_LINE_MARKER) {
|
||||
fwrite(uip.inbuf + 1, inbufptr - 1, 1, stderr);
|
||||
} else if(is_sensible_string(uip.inbuf, inbufptr)) {
|
||||
fwrite(uip.inbuf, inbufptr, 1, stderr);
|
||||
} else {
|
||||
fprintf(stderr, "serial_to_wpcap: drop packet len=%d ecode=%d\n",
|
||||
inbufptr, ecode);
|
||||
}
|
||||
inbufptr = 0;
|
||||
break;
|
||||
}
|
||||
PROGRESS("s");
|
||||
|
||||
if(send_eth) {
|
||||
raw_send(uip.inbuf, inbufptr);
|
||||
} else {
|
||||
/* printf("Sending to wpcap\n");*/
|
||||
if(uip.iphdr.ip_id != last_id) {
|
||||
last_id = uip.iphdr.ip_id;
|
||||
print_packet("to wpcap: ", uip.inbuf, inbufptr);
|
||||
wpcap_send(uip.inbuf, inbufptr);
|
||||
} else {
|
||||
/*print_packet("IGNORED to wpcap: ", uip.inbuf, inbufptr);*/
|
||||
}
|
||||
}
|
||||
/* printf("After sending to wpcap\n");*/
|
||||
inbufptr = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SLIP_ESC:
|
||||
/* TODO We do not actually check that we have another byte incoming, so
|
||||
* we may block here */
|
||||
read(STDIN_FILENO, &c, 1);
|
||||
|
||||
switch (c) {
|
||||
case SLIP_ESC_END:
|
||||
c = SLIP_END;
|
||||
break;
|
||||
case SLIP_ESC_ESC:
|
||||
c = SLIP_ESC;
|
||||
break;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
uip.inbuf[inbufptr++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned char stdout_buf[2000];
|
||||
int stdout_buf_cnt;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
stdout_write(unsigned char c)
|
||||
{
|
||||
if(stdout_buf_cnt >= sizeof(stdout_buf)) {
|
||||
err(1, "stdout_write overflow");
|
||||
}
|
||||
stdout_buf[stdout_buf_cnt] = c;
|
||||
stdout_buf_cnt++;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
stdout_buf_empty(void)
|
||||
{
|
||||
return stdout_buf_cnt == 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
stdout_flushbuf(void)
|
||||
{
|
||||
if(stdout_buf_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(stdout_buf, stdout_buf_cnt, 1, stdout);
|
||||
stdout_buf_cnt = 0;
|
||||
fflush(stdout);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
write_slip_stdout(void *inbuf, int len)
|
||||
{
|
||||
u_int8_t *p = inbuf;
|
||||
int i, ecode;
|
||||
struct ip *iphdr = inbuf;
|
||||
|
||||
if(!send_eth) {
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
/*fprintf(stderr, "write_slip_stdout: %d\n", len);*/
|
||||
ecode = check_ip(inbuf, len);
|
||||
if(ecode < 0) {
|
||||
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(iphdr->ip_id == 0 && iphdr->ip_off & IP_DF) {
|
||||
uint16_t nid = uip_htons(ip_id++);
|
||||
iphdr->ip_id = nid;
|
||||
nid = ~nid; /* negate */
|
||||
iphdr->ip_sum += nid; /* add */
|
||||
if(iphdr->ip_sum < nid) { /* 1-complement overflow? */
|
||||
iphdr->ip_sum++;
|
||||
}
|
||||
ecode = check_ip(inbuf, len);
|
||||
if(ecode < 0) {
|
||||
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
iphdr->ip_ttl = uip_htons(uip_htons(iphdr->ip_ttl) + 1);
|
||||
if(iphdr->ip_ttl == 0) {
|
||||
fprintf(stderr, "Packet with ttl %d dropped\n", iphdr->ip_ttl);
|
||||
return;
|
||||
}
|
||||
iphdr->ip_sum = 0;
|
||||
iphdr->ip_sum = ~chksum(iphdr, 4 * (iphdr->ip_vhl & IP_HL));
|
||||
ecode = check_ip(inbuf, len);
|
||||
if(ecode < 0) {
|
||||
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
switch (p[i]) {
|
||||
case SLIP_END:
|
||||
stdout_write(SLIP_ESC);
|
||||
stdout_write(SLIP_ESC_END);
|
||||
break;
|
||||
case SLIP_ESC:
|
||||
stdout_write(SLIP_ESC);
|
||||
stdout_write(SLIP_ESC_ESC);
|
||||
break;
|
||||
default:
|
||||
stdout_write(p[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
stdout_write(SLIP_END);
|
||||
/* printf("slip end\n");*/
|
||||
PROGRESS("t");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*const char *ipaddr;*/
|
||||
/*const char *netmask;*/
|
||||
static int got_sigalarm;
|
||||
void
|
||||
sigalarm(int signo)
|
||||
{
|
||||
got_sigalarm = 1;
|
||||
return;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
sigalarm_reset(void)
|
||||
{
|
||||
#ifdef linux
|
||||
#define TIMEOUT (997*1000)
|
||||
#else
|
||||
#define TIMEOUT (2451*1000)
|
||||
#endif
|
||||
ualarm(TIMEOUT, TIMEOUT);
|
||||
got_sigalarm = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int ret;
|
||||
char buf[4000];
|
||||
int logging = 0;
|
||||
|
||||
ip_id = getpid() * time(NULL);
|
||||
|
||||
while((c = getopt(argc, argv, "E:D:hl:t:T")) != -1) {
|
||||
switch (c) {
|
||||
case 'E':
|
||||
send_eth = 1;
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
should_print = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
logging = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
err(1,
|
||||
"usage: wpcapstdio [-E] [-l] [-T] <IP address of local Ethernet card> <IP address of SLIP network> <netmask of SLIP network>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= (optind - 1);
|
||||
argv += (optind - 1);
|
||||
|
||||
if(argc != 4) {
|
||||
err(1, "usage: wpcapstdio [-E] [-T] <IP address of local Ethernet card> <IP address of SLIP network> <netmask of SLIP network>");
|
||||
}
|
||||
|
||||
wpcap_start(argv[1], argv[2], argv[3], logging);
|
||||
stdout_write(SLIP_END);
|
||||
|
||||
atexit(cleanup);
|
||||
signal(SIGHUP, sigcleanup);
|
||||
signal(SIGTERM, sigcleanup);
|
||||
signal(SIGINT, sigcleanup);
|
||||
signal(SIGALRM, sigalarm);
|
||||
|
||||
while(1) {
|
||||
if(got_sigalarm) {
|
||||
/* Send "?IPA". */
|
||||
stdout_write('?');
|
||||
stdout_write('I');
|
||||
stdout_write('P');
|
||||
stdout_write('A');
|
||||
stdout_write(SLIP_END);
|
||||
got_sigalarm = 0;
|
||||
}
|
||||
|
||||
if(stdout_buf_empty()) {
|
||||
char *pbuf = buf;
|
||||
|
||||
ret = wpcap_poll(&pbuf, send_eth);
|
||||
if(ret > 0) {
|
||||
if(send_eth) {
|
||||
write_slip_stdout(pbuf, ret);
|
||||
stdout_flushbuf();
|
||||
} else {
|
||||
struct ip *iphdr = (struct ip *)pbuf;
|
||||
if(iphdr->ip_id != last_id) {
|
||||
/*last_id = iphdr->ip_id;*/
|
||||
print_packet("to stdout: ", (uint8_t*)pbuf, ret);
|
||||
write_slip_stdout(pbuf, ret);
|
||||
stdout_flushbuf();
|
||||
} else {
|
||||
/*print_packet("IGNORED to stdout: ", (uint8_t*)pbuf, ret);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!stdout_buf_empty()) {
|
||||
stdout_flushbuf();
|
||||
}
|
||||
|
||||
{
|
||||
fd_set s_rd;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100;
|
||||
|
||||
do {
|
||||
FD_ZERO(&s_rd);
|
||||
FD_SET(fileno(stdin), &s_rd);
|
||||
select(fileno(stdin) + 1, &s_rd, NULL, NULL, &tv);
|
||||
if(FD_ISSET(fileno(stdin), &s_rd)) {
|
||||
serial_to_wpcap();
|
||||
}
|
||||
} while(FD_ISSET(fileno(stdin), &s_rd));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
Loading…
Reference in a new issue