Compare commits

..

1 Commits
master ... coap

Author SHA1 Message Date
giomba f34833e955 coap server basics -- parse input path
receive coap request and parse path
actually this is just a stub, but hey,
it's a stable one and this is my private branch

even if this commit will probably be fast-merged '°_°
2020-01-08 22:52:59 +01:00
14 changed files with 480 additions and 510 deletions

View File

@ -6,23 +6,3 @@ A simple and trivial IPv6 stack for Arduino. Currently implements:
* ICMP Router Advertisement * ICMP Router Advertisement
* UDP server * UDP server
# Quick start
Browse `examples` directory for Arduino sketches.
```
cd examples/simple-udp-server
make build
make flash
```
# Configuration
`src/settings.h`:
* `ENABLE_SLAAC`: enable stateless auto-configuration
# Issues
* bugs:
* only known features
* nice-to-have:
* settings configuration outside library directory

View File

@ -1 +0,0 @@
/build/

View File

@ -1,15 +0,0 @@
BOARD ?= arduino:avr:diecimila
PORT ?= /dev/ttyUSB0
CCFLAGS += -Icfg
.PHONY: build flash
build:
arduino-cli compile -v -e --libraries coppino -b $(BOARD)
flash:
arduino-cli -b $(BOARD) -p $(PORT) -v upload
clean:
rm -r build

View File

@ -1,47 +0,0 @@
#include "coppino.h"
#include "ipv6.h"
#include "slip.h"
#include "udp.h"
const char MY_ADDRESS[] = "\x20\x01\x04\x70\xc8\x44\x00\x31\x00\x00\x00\x00\x00\x00\xca\xfe";
void setup()
{
/* Customize coppino library configuration settings by editing settings.h */
/* setup serial for Internet connectivity
* attach a SLIP daemon on the other endpoint; a good one is `tunslip6` by Contiki
* $ tunslip6 -s /dev/ttyUSB0 -L -v5 -B 19200 2001:db8:1324::1/64
* Note: the address given is the one on the host it is running on
*/
Serial.begin(19200);
/* set unique identifier of network hardware. It MUST be unique!
* For example, this could be your microcontroller serial number
* Note: pay attention to enter exactly 64 bits / 8 bytes
*/
ipv6::setEUI("\xde\xad\xbe\xef\x12\x34\x56\x78");
/* set global address -- will be overwritten if SLAAC is enabled and a Router Advertisement is received */
ipv6::setGlobalAddress(MY_ADDRESS);
}
void loop()
{
char message[16];
ipv6::IPv6Addr srcaddr = ipv6::IPv6Addr(MY_ADDRESS);
ipv6::IPv6Addr dstaddr = ipv6::IPv6Addr("\x20\x01\x04\x70\xc8\x44\x00\x31\x00\x00\x00\x00\x00\x00\x00\x01");
uint16_t srcport = 1337;
uint16_t dstport = 1234;
udp::UDPClient udpclient = udp::UDPClient(srcaddr, dstaddr, srcport, dstport);
while (true)
{
for (int i = 0; i < 32; ++i)
{
sprintf(message, "iteration #%d\r\n", i);
udpclient.send_datagram((const uint8_t *)message, strlen(message));
delay(1000);
}
}
}

View File

@ -1 +0,0 @@
/build/

View File

@ -1,15 +0,0 @@
BOARD ?= arduino:avr:diecimila
PORT ?= /dev/ttyUSB0
CCFLAGS += -Icfg
.PHONY: build flash
build:
arduino-cli compile -v -e --libraries coppino -b $(BOARD)
flash:
arduino-cli -b $(BOARD) -p $(PORT) -v upload
clean:
rm -r build

View File

@ -14,8 +14,6 @@ int udp_server(char* output_buffer, const char* input_buffer, int len) {
void setup() { void setup() {
pinMode(13, OUTPUT); pinMode(13, OUTPUT);
/* Customize coppino library configuration settings by editing settings.h */
/* setup serial for Internet connectivity /* setup serial for Internet connectivity
* attach a SLIP daemon on the other endpoint; a good one is `tunslip6` by Contiki * attach a SLIP daemon on the other endpoint; a good one is `tunslip6` by Contiki
* $ tunslip6 -s /dev/ttyUSB0 -L -v5 -B 19200 2001:db8:1324::1/64 * $ tunslip6 -s /dev/ttyUSB0 -L -v5 -B 19200 2001:db8:1324::1/64
@ -28,6 +26,8 @@ void setup() {
* Note: pay attention to enter exactly 64 bits / 8 bytes * Note: pay attention to enter exactly 64 bits / 8 bytes
*/ */
ipv6::setEUI("\xde\xad\xbe\xef\x12\x34\x56\x78"); ipv6::setEUI("\xde\xad\xbe\xef\x12\x34\x56\x78");
/* enable or disable IPv6 Stateless Auto-Configuration (SLAAC) */
ipv6::SLAAC(false);
/* set global address -- will be overwritten if SLAAC is enabled and a Router Advertisement is received */ /* set global address -- will be overwritten if SLAAC is enabled and a Router Advertisement is received */
ipv6::setGlobalAddress("\x20\x01\x04\x70\xc8\x44\x00\x31\x00\x00\x00\x00\x00\x00\xca\xfe"); ipv6::setGlobalAddress("\x20\x01\x04\x70\xc8\x44\x00\x31\x00\x00\x00\x00\x00\x00\xca\xfe");

124
src/coap.cpp Normal file
View File

@ -0,0 +1,124 @@
#include "coap.h"
namespace coap {
uint8_t CoapMessage::getVersion() {
return vertkl >> 6;
}
uint8_t CoapMessage::getType() {
return (vertkl & 0x30) >> 4;
}
uint8_t CoapMessage::getTKL() {
return (vertkl & 0x0f);
}
uint8_t CoapMessage::getCode() {
return code;
}
const char* CoapMessage::getMID() {
return id;
}
/* nonsense: save 8 bits in the network,
and waste tens of them for writing such an error-prone code like this! */
int CoapMessage::getOptionDelta(const unsigned char* option) {
uint8_t delta = option[0] >> 4;
if (delta <= 12) {
return delta;
}
if (delta == 13) {
delta = option[1] + 13;
return delta;
}
/* options delta larger than 269 (256 + 13) bytes are not supported */
return -1;
}
int CoapMessage::getOptionLength(const unsigned char* option) {
uint8_t len = option[0] & 0xf;
if (len <= 12) {
return len;
}
uint8_t extended_length_byte;
if (getOptionDelta(option) < 13)
extended_length_byte = option[1];
else
extended_length_byte = option[2];
if (len == 13) {
len = extended_length_byte + 13;
return len;
}
/* options longer than 269 (256 + 13) are not supported */
return -1;
}
/* offset of payload wrt beginning of option */
int CoapMessage::getOptionValueOffset(const unsigned char* option) {
int offset = 1;
if (getOptionDelta(option) >= 13) ++offset;
if (getOptionLength(option) >= 13) ++offset;
return offset;
}
const char* CoapMessage::getOptionValue(const unsigned char* option) {
return (const char*) &option[getOptionValueOffset(option)];
}
const unsigned char* CoapMessage::getOptions() {
const unsigned char* address = (const unsigned char*)this;
address += 4; /* header */
address += getTKL();
return address;
}
void CoapMessage::getUriPath(char* output_buffer, const char* last) {
/* TODO -- possible overflow, malformed input not checked */
int number = 0;
int len;
const unsigned char* options = this->getOptions();
while (number <= 11) {
number += getOptionDelta(options);
len = getOptionLength(options);
// TODO -- is here a payload? 15 - 15
if (number == 11) { /* Uri-Path option number */
*output_buffer = '/';
output_buffer += 1;
memcpy(output_buffer, getOptionValue(options), len);
output_buffer += len;
}
options += (len + getOptionValueOffset(options));
if (options == last) break;
}
*output_buffer = '\0';
return;
}
int coap_server(char* output_buffer, const char* input_buffer, int len) {
CoapMessage* input_msg = (CoapMessage*) input_buffer;
if (input_msg->getVersion() != 0x1) /* bad CoAP version number */
return -1;
if (input_msg->getType() == RESET || input_msg->getType() == ACKNOWELEDGMENT) /* not implemented on server side */
return -1;
if (input_msg->getTKL() >= 9) /* format error -- TODO, maybe we can answer RST? see RFC */
return -1;
switch (input_msg->getCode()) {
case GET:
input_msg->getUriPath(output_buffer, input_buffer + len);
return strlen(output_buffer);
break;
}
return -1;
}
} // end of namespace -- coap::

53
src/coap.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef COAP_H
#define COAP_H
#include "Arduino.h"
namespace coap {
enum Type {
CONFIRMABLE = 0,
NON_CONFIRMABLE = 1,
ACKNOWELEDGMENT = 2,
RESET = 3
};
enum Code {
EMPTY = 0x00, /* 0.00 */
GET = 0x01, /* 0.01 */
POST = 0x02, /* 0.02 */
PUT = 0x03, /* 0.03 */
DELETE = 0x04, /* 0.04 */
CONTENT = 0x45, /* 2.05 */
NOT_FOUND = 0x84,/*4.04 */
METHOD_NOT_ALLOWED = 0x85 /* 4.05 */
};
class CoapMessage {
private:
char vertkl;
char code;
char id[2];
public:
uint8_t getVersion();
uint8_t getType();
uint8_t getTKL();
uint8_t getCode();
const char* getMID();
const char* getPayload();
int getOptionDelta(const unsigned char* option);
int getOptionLength(const unsigned char* option);
const char* getOptionValue(const unsigned char* option);
int getOptionValueOffset(const unsigned char* option);
const unsigned char* getOptions();
void getUriPath(char* output_buffer, const char* last);
};
int coap_server(char* output_buffer, const char* input_buffer, int len);
}
#endif

View File

@ -1,37 +1,37 @@
#include "ipv6.h" #include "ipv6.h"
#include "udp.h" #include "udp.h"
namespace ipv6 namespace ipv6 {
{ /******** costants ********/
/******** costants ********/ const IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"); /* ff02::1 */
const IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"); /* ff02::1 */
/******** variables ********/ /******** variables ********/
uint8_t HOP_LIMIT = 64; uint8_t HOP_LIMIT = 64;
IPv6Addr LINK_LOCAL_ADDRESS; IPv6Addr LINK_LOCAL_ADDRESS;
IPv6Addr GLOBAL_ADDRESS; IPv6Addr GLOBAL_ADDRESS;
bool slaac_enable;
/******** buffers ********/ /******** buffers ********/
IPv6Packet packetin; IPv6Packet packetin;
IPv6Packet packetout; IPv6Packet packetout;
/******** FUNCTIONS *******/ /******** FUNCTIONS *******/
void setEUI(const char *eui) void setEUI(const char* eui) {
{
memset(&LINK_LOCAL_ADDRESS, 0, 16); memset(&LINK_LOCAL_ADDRESS, 0, 16);
memcpy(&LINK_LOCAL_ADDRESS, "\xfe\x80", 2); memcpy(&LINK_LOCAL_ADDRESS, "\xfe\x80", 2);
memcpy(((char *)&LINK_LOCAL_ADDRESS) + 8, eui, 8); memcpy( ((char*)&LINK_LOCAL_ADDRESS) + 8 , eui, 8);
} }
void setGlobalAddress(const char *address) void SLAAC(bool enable) {
{ slaac_enable = enable;
}
void setGlobalAddress(const char* address) {
memcpy(&GLOBAL_ADDRESS, address, 16); memcpy(&GLOBAL_ADDRESS, address, 16);
} }
uint16_t compute_checksum(const IPv6Addr *src_addr, const IPv6Addr *dst_addr, uint8_t next_header, int upper_len, const char *payload, int len) uint16_t compute_checksum(const IPv6Addr* src_addr, const IPv6Addr* dst_addr, uint8_t next_header, int upper_len, const char* payload, int len) {
{
char buffer[LEN]; char buffer[LEN];
uint32_t total; uint32_t total;
uint16_t *ptr; uint16_t* ptr;
int words; int words;
int i = len; int i = len;
@ -41,134 +41,108 @@ namespace ipv6
*/ */
/* actual payload */ /* actual payload */
memcpy(buffer, payload, len); memcpy(buffer, payload, len);
if (len % 2) if (len % 2) { /* pad with 0 if length is odd */
{ /* pad with 0 if length is odd */
buffer[len] = 0; buffer[len] = 0;
i++; i++;
} }
/* pseudo ipv6 header -- see RFC 2460, Section 8.1 */ /* pseudo ipv6 header -- see RFC 2460, Section 8.1 */
memcpy(buffer + i, src_addr, 16); memcpy(buffer + i, src_addr, 16); i += 16;
i += 16; memcpy(buffer + i, dst_addr, 16); i += 16;
memcpy(buffer + i, dst_addr, 16); memset(buffer + i, 0, 3); i+= 3; /* first 3 bytes always 0, because len always < 256 */
i += 16; buffer[i] = upper_len & 0xff; i += 1;
memset(buffer + i, 0, 3); memset(buffer + i, 0, 3); i += 3; /* zero, as per-standard */
i += 3; /* first 3 bytes always 0, because len always < 256 */ buffer[i] = next_header; i += 1;
buffer[i] = upper_len & 0xff;
i += 1;
memset(buffer + i, 0, 3);
i += 3; /* zero, as per-standard */
buffer[i] = next_header;
i += 1;
/* do computation */ /* do computation */
total = 0; total = 0;
ptr = (uint16_t *)buffer; ptr = (uint16_t*)buffer;
words = (i + 1) / 2; words = (i + 1) / 2;
while (words--) while (words--) total += *ptr++;
total += *ptr++;
while (total & 0xffff0000) while (total & 0xffff0000) {
{
total = (total >> 16) + (total & 0xffff); total = (total >> 16) + (total & 0xffff);
} }
return ~((uint16_t)total); return ~((uint16_t) total);
} }
/******** IPv6Addr ********/ /******** IPv6Addr ********/
IPv6Addr::IPv6Addr() { ; } IPv6Addr::IPv6Addr() {;}
IPv6Addr::IPv6Addr(const char *address) IPv6Addr::IPv6Addr(const char* address) {
{
memcpy(this->address, address, 16); memcpy(this->address, address, 16);
} }
/******** IPv6Packet ********/ /******** IPv6Packet ********/
IPv6Packet::IPv6Packet() IPv6Packet::IPv6Packet() {
{
memset(packet, 0, LEN); memset(packet, 0, LEN);
*(packet) = 0x60; /* IP version 6 */ *(packet) = 0x60; /* IP version 6 */
*(packet + 7) = HOP_LIMIT; /* hop limit / ttl */ *(packet + 7) = HOP_LIMIT; /* hop limit / ttl */
} }
IPv6Packet::IPv6Packet(const char *buffer, int len) IPv6Packet::IPv6Packet(const char* buffer, int len) {
{
memcpy(this->packet, buffer, len); memcpy(this->packet, buffer, len);
} }
void IPv6Packet::setNextHeader(uint8_t next_header) void IPv6Packet::setNextHeader(uint8_t next_header) {
{
*(packet + 6) = next_header; *(packet + 6) = next_header;
} }
void IPv6Packet::setLen(int len) void IPv6Packet::setLen(int len) {
{
*(packet + 4) = len >> 8; *(packet + 4) = len >> 8;
*(packet + 5) = len & 0xff; *(packet + 5) = len & 0xff;
} }
int IPv6Packet::getLen() int IPv6Packet::getLen() {
{
return ((*(packet + 4)) << 8) + (*(packet + 5)); return ((*(packet + 4)) << 8) + (*(packet + 5));
} }
void IPv6Packet::setSrcAddress(const IPv6Addr *address) void IPv6Packet::setSrcAddress(const IPv6Addr* address) {
{
memcpy(packet + 8, address, 16); memcpy(packet + 8, address, 16);
} }
void IPv6Packet::setDstAddress(const IPv6Addr *address) void IPv6Packet::setDstAddress(const IPv6Addr* address) {
{
memcpy(packet + 24, address, 16); memcpy(packet + 24, address, 16);
} }
const IPv6Addr *IPv6Packet::getSrcAddress() const IPv6Addr* IPv6Packet::getSrcAddress() {
{ return (const IPv6Addr*) (packet + 8);
return (const IPv6Addr *)(packet + 8); }
} const IPv6Addr* IPv6Packet::getDstAddress() {
const IPv6Addr *IPv6Packet::getDstAddress() return (const IPv6Addr*) (packet + 24);
{ }
return (const IPv6Addr *)(packet + 24);
}
void IPv6Packet::setFlow(const char *flow) void IPv6Packet::setFlow(const char* flow) {
{
/* three bytes /* three bytes
4 most significant bits are ignored 4 most significant bits are ignored
because only 20 bits can be used */ because only 20 bits can be used */
*(packet + 1) = (*(packet + 1)) | (flow[0] & 0x0f); /* pay attention to TC field */ *(packet + 1) = (*(packet + 1)) | (flow[0] & 0x0f); /* pay attention to TC field */
memcpy(packet + 2, flow + 1, 2); memcpy(packet + 2, flow + 1, 2);
} }
void IPv6Packet::setPayload(char *payload, int len) void IPv6Packet::setPayload(char* payload, int len) {
{
*(packet + 4 + 0) = len >> 8; *(packet + 4 + 0) = len >> 8;
*(packet + 4 + 1) = len & 0xff; *(packet + 4 + 1) = len & 0xff;
memcpy(packet + 40, payload, len); /* payload */ memcpy(packet + 40, payload, len); /* payload */
} }
void IPv6Packet::send() void IPv6Packet::send() {
{
slip::send(packet, 40 + this->getLen()); slip::send(packet, 40 + this->getLen());
} }
void IPv6Packet::doAction() void IPv6Packet::doAction() {
{
/* if destination is my address (global or link-local), or destination is "all nodes" address, then... */ /* if destination is my address (global or link-local), or destination is "all nodes" address, then... */
if ( if (
(memcmp(&(ALL_NODES_ADDRESS), packet + 24, 16) == 0) || (memcmp(&(ALL_NODES_ADDRESS), packet + 24, 16) == 0) ||
(memcmp(&(LINK_LOCAL_ADDRESS), packet + 24, 16) == 0) || (memcmp(&(LINK_LOCAL_ADDRESS), packet + 24, 16) == 0) ||
(memcmp(&(GLOBAL_ADDRESS), packet + 24, 16) == 0)) (memcmp(&(GLOBAL_ADDRESS), packet + 24, 16) == 0)) {
{
int ilen = this->getLen(); /* input payload length */ int ilen = this->getLen(); /* input payload length */
int olen; /* output payload length */ int olen; /* output payload length */
switch (*(packet + 6)) switch(*(packet + 6)) { /* next header */
{ /* next header */
case NH_ICMP: case NH_ICMP:
if ((olen = handleICMP((char *)&packetout + 40, packet + 40, ilen)) != -1) if ((olen = handleICMP((char*)&packetout + 40, packet + 40, ilen)) != -1) {
{
packetout.setLen(olen); packetout.setLen(olen);
packetout.setFlow(((char *)(&packetin)) + 1); packetout.setFlow(((char*)(&packetin)) + 1);
packetout.setSrcAddress(packetin.getDstAddress()); packetout.setSrcAddress(packetin.getDstAddress());
packetout.setDstAddress(packetin.getSrcAddress()); packetout.setDstAddress(packetin.getSrcAddress());
packetout.setNextHeader(NH_ICMP); packetout.setNextHeader(NH_ICMP);
@ -176,10 +150,9 @@ namespace ipv6
} }
break; break;
case NH_UDP: case NH_UDP:
if ((olen = udp::handleUDP((char *)&packetout + 40, packet + 40, ilen)) != -1) if ((olen = udp::handleUDP((char*)&packetout + 40, packet + 40, ilen)) != -1) {
{
packetout.setLen(olen); packetout.setLen(olen);
packetout.setFlow(((char *)(&packetin)) + 1); packetout.setFlow(((char*)(&packetin)) + 1);
packetout.setSrcAddress(packetin.getDstAddress()); packetout.setSrcAddress(packetin.getDstAddress());
packetout.setDstAddress(packetin.getSrcAddress()); packetout.setDstAddress(packetin.getSrcAddress());
packetout.setNextHeader(NH_UDP); packetout.setNextHeader(NH_UDP);
@ -191,13 +164,12 @@ namespace ipv6
break; break;
} }
} /* ...else discard packet */ } /* ...else discard packet */
} }
/* handles ICMP and (possibly) generate a reply /* handles ICMP and (possibly) generate a reply
* returns length of generated packet (written to output_buffer), or -1 if there is no reply packet * returns length of generated packet (written to output_buffer), or -1 if there is no reply packet
*/ */
int handleICMP(char *output_buffer, const char *input_buffer, int len) int handleICMP(char* output_buffer, const char* input_buffer, int len) {
{
uint8_t type = *(input_buffer); uint8_t type = *(input_buffer);
/* compute checksum, and assert validity of incoming message */ /* compute checksum, and assert validity of incoming message */
@ -214,13 +186,11 @@ namespace ipv6
output_buffer, output_buffer,
len); len);
if (memcmp(&computed_checksum, received_checksum, 2) != 0) if (memcmp(&computed_checksum, received_checksum, 2) != 0) { /* if checksum is not valid, return */
{ /* if checksum is not valid, return */
return -1; return -1;
} }
if (type == ICMP_ECHO_REQUEST_TYPE) if (type == ICMP_ECHO_REQUEST_TYPE) { /* if it is ICMPv6 Echo Request, then... */
{ /* if it is ICMPv6 Echo Request, then... */
/* Build an echo reply: /* Build an echo reply:
* the reply has the same exact format of the request, * the reply has the same exact format of the request,
* except for Type and Checksum */ * except for Type and Checksum */
@ -236,25 +206,20 @@ namespace ipv6
len); len);
memcpy(output_buffer + 2, &checksum, 2); memcpy(output_buffer + 2, &checksum, 2);
return len; return len;
}
else if (type == ICMP_RADV_TYPE && ENABLE_SLAAC) } else if (type == ICMP_RADV_TYPE && slaac_enable) { /* if it is IVMPc6 Router Advertisement, then... */
{ /* if it is IVMPc6 Router Advertisement, then... */ ICMPv6_RADV* radv = (ICMPv6_RADV*)input_buffer;
ICMPv6_RADV *radv = (ICMPv6_RADV *)input_buffer;
HOP_LIMIT = (radv->cur_hop_limit != 0) ? radv->cur_hop_limit : 64; HOP_LIMIT = (radv->cur_hop_limit != 0) ? radv->cur_hop_limit : 64;
for ( for (
ICMPv6_RADV_Option *option = (ICMPv6_RADV_Option *)(radv + 1); ICMPv6_RADV_Option* option = (ICMPv6_RADV_Option*) (radv + 1);
option != input_buffer + len; option != input_buffer + len;
option = (ICMPv6_RADV_Option *)(((char *)(option)) + option->len)) option = (ICMPv6_RADV_Option*) ( ((char*)(option)) + option->len )) {
{ if (option->type == 3 && option->len == 4) { /* if it is a ICMPv6 Prefix Information, then... */
if (option->type == 3 && option->len == 4) ICMPv6_RADV_PrefixInformation* p = (ICMPv6_RADV_PrefixInformation*) option;
{ /* if it is a ICMPv6 Prefix Information, then... */
ICMPv6_RADV_PrefixInformation *p = (ICMPv6_RADV_PrefixInformation *)option;
if (p->prefix_length != 64) if (p->prefix_length != 64) continue; /* only /64 prefix is supported */
continue; /* only /64 prefix is supported */ if (! (p->la_flags & 0x40)) continue; /* only SLAAC is supported */
if (!(p->la_flags & 0x40))
continue; /* only SLAAC is supported */
memcpy(&GLOBAL_ADDRESS, p->prefix, 8); /* set prefix -- leave host bits unchanged */ memcpy(&GLOBAL_ADDRESS, p->prefix, 8); /* set prefix -- leave host bits unchanged */
break; break;
} }
@ -263,6 +228,6 @@ namespace ipv6
return -1; return -1;
} }
return -1; return -1;
} }
} }

View File

@ -1,12 +1,10 @@
#ifndef COPPINO_IPV6_H #ifndef COPPINO_IPV6_H
#define COPPINO_IPV6_H #define COPPINO_IPV6_H
#include "settings.h"
#include "Arduino.h" #include "Arduino.h"
#include "slip.h" #include "slip.h"
namespace ipv6 namespace ipv6 {
{
/* maximum length for an IPv6 packet */ /* maximum length for an IPv6 packet */
const uint8_t LEN = 128; const uint8_t LEN = 128;
@ -19,35 +17,31 @@ namespace ipv6
const uint8_t NH_ICMP = 58; const uint8_t NH_ICMP = 58;
const uint8_t NH_UDP = 17; const uint8_t NH_UDP = 17;
class IPv6Addr class IPv6Addr {
{
private: private:
char address[16]; char address[16];
public: public:
IPv6Addr(); IPv6Addr();
IPv6Addr(const char *address); IPv6Addr(const char* address);
}; };
extern const IPv6Addr ALL_NODES_ADDRESS; extern const IPv6Addr ALL_NODES_ADDRESS;
class IPv6Packet class IPv6Packet {
{
private: private:
char packet[LEN]; char packet[LEN];
public: public:
IPv6Packet(); IPv6Packet();
IPv6Packet(const char *buffer, int len); IPv6Packet(const char* buffer, int len);
void setLen(int len); void setLen(int len);
int getLen(); int getLen();
void setSrcAddress(const IPv6Addr *address); void setSrcAddress(const IPv6Addr* address);
const IPv6Addr *getSrcAddress(); const IPv6Addr* getSrcAddress();
void setDstAddress(const IPv6Addr *address); void setDstAddress(const IPv6Addr* address);
const IPv6Addr *getDstAddress(); const IPv6Addr* getDstAddress();
void setNextHeader(uint8_t next_header); void setNextHeader(uint8_t next_header);
void setFlow(const char *flow); void setFlow(const char* flow);
void setPayload(char *payload, int len); void setPayload(char* payload, int len);
void send(); void send();
void doAction(); void doAction();
@ -58,21 +52,20 @@ namespace ipv6
extern IPv6Packet packetout; extern IPv6Packet packetout;
/* Note: content of message may be changed */ /* Note: content of message may be changed */
int handleICMP(char *output_buffer, const char *input_buffer, int len); int handleICMP(char* output_buffer, const char* input_buffer, int len);
/* Compute internet checksum. Actually it is not so straightforward: */ /* Compute internet checksum. Actually it is not so straightforward: */
uint16_t compute_checksum( uint16_t compute_checksum(
const IPv6Addr *src_addr, /* source IPv6 address */ const IPv6Addr* src_addr, /* source IPv6 address */
const IPv6Addr *dst_addr, /* destination IPv6 address */ const IPv6Addr* dst_addr, /* destination IPv6 address */
uint8_t next_header, /* IPv6 next header number */ uint8_t next_header, /* IPv6 next header number */
int upper_len, /* length as found in the upper layer protocol */ int upper_len, /* length as found in the upper layer protocol */
const char *payload, /* IPv6 payload */ const char* payload, /* IPv6 payload */
int len /* IPv6 payload length */ int len /* IPv6 payload length */
); );
/* RFC 4861 -- begin */ /* RFC 4861 -- begin */
struct ICMPv6_RADV struct ICMPv6_RADV {
{
uint8_t type; uint8_t type;
uint8_t code; uint8_t code;
char checksum[2]; char checksum[2];
@ -83,14 +76,12 @@ namespace ipv6
uint32_t retrans_time; uint32_t retrans_time;
}; };
struct ICMPv6_RADV_Option struct ICMPv6_RADV_Option {
{
uint8_t type; uint8_t type;
uint8_t len; uint8_t len;
}; };
struct ICMPv6_RADV_PrefixInformation struct ICMPv6_RADV_PrefixInformation {
{
uint8_t type; uint8_t type;
uint8_t len; uint8_t len;
uint8_t prefix_length; uint8_t prefix_length;
@ -102,8 +93,9 @@ namespace ipv6
}; };
/* RFC 4861 -- end */ /* RFC 4861 -- end */
void setEUI(const char *eui); /* 64bit Extended Unique Identifier */ void setEUI(const char* eui); /* 64bit Extended Unique Identifier */
void setGlobalAddress(const char *address); /* global IPv6 address, manually configured */ void SLAAC(bool enable); /* enable IPv6 automatic prefix configuration (listens for RADV) */
void setGlobalAddress(const char* address); /* global IPv6 address, manually configured */
} }
#endif #endif

View File

@ -1,8 +0,0 @@
#ifndef __COPPINO_SETTINGS_
#define __COPPINO_SETTINGS_
/* coppino configuration settings */
// Enable IPv6 automatic prefix configuration (listens for RADV)
constexpr bool ENABLE_SLAAC = false;
#endif

View File

@ -1,71 +1,60 @@
#include "udp.h" #include "udp.h"
namespace udp namespace udp {
{
int (*server_handler)(char *output_buffer, const char *input_buffer, int size) = NULL;
uint16_t server_port = 0;
void UDPPacket::setSrcPort(uint16_t port) int(*server_handler) (char* output_buffer, const char* input_buffer, int size) = NULL;
{ uint16_t server_port = 0;
void UDPPacket::setSrcPort(uint16_t port) {
*(packet + 0) = port >> 8; *(packet + 0) = port >> 8;
*(packet + 1) = port & 0xff; *(packet + 1) = port & 0xff;
} }
void UDPPacket::setDstPort(uint16_t port) void UDPPacket::setDstPort(uint16_t port) {
{
*(packet + 2) = port >> 8; *(packet + 2) = port >> 8;
*(packet + 3) = port & 0xff; *(packet + 3) = port & 0xff;
} }
uint16_t UDPPacket::getSrcPort() uint16_t UDPPacket::getSrcPort() {
{ return (*(packet + 0) << 8) + (uint8_t)*(packet + 1);
return (*(packet + 0) << 8) + (uint8_t) * (packet + 1); }
} uint16_t UDPPacket::getDstPort() {
uint16_t UDPPacket::getDstPort() return (*(packet + 2) << 8) + (uint8_t)*(packet + 3);
{ }
return (*(packet + 2) << 8) + (uint8_t) * (packet + 3);
}
/* sets the payload and also updates the packet length field */ /* sets the payload and also updates the packet length field */
void UDPPacket::setPayload(const char *payload, int len) void UDPPacket::setPayload(const char* payload, int len) {
{
memcpy(packet + 8, payload, len); memcpy(packet + 8, payload, len);
*(packet + 4) = (len + 8) >> 8; *(packet + 4) = (len + 8) >> 8;
*(packet + 5) = (len + 8) & 0xff; *(packet + 5) = (len + 8) & 0xff;
} }
const char *UDPPacket::getPayload() const char* UDPPacket::getPayload() {
{
return packet + 8; return packet + 8;
} }
/* computes the checksum and also updates it inside the UDP packet */ /* computes the checksum and also updates it inside the UDP packet */
void UDPPacket::computeChecksum(const ipv6::IPv6Addr *src_addr, const ipv6::IPv6Addr *dst_addr, int len) void UDPPacket::computeChecksum(const ipv6::IPv6Addr* src_addr, const ipv6::IPv6Addr* dst_addr, int len) {
{
memset(packet + 6, 0, 2); memset(packet + 6, 0, 2);
uint16_t checksum = ipv6::compute_checksum(src_addr, dst_addr, ipv6::NH_UDP, len, packet, len); uint16_t checksum = ipv6::compute_checksum(src_addr, dst_addr, ipv6::NH_UDP, len, packet, len);
memcpy(packet + 6, &checksum, 2); memcpy(packet + 6, &checksum, 2);
} }
/* sets an handler (a function) which will be called every time there is a packet for a certain given port */ /* sets an handler (a function) which will be called every time there is a packet for a certain given port */
void set_handler(uint16_t port, int (*server_handler)(char *output_buffer, const char *input_buffer, int size)) void set_handler(uint16_t port, int(* server_handler) (char* output_buffer, const char* input_buffer, int size)) {
{
udp::server_port = port; udp::server_port = port;
udp::server_handler = server_handler; udp::server_handler = server_handler;
} }
/* handles an UDP packet, and (possibly) produces a reply UDP packet /* handles an UDP packet, and (possibly) produces a reply UDP packet
* returns length of reply packet, which is written in output_buffer, or -1 if there is no reply packet * returns length of reply packet, which is written in output_buffer, or -1 if there is no reply packet
*/ */
int handleUDP(char *output_buffer, const char *input_buffer, int ilen) int handleUDP(char* output_buffer, const char* input_buffer, int ilen) {
{ UDPPacket* incoming_packet = (UDPPacket*)input_buffer;
UDPPacket *incoming_packet = (UDPPacket *)input_buffer; UDPPacket* outgoing_packet = (UDPPacket*)output_buffer;
UDPPacket *outgoing_packet = (UDPPacket *)output_buffer;
int olen; int olen;
if (incoming_packet->getDstPort() == server_port) if (incoming_packet->getDstPort() == server_port) { /* call user-defined server handler */
{ /* call user-defined server handler */ if (server_port != 0 && server_handler != NULL) {
if (server_port != 0 && server_handler != NULL)
{
olen = server_handler(outgoing_packet->getPayload(), incoming_packet->getPayload(), ilen - 8); olen = server_handler(outgoing_packet->getPayload(), incoming_packet->getPayload(), ilen - 8);
outgoing_packet->setSrcPort(incoming_packet->getDstPort()); outgoing_packet->setSrcPort(incoming_packet->getDstPort());
@ -74,9 +63,7 @@ namespace udp
outgoing_packet->computeChecksum(ipv6::packetin.getDstAddress(), ipv6::packetin.getSrcAddress(), olen + 8); outgoing_packet->computeChecksum(ipv6::packetin.getDstAddress(), ipv6::packetin.getSrcAddress(), olen + 8);
return olen + 8; return olen + 8;
} }
} } else { /* default UDP application handler: echoes back the packet content */
else
{ /* default UDP application handler: echoes back the packet content */
outgoing_packet->setSrcPort(incoming_packet->getDstPort()); outgoing_packet->setSrcPort(incoming_packet->getDstPort());
outgoing_packet->setDstPort(incoming_packet->getSrcPort()); outgoing_packet->setDstPort(incoming_packet->getSrcPort());
outgoing_packet->setPayload(incoming_packet->getPayload(), ilen - 8); outgoing_packet->setPayload(incoming_packet->getPayload(), ilen - 8);
@ -85,34 +72,6 @@ namespace udp
} }
return -1; return -1;
} }
UDPClient::UDPClient(
const ipv6::IPv6Addr &_srcaddr,
ipv6::IPv6Addr &_dstaddr,
const uint16_t _srcport,
const uint16_t _dstport) : srcaddr(_srcaddr),
dstaddr(_dstaddr),
srcport(_srcport),
dstport(_dstport)
{
;
}
void UDPClient::send_datagram(const uint8_t *obuffer, size_t len)
{
UDPPacket *outgoing_packet = (UDPPacket *)(((uint8_t *)&ipv6::packetout) + 40);
outgoing_packet->setSrcPort(srcport);
outgoing_packet->setDstPort(dstport);
outgoing_packet->setPayload((const char *)obuffer, len);
outgoing_packet->computeChecksum(&srcaddr, &dstaddr, len + 8);
ipv6::packetout.setLen(len + 8);
ipv6::packetout.setFlow("\x26\x12\x21");
ipv6::packetout.setSrcAddress(&srcaddr);
ipv6::packetout.setDstAddress(&dstaddr);
ipv6::packetout.setNextHeader(ipv6::NH_UDP);
ipv6::packetout.send();
}
} }

View File

@ -4,43 +4,27 @@
#include "Arduino.h" #include "Arduino.h"
#include "ipv6.h" #include "ipv6.h"
namespace udp namespace udp {
{ class UDPPacket {
class UDPPacket
{
private: private:
char packet[ipv6::LEN - 40]; char packet[ipv6::LEN - 40];
public: public:
void setSrcPort(uint16_t port); void setSrcPort(uint16_t port);
uint16_t getSrcPort(); uint16_t getSrcPort();
void setDstPort(uint16_t port); void setDstPort(uint16_t port);
uint16_t getDstPort(); uint16_t getDstPort();
const char *UDPPacket::getPayload(); const char* UDPPacket::getPayload();
void setPayload(const char *payload, int len); /* also sets proper length */ void setPayload(const char* payload, int len); /* also sets proper length */
void computeChecksum(const ipv6::IPv6Addr *src_addr, const ipv6::IPv6Addr *dst_addr, int len); /* computes and updates checksum in the packet */ void computeChecksum(const ipv6::IPv6Addr* src_addr, const ipv6::IPv6Addr* dst_addr, int len); /* computes and updates checksum in the packet */
};
class UDPClient
{
private:
const ipv6::IPv6Addr &srcaddr;
const ipv6::IPv6Addr &dstaddr;
const uint16_t srcport;
const uint16_t dstport;
public:
UDPClient(const ipv6::IPv6Addr &srcaddr, ipv6::IPv6Addr &dstaddr, const uint16_t srcport, const uint16_t dstport);
void send_datagram(const uint8_t *payload, size_t len);
}; };
/* UDP handler for lower layer protocol */ /* UDP handler for lower layer protocol */
int handleUDP(char *output_buffer, const char *input_buffer, int len); int handleUDP(char* output_buffer, const char* input_buffer, int len);
/* pointer to server handler function */ /* pointer to server handler function */
extern int (*server_handler)(char *output_buffer, const char *buffer, int size); extern int(*server_handler) (char* output_buffer, const char* buffer, int size);
extern uint16_t server_port; extern uint16_t server_port;
void set_handler(uint16_t port, int (*handler)(char *output_buffer, const char *input_buffer, int size)); void set_handler(uint16_t port, int(* handler) (char* output_buffer, const char* input_buffer, int size));
} }
#endif #endif