1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

Merge pull request #2688 from authmillenon/ng_slip/feat/initial

ng_slip: initial import
This commit is contained in:
Martine Lenders 2015-05-23 21:19:29 +02:00
commit 1d74a730a6
34 changed files with 3938 additions and 4054 deletions

View File

@ -180,6 +180,10 @@ ifneq (,$(filter ng_pktdump,$(USEMODULE)))
USEMODULE += od USEMODULE += od
endif endif
ifneq (,$(filter ng_slip,$(USEMODULE)))
USEMODULE += ng_netbase
endif
ifneq (,$(filter aodvv2,$(USEMODULE))) ifneq (,$(filter aodvv2,$(USEMODULE)))
USEMODULE += vtimer USEMODULE += vtimer
USEMODULE += sixlowpan USEMODULE += sixlowpan

View File

@ -0,0 +1 @@
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1\. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer\. 2\. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution\. 3\. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission\. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED\. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION\) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \(INCLUDING NEGLIGENCE OR OTHERWISE\) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE\.

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +0,0 @@
CFLAGS = -lrt -pthread -Wall
CC = gcc
DOCTOOL = doxygen
TESTING = -D BORDER_TESTING
all: sixlowdriver doc
SRC = main.c sixlowdriver.c serial.c control_2xxx.c multiplex.c flowcontrol.c serialnumber.c
TARGETDIR = ../../bin/linux
DOCDIR = ../../Documentation/linux
sixlowdriver: $(SRC)
mkdir -p $(TARGETDIR) &> /dev/null
$(CC) $(CFLAGS) -o $(TARGETDIR)/sixlowpan $(SRC)
sixlowtest: $(SRC) testing.c
mkdir -p $(TARGETDIR) &> /dev/null
$(CC) $(CFLAGS) $(TESTING) -o $(TARGETDIR)/sixlowpan $(SRC) testing.c
doc: $(SRC)
mkdir -p $(DOCDIR) &> /dev/null
$(DOCTOOL) > /dev/null

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include "control_2xxx.h"
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include "serial.h"
void hard_reset_to_bootloader(void)
{
printf("Reset CPU (into bootloader)\r\n");
set_rts(1); /* RTS (ttl level) connects to P0.14 */
set_dtr(1); /* DTR (ttl level) connects to RST */
send_break_signal(); /* or break detect circuit to RST */
usleep(75000);
set_dtr(0); /* allow the CPU to run */
set_baud(baud_rate);
set_rts(1); /* set RTS again (as it has been reset by set_baudrate) */
usleep(40000);
}
void hard_reset_to_user_code(void)
{
printf("Reset CPU (into user code)\r\n");
set_rts(0); /* RTS (ttl level) connects to P0.14 */
set_dtr(1); /* DTR (ttl level) connects to RST */
send_break_signal(); /* or break detect circuit to RST */
usleep(75000);
set_dtr(0); /* allow the CPU to run */
usleep(40000);
}

View File

@ -1,16 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/* token from pseudoterm */
#ifndef CONTROL_2XXXX_H
#define CONTROL_2XXXX_H
void hard_reset_to_bootloader(void);
void hard_reset_to_user_code(void);
#endif // ..._H

View File

@ -1,172 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#ifdef BORDER_TESTING
#include "testing.h"
#endif
#include "flowcontrol.h"
#include "multiplex.h"
flowcontrol_stat_t slwin_stat;
uint8_t connection_established;
void *resend_thread_f(void *args)
{
uint8_t seq_num = *((uint8_t *)args);
struct send_slot *slot = &(slwin_stat.send_win[seq_num % BORDER_SWS]);
while (1) {
usleep(BORDER_SL_TIMEOUT);
if (seq_num == ((border_packet_t *)(slot->frame))->seq_num) {
writepacket(slot->frame, slot->frame_len);
}
else {
return NULL;
}
}
}
void init_threeway_handshake(const struct in6_addr *addr)
{
border_syn_packet_t *syn = (border_syn_packet_t *)get_serial_out_buffer(0);
syn->empty = 0;
syn->type = BORDER_PACKET_CONF_TYPE;
syn->next_seq_num = slwin_stat.last_frame + 1;
syn->conftype = BORDER_CONF_SYN;
syn->next_exp = slwin_stat.next_exp;
memcpy(&(syn->addr), addr, 16);
do {
writepacket((uint8_t *)syn, sizeof(border_syn_packet_t));
usleep(BORDER_SL_TIMEOUT);
}
while (!connection_established);
}
void signal_connection_established(void)
{
connection_established = 1;
}
void flowcontrol_init(const struct in6_addr *addr)
{
int i;
slwin_stat.last_frame = 0xFF;
slwin_stat.last_ack = slwin_stat.last_frame;
connection_established = 0;
sem_init(&slwin_stat.send_win_not_full, 0, BORDER_SWS);
for (i = 0; i < BORDER_SWS; i++) {
slwin_stat.send_win[i].frame_len = 0;
}
memset(&slwin_stat.send_win, 0, sizeof(struct send_slot) * BORDER_SWS);
slwin_stat.next_exp = 0;
for (i = 0; i < BORDER_RWS; i++) {
slwin_stat.recv_win[i].received = 0;
slwin_stat.recv_win[i].frame_len = 0;
}
memset(&slwin_stat.recv_win, 0, sizeof(struct recv_slot) * BORDER_RWS);
init_threeway_handshake(addr);
}
void flowcontrol_destroy(void)
{
sem_destroy(&slwin_stat.send_win_not_full);
}
static int in_window(uint8_t seq_num, uint8_t min, uint8_t max)
{
uint8_t pos = seq_num - min;
uint8_t maxpos = max - min + 1;
return pos < maxpos;
}
void send_ack(uint8_t seq_num)
{
border_packet_t *packet = (border_packet_t *)get_serial_out_buffer(0);
packet->empty = 0;
packet->type = BORDER_PACKET_ACK_TYPE;
packet->seq_num = seq_num;
writepacket((uint8_t *)packet, sizeof(border_packet_t));
}
void flowcontrol_send_over_tty(border_packet_t *packet, int len)
{
struct send_slot *slot;
uint8_t args[] = {packet->seq_num};
sem_wait(&(slwin_stat.send_win_not_full));
packet->seq_num = ++slwin_stat.last_frame;
slot = &(slwin_stat.send_win[packet->seq_num % BORDER_SWS]);
memcpy(slot->frame, (uint8_t *)packet, len);
slot->frame_len = len;
pthread_create(&slot->resend_thread, NULL, resend_thread_f, (void *)args);
#ifdef BORDER_TESTING
testing_start(packet->seq_num);
#endif
writepacket((uint8_t *)packet, len);
}
void flowcontrol_deliver_from_tty(const border_packet_t *packet, int len)
{
if (packet->type == BORDER_PACKET_ACK_TYPE) {
if (in_window(packet->seq_num, slwin_stat.last_ack + 1, slwin_stat.last_frame)) {
do {
struct send_slot *slot;
slot = &(slwin_stat.send_win[++slwin_stat.last_ack % BORDER_SWS]);
#ifdef BORDER_TESTING
testing_stop(slwin_stat.last_ack);
#endif
pthread_cancel(slot->resend_thread);
memset(&slot->frame, 0, BUFFER_SIZE);
slot->frame_len = 0;
sem_post(&slwin_stat.send_win_not_full);
}
while (slwin_stat.last_ack != packet->seq_num);
}
}
else {
struct recv_slot *slot;
slot = &slwin_stat.recv_win[packet->seq_num % BORDER_RWS];
if (!in_window(packet->seq_num,
slwin_stat.next_exp,
slwin_stat.next_exp + BORDER_RWS - 1)) {
return;
}
memcpy(slot->frame, (uint8_t *)packet, len);
slot->received = 1;
if (packet->seq_num == slwin_stat.next_exp) {
while (slot->received) {
demultiplex((border_packet_t *)slot->frame, slot->frame_len);
memset(&slot->frame, 0, BUFFER_SIZE);
slot->received = 0;
slot = &slwin_stat.recv_win[++slwin_stat.next_exp % BORDER_RWS];
}
}
send_ack(slwin_stat.next_exp - 1);
}
}

View File

@ -1,138 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @brief Public declarations for the flow control jobs via the
* serial interface for the 6LoWPAN Border Router driver.
*/
#ifndef FLOWCONTROL_H
#define FLOWCONTROL_H
#include <stdint.h>
#include <pthread.h>
#include <semaphore.h>
#include <netinet/in.h>
#include "multiplex.h"
/* packet types for flowcontrol */
#define BORDER_PACKET_ACK_TYPE 1 ///< Packet type for acknowledgement packets (for flow control).
/* configuration types for flowcontrol */
#define BORDER_CONF_SYN 0 ///< Configuration packet type for SYN-Packets.
#define BORDER_CONF_SYNACK 1 ///< Configuration packet type for SYN/ACK-Packets.
#define BORDER_SWS 1 ///< Sending window size for flow control.
#define BORDER_RWS 1 ///< Receiving window size for flow control.
#define BORDER_SL_TIMEOUT 500000 ///< Timeout time (in µsec) for flow control.
/**
* @brief State of the sliding window algorithm, used for flow control
* @see "Computernetze -- Eine systemorientierte Einführung",
* L.L. Peterson, B.S. Davie, dpunkt-lehrbuch, 2008
*/
typedef struct flowcontrol_stat_t {
/* Sender state */
uint8_t last_ack; ///< Sequence number of the last received acknowledgement.
uint8_t last_frame; ///< Sequence number of the last send frame.
/**
* @brief Semaphore, that locks if sending window is full.
*/
sem_t send_win_not_full;
/**
* @brief a slot in the sending window
*/
struct send_slot {
pthread_t resend_thread; ///< Thread that handles the resending of this slot's frame (if needed).
uint8_t frame[BUFFER_SIZE]; ///< This slot's frame.
size_t frame_len; ///< The length of this slot's frame.
} send_win[BORDER_SWS]; ///< The sending window.
/* Receiver state */
uint8_t next_exp; ///< The next expected sequence number to be received.
/**
* @brief a receiving in the sending window
*/
struct recv_slot {
int8_t received; ///< 0 if this slot is empty, != 0 if this slot contains a received frame.
uint8_t frame[BUFFER_SIZE]; ///< This slot's frame
size_t frame_len; ///< The length of this slot's frame.
} recv_win[BORDER_RWS]; ///< The receiving window.
} flowcontrol_stat_t;
/**
* @brief Describes a SYN packet for connection establishment of
* the serial line.
* @extends border_conf_header_t
*/
typedef struct __attribute__((packed)) border_syn_packet_t {
uint8_t empty;
uint8_t type;
/**
* @brief Next sequence number
*
* Communicates the next local sequence number to be send to the
* MSB-A2 (for flow control).
*
* This replaces @ref border_conf_header_t::seq_num of normal
* configuration packets.
*/
uint8_t next_seq_num;
uint8_t conftype;
/**
* @brief Next expected sequence number
*
* Communicates to the MSB-A2 which sequence number the driver
* expects next.
*/
uint8_t next_exp;
struct in6_addr addr; ///< IPv6-Address of this border router.
} border_syn_packet_t;
/**
* @brief Sets the flow control algorithm to the initial state.
* @param[in] addr The IP address that should be communicated to the
* LoWPAN interface.
*/
void flowcontrol_init(const struct in6_addr *addr);
/**
* @brief Destroys the state struct for the flow control algorithm.
*/
void flowcontrol_destroy(void);
/**
* @brief Singals the flow control algorith, that an connection
* was established (because a SYNACK packet was received).
*/
void signal_connection_established(void);
/**
* @brief Sends a packet via the serial interface.
* @param[in,out] packet The packet that is to be send via the
* serial interface. The function sets the
* sequence number of the packet for flow
* control.
* @param[in] len Length of the packet.
*/
void flowcontrol_send_over_tty(border_packet_t *packet, int len);
/**
* @brief Delivers all actions that should be done by the sliding
* window on receiving a packet.
* @param[in] packet The packet the was received via the serial
* interface.
* @param[in] len Length of the packet.
*/
void flowcontrol_deliver_from_tty(const border_packet_t *packet, int len);
#endif /* FLOWCONTROL_H*/

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "sixlowdriver.h"
#ifdef BORDER_TESTING
#include "testing.h"
#endif
int main(int argc, char **argv)
{
if (argc < 4) {
fprintf(stderr, "Usage: %s r_addr if_name tty_dev\n", argv[0]);
return -1;
}
char addr[IPV6_ADDR_LEN];
sprintf(addr, "abcd::1034:00FF:FE00:%s/64", argv[1]);
char if_name[IF_NAME_LEN];
strncpy(if_name, argv[2], IF_NAME_LEN);
char tty_dev[DEV_LEN];
strncpy(tty_dev, argv[3], DEV_LEN);
if (border_initialize(if_name, addr, tty_dev) == 0) {
#ifdef BORDER_TESTING
char ping_addr[IPV6_ADDR_LEN];
float interval;
if (argc < 9) {
fprintf(stderr, "Usage: %s r_addr if_name tty_dev ping_id result_dir skeleton_file ping_count interval\n", argv[0]);
return -1;
}
sscanf(argv[8], "%20f", &interval);
sprintf(ping_addr, "abcd::%s/64", argv[4]);
start_test(ping_addr, argv[5], argv[6], atoi(argv[7]), interval);
#else
while (1);
#endif
}
return 0;
}

View File

@ -1,287 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include "flowcontrol.h"
#include "multiplex.h"
#include "serial.h"
#include "sixlowdriver.h"
#define END 0xC0
#define ESC 0xDB
#define END_ESC 0xDC
#define ESC_ESC 0xDD
uint8_t serial_out_buf[BUFFER_SIZE];
uint8_t serial_in_buf[BUFFER_SIZE];
uint8_t *get_serial_out_buffer(int offset)
{
if (offset > BUFFER_SIZE) {
return NULL;
}
return &(serial_out_buf[offset]);
}
uint8_t *get_serial_in_buffer(int offset)
{
if (offset > BUFFER_SIZE) {
return NULL;
}
return &(serial_in_buf[offset]);
}
int init_multiplex(const char *tty_dev)
{
return open_serial_port(tty_dev);
}
uint8_t serial_read_byte()
{
unsigned char c;
read_serial_port(&c, 1);
return (uint8_t)c;
}
int readpacket(uint8_t *packet_buf, size_t size)
{
uint8_t *line_buf_ptr = packet_buf;
uint8_t esc = 0;
uint8_t translate = 1;
while ((line_buf_ptr - packet_buf) < size - 1) {
uint8_t byte = serial_read_byte();
if (translate && byte == END) {
break;
}
if (line_buf_ptr == packet_buf && byte != 0) {
translate = 0;
}
if (line_buf_ptr > packet_buf && !translate && byte == '\n') {
*line_buf_ptr++ = '\0';
return line_buf_ptr - packet_buf;
}
if (translate) {
if (esc) {
esc = 0;
switch (byte) {
case (END_ESC): {
*line_buf_ptr++ = END;
continue;
}
case (ESC_ESC): {
*line_buf_ptr++ = ESC;
continue;
}
default:
continue;
}
}
if (byte == ESC) {
esc = 1;
continue;
}
}
*line_buf_ptr++ = byte;
}
return (line_buf_ptr - packet_buf);
}
int writepacket(uint8_t *packet_buf, size_t size)
{
uint8_t packet_tmp[2 * BUFFER_SIZE];
uint8_t *byte_ptr = packet_buf;
uint8_t *tmp_ptr = packet_tmp;
if (2 * size + 1 > BUFFER_SIZE) {
return -1;
}
while ((byte_ptr - packet_buf) < size) {
switch (*byte_ptr) {
case (END): {
*byte_ptr = END_ESC;
*tmp_ptr = ESC;
tmp_ptr++;
break;
}
case (ESC): {
*byte_ptr = ESC_ESC;
*tmp_ptr = ESC;
tmp_ptr++;
break;
}
default: {
break;
}
}
*tmp_ptr = *byte_ptr;
byte_ptr++;
tmp_ptr++;
}
*tmp_ptr++ = END;
write_serial_port(packet_tmp, tmp_ptr - packet_tmp);
return 0;
}
void demultiplex(const border_packet_t *packet, int len)
{
switch (packet->type) {
case (BORDER_PACKET_RAW_TYPE): {
printf("\033[00;33m[via serial interface] %s\033[00m\n",
((unsigned char *)packet) + sizeof(border_packet_t)
);
break;
}
case (BORDER_PACKET_L3_TYPE): {
border_l3_header_t *l3_header_buf = (border_l3_header_t *)packet;
switch (l3_header_buf->ethertype) {
case (ETHERTYPE_IPV6): {
printf("INFO: IPv6-Packet %d received\n", l3_header_buf->seq_num);
struct ip6_hdr *ip6_buf = (struct ip6_hdr *)(((unsigned char *)packet) + sizeof(border_l3_header_t));
border_send_ipv6_over_tun(get_tun_fd(), ip6_buf);
break;
}
default:
printf("INFO: Unknown ethertype %04x for packet %d\n", l3_header_buf->ethertype, l3_header_buf->seq_num);
break;
}
break;
}
case (BORDER_PACKET_CONF_TYPE): {
border_conf_header_t *conf_header_buf = (border_conf_header_t *)packet;
switch (conf_header_buf->conftype) {
case (BORDER_CONF_SYNACK): {
printf("INFO: SYNACK-Packet %d received\n", conf_header_buf->seq_num);
signal_connection_established();
break;
}
case (BORDER_CONF_CONTEXT): {
printf("INFO: Context packet (%d) received, "
"but nothing is implemented yet for this case.\n",
conf_header_buf->seq_num);
break;
}
case (BORDER_CONF_IPADDR): {
char str_addr[IPV6_ADDR_LEN];
border_addr_packet_t *addr_packet = (border_addr_packet_t *)packet;
printf("INFO: Address packet (%d) received.\n",
conf_header_buf->seq_num);
inet_ntop(AF_INET6, &addr_packet->addr, str_addr, IPV6_ADDR_LEN);
tun_add_addr(str_addr);
}
default:
printf("INFO: Unknown conftype %02x for packet %d\n",
conf_header_buf->conftype,
conf_header_buf->seq_num);
break;
}
break;
}
default:
printf("INFO: Unknown border packet type %02x for packet %d\n", packet->type, packet->seq_num);
//print_packet_hex((unsigned char *)packet,len);
break;
}
}
void multiplex_send_context_over_tty(const border_context_t *context)
{
border_context_packet_t *con_packet = (border_context_packet_t *)get_serial_out_buffer(0);
con_packet->empty = 0;
con_packet->type = BORDER_PACKET_CONF_TYPE;
con_packet->conftype = BORDER_CONF_CONTEXT;
memcpy(
&con_packet->context,
context,
sizeof(border_context_t)
);
flowcontrol_send_over_tty(
(border_packet_t *) con_packet,
sizeof(border_context_packet_t)
);
}
void multiplex_send_addr_over_tty(struct in6_addr *addr)
{
border_addr_packet_t *packet = (border_addr_packet_t *)get_serial_out_buffer(0);
packet->empty = 0;
packet->type = BORDER_PACKET_CONF_TYPE;
packet->conftype = BORDER_CONF_IPADDR;
memcpy(
&packet->addr,
addr,
sizeof(struct in6_addr)
);
flowcontrol_send_over_tty(
(border_packet_t *) packet,
sizeof(border_addr_packet_t)
);
}
void multiplex_send_ipv6_over_tty(const struct ip6_hdr *packet)
{
border_l3_header_t *l3_hdr = (border_l3_header_t *)get_serial_out_buffer(0);
size_t packet_size = sizeof(struct ip6_hdr) + packet->ip6_plen;
l3_hdr->empty = 0;
l3_hdr->type = BORDER_PACKET_L3_TYPE;
l3_hdr->ethertype = ETHERTYPE_IPV6;
memcpy(
get_serial_out_buffer(0) + sizeof(border_l3_header_t),
packet,
packet_size
);
flowcontrol_send_over_tty(
(border_packet_t *) l3_hdr,
sizeof(border_l3_header_t) + packet_size
);
}

View File

@ -1,202 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @brief Public declarations for the multiplexing jobs via the
* serial interface for the 6LoWPAN Border Router driver.
*/
#ifndef MULTIPLEX_H
#define MULTIPLEX_H
#include <netinet/ip6.h>
#include <stdint.h>
#include "sixlowdriver.h"
#define MTU 1280 ///< MTU for IPv6 packets on serial interface.
/* packet types of tty-packets */
#define BORDER_PACKET_RAW_TYPE 0 ///< Packet type for raw packets.
#define BORDER_PACKET_CONF_TYPE 2 ///< Packet type for configuration packets.
#define BORDER_PACKET_L3_TYPE 3 ///< Packet type for layer 3 packets.
/* configuration types */
#define BORDER_CONF_CONTEXT 2 ///< Configuration packet type for context updates.
#define BORDER_CONF_IPADDR 3 ///< Configuration packet type for IP address updates.
/* ethertypes for L3 packets */
#define ETHERTYPE_IPV6 0x86DD ///< Ethertype for IPv6-Datagrams.
/**
* @brief Describes packets for transmission via serial interface.
*/
typedef struct __attribute__((packed)) border_packet_t {
/**
* @brief Reserved byte.
*
* Must be always 0 to distinguish packets from MSB-A2
* stdout/stdin/stderr.
*/
uint8_t empty;
uint8_t type; ///< Type of the packet.
uint8_t seq_num; ///< Sequence number of the packet (for flow control).
} border_packet_t;
/**
* @brief Describes a layer 3 packet header for transmission via
* serial interface.
* @extends border_packet_t
*/
typedef struct __attribute__((packed)) border_l3_header_t {
uint8_t empty;
uint8_t type;
uint8_t seq_num;
uint16_t ethertype; ///< Ethertype of the layer 3 packet.
} border_l3_header_t;
/**
* @brief Describes a configuration packet header for transmission via
* serial interface.
* @extends border_packet_t
*/
typedef struct __attribute__((packed)) border_conf_header_t {
uint8_t empty;
uint8_t type;
uint8_t seq_num;
uint8_t conftype; ///< Configuration packet type of this packet.
} border_conf_header_t;
/**
* @brief Describes an address configuration packet.
* @extends border_conf_header_t
*
* This packet type enables the driver to add new IPv6 addresses to
* the border router.
*/
typedef struct __attribute__((packed)) border_addr_packet_t {
uint8_t empty;
uint8_t type;
uint8_t seq_num;
uint8_t conftype;
/**
* @brief Version for this IP address (send with the ABRO for PIs,
* s. draft-ietf-6lowpan-nd-17).
*/
uint16_t version;
struct in6_addr addr; ///< New IPv6-Address to be added to this border router.
} border_addr_packet_t;
/**
* @brief Describes a context configuration packet.
* @extends border_conf_header_t
*
* This packet type enables the driver to manipulate Context Informations
* in the LoWPAN.
*/
typedef struct __attribute__((packed)) border_context_packet_t {
uint8_t empty;
uint8_t type;
uint8_t seq_num;
uint8_t conftype;
border_context_t context; ///< Describes the context to be manipulated.
} border_context_packet_t;
/**
* @brief Size of all packet buffers in this driver.
*
* @ref border_l3_header_t was since packets of this type may be the
* longest (with payload).
*/
#define BUFFER_SIZE sizeof (border_l3_header_t) + MTU
/**
* @brief Initializes multiplexer
* @param[in] tty_dev Filename of the serial interface over which the
* multiplexer should multiplex.
* @return 0 if successfull, -1 if not.
*/
int init_multiplex(const char *tty_dev);
/**
* @brief Returns a pointer to a cell in the buffer for the output
* data, that shall be send via the serial interface.
* @param[in] offset The offset from the start of the buffer.
* @return Pointer to a cell in the buffer for the output
* data. The size of the buffer is then
* \ref BUFFER_SIZE - <em>offset</em>.
*/
uint8_t *get_serial_out_buffer(int offset);
/**
* @brief Returns a pointer to a cell in the buffer for the input
* data, that was received via the serial interface.
* @param[in] offset The offset from the start of the buffer.
* @return Pointer to a cell in the buffer for the input
* data. The size of the buffer is then
* \ref BUFFER_SIZE - <em>offset</em>.
*/
uint8_t *get_serial_in_buffer(int offset);
/**
* @brief Demultiplexes a packet, that was received via the serial
* interface.
* @param[in] packet Packet, that should be demultiplexed.
* @param[in] len Length of the packet, that should be
* demultiplexed.
*/
void demultiplex(const border_packet_t *packet, int len);
/**
* @brief Sends an IPv6 datagram via the serial interface.
* @param[in] packet The IPv6 datagram that is to be send via the
* serial interface and starts with an IPv6 header.
*
* The function uses the payload length field of the IPv6 Header to
* determine the length of the overall packet. The payload bytes
* <em>must</em> follow the header in memory.
*/
void multiplex_send_ipv6_over_tty(const struct ip6_hdr *packet);
/**
* @brief Sends context information via the serial interface.
* @param[in] context The context information that is to be send via
* the serial interface.
*/
void multiplex_send_context_over_tty(const border_context_t *context);
/**
* @brief Sends new IPv6 address via the serial interface.
* @param[in] addr The new address that is to be send via
* the serial interface.
*/
void multiplex_send_addr_over_tty(struct in6_addr *addr);
/**
* @brief Reads a packet up to a length of <em>size</em> bytes from
* the serial interface and saves it to <em>packet_buf</em>.
* @param[out] packet_buf The buffer the read packet should be written
* into.
* @param[in] size The maximum number of bytes to be read.
* @return The number of bytes read.
*/
int readpacket(uint8_t *packet_buf, size_t size);
/**
* @brief Writes a packet up to a length of <em>size</em> bytes from
* <em>packet_buf</em> to the serial interface.
* @param[in] packet_buf The buffer from which the packet should be
* written.
* @param[in] size The maximum number of bytes to be written.
* @return The number of bytes written.
*/
int writepacket(uint8_t *packet_buf, size_t size);
#endif /* SIXLOWBORDER_H*/

View File

@ -1,426 +0,0 @@
/*
* LPC 2000 Loader, http://www.pjrc.com/arm/lpc2k_pgm
* Copyright (c) 2004, PJRC.COM, LLC, <paul@pjrc.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* If this code fails to build, please provide at least the following
* information when requesting (free) technical support.
*
* 1: Complete copy of all messages during the build.
* 2: Output of "gtk-config --version"
* 3: Output of "gtk-config --libs"
* 4: Output of "gtk-config --cflags"
* 5: Output of "uname -a"
* 6: Version of GTK installed... eg, type: ls -l /lib/libgtk*
* 7: Other info... which linux distribution, version, other software
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#ifdef LINUX
#include <linux/serial.h>
#endif
#include "serial.h"
int port_fd = -1;
static tcflag_t baud_name_to_flags(const char *baud_name);
static void report_open_error(const char *filename, int err);
char *baud_rate = "115200";
int open_serial_port(const char *port_name)
{
int r;
if (port_fd >= 0) {
close(port_fd);
}
port_fd = open(port_name, O_RDWR);
if (port_fd < 0) {
report_open_error(port_name, errno);
return -1;
}
r = set_baud(baud_rate);
if (r == 0) {
printf("Port \"%s\" opened at %s baud\r\n",
port_name, baud_rate);
}
else {
printf("Port \"%s\" opened, unable to set baud to %s\r\n",
port_name, baud_rate);
}
#ifdef LINUX
{
struct serial_struct kernel_serial_settings;
/* attempt to set low latency mode, but don't worry if we can't */
r = ioctl(port_fd, TIOCGSERIAL, &kernel_serial_settings);
if (r < 0) {
return 0;
}
kernel_serial_settings.flags |= ASYNC_LOW_LATENCY;
ioctl(port_fd, TIOCSSERIAL, &kernel_serial_settings);
}
#endif
return 0;
}
/* if the port can't be opened, try to print as much info as
* possible, so the problem can be resolved (usually permissions)
*/
static void report_open_error(const char *filename, int err)
{
struct stat info;
uid_t my_uid;
gid_t my_gid;
char my_uname[64], my_gname[64], file_uname[64], file_gname[64];
struct passwd *p;
struct group *g;
mode_t perm;
int r;
printf("\r\n");
printf("Unable to open \"%s\"\r\n", filename);
if (err == EACCES) {
printf("You don't have permission to access %s\r\n", filename);
}
r = stat(filename, &info);
if (r < 0) {
if (errno == ENOENT) {
printf("file %s does not exist\r\n", filename);
}
else if (errno == ELOOP) {
printf("too many symbolic links\r\n");
}
else if (errno == EACCES) {
printf("permission denied to get file status\r\n");
}
else {
printf("Unable to get file status, err%d\r\n", errno);
}
return;
}
my_uid = getuid();
my_gid = getgid();
p = getpwuid(my_uid);
if (p) {
snprintf(my_uname, sizeof(my_uname),
"\"%s\" (gid=%d)", p->pw_name, (int)my_uid);
}
else {
snprintf(my_uname, sizeof(my_uname),
"(gid=%d)", (int)my_uid);
}
p = getpwuid(info.st_uid);
if (p) {
snprintf(file_uname, sizeof(file_uname),
"\"%s\" (uid=%d)", p->pw_name, (int)info.st_uid);
}
else {
snprintf(file_uname, sizeof(file_uname),
"(uid=%d)", (int)info.st_uid);
}
g = getgrgid(my_gid);
if (g) {
snprintf(my_gname, sizeof(my_gname),
"\"%s\" (gid=%d)", g->gr_name, (int)my_gid);
}
else {
snprintf(my_gname, sizeof(my_gname),
"(gid=%d)", (int)my_gid);
}
g = getgrgid(info.st_gid);
if (g) {
snprintf(file_gname, sizeof(file_gname),
"\"%s\" (uid=%d)", g->gr_name, (int)info.st_gid);
}
else {
snprintf(file_gname, sizeof(file_gname),
"(uid=%d)", (int)info.st_gid);
}
/* printf("%s is owned by: user %s, group %s\r\n",
filename, file_uname, file_gname); */
perm = info.st_mode;
if ((perm & S_IROTH) && (perm & S_IWOTH)) {
printf("%s has read/write permission for everybody\r\n",
filename);
}
else {
printf("%s is not read/write for everybody, so\r\n", filename);
printf(" you must match either user or group permission\r\n");
int perm_ok = 0;
if ((perm & S_IRUSR) && (perm & S_IWUSR)) {
printf("%s has read/write permission for user %s\r\n",
filename, file_uname);
perm_ok = 1;
}
if ((perm & S_IRGRP) && (perm & S_IWGRP)) {
printf("%s has read/write permission for group %s\r\n",
filename, file_gname);
perm_ok = 1;
}
if (perm_ok == 0) {
printf("%s does not read/write permission for user or group!\r\n",
filename);
}
else {
printf("Your access privs: user %s, group %s\r\n",
my_uname, my_gname);
}
}
printf("\r\n");
}
int write_serial_port(const void *buf, int num)
{
return(write(port_fd, buf, num));
}
void input_flush_serial_port(void)
{
tcflush(port_fd, TCIFLUSH);
}
int read_serial_port_nb(unsigned char *buf, int bufsize)
{
int num, flags;
flags = fcntl(port_fd, F_GETFL);
fcntl(port_fd, F_SETFL, flags | O_NONBLOCK);
num = read(port_fd, buf, bufsize);
fcntl(port_fd, F_SETFL, flags);
return num;
}
int read_serial_port(unsigned char *buf, int bufsize)
{
int num;
num = read(port_fd, buf, bufsize);
return num;
}
void send_break_signal(void)
{
tcsendbreak(port_fd, 0);
}
void close_serial_port(void)
{
if (port_fd >= 0) {
close(port_fd);
port_fd = -1;
}
}
tcflag_t baud_name_to_flags(const char *baud_name)
{
if (strcmp(baud_name, "230400") == 0) {
return B230400;
}
if (strcmp(baud_name, "115200") == 0) {
return B115200;
}
if (strcmp(baud_name, "57600") == 0) {
return B57600;
}
if (strcmp(baud_name, "38400") == 0) {
return B38400;
}
if (strcmp(baud_name, "19200") == 0) {
return B19200;
}
if (strcmp(baud_name, "9600") == 0) {
return B9600;
}
if (strcmp(baud_name, "4800") == 0) {
return B4800;
}
if (strcmp(baud_name, "2400") == 0) {
return B2400;
}
if (strcmp(baud_name, "1200") == 0) {
return B1200;
}
if (strcmp(baud_name, "300") == 0) {
return B300;
}
return B0;
}
int set_baud(const char *baud_name)
{
struct termios port_setting;
tcflag_t baud;
int r;
if (port_fd < 0) {
return -1;
}
baud = baud_name_to_flags(baud_name);
if (baud == B0) {
return -2;
}
r = tcgetattr(port_fd, &port_setting);
if (r != 0) {
return -3;
}
port_setting.c_iflag = IGNBRK | IGNPAR;
port_setting.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
port_setting.c_oflag = 0;
port_setting.c_lflag = 0;
r = tcsetattr(port_fd, TCSAFLUSH, &port_setting);
if (r != 0) {
return -4;
}
return 0;
}
// Normally this should never be used... except to pass the port
// file descriptor to the GTK event monitoring loop. All other
// use of the serial port is supposed to happen in the file.
int serial_port_fd(void)
{
return port_fd;
}
void set_rts(int val)
{
int flags;
int result;
result = ioctl(port_fd, TIOCMGET, &flags);
if (result == -1) {
printf("Error %i while reading port io flags\n", errno);
return;
}
if (val) {
flags |= TIOCM_RTS;
}
else {
flags &= ~(TIOCM_RTS);
}
result = ioctl(port_fd, TIOCMSET, &flags);
if (result == -1) {
printf("Error %i while setting port io flags\n", errno);
}
}
void set_dtr(int val)
{
int flags;
int result;
result = ioctl(port_fd, TIOCMGET, &flags);
if (result == -1) {
printf("Error %i while reading port io flags\n", errno);
return;
}
if (val) {
flags |= TIOCM_DTR;
}
else {
flags &= ~(TIOCM_DTR);
}
result = ioctl(port_fd, TIOCMSET, &flags);
if (result == -1) {
printf("Error %i while setting port io flags\n", errno);
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/* token from pseudoterm */
#ifndef SERIAL_H
#define SERIAL_H
extern char *baud_rate;
int open_serial_port(const char *port_name);
int write_serial_port(const void *buf, int num);
void input_flush_serial_port(void);
int read_serial_port_nb(unsigned char *buf, int bufsize);
int read_serial_port(unsigned char *buf, int bufsize);
void close_serial_port(void);
void send_break_signal(void);
int set_baud(const char *baud_name);
int serial_port_fd(void);
void set_rts(int val);
void set_dtr(int val);
void change_baud(const char *baud_name);
#endif // SERIAL_H

View File

@ -1,90 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include "serialnumber.h"
int serial_add8(uint8_t s, uint8_t n)
{
if (n > 127) {
return -1;
}
uint16_t sum = s + n;
return (uint8_t)(sum % 256);
}
int serial_add16(uint16_t s, uint16_t n)
{
if (n > 32767) {
return -1;
}
uint32_t sum = s + n;
return (uint16_t)(sum % 65536);
}
int serial_add32(uint32_t s, uint32_t n)
{
if (n > 2147483647) {
return -1;
}
uint64_t sum = s + n;
return (uint32_t)(sum % 4294967296);
}
serial_comp_res_t serial_comp8(uint8_t s1, uint8_t s2)
{
if (s1 == s2) {
return EQUAL;
}
if ((s1 < s2 && s1 - s2 < 128) || (s1 > s2 && s1 - s2 > 128)) {
return LESS;
}
if ((s1 < s2 && s1 - s2 > 128) || (s1 > s2 && s1 - s2 < 128)) {
return GREATER;
}
return UNDEF;
}
serial_comp_res_t serial_comp16(uint16_t s1, uint16_t s2)
{
if (s1 == s2) {
return EQUAL;
}
if ((s1 < s2 && s1 - s2 < 32768) || (s1 > s2 && s1 - s2 > 32768)) {
return LESS;
}
if ((s1 < s2 && s1 - s2 > 32768) || (s1 > s2 && s1 - s2 < 32768)) {
return GREATER;
}
return UNDEF;
}
serial_comp_res_t serial_comp32(uint32_t s1, uint32_t s2)
{
if (s1 == s2) {
return EQUAL;
}
if ((s1 < s2 && s1 - s2 < 2147483648) || (s1 > s2 && s1 - s2 > 2147483648)) {
return LESS;
}
if ((s1 < s2 && s1 - s2 > 2147483648) || (s1 > s2 && s1 - s2 < 2147483648)) {
return GREATER;
}
return UNDEF;
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @brief Serial number arithmetics after RFC 1982, section 3
*/
#ifndef SERIALNUMBER_H
#define SERIALNUMBER_H
#include <stdint.h>
/**
* @brief Results for the serial number comparisson.
*/
typedef enum serial_comp_res_t {
LESS, EQUAL, GREATER, UNDEF
} serial_comp_res_t;
/**
* @brief Addition for 8-bit unsigned integers in serial number
* arithmetics (corresponding RFC 1982, section 3.1).
* @param[in] s first summand in [0 .. 2^8 - 1].
* @param[in] n second summand in [0 .. 2^7 - 1].
* @return Sum corresponding RFC1982 section 3.1 if <em>n</em> in [0 .. 2^7 - 1] or
* -1 if <em>n</em> not in [0 .. 2^7 - 1].
**/
int serial_add8(uint8_t s, uint8_t n);
/**
* @brief Addition for 16-bit unsigned integers in serial number
* arithmetics (corresponding RFC 1982, section 3.1).
* @param[in] s first summand in [0 .. 2^16 - 1].
* @param[in] n second summand in [0 .. 2^15 - 1].
* @return Sum corresponding RFC 1982 section 3.1 if <em>n</em> in [0 .. 2^15 - 1] or
* -1 if <em>n</em> not in [0 .. 2^15 - 1].
**/
int serial_add16(uint16_t s, uint16_t n);
/**
* @brief Addition for 32-bit unsigned integers in serial number
* arithmetics (corresponding RFC1982, section 3.1).
* @param[in] s first summand in [0 .. 2^32 - 1].
* @param[in] n second summand in [0 .. 2^31 - 1].
* @return Sum corresponding RFC 1982 section 3.1 if <em>n</em> in [0 .. 2^31 - 1] or
* -1 if <em>n</em> not in [0 .. 2^31 - 1].
**/
int serial_add32(uint32_t s, uint32_t n);
/**
* @brief Comparison of 8-bit unsigned integers in serial number
* arithmetics (corresponding RFC 1982, section 3.2).
* @param[in] s1 first argument.
* @param[in] s2 second argument.
* @return <tt>LESS</tt> if <em>s1</em> < <em>s2</em>.
* <tt>EQUAL</tt> if <em>s1</em> = <em>s2</em>.
* <tt>GREATER</tt> if <em>s1</em> > <em>s2</em>.
* else <tt>UNDEF</tt> (see RFC 1982, section 3.2).
**/
serial_comp_res_t serial_comp8(uint8_t s1, uint8_t s2);
/**
* @brief Comparison of 16-bit unsigned integers in serial number
* arithmetics (corresponding RFC 1982, section 3.2).
* @param[in] s1 first argument.
* @param[in] s2 second argument.
* @return <tt>LESS</tt> if <em>s1</em> < <em>s2</em>.
* <tt>EQUAL</tt> if <em>s1</em> = <em>s2</em>.
* <tt>GREATER</tt> if <em>s1</em> > <em>s2</em>.
* else <tt>UNDEF</tt> (see RFC 1982, section 3.2).
**/
serial_comp_res_t serial_comp16(uint16_t s1, uint16_t s2);
/**
* @brief Comparison of 32-bit unsigned integers in serial number
* arithmetics (corresponding RFC1982, section 3.2).
* @param[in] s1 first argument.
* @param[in] s2 second argument.
* @return <tt>LESS</tt> if <em>s1</em> < <em>s2</em>.
* <tt>EQUAL</tt> if <em>s1</em> = <em>s2</em>.
* <tt>GREATER</tt> if <em>s1</em> > <em>s2</em>.
* else <tt>UNDEF</tt> (see RFC 1982, section 3.2).
**/
serial_comp_res_t serial_comp32(uint32_t s1, uint32_t s2);
#endif /* SERIALNUMBER_H*/

View File

@ -1,335 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/ip6.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/if_tun.h>
#include "sixlowdriver.h"
#include "multiplex.h"
#include "flowcontrol.h"
#include "serialnumber.h"
#include "control_2xxx.h"
#define TUNDEV "/dev/net/tun"
#define MAXIMUM_CONTEXTS 16
char tun_if_name[IF_NAME_LEN];
uint8_t tun_out_buf[BUFFER_SIZE];
uint8_t tun_in_buf[BUFFER_SIZE];
/* Cell i is defined as empty if context_cache[i].cid != i */
border_context_t context_cache[MAXIMUM_CONTEXTS];
int tun_fd;
pthread_t serial_reader, tun_reader;
uint16_t abro_version = 0;
uint16_t get_abro_version()
{
return abro_version;
}
uint16_t get_next_abro_version()
{
abro_version = serial_add16(abro_version, 1);
return abro_version;
}
int get_tun_fd(void)
{
return tun_fd;
}
void *serial_reader_f(void *arg)
{
unsigned char buf[BUFFER_SIZE];
border_packet_t *packet_buf;
while (1) {
int n = readpacket(buf, BUFFER_SIZE);
if (n > 0) {
if (buf[0] == 0) {
packet_buf = (border_packet_t *)buf;
flowcontrol_deliver_from_tty(packet_buf, n);
continue;
}
printf("\033[00;33m[via serial interface] %s\033[00m\n", buf);
}
}
}
int tun_to_serial_packet(uint8_t *serial_packet, uint8_t *tun_packet, size_t packet_size)
{
struct tun_pi *tun_hdr = (struct tun_pi *)tun_packet;
border_l3_header_t *l3_hdr = (border_l3_header_t *)serial_packet;
l3_hdr->empty = 0;
l3_hdr->type = BORDER_PACKET_L3_TYPE;
l3_hdr->ethertype = ntohs(tun_hdr->proto);
memcpy(
serial_packet + sizeof(border_l3_header_t),
tun_packet + sizeof(struct tun_pi),
packet_size - sizeof(struct tun_pi)
);
return (sizeof(border_l3_header_t) + (packet_size - sizeof(struct tun_pi)));
}
void *tun_reader_f(void *args)
{
unsigned char data[BUFFER_SIZE];
while (1) {
size_t bytes = read(tun_fd, (void *)data, BUFFER_SIZE);
if (bytes > 0) {
bytes = tun_to_serial_packet(tun_in_buf, (uint8_t *)data, bytes);
flowcontrol_send_over_tty((border_packet_t *)tun_in_buf, bytes);
}
}
}
void border_send_ipv6_over_tun(int fd, const struct ip6_hdr *packet)
{
uint8_t tun_packet[BUFFER_SIZE];
int packet_size = packet->ip6_plen + sizeof(struct ip6_hdr);
struct tun_pi *tun_hdr = (struct tun_pi *)tun_packet;
tun_hdr->flags = 0;
tun_hdr->proto = htons(ETHERTYPE_IPV6);
memcpy(tun_packet + sizeof(struct tun_pi), (uint8_t *)packet, packet_size);
write(tun_fd, tun_packet, packet_size + sizeof(struct tun_pi));
}
int tun_set_owner(int fd, const uid_t *uid, const gid_t *gid)
{
if (uid != NULL) {
if (*uid != -1 && ioctl(fd, TUNSETOWNER, *uid)) {
return -1;
}
}
if (gid != NULL) {
if (*gid != -1 && ioctl(fd, TUNSETGROUP, *gid)) {
return -1;
}
}
return 0;
}
int tun_add_addr(const char *ip_addr)
{
char command[21 + IPV6_ADDR_LEN + IF_NAME_LEN];
printf("INFO: ip addr add %s dev %s\n", ip_addr, tun_if_name);
sprintf(command, "ip addr add %s dev %s", ip_addr, tun_if_name);
if (system(command) != 0) {
return -1;
}
return 0;
}
/* Source: http://backreference.org/2010/03/26/tuntap-interface-tutorial/
*/
int open_tun(char *if_name, int flags)
{
struct ifreq ifr;
int fd, err;
/* Arguments taken by the function:
*
* char *if_name: the name of an interface (or '\0'). MUST have enough
* space to hold the interface name if '\0' is passed
* int flags: interface flags (eg, IFF_TUN etc.)
*/
/* open the clone device */
if ((fd = open(TUNDEV, O_RDWR)) < 0) {
return fd;
}
/* preparation of the struct ifr, of type "struct ifreq" */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
if (*if_name) {
/* if a device name was specified, put it in the structure; otherwise,
* the kernel will try to allocate the "next" device of the
* specified type */
strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
}
/* try to create the device */
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
}
/* if the operation was successful, write back the name of the
* interface to the variable "if_name", so the caller can know
* it. Note that the caller MUST reserve space in *if_name (see calling
* code below) */
strcpy(if_name, ifr.ifr_name);
/* this is the special file descriptor that the caller will use to talk
* with the virtual interface */
return fd;
}
int context_empty(uint8_t cid)
{
return context_cache[cid].cid != cid;
}
int border_update_context(uint8_t cid, const struct in6_addr *prefix,
uint8_t len, uint8_t comp,
uint16_t lifetime)
{
if (cid >= MAXIMUM_CONTEXTS) {
return -1;
}
len = (len <= 128) ? len : 128;
if (context_empty(cid)) {
context_cache[cid].version = get_abro_version();
}
else {
context_cache[cid].version = get_next_abro_version();
}
context_cache[cid].cid = cid;
memcpy(&(context_cache[cid].prefix), prefix, len);
context_cache[cid].len = len;
context_cache[cid].comp = comp;
context_cache[cid].lifetime = lifetime;
multiplex_send_context_over_tty(&context_cache[cid]);
return 0;
}
int border_renew_existing_context(uint8_t cid)
{
if (cid >= MAXIMUM_CONTEXTS) {
return -1;
}
if (context_empty(cid)) {
return -1;
}
multiplex_send_context_over_tty(&context_cache[cid]);
return 0;
}
void border_remove_context(uint8_t cid)
{
if (cid >= MAXIMUM_CONTEXTS) {
return;
}
if (context_empty(cid)) {
return;
}
context_cache[cid].version = get_next_abro_version();
context_cache[cid].lifetime = 0;
multiplex_send_context_over_tty(&context_cache[cid]);
context_cache[cid].cid = 0xFF;
}
int border_add_addr(const char *ip_addr)
{
struct in6_addr parsed_addr;
if (inet_pton(AF_INET6, ip_addr, &parsed_addr) != 1) {
return -1;
}
tun_add_addr(ip_addr);
multiplex_send_addr_over_tty(&parsed_addr);
return 0;
}
int border_initialize(char *if_name, const char *ip_addr, const char *tty_dev)
{
int res, i;
char command[21 + IPV6_ADDR_LEN + IF_NAME_LEN];
char ip_addr_cpy[IPV6_ADDR_LEN + 1];
struct in6_addr parsed_addr;
strncpy(ip_addr_cpy, ip_addr, IPV6_ADDR_LEN);
ip_addr_cpy[IPV6_ADDR_LEN] = '\0';
strtok(ip_addr_cpy, "/");
if ((res = inet_pton(AF_INET6, ip_addr_cpy, &parsed_addr)) != 1) {
return res;
}
if ((res = init_multiplex(tty_dev)) != 0) {
return res;
}
tun_fd = open_tun(if_name, IFF_TUN);
printf("INFO: ip link set %s up\n", if_name);
sprintf(command, "ip link set %s up", if_name);
strncpy(tun_if_name, if_name, IF_NAME_LEN);
if ((res = system(command)) != 0) {
return res;
}
if ((res = tun_add_addr(ip_addr)) != 0) {
return res;
}
// initialize context cache as empty.
for (i = 0; i < MAXIMUM_CONTEXTS; i++) {
context_cache[i].cid = 0xFF;
}
pthread_create(&serial_reader, NULL, serial_reader_f, NULL);
hard_reset_to_user_code();
flowcontrol_init(&parsed_addr);
pthread_create(&tun_reader, NULL, tun_reader_f, NULL);
return 0;
}

View File

@ -1,177 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @brief Public declarations for the 6LoWPAN Border Router driver.
*/
#ifndef SIXLOWDRIVER_H
#define SIXLOWDRIVER_H
#include <stdint.h>
#include <sys/types.h>
#include <netinet/ip6.h>
/**
* @brief The maximum string length of an IPv6 address in text representation.
*/
#define IPV6_ADDR_LEN 40
#define IF_NAME_LEN 10 ///< Maximum length of an interface name
#define DEV_LEN 20 ///< Maximum length of a device filename
/**
* @brief Defines the format of the context information.
*/
typedef struct __attribute__((packed)) border_context_t {
uint16_t version; ///< Version of this context, send via the ABRO (s. draft-ietf-6lowpan-nd-17).
uint8_t cid; ///< The CID of the Context (s. draft-ietf-6lowpan-nd-17).
struct in6_addr prefix; ///< The prefix this context defines.
uint8_t len; ///< The length of the prefix in bits.
uint8_t comp; ///< Flag to determine if Context is allowed for compression (s. draft-ietf-6lowpan-nd-17).
uint16_t lifetime; ///< Lifetime of this context (s. draft-ietf-6lowpan-nd-17).
} border_context_t;
/**
* @brief Initializes a TUN- or TAP-Interface.
* @param[in,out] dev The name of the new interface. If the name
* is not given, it is chosen by the kernel
* and returned to the caller.
* @param[in] flags Flags that signify the interface type
* (<tt>IFF_TUN</tt> = TUN interface,
* <tt>IFF_TAP</tt> = TAP interface,
* @return The file descriptor to the new interface.
* <tt>IFF_NO_PI</tt> = provide no packet information).
* @see http://backreference.org/2010/03/26/tuntap-interface-tutorial/
* @see http://www.kernel.org/pub/linux/kernel/people/marcelo/linux-2.4/Documentation/networking/tuntap.txt
*
* Initializes a TUN- or TAP-Interface by the name <em>dev</em>. Which kind
* of interface is defined by <em>flags</em>. The function returns the file
* descriptor to the interface, which can be accessed via the
* POSIX.1-2001 functions <tt>read()</tt> and <tt>write()</tt>
*/
int open_tun(char *dev, int flags);
/**
* @brief Returns the file descriptor to the TUN interface.
* @return The file descriptor to the TUN interface initialized by
* open_tun()
*
* open_tun() needs to be called before. Otherwise the result of this
* function may not make sense.
*/
int get_tun_fd(void);
/**
* @brief Sets the owner of a TUN- or TAP-Interface.
* @param[in] fd The file descriptor to the interface to be changed.
* @param[in] uid User ID of the new user to be assigned.
* @param[in] gid Group ID of the new group to be assigned.
* @return 0, if successful, -1 if not.
*/
int tun_set_owner(int fd, const uid_t *uid, const gid_t *gid);
/**
* @brief Adds a new IPv6 address to the TUN interface.
* @param[in] ip_addr The new address.
* @return 0, if <em>ip_addr</em> is a valid IPv6 address, -1, if not.
*/
int tun_add_addr(const char *ip_addr);
/**
* @brief Initializes the border router.
* @param[in,out] if_name The name of the new TUN interface. If the
* name is not given, it is chosen by the
* kernel and returned to the caller.
* @param[in] ip_addr The IPv6 Address, that is initially attached
* to the LoWPAN Border Router.
* @param[in] tty_dev Device file of the serial interface the
* MSB-A2 is attached to.
* @return 0 if successfull,
* != 0 if an error occurs.
*/
int border_initialize(char *if_name, const char *ip_addr, const char *tty_dev);
/**
* @brief Sends an IPv6 datagram via the TUN interface.
* @param[in] fd The file descriptor of the TUN interface
* @param[in] packet The IPv6 datagram that is to be send via the
* TUN interface and starts with an IPv6 header.
*
* The function uses the payload length field of the IPv6 Header to
* determine the length of the overall packet. The payload bytes
* <em>must</em> follow the header in memory.
*/
void border_send_ipv6_over_tun(int fd, const struct ip6_hdr *packet);
/**
* @brief Updates 6LoWPAN contex information.
* @param[in] cid The context identifier, only values < 16
* are allowed.
* @param[in] prefix The prefix that shall be associated with the
* <em>cid</em>.
* @param[in] len The length of the <em>prefix</em> in bits.
* @param[in] comp Flag to determine if Context is allowed for
* compression (s. draft-ietf-6lowpan-nd-17).
* @param[in] lifetime Lifetime of this context
* (s. draft-ietf-6lowpan-nd-17).
* @return If cid < 16 than it is 0, otherwise -1.
*/
int border_update_context(uint8_t cid, const struct in6_addr *prefix,
uint8_t len, uint8_t comp,
uint16_t lifetime);
/**
* @brief Updates 6LoWPAN contex information, as it is stored in the
* border router (e.g. to maintain a context which lifetime
* is about to run out).
* @param[in] cid The context identifier.
* @return 0, if the context identifiet by cid is stored in the border
* router, -1 if not.
*
* The information taken for this update ist the last, that was used
* with \ref border_update_context().
*/
int border_renew_existing_context(uint8_t cid);
/**
* @brief Removes 6LoWPAN context information.
* @param[in] cid The context identifier.
*
* The information taken for this update ist the last, that was used
* with \ref border_update_context().
*/
void border_remove_context(uint8_t cid);
/**
* @brief Adds a new IPv6 address to the whole interface (TUN and
* sensor node).
* @param[in] ip_addr The new address.
* @return 0, if <em>ip_addr</em> is a valid IPv6 address, -1, if not.
*/
int border_add_addr(const char *ip_addr);
/**
* @brief Getter for the current version for ABROs send by this
* router.
* @return This border router's current version.
*/
uint16_t get_abro_version(void);
/**
* @brief Increments and updates the version for ABROs send by this
* router.
* @return This border router's new ABRO version.
*/
uint16_t get_next_abro_version(void);
#endif /* SIXLOWDRIVER_H*/

View File

@ -1,179 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "testing.h"
#include "flowcontrol.h"
struct timeval timers[256];
struct test_stats *stats = NULL;
int run_counter;
FILE *stats_file = NULL;
void init_file(const char *skeleton_file_name,
int runs_per_test, float interval)
{
FILE *skeleton_file = NULL;
char line[1024];
skeleton_file = fopen(skeleton_file_name, "r");
while (fgets(line, 1024, skeleton_file) != NULL) {
if (strncmp(line, "# sending window size=%d\n", 1024) == 0) {
fprintf(stats_file, line, BORDER_SWS);
}
else if (strncmp(line, "# count=%ld (-c)\n", 1024) == 0) {
fprintf(stats_file, line, runs_per_test);
}
else if (strncmp(line, "# interval=%f (-i)\n", 1024) == 0) {
fprintf(stats_file, line, interval);
}
else {
fprintf(stats_file, "%s", line);
}
}
fclose(skeleton_file);
}
int testing_init(const char *stats_file_name,
const char *skeleton_file_name,
int runs_per_test, float interval)
{
if (stats_file != NULL) {
return -1;
}
stats = (struct test_stats *)calloc(runs_per_test, sizeof(struct test_stats));
run_counter = 0;
stats_file = fopen(stats_file_name, "w");
if (stats_file == NULL) {
return -1;
}
init_file(skeleton_file_name, runs_per_test, interval);
return 0;
}
int testing_destroy()
{
int res, i;
for (i = 0; i < run_counter; i++) {
fprintf(stats_file, "%7d\t%3d\t%7ld\n",
i, stats[i].seq_num, stats[i].time_diff
);
}
free(stats);
stats = NULL;
res = fclose(stats_file);
stats_file = NULL;
return res;
}
void testing_start(uint8_t seq_num)
{
if (stats_file == NULL) {
return;
}
gettimeofday(&(timers[seq_num]), NULL);
}
void testing_stop(uint8_t seq_num)
{
if (stats_file == NULL) {
return;
}
struct timeval start = timers[seq_num], end;
gettimeofday(&end, NULL);
stats[run_counter].seq_num = seq_num;
stats[run_counter].time_diff = (end.tv_sec - start.tv_sec) * 1000;
stats[run_counter].time_diff += (end.tv_usec - start.tv_usec) / 1000;
run_counter++;
}
void generate_filename(
char *filename,
const char *results_dir_name,
int runs_per_test,
float interval)
{
time_t today;
struct tm *tmp = NULL;
char timestr[16];
FILE *test = NULL;
int count = 1;
today = time(NULL);
tmp = localtime(&today);
if (tmp == NULL) {
perror("localtime");
return;
}
strftime(timestr, 16, "%Y.%m.%d", tmp);
do {
sprintf(filename,
"%s/%s-Results-Ping6_%d_%d_%f-%d.txt",
results_dir_name,
timestr,
BORDER_SWS,
runs_per_test,
interval,
count++
);
}
while ((test = fopen(filename, "r")) != NULL);
if (test != NULL) {
fclose(test);
}
}
void start_test(const char *ping_addr,
const char *results_dir_name, const char *skeleton_file,
int runs_per_test, float interval)
{
printf("%d, %f\n", runs_per_test, interval);
char command[50];
char filename[50];
generate_filename(filename, results_dir_name, runs_per_test, interval);
sprintf(command, "ping6 -v -f -c %d -i %f -W 1 abcd::d",
runs_per_test,
interval
);
testing_init(filename, skeleton_file, runs_per_test, interval);
puts(command);
system(command);
testing_destroy();
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @brief Test suite for the 6LoWPAN Border Router.
*
* The tests are managed in the following way:
* Packets (ICMPv6 Echo Request) are send onto the sensor node
* via the serial interface. The user can then decide what she
* wants to measure by calling testing_start() to start the
* measuring and testing_stop() to end it.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef TESTING_H
#define TESTING_H
#include <stdint.h>
/**
* @brief Defines the format to store test results.
*/
struct test_stats {
uint8_t seq_num; ///< Sequence number of the send packet.
/**
* @brief Time difference between call of testing_start() and
* testing_stop().
*/
long int time_diff;
};
/**
* @brief Starts a test measuring.
* @param[in] seq_num Sequence number of the measurement.
*/
void testing_start(uint8_t seq_num);
/**
* @brief Stops a test measuring.
* @param[in] seq_num Sequence number of the measurement.
*/
void testing_stop(uint8_t seq_num);
/**
* @brief Starts the sending of the packets and initialises the
* test environment
* @param[in] ping_addr The address the packets should be
* send to.
* @param[in] results_dir_name Name of the results directory.
* @param[in] skeleton_file Name of the skeleton file, where
* the template for the results file
* is. Lines of the formats
* <tt>"# count=%ld (-c)\n"</tt> and
* <tt>"# interval=%0.2f (-i)\n"</tt>
* will be replaced with <tt>\%ld</tt>
* set to <em>runs_per_test</em> and
* <tt>\%0.2f</tt> set to
* <em>interval</em>.
* @param[in] runs_per_test How many packets shall be send in
* this test.
* @param[in] interval How many seconds shall lay between
* the sending of each packet.
*/
void start_test(const char *ping_addr,
const char *results_dir_name, const char *skeleton_file,
int runs_per_test, float interval);
#endif /* TESTING_H*/

3
dist/tools/tunslip/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
tapslip6
tunslip
tunslip6

10
dist/tools/tunslip/Makefile vendored Normal file
View File

@ -0,0 +1,10 @@
PREFIX ?= /usr/local
BIN = tapslip6 tunslip tunslip6
all: $(BIN)
install:
mkdir -p $(PREFIX)/bin && install $(BIN) $(PREFIX)/bin
uninstall:
rm -f $(foreach bin,$(BIN),$(PREFIX)/bin/$(bin))

43
dist/tools/tunslip/README.md vendored Normal file
View File

@ -0,0 +1,43 @@
Creating a SLIP network interface
=================================
The module `ng_slip` (Serial line IP) enables the RIOT network stack to
communicate IP packets over the serial interface. This collection of tools
originally from Contiki [1] enables Linux to interpret this data. Though there
is a tool for such operations on Linux (`slattach`) it is only able to handle
IPv4 packages and is unnessarily complicated.
# Installation
Just install them using
``` {.sh}
make
sudo make install
```
By default they are installed to the `/usr/local/bin` directory, you can however
change that by setting the PREFIX environment variable
``` {.sh}
export PREFIX=${HOME}/.local
make
sudo make install
```
# Usage
`tapslip6` allows you to open a TAP interface (includes link-layer data) for
a serial interace handling IPv6 data,
`tunslip` allows you to open a TUN interface (includes only network-layer data)
for a serial interace handling IPv4 data, and
`tunslip6` allows you to open a TUN interface (includes only network-layer data)
for a serial interace handling IPv6 data.
For more information use the help feature of the tools
``` {.sh}
tapslip -h
tunslip -h
tunslip6 -h
```
[1] https://github.com/contiki-os/contiki/tree/a4206273a5a491949f9e565e343f31908173c998/tools

748
dist/tools/tunslip/tapslip6.c vendored Normal file
View File

@ -0,0 +1,748 @@
/*
* Copyright (c) 2001, Adam Dunkels.
* Copyright (c) 2009, Joakim Eriksson, Niclas Finne.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This file is part of the uIP TCP/IP stack.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
in_addr_t giaddr;
in_addr_t netaddr;
in_addr_t circuit_addr;
int ssystem(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
void write_to_serial(int outfd, void *inbuf, int len);
//#define PROGRESS(s) fprintf(stderr, s)
#define PROGRESS(s) do { } while (0)
#define USAGE_STRING "usage: tapslip6 [-B baudrate] [-s siodev] [-t tundev] ipaddress netmask"
char tundev[1024] = { "tap0" };
int
ssystem(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
int
ssystem(const char *fmt, ...)
{
char cmd[128];
va_list ap;
va_start(ap, fmt);
vsnprintf(cmd, sizeof(cmd), fmt, ap);
va_end(ap);
printf("%s\n", cmd);
fflush(stdout);
return system(cmd);
}
#define SLIP_END 0300
#define SLIP_ESC 0333
#define SLIP_ESC_END 0334
#define SLIP_ESC_ESC 0335
static void
print_packet(u_int8_t *p, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%02x", p[i]);
if ((i & 3) == 3) {
printf(" ");
}
if ((i & 15) == 15) {
printf("\n");
}
}
printf("\n");
}
int
is_sensible_string(const unsigned char *s, int len)
{
int i;
for (i = 1; i < len; i++) {
if (s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
continue;
}
else if (s[i] < ' ' || '~' < s[i]) {
return 0;
}
}
return 1;
}
/*
* Read from serial, when we have a packet write it to tun. No output
* buffering, input buffered by stdio.
*/
void
serial_to_tun(FILE *inslip, int outfd)
{
static union {
unsigned char inbuf[2000];
} uip;
static int inbufptr = 0;
int ret;
unsigned char c;
#ifdef linux
ret = fread(&c, 1, 1, inslip);
if (ret == -1 || ret == 0) {
err(1, "serial_to_tun: read");
}
goto after_fread;
#endif
read_more:
if (inbufptr >= sizeof(uip.inbuf)) {
inbufptr = 0;
}
ret = fread(&c, 1, 1, inslip);
#ifdef linux
after_fread:
#endif
if (ret == -1) {
err(1, "serial_to_tun: read");
}
if (ret == 0) {
clearerr(inslip);
return;
fprintf(stderr, "serial_to_tun: EOF\n");
exit(1);
}
/* fprintf(stderr, ".");*/
switch (c) {
case SLIP_END:
if (inbufptr > 0) {
if (uip.inbuf[0] == '!') {
if (uip.inbuf[1] == 'M') {
/* Read gateway MAC address and autoconfigure tap0 interface */
char macs[24];
int i, pos;
for (i = 0, pos = 0; i < 16; i++) {
macs[pos++] = uip.inbuf[2 + i];
if ((i & 1) == 1 && i < 14) {
macs[pos++] = ':';
}
}
macs[pos] = '\0';
printf("*** Gateway's MAC address: %s\n", macs);
ssystem("ifconfig %s down", tundev);
ssystem("ifconfig %s hw ether %s", tundev, &macs[6]);
ssystem("ifconfig %s up", tundev);
}
#define DEBUG_LINE_MARKER '\r'
}
else if (uip.inbuf[0] == DEBUG_LINE_MARKER) {
fwrite(uip.inbuf + 1, inbufptr - 1, 1, stdout);
}
else if (is_sensible_string(uip.inbuf, inbufptr)) {
fwrite(uip.inbuf, inbufptr, 1, stdout);
}
else {
printf("Writing to tun len: %d\n", inbufptr);
/* print_packet(uip.inbuf, inbufptr);*/
if (write(outfd, uip.inbuf, inbufptr) != inbufptr) {
err(1, "serial_to_tun: write");
}
}
inbufptr = 0;
}
break;
case SLIP_ESC:
if (fread(&c, 1, 1, inslip) != 1) {
clearerr(inslip);
/* Put ESC back and give up! */
ungetc(SLIP_ESC, inslip);
return;
}
switch (c) {
case SLIP_ESC_END:
c = SLIP_END;
break;
case SLIP_ESC_ESC:
c = SLIP_ESC;
break;
}
/* FALLTHROUGH */
default:
uip.inbuf[inbufptr++] = c;
break;
}
goto read_more;
}
unsigned char slip_buf[2000];
int slip_end, slip_begin;
void
slip_send(int fd, unsigned char c)
{
if (slip_end >= sizeof(slip_buf)) {
err(1, "slip_send overflow");
}
slip_buf[slip_end] = c;
slip_end++;
}
int
slip_empty()
{
return slip_end == 0;
}
void
slip_flushbuf(int fd)
{
int n;
if (slip_empty()) {
return;
}
n = write(fd, slip_buf + slip_begin, (slip_end - slip_begin));
if (n == -1 && errno != EAGAIN) {
err(1, "slip_flushbuf write failed");
}
else if (n == -1) {
PROGRESS("Q"); /* Outqueueis full! */
}
else {
slip_begin += n;
if (slip_begin == slip_end) {
slip_begin = slip_end = 0;
}
}
}
void
write_to_serial(int outfd, void *inbuf, int len)
{
u_int8_t *p = inbuf;
int i, ecode;
/* printf("Got packet of length %d - write SLIP\n", len);*/
/* print_packet(p, len);*/
/* It would be ``nice'' to send a SLIP_END here but it's not
* really necessary.
*/
/* slip_send(outfd, SLIP_END); */
/* printf("writing packet to serial!!!%d\n", len);*/
for (i = 0; i < len; i++) {
switch (p[i]) {
case SLIP_END:
slip_send(outfd, SLIP_ESC);
slip_send(outfd, SLIP_ESC_END);
break;
case SLIP_ESC:
slip_send(outfd, SLIP_ESC);
slip_send(outfd, SLIP_ESC_ESC);
break;
default:
slip_send(outfd, p[i]);
break;
}
}
slip_send(outfd, SLIP_END);
PROGRESS("t");
}
/*
* Read from tun, write to slip.
*/
void
tun_to_serial(int infd, int outfd)
{
struct {
unsigned char inbuf[2000];
} uip;
int size;
if ((size = read(infd, uip.inbuf, 2000)) == -1) {
err(1, "tun_to_serial: read");
}
write_to_serial(outfd, uip.inbuf, size);
}
#ifndef BAUDRATE
#define BAUDRATE B115200
#endif
speed_t b_rate = BAUDRATE;
void
stty_telos(int fd)
{
struct termios tty;
speed_t speed = b_rate;
int i;
if (tcflush(fd, TCIOFLUSH) == -1) {
err(1, "tcflush");
}
if (tcgetattr(fd, &tty) == -1) {
err(1, "tcgetattr");
}
cfmakeraw(&tty);
/* Nonblocking read. */
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 0;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag &= ~HUPCL;
tty.c_cflag &= ~CLOCAL;
cfsetispeed(&tty, speed);
cfsetospeed(&tty, speed);
if (tcsetattr(fd, TCSAFLUSH, &tty) == -1) {
err(1, "tcsetattr");
}
#if 1
/* Nonblocking read and write. */
/* if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */
tty.c_cflag |= CLOCAL;
if (tcsetattr(fd, TCSAFLUSH, &tty) == -1) {
err(1, "tcsetattr");
}
i = TIOCM_DTR;
if (ioctl(fd, TIOCMBIS, &i) == -1) {
err(1, "ioctl");
}
#endif
usleep(10 * 1000); /* Wait for hardware 10ms. */
/* Flush input and output buffers. */
if (tcflush(fd, TCIOFLUSH) == -1) {
err(1, "tcflush");
}
}
int
devopen(const char *dev, int flags)
{
char t[1024];
strcpy(t, "/dev/");
strcat(t, dev);
return open(t, flags);
}
#ifdef linux
#include <linux/if.h>
#include <linux/if_tun.h>
int
tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
return -1;
}
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (*dev != 0) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
}
strcpy(dev, ifr.ifr_name);
return fd;
}
#else
int
tun_alloc(char *dev)
{
return devopen(dev, O_RDWR);
}
#endif
const char *ipaddr;
const char *netmask;
void
cleanup(void)
{
ssystem("ifconfig %s down", tundev);
#ifndef linux
ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
#endif
/* ssystem("arp -d %s", ipaddr); */
ssystem("netstat -nr"
" | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
" | sh",
tundev);
}
void
sigcleanup(int signo)
{
fprintf(stderr, "signal %d\n", signo);
exit(0); /* exit(0) will call cleanup() */
}
static int got_sigalarm;
static int request_mac;
void
sigalarm(int signo)
{
got_sigalarm = 1;
return;
}
void
sigalarm_reset()
{
#ifdef linux
#define TIMEOUT (997*1000)
#else
#define TIMEOUT (2451*1000)
#endif
ualarm(TIMEOUT, TIMEOUT);
got_sigalarm = 0;
}
void
ifconf(const char *tundev, const char *ipaddr, const char *netmask)
{
struct in_addr netname;
netname.s_addr = inet_addr(ipaddr) & inet_addr(netmask);
#ifdef linux
ssystem("ifconfig %s inet `hostname` up", tundev);
if (strcmp(ipaddr, "0.0.0.0") != 0) {
ssystem("route add -net %s netmask %s dev %s",
inet_ntoa(netname), netmask, tundev);
}
#else
ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr);
if (strcmp(ipaddr, "0.0.0.0") != 0) {
ssystem("route add -net %s -netmask %s -interface %s",
inet_ntoa(netname), netmask, tundev);
}
ssystem("sysctl -w net.inet.ip.forwarding=1");
#endif /* !linux */
ssystem("ifconfig %s\n", tundev);
}
int
main(int argc, char **argv)
{
int c;
int tunfd, slipfd, maxfd;
int ret;
fd_set rset, wset;
FILE *inslip;
const char *siodev = NULL;
int baudrate = -2;
request_mac = 1;
setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */
while ((c = getopt(argc, argv, "B:D:hs:t:")) != -1) {
switch (c) {
case 'B':
baudrate = atoi(optarg);
break;
case 's':
if (strncmp("/dev/", optarg, 5) == 0) {
siodev = optarg + 5;
}
else {
siodev = optarg;
}
break;
case 't':
if (strncmp("/dev/", optarg, 5) == 0) {
strcpy(tundev, optarg + 5);
}
else {
strcpy(tundev, optarg);
}
break;
case '?':
case 'h':
default:
errx(1, USAGE_STRING);
break;
}
}
argc -= (optind - 1);
argv += (optind - 1);
if (argc != 3 && argc != 4) {
errx(1, USAGE_STRING);
}
ipaddr = argv[1];
netmask = argv[2];
circuit_addr = inet_addr(ipaddr);
netaddr = inet_addr(ipaddr) & inet_addr(netmask);
switch (baudrate) {
case -2:
break; /* Use default. */
case 9600:
b_rate = B9600;
break;
case 19200:
b_rate = B19200;
break;
case 38400:
b_rate = B38400;
break;
case 57600:
b_rate = B57600;
break;
case 115200:
b_rate = B115200;
break;
default:
err(1, "unknown baudrate %d", baudrate);
break;
}
if (siodev != NULL) {
slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
if (slipfd == -1) {
err(1, "can't open siodev ``/dev/%s''", siodev);
}
}
else {
static const char *siodevs[] = {
"ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
};
int i;
for (i = 0; i < 3; i++) {
siodev = siodevs[i];
slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
if (slipfd != -1) {
break;
}
}
if (slipfd == -1) {
err(1, "can't open siodev");
}
}
fprintf(stderr, "slip started on ``/dev/%s''\n", siodev);
stty_telos(slipfd);
slip_send(slipfd, SLIP_END);
inslip = fdopen(slipfd, "r");
if (inslip == NULL) {
err(1, "main: fdopen");
}
tunfd = tun_alloc(tundev);
printf("opening: %s", tundev);
if (tunfd == -1) {
err(1, "main: open");
}
fprintf(stderr, "opened device ``/dev/%s''\n", tundev);
atexit(cleanup);
signal(SIGHUP, sigcleanup);
signal(SIGTERM, sigcleanup);
signal(SIGINT, sigcleanup);
signal(SIGALRM, sigalarm);
ifconf(tundev, ipaddr, netmask);
while (1) {
maxfd = 0;
FD_ZERO(&rset);
FD_ZERO(&wset);
/* request mac address from gateway node for autoconfiguration of
ethernet interface tap0 */
if (request_mac) {
slip_send(slipfd, '?');
slip_send(slipfd, 'M');
slip_send(slipfd, SLIP_END);
request_mac = 0;
}
if (got_sigalarm) {
/* Send "?IPA". */
slip_send(slipfd, '?');
slip_send(slipfd, 'I');
slip_send(slipfd, 'P');
slip_send(slipfd, 'A');
slip_send(slipfd, SLIP_END);
got_sigalarm = 0;
}
if (!slip_empty()) { /* Anything to flush? */
FD_SET(slipfd, &wset);
}
FD_SET(slipfd, &rset); /* Read from slip ASAP! */
if (slipfd > maxfd) {
maxfd = slipfd;
}
/* We only have one packet at a time queued for slip output. */
if (slip_empty()) {
FD_SET(tunfd, &rset);
if (tunfd > maxfd) {
maxfd = tunfd;
}
}
ret = select(maxfd + 1, &rset, &wset, NULL, NULL);
if (ret == -1 && errno != EINTR) {
err(1, "select");
}
else if (ret > 0) {
if (FD_ISSET(slipfd, &rset)) {
serial_to_tun(inslip, tunfd);
}
if (FD_ISSET(slipfd, &wset)) {
slip_flushbuf(slipfd);
sigalarm_reset();
}
if (slip_empty() && FD_ISSET(tunfd, &rset)) {
tun_to_serial(tunfd, slipfd);
slip_flushbuf(slipfd);
sigalarm_reset();
}
}
}
}

1267
dist/tools/tunslip/tunslip.c vendored Normal file

File diff suppressed because it is too large Load Diff

1275
dist/tools/tunslip/tunslip6.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -119,6 +119,9 @@ endif
ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE))) ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/netif DIRS += net/network_layer/ng_sixlowpan/netif
endif endif
ifneq (,$(filter ng_slip,$(USEMODULE)))
DIRS += net/link_layer/ng_slip
endif
ifneq (,$(filter netapi,$(USEMODULE))) ifneq (,$(filter netapi,$(USEMODULE)))
DIRS += net/crosslayer/netapi DIRS += net/crosslayer/netapi
endif endif

View File

@ -82,6 +82,10 @@ ifneq (,$(filter cpp11-compat,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/cpp11-compat/include USEMODULE_INCLUDES += $(RIOTBASE)/sys/cpp11-compat/include
endif endif
ifneq (,$(filter ng_slip,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
ifneq (,$(filter embunit,$(USEMODULE))) ifneq (,$(filter embunit,$(USEMODULE)))
ifeq ($(OUTPUT),XML) ifeq ($(OUTPUT),XML)
CFLAGS += -DOUTPUT=OUTPUT_XML CFLAGS += -DOUTPUT=OUTPUT_XML

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/**
* @ingroup auto_init_ng_netif
* @{
*
* @file
* @brief Auto initialization for XBee network interfaces
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifdef MODULE_NG_SLIP
#include "board.h"
#include "net/ng_nomac.h"
#include "net/ng_netbase.h"
#include "slip.h"
#include "slip_params.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define SLIP_NUM (sizeof(ng_slip_params)/sizeof(ng_slip_params_t))
static ng_slip_dev_t slip_devs[SLIP_NUM];
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define SLIP_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT)
#define SLIP_PRIO (PRIORITY_MAIN - 3)
/**
* @brief Stacks for the MAC layer threads
*/
static char _slip_stacks[SLIP_STACKSIZE][SLIP_NUM];
void auto_init_slip(void)
{
for (int i = 0; i < SLIP_NUM; i++) {
const ng_slip_params_t *p = &ng_slip_params[i];
DEBUG("Initializing SLIP radio at UART_%d\n", p->uart);
kernel_pid_t res = ng_slip_init(&slip_devs[i], p->uart, p->baudrate,
_slip_stacks[i], SLIP_STACKSIZE,
SLIP_PRIO);
if (res <= KERNEL_PID_UNDEF) {
DEBUG("Error initializing XBee radio device!");
}
}
}
#endif /* MODULE_NG_SLIP */
/** @} */

93
sys/include/net/ng_slip.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_ng_slip SLIP
* @ingroup net
* @brief Provides a SLIP interface over UART utilizing
* @ref driver_periph_uart.
* @see <a href="https://www.ietf.org/rfc/rfc1055">RFC 1055</a>
* @{
*
* @file
* @brief SLIP interface defintion
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef NG_SLIP_H_
#define NG_SLIP_H_
#include <inttypes.h>
#include "net/ng_netbase.h"
#include "periph/uart.h"
#include "ringbuffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief UART buffer size used for TX and RX buffers
*
* Reduce this value if your expected traffic does not include full IPv6 MTU
* sized packets
*/
#ifndef NG_SLIP_BUFSIZE
#define NG_SLIP_BUFSIZE (1500U)
#endif
/**
* @brief Device descriptor for SLIP devices
*/
typedef struct {
uart_t uart; /**< the UART interface */
ringbuffer_t *in_buf; /**< RX buffer */
ringbuffer_t *out_buf; /**< TX buffer */
char rx_mem[NG_SLIP_BUFSIZE]; /**< memory used by RX buffer */
char tx_mem[NG_SLIP_BUFSIZE]; /**< memory used by TX buffer */
uint32_t in_bytes; /**< the number of bytes received of a
* currently incoming packet */
uint16_t in_esc; /**< receiver is in escape mode */
kernel_pid_t slip_pid; /**< PID of the device thread */
} ng_slip_dev_t;
/**
* @brief auto_init struct holding SLIP initalization params
*/
typedef struct xbee_params {
uart_t uart; /**< UART interfaced the device is connected to */
uint32_t baudrate; /**< baudrate to use */
} xbee_params_t;
/**
* @brief Initializes a new @ref net_ng_slip control thread for UART device
* @p uart
*
* @param[in] dev un-initialized SLIP device descriptor
* @param[in] uart UART device to use
* @param[in] baudrate baudrate to use
* @param[in] stack stack memory to use for the SLIP devices thread
* @param[in] stack_size size of @p stack
* @param[in] priority priority for the newly created thread
*
* @return PID of SLIP thread on success
* @return -EFAULT, if slip thread could not be created
* @return -ENODEV, if ng_slip_dev_t::uart of @p dev was no valid UART
*/
kernel_pid_t ng_slip_init(ng_slip_dev_t *dev, uart_t uart, uint32_t baudrate,
char *stack, size_t stack_size, char priority);
#ifdef __cplusplus
}
#endif
#endif /* __SLIP_H_ */
/** @} */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,284 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_slip
* @{
*
* @file
* @brief SLIP device implementation
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "kernel_types.h"
#include "msg.h"
#include "net/ng_netbase.h"
#include "periph/uart.h"
#include "ringbuffer.h"
#include "thread.h"
#include "net/ng_ipv6/hdr.h"
#include "net/ng_slip.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define _SLIP_END ('\xc0')
#define _SLIP_ESC ('\xdb')
#define _SLIP_END_ESC ('\xdc')
#define _SLIP_ESC_ESC ('\xdd')
#define _SLIP_MSG_TYPE (0xc1dc) /* chosen randomly */
#define _SLIP_NAME "SLIP"
#define _SLIP_MSG_QUEUE_SIZE (8U)
#define _SLIP_DEV(arg) ((ng_slip_dev_t *)arg)
/* UART callbacks */
static void _slip_rx_cb(void *arg, char data)
{
if (data == _SLIP_END) {
msg_t msg;
msg.type = _SLIP_MSG_TYPE;
msg.content.value = _SLIP_DEV(arg)->in_bytes;
msg_send_int(&msg, _SLIP_DEV(arg)->slip_pid);
_SLIP_DEV(arg)->in_bytes = 0;
}
if (_SLIP_DEV(arg)->in_esc) {
_SLIP_DEV(arg)->in_esc = 0;
switch (data) {
case (_SLIP_END_ESC):
if (ringbuffer_add_one(_SLIP_DEV(arg)->in_buf, _SLIP_END) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
break;
case (_SLIP_ESC_ESC):
if (ringbuffer_add_one(_SLIP_DEV(arg)->in_buf, _SLIP_ESC) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
break;
default:
break;
}
}
else if (data == _SLIP_ESC) {
_SLIP_DEV(arg)->in_esc = 1;
}
else {
if (ringbuffer_add_one(_SLIP_DEV(arg)->in_buf, data) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
}
}
int _slip_tx_cb(void *arg)
{
if (_SLIP_DEV(arg)->out_buf->avail > 0) {
char c = (char)ringbuffer_get_one(_SLIP_DEV(arg)->out_buf);
uart_write((uart_t)(_SLIP_DEV(arg)->uart), c);
return 1;
}
return 0;
}
/* SLIP receive handler */
static void _slip_receive(ng_slip_dev_t *dev, size_t bytes)
{
ng_netif_hdr_t *hdr;
ng_netreg_entry_t *sendto;
ng_pktsnip_t *pkt, *netif_hdr;
pkt = ng_pktbuf_add(NULL, NULL, bytes, NG_NETTYPE_UNDEF);
if (pkt == NULL) {
DEBUG("slip: no space left in packet buffer\n");
return;
}
netif_hdr = ng_pktbuf_add(pkt, NULL, sizeof(ng_netif_hdr_t),
NG_NETTYPE_NETIF);
if (netif_hdr == NULL) {
DEBUG("slip: no space left in packet buffer\n");
ng_pktbuf_release(pkt);
return;
}
hdr = netif_hdr->data;
ng_netif_hdr_init(hdr, 0, 0);
hdr->if_pid = thread_getpid();
if (ringbuffer_get(dev->in_buf, pkt->data, bytes) != bytes) {
DEBUG("slip: could not read %zu bytes from ringbuffer\n", bytes);
ng_pktbuf_release(pkt);
return;
}
#ifdef MODULE_NG_IPV6
if ((pkt->size >= sizeof(ng_ipv6_hdr_t)) && ng_ipv6_hdr_is_ipv6_hdr(pkt->data)) {
pkt->type = NG_NETTYPE_IPV6;
}
#endif
sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL);
if (sendto == NULL) {
DEBUG("slip: unable to forward packet of type %i\n", pkt->type);
ng_pktbuf_release(pkt);
}
ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1);
while (sendto != NULL) {
DEBUG("slip: sending pkt %p to PID %u\n", pkt, sendto->pid);
ng_netapi_receive(sendto->pid, pkt);
sendto = ng_netreg_getnext(sendto);
}
}
static inline void _slip_send_char(ng_slip_dev_t *dev, char c)
{
ringbuffer_add_one(dev->out_buf, c);
uart_tx_begin(dev->uart);
}
/* SLIP send handler */
static void _slip_send(ng_slip_dev_t *dev, ng_pktsnip_t *pkt)
{
ng_pktsnip_t *ptr;
ptr = pkt->next; /* ignore ng_netif_hdr_t, we don't need it */
while (ptr != NULL) {
DEBUG("slip: send pktsnip of length %zu over UART_%d\n", ptr->size, uart);
char *data = ptr->data;
for (size_t i = 0; i < ptr->size; i++) {
switch (data[i]) {
case _SLIP_END:
DEBUG("slip: encountered END byte on send: stuff with ESC\n");
_slip_send_char(dev, _SLIP_ESC);
_slip_send_char(dev, _SLIP_END_ESC);
break;
case _SLIP_ESC:
DEBUG("slip: encountered ESC byte on send: stuff with ESC\n");
_slip_send_char(dev, _SLIP_ESC);
_slip_send_char(dev, _SLIP_ESC_ESC);
break;
default:
_slip_send_char(dev, data[i]);
break;
}
}
ptr = ptr->next;
}
_slip_send_char(dev, _SLIP_END);
ng_pktbuf_release(pkt);
}
static void *_slip(void *args)
{
ng_slip_dev_t *dev = _SLIP_DEV(args);
msg_t msg, reply, msg_q[_SLIP_MSG_QUEUE_SIZE];
msg_init_queue(msg_q, _SLIP_MSG_QUEUE_SIZE);
dev->slip_pid = thread_getpid();
ng_netif_add(dev->slip_pid);
DEBUG("slip: SLIP runs on UART_%d\n", uart);
while (1) {
DEBUG("slip: waiting for incoming messages\n");
msg_receive(&msg);
switch (msg.type) {
case _SLIP_MSG_TYPE:
DEBUG("slip: incoming message from UART in buffer\n");
_slip_receive(dev, (size_t)msg.content.value);
break;
case NG_NETAPI_MSG_TYPE_SND:
DEBUG("slip: NG_NETAPI_MSG_TYPE_SND received\n");
_slip_send(dev, (ng_pktsnip_t *)msg.content.ptr);
break;
case NG_NETAPI_MSG_TYPE_GET:
case NG_NETAPI_MSG_TYPE_SET:
DEBUG("slip: NG_NETAPI_MSG_TYPE_GET or NG_NETAPI_MSG_TYPE_SET received\n");
reply.type = NG_NETAPI_MSG_TYPE_ACK;
reply.content.value = (uint32_t)(-ENOTSUP);
DEBUG("slip: I don't support these but have to reply.\n");
msg_reply(&msg, &reply);
break;
}
}
/* should be never reached */
return NULL;
}
kernel_pid_t ng_slip_init(ng_slip_dev_t *dev, uart_t uart, uint32_t baudrate,
char *stack, size_t stack_size, char priority)
{
int res;
kernel_pid_t pid;
/* reset device descriptor fields */
dev->in_bytes = 0;
dev->in_esc = 0;
dev->slip_pid = KERNEL_PID_UNDEF;
/* initialize buffers */
ringbuffer_init(dev->in_buf, dev->rx_mem, sizeof(dev->rx_mem));
ringbuffer_init(dev->out_buf, dev->tx_mem, sizeof(dev->tx_mem));
/* initialize UART */
DEBUG("slip: initialize UART_%d\n", uart);
res = uart_init(uart, baudrate, _slip_rx_cb, _slip_tx_cb, dev);
if (res < 0) {
DEBUG("slip: error initializing UART_%i with baudrate %u\n",
uart, baudrate);
return -ENODEV;
}
/* start SLIP thread */
DEBUG("slip: starting SLIP thread\n");
pid = thread_create(stack, stack_size, priority, CREATE_STACKTEST,
_slip, dev, _SLIP_NAME);
if (pid < 0) {
DEBUG("slip: unable to create SLIP thread\n");
return -EFAULT;
}
return res;
}

25
tests/slip/Makefile Normal file
View File

@ -0,0 +1,25 @@
APPLICATION = driver_slip
include ../Makefile.tests_common
BOARD_INSUFFICIENT_RAM := stm32f0discovery
USEMODULE += ng_netbase
USEMODULE += ng_pktdump
USEMODULE += ng_slip
USEMODULE += shell
USEMODULE += shell_commands
ifneq (,$(SLIP_UART))
CFLAGS += -DSLIP_UART=$(SLIP_UART)
else
# set default
CFLAGS += -DSLIP_UART=UART_0
endif
ifneq (,$(SLIP_BAUDRATE))
CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE)
else
# set default
CFLAGS += -DSLIP_BAUDRATE=115200
endif
include $(RIOTBASE)/Makefile.include

76
tests/slip/main.c Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for ng_tapnet network device driver
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "shell_commands.h"
#include "net/ng_netbase.h"
#include "net/ng_pktdump.h"
/**
* @brief Buffer size used by the shell
*/
#define SHELL_BUFSIZE (64U)
/**
* @brief Read chars from STDIO
*/
int shell_read(void)
{
return (int)getchar();
}
/**
* @brief Write chars to STDIO
*/
void shell_put(int c)
{
putchar((char)c);
}
/**
* @brief Maybe you are a golfer?!
*/
int main(void)
{
shell_t shell;
ng_netreg_entry_t dump;
puts("SLIP test");
/* initialize and register pktdump */
dump.pid = ng_pktdump_getpid();
dump.demux_ctx = NG_NETREG_DEMUX_CTX_ALL;
if (dump.pid <= KERNEL_PID_UNDEF) {
puts("Error starting pktdump thread");
return -1;
}
ng_netreg_register(NG_NETTYPE_UNDEF, &dump);
/* start the shell */
puts("Initialization OK, starting shell now");
shell_init(&shell, NULL, SHELL_BUFSIZE, shell_read, shell_put);
shell_run(&shell);
return 0;
}

37
tests/slip/slip_params.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief slip parameters example, used by auto_init_ng_netif
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef SLIP_PARAMS_H
#define SLIP_PARAMS_H
#ifdef __cplusplus
extern "C" {
#endif
static xbee_params_t xbee_params[] = {
{
.uart = SLIP_UART,
.baudrate = SLIP_BAUDRATE,
},
};
#ifdef __cplusplus
}
#endif
#endif /* SLIP_PARAMS_H */
/** @} */