Compare commits
6 Commits
dc03eeb307
...
9febc5dc06
Author | SHA1 | Date | |
---|---|---|---|
9febc5dc06 | |||
7cfec6898e | |||
09febbfb75 | |||
842dc10a5a | |||
42e70e9c20 | |||
3d206c0d23 |
20
README.md
20
README.md
@ -6,3 +6,23 @@ 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
|
||||||
|
|
||||||
|
1
examples/simple-udp-client/.gitignore
vendored
Normal file
1
examples/simple-udp-client/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build/
|
15
examples/simple-udp-client/Makefile
Normal file
15
examples/simple-udp-client/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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
|
47
examples/simple-udp-client/simple-udp-client.ino
Normal file
47
examples/simple-udp-client/simple-udp-client.ino
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
examples/simple-udp-server/.gitignore
vendored
Normal file
1
examples/simple-udp-server/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build/
|
15
examples/simple-udp-server/Makefile
Normal file
15
examples/simple-udp-server/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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
|
@ -14,6 +14,8 @@ 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
|
||||||
@ -26,8 +28,6 @@ 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");
|
||||||
|
|
||||||
|
123
src/ipv6.cpp
123
src/ipv6.cpp
@ -1,7 +1,8 @@
|
|||||||
#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 */
|
||||||
|
|
||||||
@ -9,26 +10,25 @@ const IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\
|
|||||||
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 SLAAC(bool enable) {
|
void setGlobalAddress(const char *address)
|
||||||
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;
|
||||||
@ -41,26 +41,35 @@ uint16_t compute_checksum(const IPv6Addr* src_addr, const IPv6Addr* dst_addr, ui
|
|||||||
*/
|
*/
|
||||||
/* actual payload */
|
/* actual payload */
|
||||||
memcpy(buffer, payload, len);
|
memcpy(buffer, payload, len);
|
||||||
if (len % 2) { /* pad with 0 if length is odd */
|
if (len % 2)
|
||||||
|
{ /* 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); i += 16;
|
memcpy(buffer + i, src_addr, 16);
|
||||||
memcpy(buffer + i, dst_addr, 16); i += 16;
|
i += 16;
|
||||||
memset(buffer + i, 0, 3); i+= 3; /* first 3 bytes always 0, because len always < 256 */
|
memcpy(buffer + i, dst_addr, 16);
|
||||||
buffer[i] = upper_len & 0xff; i += 1;
|
i += 16;
|
||||||
memset(buffer + i, 0, 3); i += 3; /* zero, as per-standard */
|
memset(buffer + i, 0, 3);
|
||||||
buffer[i] = next_header; i += 1;
|
i += 3; /* first 3 bytes always 0, because len always < 256 */
|
||||||
|
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--) total += *ptr++;
|
while (words--)
|
||||||
|
total += *ptr++;
|
||||||
|
|
||||||
while (total & 0xffff0000) {
|
while (total & 0xffff0000)
|
||||||
|
{
|
||||||
total = (total >> 16) + (total & 0xffff);
|
total = (total >> 16) + (total & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,48 +79,59 @@ uint16_t compute_checksum(const IPv6Addr* src_addr, const IPv6Addr* dst_addr, ui
|
|||||||
/******** 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 */
|
||||||
@ -119,28 +139,34 @@ void IPv6Packet::setFlow(const char* flow) {
|
|||||||
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)) { /* next header */
|
switch (*(packet + 6))
|
||||||
|
{ /* 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());
|
||||||
@ -150,7 +176,8 @@ void IPv6Packet::doAction() {
|
|||||||
}
|
}
|
||||||
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());
|
||||||
@ -169,7 +196,8 @@ void IPv6Packet::doAction() {
|
|||||||
/* 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 */
|
||||||
@ -186,11 +214,13 @@ int handleICMP(char* output_buffer, const char* input_buffer, int len) {
|
|||||||
output_buffer,
|
output_buffer,
|
||||||
len);
|
len);
|
||||||
|
|
||||||
if (memcmp(&computed_checksum, received_checksum, 2) != 0) { /* if checksum is not valid, return */
|
if (memcmp(&computed_checksum, received_checksum, 2) != 0)
|
||||||
|
{ /* if checksum is not valid, return */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ICMP_ECHO_REQUEST_TYPE) { /* if it is ICMPv6 Echo Request, then... */
|
if (type == ICMP_ECHO_REQUEST_TYPE)
|
||||||
|
{ /* 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 */
|
||||||
@ -206,20 +236,25 @@ int handleICMP(char* output_buffer, const char* input_buffer, int len) {
|
|||||||
len);
|
len);
|
||||||
memcpy(output_buffer + 2, &checksum, 2);
|
memcpy(output_buffer + 2, &checksum, 2);
|
||||||
return len;
|
return len;
|
||||||
|
}
|
||||||
} else if (type == ICMP_RADV_TYPE && slaac_enable) { /* if it is IVMPc6 Router Advertisement, then... */
|
else if (type == ICMP_RADV_TYPE && ENABLE_SLAAC)
|
||||||
|
{ /* 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)
|
||||||
|
{ /* if it is a ICMPv6 Prefix Information, then... */
|
||||||
ICMPv6_RADV_PrefixInformation *p = (ICMPv6_RADV_PrefixInformation *)option;
|
ICMPv6_RADV_PrefixInformation *p = (ICMPv6_RADV_PrefixInformation *)option;
|
||||||
|
|
||||||
if (p->prefix_length != 64) continue; /* only /64 prefix is supported */
|
if (p->prefix_length != 64)
|
||||||
if (! (p->la_flags & 0x40)) continue; /* only SLAAC is supported */
|
continue; /* only /64 prefix 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;
|
||||||
}
|
}
|
||||||
|
22
src/ipv6.h
22
src/ipv6.h
@ -1,10 +1,12 @@
|
|||||||
#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;
|
||||||
|
|
||||||
@ -17,9 +19,11 @@ 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);
|
||||||
@ -27,9 +31,11 @@ namespace ipv6 {
|
|||||||
|
|
||||||
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);
|
||||||
@ -65,7 +71,8 @@ namespace ipv6 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/* 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];
|
||||||
@ -76,12 +83,14 @@ 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;
|
||||||
@ -94,7 +103,6 @@ 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 SLAAC(bool enable); /* enable IPv6 automatic prefix configuration (listens for RADV) */
|
|
||||||
void setGlobalAddress(const char *address); /* global IPv6 address, manually configured */
|
void setGlobalAddress(const char *address); /* global IPv6 address, manually configured */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/settings.h
Normal file
8
src/settings.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef __COPPINO_SETTINGS_
|
||||||
|
#define __COPPINO_SETTINGS_
|
||||||
|
|
||||||
|
/* coppino configuration settings */
|
||||||
|
// Enable IPv6 automatic prefix configuration (listens for RADV)
|
||||||
|
constexpr bool ENABLE_SLAAC = false;
|
||||||
|
|
||||||
|
#endif
|
69
src/udp.cpp
69
src/udp.cpp
@ -1,46 +1,54 @@
|
|||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
|
|
||||||
namespace udp {
|
namespace udp
|
||||||
|
{
|
||||||
int (*server_handler)(char *output_buffer, const char *input_buffer, int size) = NULL;
|
int (*server_handler)(char *output_buffer, const char *input_buffer, int size) = NULL;
|
||||||
uint16_t server_port = 0;
|
uint16_t server_port = 0;
|
||||||
|
|
||||||
void UDPPacket::setSrcPort(uint16_t port) {
|
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;
|
||||||
}
|
}
|
||||||
@ -48,13 +56,16 @@ void set_handler(uint16_t port, int(* server_handler) (char* output_buffer, cons
|
|||||||
/* 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) { /* call user-defined server handler */
|
if (incoming_packet->getDstPort() == server_port)
|
||||||
if (server_port != 0 && server_handler != NULL) {
|
{ /* call user-defined server handler */
|
||||||
|
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());
|
||||||
@ -63,7 +74,9 @@ int handleUDP(char* output_buffer, const char* input_buffer, int ilen) {
|
|||||||
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);
|
||||||
@ -74,4 +87,32 @@ int handleUDP(char* output_buffer, const char* input_buffer, int ilen) {
|
|||||||
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
20
src/udp.h
20
src/udp.h
@ -4,10 +4,13 @@
|
|||||||
#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();
|
||||||
@ -18,6 +21,19 @@ namespace udp {
|
|||||||
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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user