First commit

This commit is contained in:
giomba 2019-12-23 14:13:13 +01:00
commit 12d09f24c5
7 changed files with 368 additions and 0 deletions

35
coppino-main.ino Normal file
View File

@ -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);
}

24
coppino.h Normal file
View File

@ -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

79
coppino.ino Normal file
View File

@ -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));
}
}

48
ipv6.h Normal file
View File

@ -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

109
ipv6.ino Normal file
View File

@ -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;
}
}

16
slip.h Normal file
View File

@ -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

57
slip.ino Normal file
View File

@ -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 */