First commit
This commit is contained in:
commit
12d09f24c5
35
coppino-main.ino
Normal file
35
coppino-main.ino
Normal 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
24
coppino.h
Normal 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
79
coppino.ino
Normal 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
48
ipv6.h
Normal 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
109
ipv6.ino
Normal 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
16
slip.h
Normal 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
57
slip.ino
Normal 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 */
|
Loading…
Reference in New Issue
Block a user