Merge branch 'master' of git://github.com/contiki-os/contiki into ds6_period_configurable
This commit is contained in:
commit
446208dc1c
107 changed files with 8338 additions and 1318 deletions
|
@ -1155,6 +1155,7 @@ cfs_write(int fd, const void *buf, unsigned size)
|
|||
int i;
|
||||
struct log_param lp;
|
||||
cfs_offset_t bytes_left;
|
||||
int8_t need_dummy_write;
|
||||
const char dummy[1] = { 0xff };
|
||||
#endif
|
||||
|
||||
|
@ -1188,6 +1189,7 @@ cfs_write(int fd, const void *buf, unsigned size)
|
|||
#else
|
||||
if(FILE_MODIFIED(file) || fdp->offset < file->end) {
|
||||
#endif
|
||||
need_dummy_write = 0;
|
||||
for(bytes_left = size; bytes_left > 0;) {
|
||||
lp.offset = fdp->offset;
|
||||
lp.buf = buf;
|
||||
|
@ -1212,13 +1214,19 @@ cfs_write(int fd, const void *buf, unsigned size)
|
|||
occur while writing log records. */
|
||||
if(fdp->offset > file->end) {
|
||||
file->end = fdp->offset;
|
||||
need_dummy_write = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fdp->offset > file->end) {
|
||||
/* Update the original file's end with a dummy write. */
|
||||
COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset));
|
||||
if(need_dummy_write) {
|
||||
/*
|
||||
* A log record has been written at an offset beyond the original
|
||||
* extent's end. Consequently, we need to write a dummy value at the
|
||||
* corresponding end offset in the original extent to ensure that
|
||||
* the correct file size is calculated when opening the file again.
|
||||
*/
|
||||
COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset - 1));
|
||||
}
|
||||
} else {
|
||||
#endif /* COFFEE_MICRO_LOGS */
|
||||
|
|
|
@ -54,6 +54,9 @@
|
|||
|
||||
#include "net/ip/psock.h"
|
||||
|
||||
#include "net/ip/udp-socket.h"
|
||||
#include "net/ip/tcp-socket.h"
|
||||
|
||||
#include "net/rime/rime.h"
|
||||
|
||||
#include "net/netstack.h"
|
||||
|
|
|
@ -82,10 +82,11 @@ void spi_init(void);
|
|||
} while(0)
|
||||
|
||||
/* Flush the SPI read register */
|
||||
#ifndef SPI_FLUSH
|
||||
#define SPI_FLUSH() \
|
||||
do { \
|
||||
SPI_RXBUF; \
|
||||
} while(0);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SPI_H_ */
|
||||
|
|
365
core/net/ip/tcp-socket.c
Normal file
365
core/net/ip/tcp-socket.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* 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 "lib/list.h"
|
||||
|
||||
#include "tcp-socket.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
LIST(socketlist);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(tcp_socket_process, "TCP socket process");
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
call_event(struct tcp_socket *s, tcp_socket_event_t event)
|
||||
{
|
||||
if(s != NULL && s->event_callback != NULL) {
|
||||
s->event_callback(s, s->ptr, event);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
senddata(struct tcp_socket *s)
|
||||
{
|
||||
int len;
|
||||
|
||||
if(s->output_data_len > 0) {
|
||||
len = MIN(s->output_data_len, uip_mss());
|
||||
s->output_data_send_nxt = len;
|
||||
uip_send(s->output_data_ptr, len);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
acked(struct tcp_socket *s)
|
||||
{
|
||||
if(s->output_data_len > 0) {
|
||||
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||
outputbuf_lastsent */
|
||||
|
||||
if(s->output_data_send_nxt > 0) {
|
||||
memcpy(&s->output_data_ptr[0],
|
||||
&s->output_data_ptr[s->output_data_send_nxt],
|
||||
s->output_data_maxlen - s->output_data_send_nxt);
|
||||
}
|
||||
if(s->output_data_len < s->output_data_send_nxt) {
|
||||
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||
s->output_data_len,
|
||||
s->output_data_send_nxt);
|
||||
}
|
||||
s->output_data_len -= s->output_data_send_nxt;
|
||||
s->output_data_send_nxt = 0;
|
||||
|
||||
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
newdata(struct tcp_socket *s)
|
||||
{
|
||||
uint16_t len, copylen, bytesleft;
|
||||
uint8_t *dataptr;
|
||||
len = uip_datalen();
|
||||
dataptr = uip_appdata;
|
||||
|
||||
/* We have a segment with data coming in. We copy as much data as
|
||||
possible into the input buffer and call the input callback
|
||||
function. The input callback returns the number of bytes that
|
||||
should be retained in the buffer, or zero if all data should be
|
||||
consumed. If there is data to be retained, the highest bytes of
|
||||
data are copied down into the input buffer. */
|
||||
do {
|
||||
copylen = MIN(len, s->input_data_maxlen);
|
||||
memcpy(s->input_data_ptr, dataptr, copylen);
|
||||
if(s->input_callback) {
|
||||
bytesleft = s->input_callback(s, s->ptr,
|
||||
s->input_data_ptr, copylen);
|
||||
} else {
|
||||
bytesleft = 0;
|
||||
}
|
||||
if(bytesleft > 0) {
|
||||
printf("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
|
||||
}
|
||||
dataptr += copylen;
|
||||
len -= copylen;
|
||||
|
||||
} while(len > 0);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
relisten(struct tcp_socket *s)
|
||||
{
|
||||
if(s != NULL && s->listen_port != 0) {
|
||||
s->flags |= TCP_SOCKET_FLAGS_LISTENING;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
appcall(void *state)
|
||||
{
|
||||
struct tcp_socket *s = state;
|
||||
|
||||
if(uip_connected()) {
|
||||
/* Check if this connection originated in a local listen
|
||||
socket. We do this by checking the state pointer - if NULL,
|
||||
this is an incoming listen connection. If so, we need to
|
||||
connect the socket to the uip_conn and call the event
|
||||
function. */
|
||||
if(s == NULL) {
|
||||
for(s = list_head(socketlist);
|
||||
s != NULL;
|
||||
s = list_item_next(s)) {
|
||||
if((s->flags & TCP_SOCKET_FLAGS_LISTENING) != 0 &&
|
||||
s->listen_port != 0 &&
|
||||
s->listen_port == uip_htons(uip_conn->lport)) {
|
||||
s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
|
||||
tcp_markconn(uip_conn, s);
|
||||
call_event(s, TCP_SOCKET_CONNECTED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call_event(s, TCP_SOCKET_CONNECTED);
|
||||
}
|
||||
|
||||
if(s == NULL) {
|
||||
uip_abort();
|
||||
} else {
|
||||
if(uip_newdata()) {
|
||||
newdata(s);
|
||||
}
|
||||
senddata(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(uip_timedout()) {
|
||||
call_event(s, TCP_SOCKET_TIMEDOUT);
|
||||
relisten(s);
|
||||
}
|
||||
|
||||
if(uip_aborted()) {
|
||||
call_event(s, TCP_SOCKET_ABORTED);
|
||||
relisten(s);
|
||||
}
|
||||
|
||||
if(s == NULL) {
|
||||
uip_abort();
|
||||
return;
|
||||
}
|
||||
|
||||
if(uip_acked()) {
|
||||
acked(s);
|
||||
}
|
||||
if(uip_newdata()) {
|
||||
newdata(s);
|
||||
}
|
||||
|
||||
if(uip_rexmit() ||
|
||||
uip_newdata() ||
|
||||
uip_acked()) {
|
||||
senddata(s);
|
||||
} else if(uip_poll()) {
|
||||
senddata(s);
|
||||
}
|
||||
|
||||
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||
uip_close();
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
relisten(s);
|
||||
}
|
||||
|
||||
if(uip_closed()) {
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
relisten(s);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(tcp_socket_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
|
||||
if(ev == tcpip_event) {
|
||||
appcall(data);
|
||||
}
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
init(void)
|
||||
{
|
||||
static uint8_t inited = 0;
|
||||
if(!inited) {
|
||||
list_init(socketlist);
|
||||
process_start(&tcp_socket_process, NULL);
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||
uint8_t *input_databuf, int input_databuf_len,
|
||||
uint8_t *output_databuf, int output_databuf_len,
|
||||
tcp_socket_data_callback_t input_callback,
|
||||
tcp_socket_event_callback_t event_callback)
|
||||
{
|
||||
|
||||
init();
|
||||
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
s->ptr = ptr;
|
||||
s->input_data_ptr = input_databuf;
|
||||
s->input_data_maxlen = input_databuf_len;
|
||||
s->output_data_ptr = output_databuf;
|
||||
s->output_data_maxlen = output_databuf_len;
|
||||
s->input_callback = input_callback;
|
||||
s->event_callback = event_callback;
|
||||
list_add(socketlist, s);
|
||||
|
||||
s->listen_port = 0;
|
||||
s->flags = TCP_SOCKET_FLAGS_NONE;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
uint16_t port)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||
PROCESS_CONTEXT_END();
|
||||
if(s->c == NULL) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_listen(struct tcp_socket *s,
|
||||
uint16_t port)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->listen_port = port;
|
||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||
tcp_listen(uip_htons(port));
|
||||
PROCESS_CONTEXT_END();
|
||||
s->flags |= TCP_SOCKET_FLAGS_LISTENING;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_unlisten(struct tcp_socket *s)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||
tcp_unlisten(uip_htons(s->listen_port));
|
||||
PROCESS_CONTEXT_END();
|
||||
s->listen_port = 0;
|
||||
s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_send(struct tcp_socket *s,
|
||||
const uint8_t *data, int datalen)
|
||||
{
|
||||
int len;
|
||||
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = MIN(datalen, s->output_data_maxlen - s->output_data_len);
|
||||
|
||||
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||
s->output_data_len += len;
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_send_str(struct tcp_socket *s,
|
||||
const char *str)
|
||||
{
|
||||
return tcp_socket_send(s, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_close(struct tcp_socket *s)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->flags |= TCP_SOCKET_FLAGS_CLOSING;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_unregister(struct tcp_socket *s)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcp_socket_unlisten(s);
|
||||
if(s->c != NULL) {
|
||||
tcp_attach(s->c, NULL);
|
||||
}
|
||||
list_remove(socketlist, s);
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
268
core/net/ip/tcp-socket.h
Normal file
268
core/net/ip/tcp-socket.h
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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 TCP_SOCKET_H
|
||||
#define TCP_SOCKET_H
|
||||
|
||||
struct tcp_socket;
|
||||
|
||||
typedef enum {
|
||||
TCP_SOCKET_CONNECTED,
|
||||
TCP_SOCKET_CLOSED,
|
||||
TCP_SOCKET_TIMEDOUT,
|
||||
TCP_SOCKET_ABORTED,
|
||||
TCP_SOCKET_DATA_SENT
|
||||
} tcp_socket_event_t;
|
||||
|
||||
/**
|
||||
* \brief TCP data callback function
|
||||
* \param s A pointer to a TCP socket
|
||||
* \param ptr A user-defined pointer
|
||||
* \param input_data_ptr A pointer to the incoming data
|
||||
* \param input_data_len The length of the incoming data
|
||||
* \return The function should return the number of bytes to leave in the input buffer
|
||||
*
|
||||
* The TCP socket input callback function gets
|
||||
* called whenever there is new data on the socket. The
|
||||
* function can choose to either consume the data
|
||||
* directly, or leave it in the buffer for later. The
|
||||
* function must return the amount of data to leave in the
|
||||
* buffer. I.e., if the callback function consumes all
|
||||
* incoming data, it should return 0.
|
||||
*/
|
||||
typedef int (* tcp_socket_data_callback_t)(struct tcp_socket *s,
|
||||
void *ptr,
|
||||
const uint8_t *input_data_ptr,
|
||||
int input_data_len);
|
||||
|
||||
|
||||
/**
|
||||
* \brief TCP event callback function
|
||||
* \param s A pointer to a TCP socket
|
||||
* \param ptr A user-defined pointer
|
||||
* \param event The event number
|
||||
*
|
||||
* The TCP socket event callback function gets
|
||||
* called whenever there is an event on a socket, such as
|
||||
* the socket getting connected or closed.
|
||||
*/
|
||||
typedef void (* tcp_socket_event_callback_t)(struct tcp_socket *s,
|
||||
void *ptr,
|
||||
tcp_socket_event_t event);
|
||||
|
||||
struct tcp_socket {
|
||||
struct tcp_socket *next;
|
||||
|
||||
tcp_socket_data_callback_t input_callback;
|
||||
tcp_socket_event_callback_t event_callback;
|
||||
void *ptr;
|
||||
|
||||
struct process *p;
|
||||
|
||||
uint8_t *input_data_ptr;
|
||||
uint8_t *output_data_ptr;
|
||||
|
||||
uint16_t input_data_maxlen;
|
||||
uint16_t input_data_len;
|
||||
uint16_t output_data_maxlen;
|
||||
uint16_t output_data_len;
|
||||
uint16_t output_data_send_nxt;
|
||||
|
||||
uint8_t flags;
|
||||
uint16_t listen_port;
|
||||
struct uip_conn *c;
|
||||
};
|
||||
|
||||
enum {
|
||||
TCP_SOCKET_FLAGS_NONE = 0x00,
|
||||
TCP_SOCKET_FLAGS_LISTENING = 0x01,
|
||||
TCP_SOCKET_FLAGS_CLOSING = 0x02,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register a TCP socket
|
||||
* \param s A pointer to a TCP socket
|
||||
* \param ptr A user-defined pointer that will be sent to callbacks for this socket
|
||||
* \param input_databuf A pointer to a memory area this socket will use for input data
|
||||
* \param input_databuf_len The size of the input data buffer
|
||||
* \param output_databuf A pointer to a memory area this socket will use for outgoing data
|
||||
* \param output_databuf_len The size of the output data buffer
|
||||
* \param data_callback A pointer to the data callback function for this socket
|
||||
* \param event_callback A pointer to the event callback function for this socket
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function registers a TCP socket. The function sets
|
||||
* up the output and input buffers for the socket and
|
||||
* callback pointers.
|
||||
*
|
||||
* TCP sockets use input and output buffers for incoming
|
||||
* and outgoing data. The memory for these buffers must be
|
||||
* allocated by the caller. The size of the buffers
|
||||
* determine the amount of data that can be received and
|
||||
* sent, and the principle is that the application that
|
||||
* sets up the TCP socket will know roughly how large
|
||||
* these buffers should be. The rule of thumb is that the
|
||||
* input buffer should be large enough to hold the largest
|
||||
* application layer message that the application will
|
||||
* receive and the output buffer should be large enough to
|
||||
* hold the largest application layer message the
|
||||
* application will send.
|
||||
*
|
||||
* TCP throttles incoming data so that if the input buffer
|
||||
* is filled, the connection will halt until the
|
||||
* application has read out the data from the input
|
||||
* buffer.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||
uint8_t *input_databuf, int input_databuf_len,
|
||||
uint8_t *output_databuf, int output_databuf_len,
|
||||
tcp_socket_data_callback_t data_callback,
|
||||
tcp_socket_event_callback_t event_callback);
|
||||
|
||||
/**
|
||||
* \brief Connect a TCP socket to a remote host
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \param ipaddr The IP address of the remote host
|
||||
* \param port The TCP port number, in host byte order, of the remote host
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function connects a TCP socket to a remote host.
|
||||
*
|
||||
* When the socket has connected, the event callback will
|
||||
* get called with the TCP_SOCKET_CONNECTED event. If the
|
||||
* remote host does not accept the connection, the
|
||||
* TCP_SOCKET_ABORTED will be sent to the callback. If the
|
||||
* connection times out before conecting to the remote
|
||||
* host, the TCP_SOCKET_TIMEDOUT event is sent to the
|
||||
* callback.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
* \brief Start listening on a specific port
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \param port The TCP port number, in host byte order, of the remote host
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function causes the TCP socket to start listening
|
||||
* on the given TCP port.
|
||||
*
|
||||
* Several sockets can listen on the same port. If a
|
||||
* remote host connects to the port, one of the listening
|
||||
* sockets will get connected and the event callback will
|
||||
* be called with the TCP_SOCKET_CONNECTED event. When the
|
||||
* connection closes, the socket will go back to listening
|
||||
* for new connections.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_listen(struct tcp_socket *s,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
* \brief Stop listening for new connections
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function causes a listening TCP socket to stop
|
||||
* listen. The socket must previously been put into listen
|
||||
* mode with tcp_socket_listen().
|
||||
*
|
||||
*/
|
||||
int tcp_socket_unlisten(struct tcp_socket *s);
|
||||
|
||||
/**
|
||||
* \brief Send data on a connected TCP socket
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \param dataptr A pointer to the data to be sent
|
||||
* \param datalen The length of the data to be sent
|
||||
* \retval -1 If an error occurs
|
||||
* \return The number of bytes that were successfully sent
|
||||
*
|
||||
* This function sends data over a connected TCP
|
||||
* socket. The data is placed in the output buffer and
|
||||
* sent to the remote host as soon as possiblce. When the
|
||||
* data has been acknowledged by the remote host, the
|
||||
* event callback is sent with the TCP_SOCKET_DATA_SENT
|
||||
* event.
|
||||
*/
|
||||
int tcp_socket_send(struct tcp_socket *s,
|
||||
const uint8_t *dataptr,
|
||||
int datalen);
|
||||
|
||||
/**
|
||||
* \brief Send a string on a connected TCP socket
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \param strptr A pointer to the string to be sent
|
||||
* \retval -1 If an error occurs
|
||||
* \return The number of bytes that were successfully sent
|
||||
*
|
||||
* This is a convenience function for sending strings on a
|
||||
* TCP socket. The function calls tcp_socket_send() to
|
||||
* send the string.
|
||||
*/
|
||||
int tcp_socket_send_str(struct tcp_socket *s,
|
||||
const char *strptr);
|
||||
|
||||
/**
|
||||
* \brief Close a connected TCP socket
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function closes a connected TCP socket. When the
|
||||
* socket has been successfully closed, the event callback
|
||||
* is called with the TCP_SOCKET_CLOSED event.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_close(struct tcp_socket *s);
|
||||
|
||||
/**
|
||||
* \brief Unregister a registered socket
|
||||
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||
* \retval -1 If an error occurs
|
||||
* \retval 1 If the operation succeeds.
|
||||
*
|
||||
* This function unregisters a previously registered
|
||||
* socket. This must be done if the process will be
|
||||
* unloaded from memory. If the TCP socket is connected,
|
||||
* the connection will be reset.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_unregister(struct tcp_socket *s);
|
||||
#endif /* TCP_SOCKET_H */
|
199
core/net/ip/udp-socket.c
Normal file
199
core/net/ip/udp-socket.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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-net.h"
|
||||
#include "udp-socket.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
PROCESS(udp_socket_process, "UDP socket process");
|
||||
|
||||
static uint8_t buf[UIP_BUFSIZE];
|
||||
|
||||
#define UIP_IP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
init(void)
|
||||
{
|
||||
static uint8_t inited = 0;
|
||||
if(!inited) {
|
||||
inited = 1;
|
||||
process_start(&udp_socket_process, NULL);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_register(struct udp_socket *c,
|
||||
void *ptr,
|
||||
udp_socket_input_callback_t input_callback)
|
||||
{
|
||||
init();
|
||||
|
||||
if(c == NULL) {
|
||||
return -1;
|
||||
}
|
||||
c->ptr = ptr;
|
||||
c->input_callback = input_callback;
|
||||
|
||||
c->p = PROCESS_CURRENT();
|
||||
PROCESS_CONTEXT_BEGIN(&udp_socket_process);
|
||||
c->udp_conn = udp_new(NULL, 0, c);
|
||||
PROCESS_CONTEXT_END();
|
||||
|
||||
if(c->udp_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_close(struct udp_socket *c)
|
||||
{
|
||||
if(c == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if(c->udp_conn != NULL) {
|
||||
uip_udp_remove(c->udp_conn);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_bind(struct udp_socket *c,
|
||||
uint16_t local_port)
|
||||
{
|
||||
if(c == NULL || c->udp_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
udp_bind(c->udp_conn, UIP_HTONS(local_port));
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_connect(struct udp_socket *c,
|
||||
uip_ipaddr_t *remote_addr,
|
||||
uint16_t remote_port)
|
||||
{
|
||||
if(c == NULL || c->udp_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(remote_addr != NULL) {
|
||||
uip_ipaddr_copy(&c->udp_conn->ripaddr, remote_addr);
|
||||
}
|
||||
c->udp_conn->rport = UIP_HTONS(remote_port);
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_send(struct udp_socket *c,
|
||||
const void *data, uint16_t datalen)
|
||||
{
|
||||
if(c == NULL || c->udp_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uip_udp_packet_send(c->udp_conn, data, datalen);
|
||||
return datalen;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
udp_socket_sendto(struct udp_socket *c,
|
||||
const void *data, uint16_t datalen,
|
||||
const uip_ipaddr_t *to,
|
||||
uint16_t port)
|
||||
{
|
||||
if(c == NULL || c->udp_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(c->udp_conn != NULL) {
|
||||
uip_udp_packet_sendto(c->udp_conn, data, datalen,
|
||||
to, UIP_HTONS(port));
|
||||
return datalen;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(udp_socket_process, ev, data)
|
||||
{
|
||||
struct udp_socket *c;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
if(ev == tcpip_event) {
|
||||
|
||||
/* An appstate pointer is passed to use from the IP stack
|
||||
through the 'data' pointer. We registered this appstate when
|
||||
we did the udp_new() call in udp_socket_register() as the
|
||||
struct udp_socket pointer. So we extract this
|
||||
pointer and use it when calling the reception callback. */
|
||||
c = (struct udp_socket *)data;
|
||||
|
||||
/* Defensive coding: although the appstate *should* be non-null
|
||||
here, we make sure to avoid the program crashing on us. */
|
||||
if(c != NULL) {
|
||||
|
||||
/* If we were called because of incoming data, we should call
|
||||
the reception callback. */
|
||||
if(uip_newdata()) {
|
||||
/* Copy the data from the uIP data buffer into our own
|
||||
buffer to avoid the uIP buffer being messed with by the
|
||||
callee. */
|
||||
memcpy(buf, uip_appdata, uip_datalen());
|
||||
|
||||
/* Call the client process. We use the PROCESS_CONTEXT
|
||||
mechanism to temporarily switch process context to the
|
||||
client process. */
|
||||
if(c->input_callback != NULL) {
|
||||
PROCESS_CONTEXT_BEGIN(c->p);
|
||||
c->input_callback(c, c->ptr,
|
||||
&(UIP_IP_BUF->srcipaddr),
|
||||
UIP_HTONS(UIP_IP_BUF->srcport),
|
||||
&(UIP_IP_BUF->destipaddr),
|
||||
UIP_HTONS(UIP_IP_BUF->destport),
|
||||
buf, uip_datalen());
|
||||
PROCESS_CONTEXT_END();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
193
core/net/ip/udp-socket.h
Normal file
193
core/net/ip/udp-socket.h
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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 UDP_SOCKET_H
|
||||
#define UDP_SOCKET_H
|
||||
|
||||
#include "net/ip/uip.h"
|
||||
|
||||
struct udp_socket;
|
||||
|
||||
/**
|
||||
* \brief A UDP socket callback function
|
||||
* \param c A pointer to the struct udp_socket that received the data
|
||||
* \param ptr An opaque pointer that was specified when the UDP socket was registered with udp_socket_register()
|
||||
* \param source_addr The IP address from which the datagram was sent
|
||||
* \param source_port The UDP port number, in host byte order, from which the datagram was sent
|
||||
* \param dest_addr The IP address that this datagram was sent to
|
||||
* \param dest_port The UDP port number, in host byte order, that the datagram was sent to
|
||||
* \param data A pointer to the data contents of the UDP datagram
|
||||
* \param datalen The length of the data being pointed to by the data pointer
|
||||
*
|
||||
* Each UDP socket has a callback function that is
|
||||
* registered as part of the call to
|
||||
* udp_socket_register(). The callback function gets
|
||||
* called every time a UDP packet is received.
|
||||
*/
|
||||
typedef void (* udp_socket_input_callback_t)(struct udp_socket *c,
|
||||
void *ptr,
|
||||
const uip_ipaddr_t *source_addr,
|
||||
uint16_t source_port,
|
||||
const uip_ipaddr_t *dest_addr,
|
||||
uint16_t dest_port,
|
||||
const uint8_t *data,
|
||||
uint16_t datalen);
|
||||
|
||||
struct udp_socket {
|
||||
udp_socket_input_callback_t input_callback;
|
||||
void *ptr;
|
||||
|
||||
struct process *p;
|
||||
|
||||
struct uip_udp_conn *udp_conn;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register a UDP socket
|
||||
* \param c A pointer to the struct udp_socket that should be registered
|
||||
* \param ptr An opaque pointer that will be passed to callbacks
|
||||
* \param receive_callback A function pointer to the callback function that will be called when data arrives
|
||||
* \retval -1 The registration failed
|
||||
* \retval 1 The registration succeeded
|
||||
*
|
||||
* This function registers the UDP socket with the
|
||||
* system. A UDP socket must be registered before any data
|
||||
* can be sent or received over the socket.
|
||||
*
|
||||
* The caller must allocate memory for the struct
|
||||
* udp_socket that is to be registered.
|
||||
*
|
||||
* A UDP socket can begin to receive data by calling
|
||||
* udp_socket_bind().
|
||||
*
|
||||
*/
|
||||
int udp_socket_register(struct udp_socket *c,
|
||||
void *ptr,
|
||||
udp_socket_input_callback_t receive_callback);
|
||||
|
||||
/**
|
||||
* \brief Bind a UDP socket to a local port
|
||||
* \param c A pointer to the struct udp_socket that should be bound to a local port
|
||||
* \param local_port The UDP port number, in host byte order, to bind the UDP socket to
|
||||
* \retval -1 Binding the UDP socket to the local port failed
|
||||
* \retval 1 Binding the UDP socket to the local port succeeded
|
||||
*
|
||||
* This function binds the UDP socket to a local port so
|
||||
* that it will begin to receive data that arrives on the
|
||||
* specified port. A UDP socket will receive data
|
||||
* addressed to the specified port number on any IP
|
||||
* address of the host.
|
||||
*
|
||||
* A UDP socket that is bound to a local port will use
|
||||
* this port number as a source port in outgoing UDP
|
||||
* messages.
|
||||
*
|
||||
*/
|
||||
int udp_socket_bind(struct udp_socket *c,
|
||||
uint16_t local_port);
|
||||
|
||||
/**
|
||||
* \brief Bind a UDP socket to a remote address and port
|
||||
* \param c A pointer to the struct udp_socket that should be connected
|
||||
* \param remote_addr The IP address of the remote host, or NULL if the UDP socket should only be connected to a specific port
|
||||
* \param remote_port The UDP port number, in host byte order, to which the UDP socket should be connected
|
||||
* \retval -1 Connecting the UDP socket failed
|
||||
* \retval 1 Connecting the UDP socket succeeded
|
||||
*
|
||||
* This function connects the UDP socket to a specific
|
||||
* remote port and optional remote IP address. When a UDP
|
||||
* socket is connected to a remote port and address, it
|
||||
* will only receive packets that are sent from the remote
|
||||
* port and address. When sending data over a connected
|
||||
* UDP socket, the data will be sent to the connected
|
||||
* remote address.
|
||||
*
|
||||
* A UDP socket can be connected to a remote port, but not
|
||||
* a remote IP address, by providing a NULL parameter as
|
||||
* the remote_addr parameter. This lets the UDP socket
|
||||
* receive data from any IP address on the specified port.
|
||||
*
|
||||
*/
|
||||
int udp_socket_connect(struct udp_socket *c,
|
||||
uip_ipaddr_t *remote_addr,
|
||||
uint16_t remote_port);
|
||||
/**
|
||||
* \brief Send data on a UDP socket
|
||||
* \param c A pointer to the struct udp_socket on which the data should be sent
|
||||
* \param data A pointer to the data that should be sent
|
||||
* \param datalen The length of the data to be sent
|
||||
* \return The number of bytes sent, or -1 if an error occurred
|
||||
*
|
||||
* This function sends data over a UDP socket. The UDP
|
||||
* socket must have been connected to a remote address and
|
||||
* port with udp_socket_connect().
|
||||
*
|
||||
*/
|
||||
int udp_socket_send(struct udp_socket *c,
|
||||
const void *data, uint16_t datalen);
|
||||
|
||||
/**
|
||||
* \brief Send data on a UDP socket to a specific address and port
|
||||
* \param c A pointer to the struct udp_socket on which the data should be sent
|
||||
* \param data A pointer to the data that should be sent
|
||||
* \param datalen The length of the data to be sent
|
||||
* \param addr The IP address to which the data should be sent
|
||||
* \param port The UDP port number, in host byte order, to which the data should be sent
|
||||
* \return The number of bytes sent, or -1 if an error occurred
|
||||
*
|
||||
* This function sends data over a UDP socket to a
|
||||
* specific address and port.
|
||||
*
|
||||
* The UDP socket does not have to be connected to use
|
||||
* this function.
|
||||
*
|
||||
*/
|
||||
int udp_socket_sendto(struct udp_socket *c,
|
||||
const void *data, uint16_t datalen,
|
||||
const uip_ipaddr_t *addr, uint16_t port);
|
||||
|
||||
/**
|
||||
* \brief Close a UDP socket
|
||||
* \param c A pointer to the struct udp_socket to be closed
|
||||
* \retval -1 If closing the UDP socket failed
|
||||
* \retval 1 If closing the UDP socket succeeded
|
||||
*
|
||||
* This function closes a UDP socket that has previously
|
||||
* been registered with udp_socket_register(). All
|
||||
* registered UDP sockets must be closed before exiting
|
||||
* the process that registered them, or undefined behavior
|
||||
* may occur.
|
||||
*
|
||||
*/
|
||||
int udp_socket_close(struct udp_socket *c);
|
||||
|
||||
#endif /* UDP_SOCKET_H */
|
|
@ -42,6 +42,7 @@
|
|||
extern uint16_t uip_slen;
|
||||
|
||||
#include "net/ip/uip-udp-packet.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -57,6 +58,14 @@ uip_udp_packet_send(struct uip_udp_conn *c, const void *data, int len)
|
|||
len > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN?
|
||||
UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN: len);
|
||||
uip_process(UIP_UDP_SEND_CONN);
|
||||
|
||||
#if UIP_CONF_IPV6_MULTICAST
|
||||
/* Let the multicast engine process the datagram before we send it */
|
||||
if(uip_is_addr_mcast_routable(&uip_udp_conn->ripaddr)) {
|
||||
UIP_MCAST6.out();
|
||||
}
|
||||
#endif /* UIP_IPV6_MULTICAST */
|
||||
|
||||
#if UIP_CONF_IPV6
|
||||
tcpip_ipv6_output();
|
||||
#else
|
||||
|
|
|
@ -2093,6 +2093,35 @@ CCIF extern uip_lladdr_t uip_lladdr;
|
|||
#define uip_is_addr_mcast(a) \
|
||||
(((a)->u8[0]) == 0xFF)
|
||||
|
||||
/**
|
||||
* \brief is address a global multicast address (FFxE::/16),
|
||||
* a is of type uip_ip6addr_t*
|
||||
* */
|
||||
#define uip_is_addr_mcast_global(a) \
|
||||
((((a)->u8[0]) == 0xFF) && \
|
||||
(((a)->u8[1] & 0x0F) == 0x0E))
|
||||
|
||||
/**
|
||||
* \brief is address a non-routable multicast address.
|
||||
* Scopes 1 (interface-local) and 2 (link-local) are non-routable
|
||||
* See RFC4291 and draft-ietf-6man-multicast-scopes
|
||||
* a is of type uip_ip6addr_t*
|
||||
* */
|
||||
#define uip_is_addr_mcast_non_routable(a) \
|
||||
((((a)->u8[0]) == 0xFF) && \
|
||||
(((a)->u8[1] & 0x0F) <= 0x02))
|
||||
|
||||
/**
|
||||
* \brief is address a routable multicast address.
|
||||
* Scope 3 (Realm-Local) or higher are routable
|
||||
* Realm-Local scope is defined in draft-ietf-6man-multicast-scopes
|
||||
* See RFC4291 and draft-ietf-6man-multicast-scopes
|
||||
* a is of type uip_ip6addr_t*
|
||||
* */
|
||||
#define uip_is_addr_mcast_routable(a) \
|
||||
((((a)->u8[0]) == 0xFF) && \
|
||||
(((a)->u8[1] & 0x0F) > 0x02))
|
||||
|
||||
/**
|
||||
* \brief is group-id of multicast address a
|
||||
* the all nodes group-id
|
||||
|
|
114
core/net/ipv6/multicast/README.md
Normal file
114
core/net/ipv6/multicast/README.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
README file for Contiki's IPv6 multicast core
|
||||
|
||||
Author: George Oikonomou
|
||||
|
||||
What does it do
|
||||
===============
|
||||
These files, alongside some core modifications, add support for IPv6 multicast
|
||||
to contiki's uIPv6 engine.
|
||||
|
||||
Currently, two modes are supported:
|
||||
|
||||
* 'Stateless Multicast RPL Forwarding' (SMRF)
|
||||
RPL in MOP 3 handles group management as per the RPL docs,
|
||||
SMRF is a lightweight engine which handles datagram forwarding.
|
||||
SMRF is documented here:
|
||||
http://dx.doi.org/10.1007/s11277-013-1250-5
|
||||
and here:
|
||||
http://dx.doi.org/10.1109/PerComW.2012.6197494
|
||||
* 'Multicast Forwarding with Trickle' according to the algorithm described
|
||||
in the internet draft:
|
||||
http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast
|
||||
The version of this draft that's currently implementated is documented
|
||||
in `roll-tm.h`
|
||||
|
||||
More engines can (and hopefully will) be added in the future. The first
|
||||
addition is most likely going to be an updated implementation of MPL
|
||||
|
||||
The Big Gotcha
|
||||
==============
|
||||
Currently we only support traffic originating and destined inside a single 6LoWPAN
|
||||
To be able to send multicast traffic from the internet to 6LoWPAN nodes or the other
|
||||
way round, we need border routers or other gateway devices to be able to achieve
|
||||
the following:
|
||||
|
||||
* Add/Remove Trickle Multicast, RPL or other HBHO headers as necessary for datagrams
|
||||
entering / exiting the 6LoWPAN
|
||||
* Advertise multicast group membership to the internet (e.g. with MLD)
|
||||
|
||||
These are currently not implemented and are in the ToDo list. Contributions welcome.
|
||||
|
||||
Where to Start
|
||||
==============
|
||||
The best place in `examples/ipv6/multicast`
|
||||
|
||||
There is a cooja example demonstrating basic functionality
|
||||
|
||||
How to Use
|
||||
==========
|
||||
Look in `core/net/ipv6/multicast/uip-mcast6-engines.h` for a list of supported
|
||||
multicast engines.
|
||||
|
||||
To turn on multicast support, add this line in your `project-` or `contiki-conf.h`
|
||||
|
||||
#define UIP_MCAST6_CONF_ENGINE xyz
|
||||
|
||||
where xyz is a value from `uip-mcast6-engines.h`
|
||||
|
||||
To disable:
|
||||
|
||||
#define UIP_MCAST6_CONF_ENGINE 0
|
||||
|
||||
You also need to make sure the multicast code gets built. Your example's
|
||||
(or platform's) Makefile should include this:
|
||||
|
||||
MODULES += core/net/ipv6/multicast
|
||||
|
||||
How to extend
|
||||
=============
|
||||
Let's assume you want to write an engine called foo.
|
||||
The multicast API defines a multicast engine driver in a fashion similar to
|
||||
the various NETSTACK layer drivers. This API defines functions for basic
|
||||
multicast operations (init, in, out).
|
||||
In order to extend multicast with a new engine, perform the following steps:
|
||||
|
||||
- Open `uip-mcast6-engines.h` and assign a unique integer code to your engine
|
||||
|
||||
#define UIP_MCAST6_ENGINE_FOO xyz
|
||||
|
||||
- Include your engine's `foo.h`
|
||||
|
||||
- In `foo.c`, implement:
|
||||
* `init()`
|
||||
* `in()`
|
||||
* `out()`
|
||||
* Define your driver like so:
|
||||
|
||||
`const struct uip_mcast6_driver foo_driver = { ... }`
|
||||
|
||||
- If you want to maintain stats:
|
||||
* Standard multicast stats are maintained in `uip_mcast6_stats`. Don't access
|
||||
this struct directly, use the macros provided in `uip-mcast6-stats.h` instead
|
||||
* You can add your own stats extensions. To do so, declare your own stats
|
||||
struct in your engine's module, e.g `struct foo_stats`
|
||||
* When you initialise the stats module with `UIP_MCAST6_STATS_INIT`, pass
|
||||
a pointer to your stats variable as the macro's argument.
|
||||
An example of how to extend multicast stats, look at the ROLL TM engine
|
||||
|
||||
- Open `uip-mcast6.h` and add a section in the `#if` spree. This aims to
|
||||
configure the uIPv6 core. More specifically, you need to:
|
||||
* Specify if you want to put RPL in MOP3 by defining
|
||||
`RPL_CONF_MULTICAST`: 1: MOP 3, 0: non-multicast MOP
|
||||
* Define your engine details
|
||||
|
||||
#define UIP_MCAST6 foo_driver
|
||||
#define UIP_MCAST6_STATS foo_stats
|
||||
typedef struct foo_stats uip_mcast6_stats_t;
|
||||
|
||||
* Optionally, add a configuration check block to stop builds when the
|
||||
configuration is not sane.
|
||||
|
||||
If you need your engine to perform operations not supported by the generic
|
||||
UIP_MCAST6 API, you will have to hook those in the uip core manually. As an
|
||||
example, see how the core is modified so that it can deliver ICMPv6 datagrams
|
||||
to the ROLL TM engine.
|
1452
core/net/ipv6/multicast/roll-tm.c
Normal file
1452
core/net/ipv6/multicast/roll-tm.c
Normal file
File diff suppressed because it is too large
Load diff
224
core/net/ipv6/multicast/roll-tm.h
Normal file
224
core/net/ipv6/multicast/roll-tm.h
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Header file for IPv6 multicast according to the algorithm in the
|
||||
* "MCAST Forwarding Using Trickle" internet draft.
|
||||
*
|
||||
* The current version of the draft can always be found in
|
||||
* http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast
|
||||
*
|
||||
* This implementation is based on the draft version stored in
|
||||
* ROLL_TM_VER.
|
||||
*
|
||||
* In draft v2, the document was renamed to
|
||||
* "Multicast Protocol for Low power and Lossy Networks (MPL)"
|
||||
* Due to very significant changes between draft versions 1 and 2,
|
||||
* MPL will be implemented as a separate engine and this file here
|
||||
* will provide legacy support for Draft v1.
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#ifndef ROLL_TM_H_
|
||||
#define ROLL_TM_H_
|
||||
|
||||
#include "contiki-conf.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-stats.h"
|
||||
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Protocol Constants */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define ROLL_TM_VER 1 /* Supported Draft Version */
|
||||
#define ROLL_TM_ICMP_CODE 0 /* ICMPv6 code field */
|
||||
#define ROLL_TM_IP_HOP_LIMIT 0xFF /* Hop limit for ICMP messages */
|
||||
#define ROLL_TM_INFINITE_REDUNDANCY 0xFF
|
||||
#define ROLL_TM_DGRAM_OUT 0
|
||||
#define ROLL_TM_DGRAM_IN 1
|
||||
|
||||
/*
|
||||
* The draft does not currently specify a default number for the trickle
|
||||
* interval nor a way to derive it. Examples however hint at 100 msec.
|
||||
*
|
||||
* In draft terminology, we use an 'aggressive' policy (M=0) and a conservative
|
||||
* one (M=1).
|
||||
*
|
||||
* When experimenting with the two policies on the sky platform,
|
||||
* an interval of 125ms proves to be way too low: When we have traffic,
|
||||
* doublings happen after the interval end and periodics fire after point T
|
||||
* within the interval (and sometimes even after interval end). When traffic
|
||||
* settles down, the code compensates the offsets.
|
||||
*
|
||||
* We consider 125, 250ms etc because they are nice divisors of 1 sec
|
||||
* (quotient is power of two). For some machines (e.g sky/msp430,
|
||||
* sensinode/cc243x), this is also a nice number of clock ticks
|
||||
*
|
||||
* After experimentation, the values of Imin leading to best performance are:
|
||||
* ContikiMAC: Imin=64 (500ms)
|
||||
* Null RDC: imin=16 (125ms)
|
||||
*/
|
||||
|
||||
/* Configuration for Timer with M=0 (aggressive) */
|
||||
#ifdef ROLL_TM_CONF_IMIN_0
|
||||
#define ROLL_TM_IMIN_0 ROLL_TM_CONF_IMIN_0
|
||||
#else
|
||||
#define ROLL_TM_IMIN_0 32 /* 250 msec */
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_IMAX_0
|
||||
#define ROLL_TM_IMAX_0 ROLL_TM_CONF_IMAX_0
|
||||
#else
|
||||
#define ROLL_TM_IMAX_0 1 /* Imax = 500ms */
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_K_0
|
||||
#define ROLL_TM_K_0 ROLL_TM_CONF_K_0
|
||||
#else
|
||||
#define ROLL_TM_K_0 ROLL_TM_INFINITE_REDUNDANCY
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_T_ACTIVE_0
|
||||
#define ROLL_TM_T_ACTIVE_0 ROLL_TM_CONF_T_ACTIVE_0
|
||||
#else
|
||||
#define ROLL_TM_T_ACTIVE_0 3
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_T_DWELL_0
|
||||
#define ROLL_TM_T_DWELL_0 ROLL_TM_CONF_T_DWELL_0
|
||||
#else
|
||||
#define ROLL_TM_T_DWELL_0 11
|
||||
#endif
|
||||
|
||||
/* Configuration for Timer with M=1 (conservative) */
|
||||
#ifdef ROLL_TM_CONF_IMIN_1
|
||||
#define ROLL_TM_IMIN_1 ROLL_TM_CONF_IMIN_1
|
||||
#else
|
||||
#define ROLL_TM_IMIN_1 64 /* 500 msec */
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_IMAX_1
|
||||
#define ROLL_TM_IMAX_1 ROLL_TM_CONF_IMAX_1
|
||||
#else
|
||||
#define ROLL_TM_IMAX_1 9 /* Imax = 256 secs */
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_K_1
|
||||
#define ROLL_TM_K_1 ROLL_TM_CONF_K_1
|
||||
#else
|
||||
#define ROLL_TM_K_1 1
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_T_ACTIVE_1
|
||||
#define ROLL_TM_T_ACTIVE_1 ROLL_TM_CONF_T_ACTIVE_1
|
||||
#else
|
||||
#define ROLL_TM_T_ACTIVE_1 3
|
||||
#endif
|
||||
|
||||
#ifdef ROLL_TM_CONF_T_DWELL_1
|
||||
#define ROLL_TM_T_DWELL_1 ROLL_TM_CONF_T_DWELL_1
|
||||
#else
|
||||
#define ROLL_TM_T_DWELL_1 12
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Configuration */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Number of Sliding Windows
|
||||
* In essence: How many unique sources of simultaneous multicast traffic do we
|
||||
* want to support for our lowpan
|
||||
* If a node is seeding two multicast streams, parametrized on different M
|
||||
* values, then this seed will occupy two different sliding windows
|
||||
*/
|
||||
#ifdef ROLL_TM_CONF_WINS
|
||||
#define ROLL_TM_WINS ROLL_TM_CONF_WINS
|
||||
#else
|
||||
#define ROLL_TM_WINS 2
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Maximum Number of Buffered Multicast Messages
|
||||
* This buffer is shared across all Seed IDs, therefore a new very active Seed
|
||||
* may eventually occupy all slots. It would make little sense (if any) to
|
||||
* define support for fewer buffered messages than seeds*2
|
||||
*/
|
||||
#ifdef ROLL_TM_CONF_BUFF_NUM
|
||||
#define ROLL_TM_BUFF_NUM ROLL_TM_CONF_BUFF_NUM
|
||||
#else
|
||||
#define ROLL_TM_BUFF_NUM 6
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Use Short Seed IDs [short: 2, long: 16 (default)]
|
||||
* It can be argued that we should (and it would be easy to) support both at
|
||||
* the same time but the draft doesn't list this as a MUST so we opt for
|
||||
* code/ram savings
|
||||
*/
|
||||
#ifdef ROLL_TM_CONF_SHORT_SEEDS
|
||||
#define ROLL_TM_SHORT_SEEDS ROLL_TM_CONF_SHORT_SEEDS
|
||||
#else
|
||||
#define ROLL_TM_SHORT_SEEDS 0
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Destination address for our ICMPv6 advertisements. The draft gives us a
|
||||
* choice between LL all-nodes or LL all-routers
|
||||
*
|
||||
* We use allrouters unless a conf directive chooses otherwise
|
||||
*/
|
||||
#ifdef ROLL_TM_CONF_DEST_ALL_NODES
|
||||
#define ROLL_TM_DEST_ALL_NODES ROLL_TM_CONF_DEST_ALL_NODES
|
||||
#else
|
||||
#define ROLL_TM_DEST_ALL_NODES 0
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* M param for our outgoing messages
|
||||
* By default, we set the M bit (conservative). Define this as 0 to clear the
|
||||
* M bit in our outgoing messages (aggressive)
|
||||
*/
|
||||
#ifdef ROLL_TM_CONF_SET_M_BIT
|
||||
#define ROLL_TM_SET_M_BIT ROLL_TM_CONF_SET_M_BIT
|
||||
#else
|
||||
#define ROLL_TM_SET_M_BIT 1
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Stats datatype */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct roll_tm_stats {
|
||||
UIP_MCAST6_STATS_DATATYPE icmp_in;
|
||||
UIP_MCAST6_STATS_DATATYPE icmp_out;
|
||||
UIP_MCAST6_STATS_DATATYPE icmp_bad;
|
||||
};
|
||||
|
||||
#endif /* ROLL_TM_H_ */
|
211
core/net/ipv6/multicast/smrf.c
Normal file
211
core/net/ipv6/multicast/smrf.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Loughborough University - Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This file implements 'Stateless Multicast RPL Forwarding' (SMRF)
|
||||
*
|
||||
* It will only work in RPL networks in MOP 3 "Storing with Multicast"
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-route.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-stats.h"
|
||||
#include "net/ipv6/multicast/smrf.h"
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/netstack.h"
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#if UIP_CONF_IPV6
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Macros */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* CCI */
|
||||
#define SMRF_FWD_DELAY() NETSTACK_RDC.channel_check_interval()
|
||||
/* Number of slots in the next 500ms */
|
||||
#define SMRF_INTERVAL_COUNT ((CLOCK_SECOND >> 2) / fwd_delay)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Internal Data */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static struct ctimer mcast_periodic;
|
||||
static uint8_t mcast_len;
|
||||
static uip_buf_t mcast_buf;
|
||||
static uint8_t fwd_delay;
|
||||
static uint8_t fwd_spread;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* uIPv6 Pointers */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
mcast_fwd(void *p)
|
||||
{
|
||||
memcpy(uip_buf, &mcast_buf, mcast_len);
|
||||
uip_len = mcast_len;
|
||||
UIP_IP_BUF->ttl--;
|
||||
tcpip_output(NULL);
|
||||
uip_len = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint8_t
|
||||
in()
|
||||
{
|
||||
rpl_dag_t *d; /* Our DODAG */
|
||||
uip_ipaddr_t *parent_ipaddr; /* Our pref. parent's IPv6 address */
|
||||
const uip_lladdr_t *parent_lladdr; /* Our pref. parent's LL address */
|
||||
|
||||
/*
|
||||
* Fetch a pointer to the LL address of our preferred parent
|
||||
*
|
||||
* ToDo: This rpl_get_any_dag() call is a dirty replacement of the previous
|
||||
* rpl_get_dag(RPL_DEFAULT_INSTANCE);
|
||||
* so that things can compile with the new RPL code. This needs updated to
|
||||
* read instance ID from the RPL HBHO and use the correct parent accordingly
|
||||
*/
|
||||
d = rpl_get_any_dag();
|
||||
if(!d) {
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
/* Retrieve our preferred parent's LL address */
|
||||
parent_ipaddr = rpl_get_parent_ipaddr(d->preferred_parent);
|
||||
parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
|
||||
|
||||
if(parent_lladdr == NULL) {
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
/*
|
||||
* We accept a datagram if it arrived from our preferred parent, discard
|
||||
* otherwise.
|
||||
*/
|
||||
if(memcmp(parent_lladdr, packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
||||
UIP_LLADDR_LEN)) {
|
||||
PRINTF("SMRF: Routable in but SMRF ignored it\n");
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
if(UIP_IP_BUF->ttl <= 1) {
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
UIP_MCAST6_STATS_ADD(mcast_in_all);
|
||||
UIP_MCAST6_STATS_ADD(mcast_in_unique);
|
||||
|
||||
/* If we have an entry in the mcast routing table, something with
|
||||
* a higher RPL rank (somewhere down the tree) is a group member */
|
||||
if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) {
|
||||
/* If we enter here, we will definitely forward */
|
||||
UIP_MCAST6_STATS_ADD(mcast_fwd);
|
||||
|
||||
/*
|
||||
* Add a delay (D) of at least SMRF_FWD_DELAY() to compensate for how
|
||||
* contikimac handles broadcasts. We can't start our TX before the sender
|
||||
* has finished its own.
|
||||
*/
|
||||
fwd_delay = SMRF_FWD_DELAY();
|
||||
|
||||
/* Finalise D: D = min(SMRF_FWD_DELAY(), SMRF_MIN_FWD_DELAY) */
|
||||
#if SMRF_MIN_FWD_DELAY
|
||||
if(fwd_delay < SMRF_MIN_FWD_DELAY) {
|
||||
fwd_delay = SMRF_MIN_FWD_DELAY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(fwd_delay == 0) {
|
||||
/* No delay required, send it, do it now, why wait? */
|
||||
UIP_IP_BUF->ttl--;
|
||||
tcpip_output(NULL);
|
||||
UIP_IP_BUF->ttl++; /* Restore before potential upstack delivery */
|
||||
} else {
|
||||
/* Randomise final delay in [D , D*Spread], step D */
|
||||
fwd_spread = SMRF_INTERVAL_COUNT;
|
||||
if(fwd_spread > SMRF_MAX_SPREAD) {
|
||||
fwd_spread = SMRF_MAX_SPREAD;
|
||||
}
|
||||
if(fwd_spread) {
|
||||
fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread));
|
||||
}
|
||||
|
||||
memcpy(&mcast_buf, uip_buf, uip_len);
|
||||
mcast_len = uip_len;
|
||||
ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL);
|
||||
}
|
||||
PRINTF("SMRF: %u bytes: fwd in %u [%u]\n",
|
||||
uip_len, fwd_delay, fwd_spread);
|
||||
}
|
||||
|
||||
/* Done with this packet unless we are a member of the mcast group */
|
||||
if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("SMRF: Not a group member. No further processing\n");
|
||||
return UIP_MCAST6_DROP;
|
||||
} else {
|
||||
PRINTF("SMRF: Ours. Deliver to upper layers\n");
|
||||
UIP_MCAST6_STATS_ADD(mcast_in_ours);
|
||||
return UIP_MCAST6_ACCEPT;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
init()
|
||||
{
|
||||
UIP_MCAST6_STATS_INIT(NULL);
|
||||
|
||||
uip_mcast6_route_init();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
out()
|
||||
{
|
||||
return;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
const struct uip_mcast6_driver smrf_driver = {
|
||||
"SMRF",
|
||||
init,
|
||||
out,
|
||||
in,
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* UIP_CONF_IPV6 */
|
75
core/net/ipv6/multicast/smrf.h
Normal file
75
core/net/ipv6/multicast/smrf.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Header file for 'Stateless Multicast RPL Forwarding' (SMRF)
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#ifndef SMRF_H_
|
||||
#define SMRF_H_
|
||||
|
||||
#include "contiki-conf.h"
|
||||
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Configuration */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Fmin */
|
||||
#ifdef SMRF_CONF_MIN_FWD_DELAY
|
||||
#define SMRF_MIN_FWD_DELAY SMRF_CONF_MIN_FWD_DELAY
|
||||
#else
|
||||
#define SMRF_MIN_FWD_DELAY 4
|
||||
#endif
|
||||
|
||||
/* Max Spread */
|
||||
#ifdef SMRF_CONF_MAX_SPREAD
|
||||
#define SMRF_MAX_SPREAD SMRF_CONF_MAX_SPREAD
|
||||
#else
|
||||
#define SMRF_MAX_SPREAD 4
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Stats datatype */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct smrf_stats {
|
||||
uint16_t mcast_in_unique;
|
||||
uint16_t mcast_in_all; /* At layer 3 */
|
||||
uint16_t mcast_in_ours; /* Unique and we are a group member */
|
||||
uint16_t mcast_fwd; /* Forwarded by us but we are not the seed */
|
||||
uint16_t mcast_out; /* We are the seed */
|
||||
uint16_t mcast_bad;
|
||||
uint16_t mcast_dropped;
|
||||
};
|
||||
|
||||
#endif /* SMRF_H_ */
|
50
core/net/ipv6/multicast/uip-mcast6-engines.h
Normal file
50
core/net/ipv6/multicast/uip-mcast6-engines.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Header file with definition of multicast engine constants
|
||||
*
|
||||
* When writing a new engine, add it here with a unique number and
|
||||
* then modify uip-mcast6.h accordingly
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#ifndef UIP_MCAST6_ENGINES_H_
|
||||
#define UIP_MCAST6_ENGINES_H_
|
||||
|
||||
#define UIP_MCAST6_ENGINE_NONE 0 /* Selecting this disables mcast */
|
||||
#define UIP_MCAST6_ENGINE_SMRF 1
|
||||
#define UIP_MCAST6_ENGINE_ROLL_TM 2
|
||||
|
||||
#endif /* UIP_MCAST6_ENGINES_H_ */
|
133
core/net/ipv6/multicast/uip-mcast6-route.c
Normal file
133
core/net/ipv6/multicast/uip-mcast6-route.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - 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 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.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Multicast routing table manipulation
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/memb.h"
|
||||
#include "net/ip/uip.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-route.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if UIP_CONF_IPV6
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Size of the multicast routing table */
|
||||
#ifdef UIP_MCAST6_ROUTE_CONF_ROUTES
|
||||
#define UIP_MCAST6_ROUTE_ROUTES UIP_MCAST6_ROUTE_CONF_ROUTES
|
||||
#else
|
||||
#define UIP_MCAST6_ROUTE_ROUTES 1
|
||||
#endif /* UIP_CONF_DS6_MCAST_ROUTES */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
LIST(mcast_route_list);
|
||||
MEMB(mcast_route_memb, uip_mcast6_route_t, UIP_MCAST6_ROUTE_ROUTES);
|
||||
|
||||
static uip_mcast6_route_t *locmcastrt;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_mcast6_route_t *
|
||||
uip_mcast6_route_lookup(uip_ipaddr_t *group)
|
||||
{
|
||||
locmcastrt = NULL;
|
||||
for(locmcastrt = list_head(mcast_route_list);
|
||||
locmcastrt != NULL;
|
||||
locmcastrt = list_item_next(locmcastrt)) {
|
||||
if(uip_ipaddr_cmp(&locmcastrt->group, group)) {
|
||||
return locmcastrt;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_mcast6_route_t *
|
||||
uip_mcast6_route_add(uip_ipaddr_t *group)
|
||||
{
|
||||
/* _lookup must return NULL, i.e. the prefix does not exist in our table */
|
||||
locmcastrt = uip_mcast6_route_lookup(group);
|
||||
if(locmcastrt == NULL) {
|
||||
/* Allocate an entry and add the group to the list */
|
||||
locmcastrt = memb_alloc(&mcast_route_memb);
|
||||
if(locmcastrt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
list_add(mcast_route_list, locmcastrt);
|
||||
}
|
||||
|
||||
/* Reaching here means we either found the prefix or allocated a new one */
|
||||
|
||||
uip_ipaddr_copy(&(locmcastrt->group), group);
|
||||
|
||||
return locmcastrt;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_mcast6_route_rm(uip_mcast6_route_t *route)
|
||||
{
|
||||
/* Make sure it's actually in the list */
|
||||
for(locmcastrt = list_head(mcast_route_list);
|
||||
locmcastrt != NULL;
|
||||
locmcastrt = list_item_next(locmcastrt)) {
|
||||
if(locmcastrt == route) {
|
||||
list_remove(mcast_route_list, route);
|
||||
memb_free(&mcast_route_memb, route);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_mcast6_route_t *
|
||||
uip_mcast6_route_list_head(void)
|
||||
{
|
||||
return list_head(mcast_route_list);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
uip_mcast6_route_count(void)
|
||||
{
|
||||
return list_length(mcast_route_list);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_mcast6_route_init()
|
||||
{
|
||||
memb_init(&mcast_route_memb);
|
||||
list_init(mcast_route_list);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* UIP_CONF_IPV6 */
|
75
core/net/ipv6/multicast/uip-mcast6-route.h
Normal file
75
core/net/ipv6/multicast/uip-mcast6-route.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - 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 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.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Multicast routing table manipulation
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
#ifndef UIP_MCAST6_ROUTE_H_
|
||||
#define UIP_MCAST6_ROUTE_H_
|
||||
|
||||
#include "contiki.h"
|
||||
#include "net/ip/uip.h"
|
||||
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \brief An entry in the multicast routing table */
|
||||
typedef struct uip_mcast6_route {
|
||||
struct uip_mcast6_route *next;
|
||||
uip_ipaddr_t group;
|
||||
uint32_t lifetime; /* seconds */
|
||||
void *dag; /* Pointer to an rpl_dag_t struct */
|
||||
} uip_mcast6_route_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \name Multicast Routing Table Manipulation */
|
||||
/** @{ */
|
||||
uip_mcast6_route_t *uip_mcast6_route_lookup(uip_ipaddr_t *group);
|
||||
uip_mcast6_route_t *uip_mcast6_route_add(uip_ipaddr_t *group);
|
||||
void uip_mcast6_route_rm(uip_mcast6_route_t *defrt);
|
||||
int uip_mcast6_route_count(void);
|
||||
uip_mcast6_route_t *uip_mcast6_route_list_head(void);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Multicast routing table init routine
|
||||
*
|
||||
* Multicast routing tables are not necessarily required by all
|
||||
* multicast engines. For instance, trickle multicast does not rely on
|
||||
* the existence of a routing table. Therefore, this function here
|
||||
* should be invoked by each engine's init routine only if the relevant
|
||||
* functionality is required. This is also why this function should not
|
||||
* get hooked into the uip-ds6 core.
|
||||
*/
|
||||
void uip_mcast6_route_init(void);
|
||||
/** @} */
|
||||
|
||||
#endif /* UIP_MCAST6_ROUTE_H_ */
|
49
core/net/ipv6/multicast/uip-mcast6-stats.c
Normal file
49
core/net/ipv6/multicast/uip-mcast6-stats.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2014, University of Bristol - http://www.bris.ac.uk
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* IPv6 multicast forwarding stats maintenance
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
#include "net/ipv6/multicast/uip-mcast6-stats.h"
|
||||
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_mcast6_stats_t uip_mcast6_stats;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_mcast6_stats_init(void *stats)
|
||||
{
|
||||
memset(&uip_mcast6_stats, 0, sizeof(uip_mcast6_stats));
|
||||
uip_mcast6_stats.engine_stats = stats;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
91
core/net/ipv6/multicast/uip-mcast6-stats.h
Normal file
91
core/net/ipv6/multicast/uip-mcast6-stats.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2014, University of Bristol - http://www.bris.ac.uk
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Header file for IPv6 multicast forwarding stats maintenance
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
#ifndef UIP_MCAST6_STATS_H_
|
||||
#define UIP_MCAST6_STATS_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki-conf.h"
|
||||
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* The platform can override the stats datatype */
|
||||
#ifdef UIP_MCAST6_CONF_STATS_DATATYPE
|
||||
#define UIP_MCAST6_STATS_DATATYPE UIP_MCAST6_CONF_STATS_DATATYPE
|
||||
#else
|
||||
#define UIP_MCAST6_STATS_DATATYPE uint16_t
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef UIP_MCAST6_CONF_STATS
|
||||
#define UIP_MCAST6_STATS UIP_MCAST6_CONF_STATS
|
||||
#else
|
||||
#define UIP_MCAST6_STATS 0
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Stats datatype */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef struct uip_mcast6_stats {
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_in_unique;
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_in_all; /* At layer 3 */
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_in_ours; /* Unique and we are a group member */
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_fwd; /* Forwarded by us but we are not the seed */
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_out; /* We are the seed */
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_bad;
|
||||
UIP_MCAST6_STATS_DATATYPE mcast_dropped;
|
||||
void *engine_stats; /* Opaque pointer to an engine's additional stats */
|
||||
} uip_mcast6_stats_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Access macros */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_MCAST6_STATS
|
||||
/* Don't access this variable directly, use the macros below */
|
||||
extern uip_mcast6_stats_t uip_mcast6_stats;
|
||||
|
||||
#define UIP_MCAST6_STATS_ADD(x) uip_mcast6_stats.x++
|
||||
#define UIP_MCAST6_STATS_GET(x) uip_mcast6_stats.x
|
||||
#define UIP_MCAST6_STATS_INIT(s) uip_mcast6_stats_init(s)
|
||||
#else /* UIP_MCAST6_STATS */
|
||||
#define UIP_MCAST6_STATS_ADD(x)
|
||||
#define UIP_MCAST6_STATS_GET(x) 0
|
||||
#define UIP_MCAST6_STATS_INIT(s)
|
||||
#endif /* UIP_MCAST6_STATS */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise multicast stats
|
||||
* \param stats A pointer to a struct holding an engine's additional statistics
|
||||
*/
|
||||
void uip_mcast6_stats_init(void *stats);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* UIP_MCAST6_STATS_H_ */
|
162
core/net/ipv6/multicast/uip-mcast6.h
Normal file
162
core/net/ipv6/multicast/uip-mcast6.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Loughborough University - Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This header file contains configuration directives for uIPv6
|
||||
* multicast support.
|
||||
*
|
||||
* We currently support 2 engines:
|
||||
* - 'Stateless Multicast RPL Forwarding' (SMRF)
|
||||
* RPL does group management as per the RPL docs, SMRF handles datagram
|
||||
* forwarding
|
||||
* - 'Multicast Forwarding with Trickle' according to the algorithm described
|
||||
* in the internet draft:
|
||||
* http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast
|
||||
*
|
||||
* \author
|
||||
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
#ifndef UIP_MCAST6_H_
|
||||
#define UIP_MCAST6_H_
|
||||
|
||||
#include "contiki-conf.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-engines.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6-route.h"
|
||||
#include "net/ipv6/multicast/smrf.h"
|
||||
#include "net/ipv6/multicast/roll-tm.h"
|
||||
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Constants */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define UIP_MCAST6_DROP 0
|
||||
#define UIP_MCAST6_ACCEPT 1
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Multicast Address Scopes (RFC 4291 & draft-ietf-6man-multicast-scopes) */
|
||||
#define UIP_MCAST6_SCOPE_INTERFACE 0x01
|
||||
#define UIP_MCAST6_SCOPE_LINK_LOCAL 0x02
|
||||
#define UIP_MCAST6_SCOPE_REALM_LOCAL 0x03 /* draft-ietf-6man-multicast-scopes */
|
||||
#define UIP_MCAST6_SCOPE_ADMIN_LOCAL 0x04
|
||||
#define UIP_MCAST6_SCOPE_SITE_LOCAL 0x05
|
||||
#define UIP_MCAST6_SCOPE_ORG_LOCAL 0x08
|
||||
#define UIP_MCAST6_SCOPE_GLOBAL 0x0E
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Choose an engine or turn off based on user configuration */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef UIP_MCAST6_CONF_ENGINE
|
||||
#define UIP_MCAST6_ENGINE UIP_MCAST6_CONF_ENGINE
|
||||
#else
|
||||
#define UIP_MCAST6_ENGINE UIP_MCAST6_ENGINE_NONE
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Multicast API. Similar to NETSTACK, each engine must define a driver and
|
||||
* populate the fields with suitable function pointers
|
||||
*/
|
||||
struct uip_mcast6_driver {
|
||||
char *name;
|
||||
|
||||
/** Initialize the multicast engine */
|
||||
void (* init)(void);
|
||||
|
||||
/**
|
||||
* \brief Process an outgoing datagram with a multicast IPv6 destination
|
||||
* address
|
||||
*
|
||||
* This may be needed if the multicast engine needs to, for example,
|
||||
* add IPv6 extension headers to the datagram, cache it, decide it
|
||||
* needs dropped etc.
|
||||
*
|
||||
* It is sometimes desirable to let the engine handle datagram
|
||||
* dispatch instead of letting the networking core do it. If the
|
||||
* engine decides to send the datagram itself, it must afterwards
|
||||
* set uip_len = 0 to prevent the networking core from sending too
|
||||
*/
|
||||
void (* out)(void);
|
||||
|
||||
/**
|
||||
* \brief Process an incoming multicast datagram and determine whether it
|
||||
* should be delivered up the stack or not.
|
||||
*
|
||||
* \return 0: Drop, 1: Deliver
|
||||
*
|
||||
* When a datagram with a multicast destination address is received,
|
||||
* the forwarding logic in core is bypassed. Instead, we let the
|
||||
* multicast engine handle forwarding internally if and as necessary.
|
||||
* This function is where forwarding logic must be hooked in.
|
||||
*
|
||||
* Once the engine is done with forwarding, it must signal via the
|
||||
* return value whether the datagram needs delivered up the network
|
||||
* stack.
|
||||
*/
|
||||
uint8_t (* in)(void);
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Get a multicast address' scope.
|
||||
* a is of type uip_ip6addr_t*
|
||||
*/
|
||||
#define uip_mcast6_get_address_scope(a) ((a)->u8[1] & 0x0F)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Configure multicast and core/net to play nicely with the selected engine */
|
||||
#if UIP_MCAST6_ENGINE
|
||||
|
||||
/* Enable Multicast hooks in the uip6 core */
|
||||
#define UIP_CONF_IPV6_MULTICAST 1
|
||||
|
||||
#if UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_ROLL_TM
|
||||
#define RPL_CONF_MULTICAST 0 /* Not used by trickle */
|
||||
#define UIP_CONF_IPV6_ROLL_TM 1 /* ROLL Trickle ICMP type support */
|
||||
|
||||
#define UIP_MCAST6 roll_tm_driver
|
||||
#elif UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_SMRF
|
||||
#define RPL_CONF_MULTICAST 1
|
||||
|
||||
#define UIP_MCAST6 smrf_driver
|
||||
#else
|
||||
#error "Multicast Enabled with an Unknown Engine."
|
||||
#error "Check the value of UIP_MCAST6_CONF_ENGINE in conf files."
|
||||
#endif
|
||||
#endif /* UIP_MCAST6_ENGINE */
|
||||
|
||||
extern const struct uip_mcast6_driver UIP_MCAST6;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Configuration Checks */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if RPL_CONF_MULTICAST && (!UIP_CONF_IPV6_RPL)
|
||||
#error "The selected Multicast mode requires UIP_CONF_IPV6_RPL != 0"
|
||||
#error "Check the value of UIP_CONF_IPV6_RPL in conf files."
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* UIP_MCAST6_H_ */
|
|
@ -512,6 +512,10 @@ uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
|
|||
}
|
||||
}
|
||||
}
|
||||
#if UIP_IPV6_MULTICAST
|
||||
} else if(uip_is_addr_mcast_routable(dst)) {
|
||||
matchaddr = uip_ds6_get_global(ADDR_PREFERRED);
|
||||
#endif
|
||||
} else {
|
||||
matchaddr = uip_ds6_get_link_local(ADDR_PREFERRED);
|
||||
}
|
||||
|
|
|
@ -74,10 +74,53 @@
|
|||
static uip_ipaddr_t tmp_ipaddr;
|
||||
|
||||
LIST(echo_reply_callback_list);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* List of input handlers */
|
||||
LIST(input_handler_list);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uip_icmp6_input_handler_t *
|
||||
input_handler_lookup(uint8_t type, uint8_t icode)
|
||||
{
|
||||
uip_icmp6_input_handler_t *handler = NULL;
|
||||
|
||||
for(handler = list_head(input_handler_list);
|
||||
handler != NULL;
|
||||
handler = list_item_next(handler)) {
|
||||
if(handler->type == type &&
|
||||
(handler->icode == icode ||
|
||||
handler->icode == UIP_ICMP6_HANDLER_CODE_ANY)) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
uip_icmp6_input(uint8_t type, uint8_t icode)
|
||||
{
|
||||
uip_icmp6_input_handler_t *handler = input_handler_lookup(type, icode);
|
||||
|
||||
if(handler == NULL) {
|
||||
return UIP_ICMP6_INPUT_ERROR;
|
||||
}
|
||||
|
||||
if(handler->handler == NULL) {
|
||||
return UIP_ICMP6_INPUT_ERROR;
|
||||
}
|
||||
|
||||
handler->handler();
|
||||
return UIP_ICMP6_INPUT_SUCCESS;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_icmp6_echo_request_input(void)
|
||||
uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
|
||||
{
|
||||
list_add(input_handler_list, handler);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
echo_request_input(void)
|
||||
{
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
uint8_t temp_ext_len;
|
||||
|
@ -275,8 +318,8 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
|
|||
tcpip_ipv6_output();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_icmp6_echo_reply_input(void)
|
||||
static void
|
||||
echo_reply_input(void)
|
||||
{
|
||||
int ttl;
|
||||
uip_ipaddr_t sender;
|
||||
|
@ -343,6 +386,8 @@ uip_icmp6_echo_reply_input(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -362,5 +407,18 @@ uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n)
|
|||
list_remove(echo_reply_callback_list, n);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UIP_ICMP6_HANDLER(echo_request_handler, ICMP6_ECHO_REQUEST,
|
||||
UIP_ICMP6_HANDLER_CODE_ANY, echo_request_input);
|
||||
UIP_ICMP6_HANDLER(echo_reply_handler, ICMP6_ECHO_REPLY,
|
||||
UIP_ICMP6_HANDLER_CODE_ANY, echo_reply_input);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_icmp6_init()
|
||||
{
|
||||
/* Register Echo Request and Reply handlers */
|
||||
uip_icmp6_register_input_handler(&echo_request_handler);
|
||||
uip_icmp6_register_input_handler(&echo_reply_handler);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
#define ICMP6_REDIRECT 137 /**< Redirect */
|
||||
|
||||
#define ICMP6_RPL 155 /**< RPL */
|
||||
#define ICMP6_PRIV_EXP_100 100 /**< Private Experimentation */
|
||||
#define ICMP6_PRIV_EXP_101 101 /**< Private Experimentation */
|
||||
#define ICMP6_PRIV_EXP_200 200 /**< Private Experimentation */
|
||||
#define ICMP6_PRIV_EXP_201 201 /**< Private Experimentation */
|
||||
#define ICMP6_ROLL_TM ICMP6_PRIV_EXP_200 /**< ROLL Trickle Multicast */
|
||||
/** @} */
|
||||
|
||||
|
||||
|
@ -104,24 +109,6 @@ typedef struct uip_icmp6_error{
|
|||
|
||||
/** \name ICMPv6 RFC4443 Message processing and sending */
|
||||
/** @{ */
|
||||
/** \
|
||||
* brief Process an echo request
|
||||
*
|
||||
* Perform a few checks, then send an Echo reply. The reply is
|
||||
* built here.
|
||||
*/
|
||||
void
|
||||
uip_icmp6_echo_request_input(void);
|
||||
|
||||
/** \
|
||||
* brief Process an echo reply
|
||||
*
|
||||
* Perform a few checks, then call applications to inform that an echo
|
||||
* reply has been received.
|
||||
*/
|
||||
void
|
||||
uip_icmp6_echo_reply_input(void);
|
||||
|
||||
/**
|
||||
* \brief Send an icmpv6 error message
|
||||
* \param type type of the error message
|
||||
|
@ -187,8 +174,66 @@ uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n,
|
|||
void
|
||||
uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n);
|
||||
|
||||
/* Generic ICMPv6 input handers */
|
||||
typedef struct uip_icmp6_input_handler {
|
||||
struct uip_icmp6_input_handler *next;
|
||||
uint8_t type;
|
||||
uint8_t icode;
|
||||
void (*handler)(void);
|
||||
} uip_icmp6_input_handler_t;
|
||||
|
||||
#define UIP_ICMP6_INPUT_SUCCESS 0
|
||||
#define UIP_ICMP6_INPUT_ERROR 1
|
||||
|
||||
#define UIP_ICMP6_HANDLER_CODE_ANY 0xFF /* Handle all codes for this type */
|
||||
|
||||
/*
|
||||
* Initialise a variable of type uip_icmp6_input_handler, to be used later as
|
||||
* the argument to uip_icmp6_register_input_handler
|
||||
*
|
||||
* The function pointer stored in this variable will get called and will be
|
||||
* expected to handle incoming ICMPv6 datagrams of the specified type/code
|
||||
*
|
||||
* If code has a value of UIP_ICMP6_HANDLER_CODE_ANY, the same function
|
||||
* will handle all codes for this type. In other words, the ICMPv6
|
||||
* message's code is "don't care"
|
||||
*/
|
||||
#define UIP_ICMP6_HANDLER(name, type, code, func) \
|
||||
static uip_icmp6_input_handler_t name = { NULL, type, code, func }
|
||||
|
||||
/**
|
||||
* \brief Handle an incoming ICMPv6 message
|
||||
* \param type The ICMPv6 message type
|
||||
* \param icode The ICMPv6 message code
|
||||
* \return Success: UIP_ICMP6_INPUT_SUCCESS, Error: UIP_ICMP6_INPUT_ERROR
|
||||
*
|
||||
* Generic handler for unknown ICMPv6 types. It will lookup for a registered
|
||||
* function capable of handing this message type. The function must have first
|
||||
* been registered with uip_icmp6_register_input_handler. The function is in
|
||||
* charge of setting uip_len to 0, otherwise the uIPv6 core will attempt to
|
||||
* send whatever remains in the UIP_IP_BUF.
|
||||
*
|
||||
* A return value of UIP_ICMP6_INPUT_ERROR means that a handler could not be
|
||||
* invoked. This is most likely because the ICMPv6 type does not have a valid
|
||||
* handler associated with it.
|
||||
|
||||
* UIP_ICMP6_INPUT_SUCCESS signifies that a handler was found for this ICMPv6
|
||||
* type and that it was invoked. It does NOT provide any indication whatsoever
|
||||
* regarding whether the handler itself succeeded.
|
||||
*/
|
||||
uint8_t uip_icmp6_input(uint8_t type, uint8_t icode);
|
||||
|
||||
/**
|
||||
* \brief Register a handler which can handle a specific ICMPv6 message type
|
||||
* \param handler A pointer to the handler
|
||||
*/
|
||||
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Initialise the uIP ICMPv6 core
|
||||
*/
|
||||
void uip_icmp6_init(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -126,8 +126,6 @@ static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
|
|||
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
|
||||
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
|
||||
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* create a llao */
|
||||
static void
|
||||
|
@ -143,8 +141,8 @@ create_llao(uint8_t *llao, uint8_t type) {
|
|||
/*------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void
|
||||
uip_nd6_ns_input(void)
|
||||
static void
|
||||
ns_input(void)
|
||||
{
|
||||
uint8_t flags;
|
||||
PRINTF("Received NS from ");
|
||||
|
@ -388,12 +386,26 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
|
|||
PRINTF("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
void
|
||||
uip_nd6_na_input(void)
|
||||
/**
|
||||
* Neighbor Advertisement Processing
|
||||
*
|
||||
* we might have to send a pkt that had been buffered while address
|
||||
* resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT)
|
||||
*
|
||||
* As per RFC 4861, on link layer that have addresses, TLLAO options MUST be
|
||||
* included when responding to multicast solicitations, SHOULD be included in
|
||||
* response to unicast (here we assume it is for now)
|
||||
*
|
||||
* NA can be received after sending NS for DAD, Address resolution or NUD. Can
|
||||
* be unsolicited as well.
|
||||
* It can trigger update of the state of the neighbor in the neighbor cache,
|
||||
* router in the router list.
|
||||
* If the NS was for DAD, it means DAD failed
|
||||
*
|
||||
*/
|
||||
static void
|
||||
na_input(void)
|
||||
{
|
||||
uint8_t is_llchange;
|
||||
uint8_t is_router;
|
||||
|
@ -548,8 +560,8 @@ discard:
|
|||
#if UIP_CONF_ROUTER
|
||||
#if UIP_ND6_SEND_RA
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_nd6_rs_input(void)
|
||||
static void
|
||||
rs_input(void)
|
||||
{
|
||||
|
||||
PRINTF("Received RS from");
|
||||
|
@ -761,11 +773,18 @@ uip_nd6_rs_output(void)
|
|||
PRINTF("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Process a Router Advertisement
|
||||
*
|
||||
* - Possible actions when receiving a RA: add router to router list,
|
||||
* recalculate reachable time, update link hop limit, update retrans timer.
|
||||
* - If MTU option: update MTU.
|
||||
* - If SLLAO option: update entry in neighbor cache
|
||||
* - If prefix option: start autoconf, add prefix to prefix list
|
||||
*/
|
||||
void
|
||||
uip_nd6_ra_input(void)
|
||||
ra_input(void)
|
||||
{
|
||||
PRINTF("Received RA from");
|
||||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
|
@ -969,6 +988,52 @@ discard:
|
|||
return;
|
||||
}
|
||||
#endif /* !UIP_CONF_ROUTER */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ICMPv6 input handlers */
|
||||
#if UIP_ND6_SEND_NA
|
||||
UIP_ICMP6_HANDLER(ns_input_handler, ICMP6_NS, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||
ns_input);
|
||||
UIP_ICMP6_HANDLER(na_input_handler, ICMP6_NA, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||
na_input);
|
||||
#endif
|
||||
|
||||
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
||||
UIP_ICMP6_HANDLER(rs_input_handler, ICMP6_RS, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||
rs_input);
|
||||
#endif
|
||||
|
||||
#if !UIP_CONF_ROUTER
|
||||
UIP_ICMP6_HANDLER(ra_input_handler, ICMP6_RA, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||
ra_input);
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_nd6_init()
|
||||
{
|
||||
|
||||
#if UIP_ND6_SEND_NA
|
||||
/* Only handle NSs if we are prepared to send out NAs */
|
||||
uip_icmp6_register_input_handler(&ns_input_handler);
|
||||
|
||||
/*
|
||||
* Only handle NAs if we are prepared to send out NAs.
|
||||
* This is perhaps logically incorrect, but this condition was present in
|
||||
* uip_process and we keep it until proven wrong
|
||||
*/
|
||||
uip_icmp6_register_input_handler(&na_input_handler);
|
||||
#endif
|
||||
|
||||
|
||||
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
||||
/* Only accept RS if we are a router and happy to send out RAs */
|
||||
uip_icmp6_register_input_handler(&rs_input_handler);
|
||||
#endif
|
||||
|
||||
#if !UIP_CONF_ROUTER
|
||||
/* Only process RAs if we are not a router */
|
||||
uip_icmp6_register_input_handler(&ra_input_handler);
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
|
|
@ -337,34 +337,8 @@ uip_nd6_ns_input(void);
|
|||
void
|
||||
uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt);
|
||||
|
||||
/**
|
||||
* \brief Process a Neighbor Advertisement
|
||||
*
|
||||
* we might have to send a pkt that had been buffered while address
|
||||
* resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT)
|
||||
*
|
||||
* As per RFC 4861, on link layer that have addresses, TLLAO options MUST be
|
||||
* included when responding to multicast solicitations, SHOULD be included in
|
||||
* response to unicast (here we assume it is for now)
|
||||
*
|
||||
* NA can be received after sending NS for DAD, Address resolution or NUD. Can
|
||||
* be unsolicited as well.
|
||||
* It can trigger update of the state of the neighbor in the neighbor cache,
|
||||
* router in the router list.
|
||||
* If the NS was for DAD, it means DAD failed
|
||||
*
|
||||
*/
|
||||
void
|
||||
uip_nd6_na_input(void);
|
||||
|
||||
#if UIP_CONF_ROUTER
|
||||
#if UIP_ND6_SEND_RA
|
||||
/**
|
||||
* \brief Process a Router Solicitation
|
||||
*
|
||||
*/
|
||||
void uip_nd6_rs_input(void);
|
||||
|
||||
/**
|
||||
* \brief send a Router Advertisement
|
||||
*
|
||||
|
@ -388,17 +362,9 @@ void uip_nd6_ra_output(uip_ipaddr_t *dest);
|
|||
void uip_nd6_rs_output(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* \brief process a Router Advertisement
|
||||
*
|
||||
* - Possible actions when receiving a RA: add router to router list,
|
||||
* recalculate reachable time, update link hop limit, update retrans timer.
|
||||
* - If MTU option: update MTU.
|
||||
* - If SLLAO option: update entry in neighbor cache
|
||||
* - If prefix option: start autoconf, add prefix to prefix list
|
||||
* \brief Initialise the uIP ND core
|
||||
*/
|
||||
void
|
||||
uip_nd6_ra_input(void);
|
||||
void uip_nd6_init(void);
|
||||
/** @} */
|
||||
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/ipv6/uip-nd6.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -410,6 +411,8 @@ uip_init(void)
|
|||
{
|
||||
|
||||
uip_ds6_init();
|
||||
uip_icmp6_init();
|
||||
uip_nd6_init();
|
||||
|
||||
#if UIP_TCP
|
||||
for(c = 0; c < UIP_LISTENPORTS; ++c) {
|
||||
|
@ -429,6 +432,10 @@ uip_init(void)
|
|||
uip_udp_conns[c].lport = 0;
|
||||
}
|
||||
#endif /* UIP_UDP */
|
||||
|
||||
#if UIP_CONF_IPV6_MULTICAST
|
||||
UIP_MCAST6.init();
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_TCP && UIP_ACTIVE_OPEN
|
||||
|
@ -1151,6 +1158,28 @@ uip_process(uint8_t flag)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process Packets with a routable multicast destination:
|
||||
* - We invoke the multicast engine and let it do its thing
|
||||
* (cache, forward etc).
|
||||
* - We never execute the datagram forwarding logic in this file here. When
|
||||
* the engine returns, forwarding has been handled if and as required.
|
||||
* - Depending on the return value, we either discard or deliver up the stack
|
||||
*
|
||||
* All multicast engines must hook in here. After this function returns, we
|
||||
* expect UIP_BUF to be unmodified
|
||||
*/
|
||||
#if UIP_CONF_IPV6_MULTICAST
|
||||
if(uip_is_addr_mcast_routable(&UIP_IP_BUF->destipaddr)) {
|
||||
if(UIP_MCAST6.in() == UIP_MCAST6_ACCEPT) {
|
||||
/* Deliver up the stack */
|
||||
goto process;
|
||||
} else {
|
||||
/* Don't deliver up the stack */
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
#endif /* UIP_IPV6_CONF_MULTICAST */
|
||||
|
||||
/* TBD Some Parameter problem messages */
|
||||
if(!uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr) &&
|
||||
|
@ -1220,6 +1249,10 @@ uip_process(uint8_t flag)
|
|||
uip_ext_bitmap = 0;
|
||||
#endif /* UIP_CONF_ROUTER */
|
||||
|
||||
#if UIP_CONF_IPV6_MULTICAST
|
||||
process:
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
switch(*uip_next_hdr){
|
||||
#if UIP_TCP
|
||||
|
@ -1389,61 +1422,17 @@ uip_process(uint8_t flag)
|
|||
UIP_ICMP6_APPCALL(UIP_ICMP_BUF->type);
|
||||
#endif /*UIP_CONF_ICMP6*/
|
||||
|
||||
switch(UIP_ICMP_BUF->type) {
|
||||
case ICMP6_NS:
|
||||
#if UIP_ND6_SEND_NA
|
||||
uip_nd6_ns_input();
|
||||
#else /* UIP_ND6_SEND_NA */
|
||||
UIP_STAT(++uip_stat.icmp.drop);
|
||||
uip_len = 0;
|
||||
#endif /* UIP_ND6_SEND_NA */
|
||||
break;
|
||||
case ICMP6_NA:
|
||||
#if UIP_ND6_SEND_NA
|
||||
uip_nd6_na_input();
|
||||
#else /* UIP_ND6_SEND_NA */
|
||||
UIP_STAT(++uip_stat.icmp.drop);
|
||||
uip_len = 0;
|
||||
#endif /* UIP_ND6_SEND_NA */
|
||||
break;
|
||||
case ICMP6_RS:
|
||||
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
||||
uip_nd6_rs_input();
|
||||
#else /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */
|
||||
/*
|
||||
* Search generic input handlers.
|
||||
* The handler is in charge of setting uip_len to 0
|
||||
*/
|
||||
if(uip_icmp6_input(UIP_ICMP_BUF->type,
|
||||
UIP_ICMP_BUF->icode) == UIP_ICMP6_INPUT_ERROR) {
|
||||
PRINTF("Unknown ICMPv6 message type/code %d\n", UIP_ICMP_BUF->type);
|
||||
UIP_STAT(++uip_stat.icmp.drop);
|
||||
UIP_STAT(++uip_stat.icmp.typeerr);
|
||||
UIP_LOG("icmp6: unknown ICMPv6 message.");
|
||||
uip_len = 0;
|
||||
#endif /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */
|
||||
break;
|
||||
case ICMP6_RA:
|
||||
#if UIP_CONF_ROUTER
|
||||
UIP_STAT(++uip_stat.icmp.drop);
|
||||
uip_len = 0;
|
||||
#else /* UIP_CONF_ROUTER */
|
||||
uip_nd6_ra_input();
|
||||
#endif /* UIP_CONF_ROUTER */
|
||||
break;
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
case ICMP6_RPL:
|
||||
uip_rpl_input();
|
||||
break;
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
case ICMP6_ECHO_REQUEST:
|
||||
uip_icmp6_echo_request_input();
|
||||
break;
|
||||
case ICMP6_ECHO_REPLY:
|
||||
/** Call echo reply input function. */
|
||||
uip_icmp6_echo_reply_input();
|
||||
PRINTF("Received an icmp6 echo reply\n");
|
||||
UIP_STAT(++uip_stat.icmp.recv);
|
||||
uip_len = 0;
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unknown icmp6 message type %d\n", UIP_ICMP_BUF->type);
|
||||
UIP_STAT(++uip_stat.icmp.drop);
|
||||
UIP_STAT(++uip_stat.icmp.typeerr);
|
||||
UIP_LOG("icmp6: unknown ICMP message.");
|
||||
uip_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(uip_len > 0) {
|
||||
|
|
|
@ -212,16 +212,17 @@ packet_sent(void *ptr, int status, int num_transmissions)
|
|||
switch(status) {
|
||||
case MAC_TX_OK:
|
||||
case MAC_TX_NOACK:
|
||||
n->transmissions++;
|
||||
n->transmissions += num_transmissions;
|
||||
break;
|
||||
case MAC_TX_COLLISION:
|
||||
n->collisions++;
|
||||
n->collisions += num_transmissions;
|
||||
break;
|
||||
case MAC_TX_DEFERRED:
|
||||
n->deferrals++;
|
||||
n->deferrals += num_transmissions;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find out what packet this callback refers to */
|
||||
for(q = list_head(n->queued_packet_list);
|
||||
q != NULL; q = list_item_next(q)) {
|
||||
if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
* Logic for Directed Acyclic Graphs in RPL.
|
||||
*
|
||||
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
|
||||
* Contributors: George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
|
||||
*/
|
||||
|
||||
|
||||
|
@ -46,6 +47,7 @@
|
|||
#include "net/ip/uip.h"
|
||||
#include "net/ipv6/uip-nd6.h"
|
||||
#include "net/nbr-table.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/memb.h"
|
||||
#include "sys/ctimer.h"
|
||||
|
@ -985,7 +987,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
instance->dio_redundancy != dio->dag_redund ||
|
||||
instance->default_lifetime != dio->default_lifetime ||
|
||||
instance->lifetime_unit != dio->lifetime_unit) {
|
||||
PRINTF("RPL: DIO for DAG instance %u uncompatible with previos DIO\n",
|
||||
PRINTF("RPL: DIO for DAG instance %u incompatible with previous DIO\n",
|
||||
dio->instance_id);
|
||||
rpl_remove_parent(p);
|
||||
dag->used = 0;
|
||||
|
@ -1147,7 +1149,13 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
rpl_dag_t *dag, *previous_dag;
|
||||
rpl_parent_t *p;
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
/* If the root is advertising MOP 2 but we support MOP 3 we can still join
|
||||
* In that scenario, we suppress DAOs for multicast targets */
|
||||
if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) {
|
||||
#else
|
||||
if(dio->mop != RPL_MOP_DEFAULT) {
|
||||
#endif
|
||||
PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
|
||||
return;
|
||||
}
|
||||
|
@ -1163,7 +1171,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
RPL_LOLLIPOP_INCREMENT(dag->version);
|
||||
rpl_reset_dio_timer(instance);
|
||||
} else {
|
||||
PRINTF("RPL: Global Repair\n");
|
||||
PRINTF("RPL: Global repair\n");
|
||||
if(dio->prefix_info.length != 0) {
|
||||
if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
|
||||
PRINTF("RPL : Prefix announced in DIO\n");
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
|
||||
* Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund <joel@sics.se>,
|
||||
* Mathieu Pouillot <m.pouillot@watteco.com>
|
||||
* George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
|
||||
*/
|
||||
|
||||
#include "net/ip/tcpip.h"
|
||||
|
@ -49,6 +50,7 @@
|
|||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/packetbuf.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
@ -86,6 +88,15 @@ static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
|||
|
||||
extern rpl_of_t RPL_OF;
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
static uip_mcast6_route_t *mcast_group;
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Initialise RPL ICMPv6 message handlers */
|
||||
UIP_ICMP6_HANDLER(dis_handler, ICMP6_RPL, RPL_CODE_DIS, dis_input);
|
||||
UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input);
|
||||
UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
|
||||
UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
get_global_addr(uip_ipaddr_t *addr)
|
||||
|
@ -163,6 +174,7 @@ dis_input(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
uip_len = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -171,12 +183,14 @@ dis_output(uip_ipaddr_t *addr)
|
|||
unsigned char *buffer;
|
||||
uip_ipaddr_t tmpaddr;
|
||||
|
||||
/* DAG Information Solicitation - 2 bytes reserved */
|
||||
/* 0 1 2 */
|
||||
/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 */
|
||||
/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
|
||||
/* | Flags | Reserved | Option(s)... */
|
||||
/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
|
||||
/*
|
||||
* DAG Information Solicitation - 2 bytes reserved
|
||||
* 0 1 2
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Flags | Reserved | Option(s)...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
buffer[0] = buffer[1] = 0;
|
||||
|
@ -236,7 +250,7 @@ dio_input(void)
|
|||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
PRINTF("\n");
|
||||
} else {
|
||||
PRINTF("RPL: Out of Memory, dropping DIO from ");
|
||||
PRINTF("RPL: Out of memory, dropping DIO from ");
|
||||
PRINT6ADDR(&from);
|
||||
PRINTF(", ");
|
||||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
|
@ -378,7 +392,7 @@ dio_input(void)
|
|||
break;
|
||||
case RPL_OPTION_PREFIX_INFO:
|
||||
if(len != 32) {
|
||||
PRINTF("RPL: DAG prefix info not ok, len != 32\n");
|
||||
PRINTF("RPL: Invalid DAG prefix info, len != 32\n");
|
||||
RPL_STAT(rpl_stats.malformed_msgs++);
|
||||
return;
|
||||
}
|
||||
|
@ -402,6 +416,8 @@ dio_input(void)
|
|||
#endif
|
||||
|
||||
rpl_process_dio(&from, &dio);
|
||||
|
||||
uip_len = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -415,7 +431,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
|
|||
#endif /* !RPL_LEAF_ONLY */
|
||||
|
||||
#if RPL_LEAF_ONLY
|
||||
/* In leaf mode, we send DIO message only as unicasts in response to
|
||||
/* In leaf mode, we only send DIO messages as unicasts in response to
|
||||
unicast DIS messages. */
|
||||
if(uc_addr == NULL) {
|
||||
PRINTF("RPL: LEAF ONLY have multicast addr: skip dio_output\n");
|
||||
|
@ -578,10 +594,11 @@ dao_input(void)
|
|||
int len;
|
||||
int i;
|
||||
int learned_from;
|
||||
rpl_parent_t *p;
|
||||
rpl_parent_t *parent;
|
||||
uip_ds6_nbr_t *nbr;
|
||||
|
||||
prefixlen = 0;
|
||||
parent = NULL;
|
||||
|
||||
uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
|
||||
|
||||
|
@ -611,15 +628,41 @@ dao_input(void)
|
|||
sequence = buffer[pos++];
|
||||
|
||||
dag = instance->current_dag;
|
||||
/* Is the DAGID present? */
|
||||
/* Is the DAG ID present? */
|
||||
if(flags & RPL_DAO_D_FLAG) {
|
||||
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
|
||||
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
|
||||
return;
|
||||
}
|
||||
pos += 16;
|
||||
} else {
|
||||
/* Perhaps, there are verification to do but ... */
|
||||
}
|
||||
|
||||
learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
|
||||
RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
|
||||
|
||||
PRINTF("RPL: DAO from %s\n",
|
||||
learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast");
|
||||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
||||
/* Check whether this is a DAO forwarding loop. */
|
||||
parent = rpl_find_parent(dag, &dao_sender_addr);
|
||||
/* check if this is a new DAO registration with an "illegal" rank */
|
||||
/* if we already route to this node it is likely */
|
||||
if(parent != NULL &&
|
||||
DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
|
||||
PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
|
||||
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
|
||||
parent->rank = INFINITE_RANK;
|
||||
parent->updated = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get the DAO from our parent, we also have a loop. */
|
||||
if(parent != NULL && parent == dag->preferred_parent) {
|
||||
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
|
||||
parent->rank = INFINITE_RANK;
|
||||
parent->updated = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there are any RPL options present. */
|
||||
|
@ -654,6 +697,17 @@ dao_input(void)
|
|||
PRINT6ADDR(&prefix);
|
||||
PRINTF("\n");
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
if(uip_is_addr_mcast_global(&prefix)) {
|
||||
mcast_group = uip_mcast6_route_add(&prefix);
|
||||
if(mcast_group) {
|
||||
mcast_group->dag = dag;
|
||||
mcast_group->lifetime = RPL_LIFETIME(instance, lifetime);
|
||||
}
|
||||
goto fwd_dao;
|
||||
}
|
||||
#endif
|
||||
|
||||
rep = uip_ds6_route_lookup(&prefix);
|
||||
|
||||
if(lifetime == RPL_ZERO_LIFETIME) {
|
||||
|
@ -687,34 +741,6 @@ dao_input(void)
|
|||
return;
|
||||
}
|
||||
|
||||
learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
|
||||
RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
|
||||
|
||||
PRINTF("RPL: DAO from %s\n",
|
||||
learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast");
|
||||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
||||
/* Check whether this is a DAO forwarding loop. */
|
||||
p = rpl_find_parent(dag, &dao_sender_addr);
|
||||
/* check if this is a new DAO registration with an "illegal" rank */
|
||||
/* if we already route to this node it is likely */
|
||||
if(p != NULL &&
|
||||
DAG_RANK(p->rank, instance) < DAG_RANK(dag->rank, instance)) {
|
||||
PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
|
||||
DAG_RANK(p->rank, instance), DAG_RANK(dag->rank, instance));
|
||||
p->rank = INFINITE_RANK;
|
||||
p->updated = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get the DAO from our parent, we also have a loop. */
|
||||
if(p != NULL && p == dag->preferred_parent) {
|
||||
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
|
||||
p->rank = INFINITE_RANK;
|
||||
p->updated = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("RPL: adding DAO route\n");
|
||||
|
||||
if((nbr = uip_ds6_nbr_lookup(&dao_sender_addr)) == NULL) {
|
||||
|
@ -740,7 +766,7 @@ dao_input(void)
|
|||
PRINTF("RPL: Neighbor already in neighbor cache\n");
|
||||
}
|
||||
|
||||
rpl_lock_parent(p);
|
||||
rpl_lock_parent(parent);
|
||||
|
||||
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
|
||||
if(rep == NULL) {
|
||||
|
@ -752,6 +778,10 @@ dao_input(void)
|
|||
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
||||
rep->state.learned_from = learned_from;
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
fwd_dao:
|
||||
#endif
|
||||
|
||||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
||||
if(dag->preferred_parent != NULL &&
|
||||
rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
|
||||
|
@ -765,6 +795,7 @@ dao_input(void)
|
|||
dao_ack_output(instance, &dao_sender_addr, sequence);
|
||||
}
|
||||
}
|
||||
uip_len = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -894,6 +925,7 @@ dao_ack_input(void)
|
|||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
PRINTF("\n");
|
||||
#endif /* DEBUG */
|
||||
uip_len = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -916,27 +948,12 @@ dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_rpl_input(void)
|
||||
rpl_icmp6_register_handlers()
|
||||
{
|
||||
PRINTF("Received an RPL control message\n");
|
||||
switch(UIP_ICMP_BUF->icode) {
|
||||
case RPL_CODE_DIO:
|
||||
dio_input();
|
||||
break;
|
||||
case RPL_CODE_DIS:
|
||||
dis_input();
|
||||
break;
|
||||
case RPL_CODE_DAO:
|
||||
dao_input();
|
||||
break;
|
||||
case RPL_CODE_DAO_ACK:
|
||||
dao_ack_input();
|
||||
break;
|
||||
default:
|
||||
PRINTF("RPL: received an unknown ICMP6 code (%u)\n", UIP_ICMP_BUF->icode);
|
||||
break;
|
||||
}
|
||||
|
||||
uip_len = 0;
|
||||
uip_icmp6_register_input_handler(&dis_handler);
|
||||
uip_icmp6_register_input_handler(&dio_handler);
|
||||
uip_icmp6_register_input_handler(&dao_handler);
|
||||
uip_icmp6_register_input_handler(&dao_ack_handler);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
|
|
@ -104,7 +104,7 @@ calculate_path_metric(rpl_parent_t *p)
|
|||
}
|
||||
|
||||
static void
|
||||
reset(rpl_dag_t *sag)
|
||||
reset(rpl_dag_t *dag)
|
||||
{
|
||||
PRINTF("RPL: Reset MRHOF\n");
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "sys/clock.h"
|
||||
#include "sys/ctimer.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \brief Is IPv6 address addr the link-local, all-RPL-nodes
|
||||
|
@ -177,8 +178,24 @@
|
|||
|
||||
#ifdef RPL_CONF_MOP
|
||||
#define RPL_MOP_DEFAULT RPL_CONF_MOP
|
||||
#else /* RPL_CONF_MOP */
|
||||
#if RPL_CONF_MULTICAST
|
||||
#define RPL_MOP_DEFAULT RPL_MOP_STORING_MULTICAST
|
||||
#else
|
||||
#define RPL_MOP_DEFAULT RPL_MOP_STORING_NO_MULTICAST
|
||||
#endif /* UIP_IPV6_MULTICAST_RPL */
|
||||
#endif /* RPL_CONF_MOP */
|
||||
|
||||
/* Emit a pre-processor error if the user configured multicast with bad MOP */
|
||||
#if RPL_CONF_MULTICAST && (RPL_MOP_DEFAULT != RPL_MOP_STORING_MULTICAST)
|
||||
#error "RPL Multicast requires RPL_MOP_DEFAULT==3. Check contiki-conf.h"
|
||||
#endif
|
||||
|
||||
/* Multicast Route Lifetime as a multiple of the lifetime unit */
|
||||
#ifdef RPL_CONF_MCAST_LIFETIME
|
||||
#define RPL_MCAST_LIFETIME RPL_CONF_MCAST_LIFETIME
|
||||
#else
|
||||
#define RPL_MCAST_LIFETIME 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -186,7 +203,7 @@
|
|||
* whose integer part can be obtained by dividing the value by
|
||||
* RPL_DAG_MC_ETX_DIVISOR.
|
||||
*/
|
||||
#define RPL_DAG_MC_ETX_DIVISOR 128
|
||||
#define RPL_DAG_MC_ETX_DIVISOR 256
|
||||
|
||||
/* DIS related */
|
||||
#define RPL_DIS_SEND 1
|
||||
|
@ -272,6 +289,7 @@ void dio_output(rpl_instance_t *, uip_ipaddr_t *uc_addr);
|
|||
void dao_output(rpl_parent_t *, uint8_t lifetime);
|
||||
void dao_output_target(rpl_parent_t *, uip_ipaddr_t *, uint8_t lifetime);
|
||||
void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t);
|
||||
void rpl_icmp6_register_handlers(void);
|
||||
|
||||
/* RPL logic functions. */
|
||||
void rpl_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include "contiki-conf.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "lib/random.h"
|
||||
#include "sys/ctimer.h"
|
||||
|
||||
|
@ -69,7 +70,7 @@ handle_periodic_timer(void *ptr)
|
|||
rpl_recalculate_ranks();
|
||||
|
||||
/* handle DIS */
|
||||
#ifdef RPL_DIS_SEND
|
||||
#if RPL_DIS_SEND
|
||||
next_dis++;
|
||||
if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) {
|
||||
next_dis = 0;
|
||||
|
@ -220,6 +221,10 @@ static void
|
|||
handle_dao_timer(void *ptr)
|
||||
{
|
||||
rpl_instance_t *instance;
|
||||
#if RPL_CONF_MULTICAST
|
||||
uip_mcast6_route_t *mcast_route;
|
||||
uint8_t i;
|
||||
#endif
|
||||
|
||||
instance = (rpl_instance_t *)ptr;
|
||||
|
||||
|
@ -234,6 +239,31 @@ handle_dao_timer(void *ptr)
|
|||
PRINTF("RPL: handle_dao_timer - sending DAO\n");
|
||||
/* Set the route lifetime to the default value. */
|
||||
dao_output(instance->current_dag->preferred_parent, instance->default_lifetime);
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
/* Send DAOs for multicast prefixes only if the instance is in MOP 3 */
|
||||
if(instance->mop == RPL_MOP_STORING_MULTICAST) {
|
||||
/* Send a DAO for own multicast addresses */
|
||||
for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
|
||||
if(uip_ds6_if.maddr_list[i].isused
|
||||
&& uip_is_addr_mcast_global(&uip_ds6_if.maddr_list[i].ipaddr)) {
|
||||
dao_output_target(instance->current_dag->preferred_parent,
|
||||
&uip_ds6_if.maddr_list[i].ipaddr, RPL_MCAST_LIFETIME);
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over multicast routes and send DAOs */
|
||||
mcast_route = uip_mcast6_route_list_head();
|
||||
while(mcast_route != NULL) {
|
||||
/* Don't send if it's also our own address, done that already */
|
||||
if(uip_ds6_maddr_lookup(&mcast_route->group) == NULL) {
|
||||
dao_output_target(instance->current_dag->preferred_parent,
|
||||
&mcast_route->group, RPL_MCAST_LIFETIME);
|
||||
}
|
||||
mcast_route = list_item_next(mcast_route);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
PRINTF("RPL: No suitable DAO parent\n");
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
#include "net/ip/uip.h"
|
||||
#include "net/ip/tcpip.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
@ -105,6 +107,9 @@ rpl_purge_routes(void)
|
|||
uip_ds6_route_t *r;
|
||||
uip_ipaddr_t prefix;
|
||||
rpl_dag_t *dag;
|
||||
#if RPL_CONF_MULTICAST
|
||||
uip_mcast6_route_t *mcast_route;
|
||||
#endif
|
||||
|
||||
/* First pass, decrement lifetime */
|
||||
r = uip_ds6_route_head();
|
||||
|
@ -146,12 +151,29 @@ rpl_purge_routes(void)
|
|||
r = uip_ds6_route_next(r);
|
||||
}
|
||||
}
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
mcast_route = uip_mcast6_route_list_head();
|
||||
|
||||
while(mcast_route != NULL) {
|
||||
if(mcast_route->lifetime <= 1) {
|
||||
uip_mcast6_route_rm(mcast_route);
|
||||
mcast_route = uip_mcast6_route_list_head();
|
||||
} else {
|
||||
mcast_route->lifetime--;
|
||||
mcast_route = list_item_next(mcast_route);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_remove_routes(rpl_dag_t *dag)
|
||||
{
|
||||
uip_ds6_route_t *r;
|
||||
#if RPL_CONF_MULTICAST
|
||||
uip_mcast6_route_t *mcast_route;
|
||||
#endif
|
||||
|
||||
r = uip_ds6_route_head();
|
||||
|
||||
|
@ -163,6 +185,19 @@ rpl_remove_routes(rpl_dag_t *dag)
|
|||
r = uip_ds6_route_next(r);
|
||||
}
|
||||
}
|
||||
|
||||
#if RPL_CONF_MULTICAST
|
||||
mcast_route = uip_mcast6_route_list_head();
|
||||
|
||||
while(mcast_route != NULL) {
|
||||
if(mcast_route->dag == dag) {
|
||||
uip_mcast6_route_rm(mcast_route);
|
||||
mcast_route = uip_mcast6_route_list_head();
|
||||
} else {
|
||||
mcast_route = list_item_next(mcast_route);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -266,6 +301,7 @@ rpl_init(void)
|
|||
|
||||
rpl_dag_init();
|
||||
rpl_reset_periodic_timer();
|
||||
rpl_icmp6_register_handlers();
|
||||
|
||||
/* add rpl multicast address */
|
||||
uip_create_linklocal_rplnodes_mcast(&rplmaddr);
|
||||
|
@ -274,6 +310,8 @@ rpl_init(void)
|
|||
#if RPL_CONF_STATS
|
||||
memset(&rpl_stats, 0, sizeof(rpl_stats));
|
||||
#endif
|
||||
|
||||
RPL_OF.reset(NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
|
|
@ -189,6 +189,9 @@ struct rpl_of {
|
|||
rpl_ocp_t ocp;
|
||||
};
|
||||
typedef struct rpl_of rpl_of_t;
|
||||
|
||||
/* Declare the selected objective function. */
|
||||
extern rpl_of_t RPL_OF;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Instance */
|
||||
struct rpl_instance {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue