commit 12d09f24c5d84c6597be5415730b698ae5d3e725 Author: giomba Date: Mon Dec 23 14:13:13 2019 +0100 First commit diff --git a/coppino-main.ino b/coppino-main.ino new file mode 100644 index 0000000..f058b40 --- /dev/null +++ b/coppino-main.ino @@ -0,0 +1,35 @@ +#include "coppino.h" +#include "ipv6.h" +#include "slip.h" + +void setup() { + pinMode(13, OUTPUT); + + Serial.begin(9600); + char addr[16] = { 0x20, 0x01, 0x04, 0x70, 0xc8, 0x44, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xfe}; + coppino::address.deserialize(addr); +} + +void loop() { + + /* some UDP stuff, just to test */ + char udp_packet[64]; + memcpy(udp_packet, "\x00\x00\x77\x77\x00\x12\x00\x00helloworld", 18); + + ipv6::IPv6Packet ip_packet; + + ip_packet.setPayload(udp_packet, 18); + ip_packet.setSrcAddress(coppino::address); + + // ipv6::IPv6Addr dst_addr("\x20\x01\x04\x70\xc8\x44\x00\x30\x53\x47\xde\x2d\x41\xb1\x5b\x8c"); + ipv6::IPv6Addr dst_addr("\x20\x01\x04\x70\xc8\x44\x00\x31\x00\x00\x00\x00\x00\x00\x00\x01"); + ip_packet.setDstAddress(dst_addr); + + ip_packet.setNextHeader(17); // UDP + + // slip::send(ip_packet.serialize(), 18 + 40); + + coppino::handler(); + + //delay(5000); +} diff --git a/coppino.h b/coppino.h new file mode 100644 index 0000000..f399890 --- /dev/null +++ b/coppino.h @@ -0,0 +1,24 @@ +#ifndef COPPINO_H +#define COPPINO_H + +#include "ipv6.h" + +namespace coppino { + const uint8_t LEN = 128; + extern ipv6::IPv6Addr address; + /* netmask: + * no netmask is needed, because everything is sent over TTL UART + * gateway: + * the same as above + */ + + void handler(void); + + void hexdump(const char* pointer, int len); + + uint16_t compute_checksum(const char* src_addr, const char* dst_addr, uint8_t next_header, const char* payload, int len); + + void blink(); +} + +#endif diff --git a/coppino.ino b/coppino.ino new file mode 100644 index 0000000..1e6dcb9 --- /dev/null +++ b/coppino.ino @@ -0,0 +1,79 @@ +#include "coppino.h" + +namespace coppino { + ipv6::IPv6Addr address; + + void handler() { + + char buffer[LEN]; + int r; + + while ((r = slip::recv(buffer, LEN)) != -1) { + ipv6::IPv6Packet packet; + packet.deserialize(buffer, r); + packet.doAction(); + } + + } + + void hexdump(const char* pointer, int len) { + for (int i = 0; i < len; ++i) { + Serial.print(pointer[i] & 0xff, HEX); + Serial.print('.'); + } + } + + uint16_t compute_checksum(const char* src_addr, const char* dst_addr, uint8_t next_header, const char* payload, int len) { + char buffer[LEN]; + uint32_t total; + uint16_t* ptr; + int words; + int i = len; + + memcpy(buffer, payload, len); + if (len % 2) { + buffer[len] = 0; + i++; + } + memcpy(buffer + i, src_addr, 16); i += 16; + memcpy(buffer + i, dst_addr, 16); i += 16; + memcpy(buffer + i, "\0\0", 2); i += 2; + buffer[i] = len >> 8; i += 1; + buffer[i] = len & 0xff; i += 1; + memcpy(buffer + i, "\0\0\0", 3); i += 3; + buffer[i] = next_header; i += 1; + + total = 0; + ptr = (uint16_t*)buffer; + words = (i + 1) / 2; + + while (words--) total += *ptr++; + + while (total & 0xffff0000) + total = (total >> 16) + (total & 0xffff); + + //total -= 64*256; // TODO -- this is an ugly fix, something is wrong somewhere else + + return ~((uint16_t) total); + /* + uint16_t checksum = 0; + for (i = 0; i < len; i = i + 2) { + part = ((*(packet + i + 0)) << 8) + *(packet + i + 1); + checksum += part; + } + for (i = 0; i < 16; i = i + 2 ) { + part = ((*(src_addr + i + 0)) << 8) + *(src_addr + i + 1); + checksum += part; + part = ((*(dst_addr + i + 0)) << 8) + *(dst_addr + i + 1); + checksum += part; + } + checksum += (len + 58); // upper-layer packet length + next header + while (checksum >> 16) + checksum = (checksum & 0xffff) + (checksum >> 16); + */ + } + + void blink() { + digitalWrite(13, !digitalRead(13)); + } +} diff --git a/ipv6.h b/ipv6.h new file mode 100644 index 0000000..53e09ed --- /dev/null +++ b/ipv6.h @@ -0,0 +1,48 @@ +#ifndef COPPINO_IPV6_H +#define COPPINO_IPV6_H + +namespace ipv6 { + + const uint8_t LEN = 128; + + class IPv6Addr { + private: + char address[16]; + public: + IPv6Addr(); + IPv6Addr(const char* address); + void deserialize(const char* address); + const char* serialize(); + }; + + extern IPv6Addr ALL_NODES_ADDRESS; + + struct ipv6_packet_header { + char field[4]; + char len[2]; + char next_header; + char hop_limit; + IPv6Addr src_addr; + IPv6Addr dst_addr; + }__attribute__((packed)); + + class IPv6Packet { + private: + char packet[LEN]; + public: + void setSrcAddress(IPv6Addr& address); + void setDstAddress(IPv6Addr& address); + void setNextHeader(uint8_t next_header); + void setPayload(char* payload, uint8_t len); + + char* serialize(); + void deserialize(const char*, uint8_t len); + + void doAction(); + }; + + /* Note: content of message may be changed */ + void handleICMP(const char* src, const char* dst, char* message, int len); +} + +#endif diff --git a/ipv6.ino b/ipv6.ino new file mode 100644 index 0000000..a76a8ef --- /dev/null +++ b/ipv6.ino @@ -0,0 +1,109 @@ +#include "ipv6.h" + +namespace ipv6 { +/******** costants ********/ +IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x01"); /* ff02::1 */ + +/******** IPv6Addr ********/ +IPv6Addr::IPv6Addr() {;} + +IPv6Addr::IPv6Addr(const char* address) { + this->deserialize(address); +} + +void IPv6Addr::deserialize(const char* address) { + memcpy(this->address, address, 16); +} + +const char* IPv6Addr::serialize() { + return this->address; +} + +/******** IPv6Packet ********/ +char* IPv6Packet::serialize() { /* do we actually need these function? everything is already store in a tokenized/serialized form */ + return packet; +} + +void IPv6Packet::deserialize(const char* buffer, uint8_t len) { + memcpy(packet, buffer, len); +} + +void IPv6Packet::setNextHeader(uint8_t next_header) { + *(packet + 6) = next_header; +} + +void IPv6Packet::setSrcAddress(IPv6Addr& address) { + memcpy(packet + 8, (void*)&address, 16); +} +void IPv6Packet::setDstAddress(IPv6Addr& address) { + memcpy(packet + 24, (void*)&address, 16); +} + +void IPv6Packet::setPayload(char* payload, uint8_t len) { + memset(packet, 0, LEN); + + ipv6_packet_header* header = (ipv6_packet_header*)packet; + memcpy(header->field, "\x60\x00\x00\x00", 4); + + memcpy(header->len + 1, (char*)&len, 1); + header->hop_limit = 64; + + memcpy(packet + sizeof(ipv6_packet_header), payload, len); + } + + void IPv6Packet::doAction() { + /* if destination is my address, or destination is "all nodes" address, then... */ + if ((memcmp(&(ALL_NODES_ADDRESS), packet + 24, 16) == 0) || (memcmp(&(coppino::address), packet + 24, 16) == 0)) { + int len = ((*(packet + 4)) << 8) + (*(packet + 5)); + + switch(*(packet + 6)) { /* next header */ + case 58: + handleICMP(packet + 8, packet + 24, packet + 40, len); + break; + case 17: + // handleUDP(packet + 40, len); + break; + default: + /* no other protocols are known here, sorry :-) */ + break; + } + } + } + +void handleICMP(const char* src_addr, const char* dst_addr, char* packet, int len) { + uint8_t type = *(packet); + uint32_t checksum = ((*(packet + 2)) << 8) + (*(packet + 3)); + uint16_t part; + IPv6Addr dst; + int i; + + switch (type) { + case 128: + /* TODO compute checksum, and assert validity of incoming message */ + /* then... */ + + /* Build an echo reply: + * the reply has the same exact format of the request, + * except for Type and Checksum */ + *(packet) = 129; /* echo reply type */ + *(packet + 2) = *(packet + 3) = 0; /* zero-checksum */ + + checksum = coppino::compute_checksum(src_addr, dst_addr, 58, packet, len); + memcpy(packet + 2, &checksum, 2); + + IPv6Packet reply_packet; + reply_packet.setPayload(packet, len); + reply_packet.setSrcAddress(coppino::address); + dst.deserialize(src_addr); + reply_packet.setDstAddress(dst); + reply_packet.setNextHeader(58); // ICMPv6 + slip::send((void*)&reply_packet, 40 + len); + break; + default: + /* no other types have been implemented */ + break; + } + return; +} + +} diff --git a/slip.h b/slip.h new file mode 100644 index 0000000..165bcdb --- /dev/null +++ b/slip.h @@ -0,0 +1,16 @@ +#ifndef COPPINO_SLIP_H +#define COPPINO_SLIP_H + +namespace slip { + + const char END = 0xc0; + const char ESC = 0xdb; + const char ESC_END = 0xdc; + const char ESC_ESC = 0xdd; + + void send(const char* buffer, uint8_t len); + int recv(char* buffer, uint8_t len); + +} + +#endif diff --git a/slip.ino b/slip.ino new file mode 100644 index 0000000..cec7ffc --- /dev/null +++ b/slip.ino @@ -0,0 +1,57 @@ +namespace slip { + + void send(const char* buffer, uint8_t len) { + // Serial.write(END); /* frame-out any possible noise on the line */ + + for (uint8_t i = 0; i < len; ++i) { + switch (buffer[i]) { + case END: + Serial.write(ESC); + Serial.write(ESC_END); + break; + case ESC: + Serial.write(ESC); + Serial.write(ESC_ESC); + break; + default: + Serial.write(buffer[i]); + break; + } + } + + Serial.write(END); + } + + int recv(char* buffer, uint8_t len) { + char r; + uint8_t i = 0; + + while (i < len) { + if (Serial.available()) { + r = Serial.read(); + + switch (r) { + case ESC: + r = Serial.read(); + if (r == ESC_END) { + buffer[i++] = END; + } else if (r == ESC_ESC) { + buffer[i++] = ESC; + } + break; + case END: + return i; + break; + default: + buffer[i++] = r; + break; + } + } + } + + + + return i; + } + +} /* namespace slip */