Porting PicoTCP WIP

This commit is contained in:
2025-10-29 14:29:06 +01:00
parent 6722f42e68
commit 815c2239fe
464 changed files with 235009 additions and 24 deletions

View File

@ -0,0 +1,36 @@
PREFIX?=../../build
CFLAGS+=-I../../include/ -I../../modules -I../../build/include -I . -ggdb
$(PREFIX)/examples/%.o: %.c
@mkdir -p $(PREFIX)/examples
@echo -e "\t[CC] $@"
@$(CC) -c $(CFLAGS) -o $@ $<
OBJS:= \
$(PREFIX)/examples/dhcp_client.o \
$(PREFIX)/examples/dhcp_server.o \
$(PREFIX)/examples/dns_sd.o \
$(PREFIX)/examples/dnsclient.o \
$(PREFIX)/examples/mdns.o \
$(PREFIX)/examples/multicast_recv.o \
$(PREFIX)/examples/multicast_ip6_recv.o \
$(PREFIX)/examples/multicast_send.o \
$(PREFIX)/examples/multicast_ip6_send.o \
$(PREFIX)/examples/natbox.o \
$(PREFIX)/examples/noop.o \
$(PREFIX)/examples/ping.o \
$(PREFIX)/examples/slaacv4.o \
$(PREFIX)/examples/sntp.o \
$(PREFIX)/examples/tcpbench.o \
$(PREFIX)/examples/tcpclient.o \
$(PREFIX)/examples/tcpecho.o \
$(PREFIX)/examples/tftp.o \
$(PREFIX)/examples/udp_client.o \
$(PREFIX)/examples/udp_echo.o \
$(PREFIX)/examples/udpnat.o \
$(PREFIX)/examples/udp_sendto_test.o \
$(PREFIX)/examples/iperfc.o \
all: $(OBJS)

View File

@ -0,0 +1,114 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_dhcp_client.h>
#include <pico_socket.h>
#include <pico_icmp4.h>
#include <pico_device.h>
/*** START DHCP Client ***/
#ifdef PICO_SUPPORT_DHCPC
/* This must stay global, its lifetime is the same as the dhcp negotiation */
uint32_t dhcpclient_xid;
static uint8_t dhcpclient_devices = 0;
void ping_callback_dhcpclient(struct pico_icmp4_stats *s)
{
char host[30] = { };
pico_ipv4_to_string(host, s->dst.addr);
if (s->err == 0) {
dbg("DHCP client: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n",
s->size, host, s->seq, (long unsigned int)s->time);
if (s->seq >= 3) {
dbg("DHCP client: TEST SUCCESS!\n");
if (--dhcpclient_devices <= 0)
exit(0);
}
} else {
dbg("DHCP client: ping %lu to %s error %d\n", s->seq, host, s->err);
dbg("DHCP client: TEST FAILED!\n");
exit(1);
}
}
void callback_dhcpclient(void *arg, int code)
{
struct pico_ip4 address = ZERO_IP4, gateway = ZERO_IP4;
char s_address[16] = { }, s_gateway[16] = { };
printf("DHCP client: callback happened with code %d!\n", code);
if (code == PICO_DHCP_SUCCESS) {
address = pico_dhcp_get_address(arg);
gateway = pico_dhcp_get_gateway(arg);
pico_ipv4_to_string(s_address, address.addr);
pico_ipv4_to_string(s_gateway, gateway.addr);
printf("DHCP client: got IP %s assigned with cli %p\n", s_address, arg);
#ifdef PICO_SUPPORT_PING
pico_icmp4_ping(s_gateway, 3, 1000, 5000, 32, ping_callback_dhcpclient);
/* optional test to check routing when links get added and deleted */
/* do {
char *new_arg = NULL, *p = NULL;
new_arg = calloc(1, strlen(s_address) + strlen(":224.7.7.7:6667:6667") + 1);
p = strcat(new_arg, s_address);
p = strcat(p + strlen(s_address), ":224.7.7.7:6667:6667");
app_mcastsend(new_arg);
} while (0);
*/
#endif
}
}
void app_dhcp_client(char *arg)
{
char *sdev = NULL;
char *nxt = arg;
struct pico_device *dev = NULL;
if (!nxt)
goto out;
while (nxt) {
if (nxt) {
nxt = cpy_arg(&sdev, nxt);
if(!sdev) {
goto out;
}
}
dev = pico_get_device(sdev);
if(dev == NULL) {
if (sdev)
free(sdev);
printf("%s: error getting device %s: %s\n", __FUNCTION__, dev->name, strerror(pico_err));
exit(255);
}
printf("Starting negotiation\n");
if (pico_dhcp_initiate_negotiation(dev, &callback_dhcpclient, &dhcpclient_xid) < 0) {
printf("%s: error initiating negotiation: %s\n", __FUNCTION__, strerror(pico_err));
if (sdev)
free(sdev);
exit(255);
}
if (sdev)
free(sdev);
dhcpclient_devices++;
}
return;
out:
fprintf(stderr, "dhcpclient expects the following format: dhcpclient:dev_name:[dev_name]\n");
if (sdev)
free(sdev);
exit(255);
}
#endif
/*** END DHCP Client ***/

View File

@ -0,0 +1,99 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_device.h>
#include <pico_dhcp_server.h>
/*** START DHCP Server ***/
#ifdef PICO_SUPPORT_DHCPD
/* ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.1:255.255.0.0: -a dhcpserver:pic0:10.40.0.1:255.255.255.0:64:128
* ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.255.0: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.255.0: \
* -a dhcpserver:pic0:10.40.0.10:255.255.255.0:64:128:pic1:10.50.0.10:255.255.255.0:64:128
*/
void app_dhcp_server(char *arg)
{
struct pico_device *dev = NULL;
struct pico_dhcp_server_setting s = {
0
};
int pool_start = 0, pool_end = 0;
char *s_name = NULL, *s_addr = NULL, *s_netm = NULL, *s_pool_start = NULL, *s_pool_end = NULL;
char *nxt = arg;
if (!nxt)
goto out;
while (nxt) {
if (nxt) {
nxt = cpy_arg(&s_name, nxt);
if (!s_name) {
goto out;
}
} else {
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_addr, nxt);
if (s_addr) {
pico_string_to_ipv4(s_addr, &s.server_ip.addr);
} else {
goto out;
}
} else {
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_netm, nxt);
if (s_netm) {
pico_string_to_ipv4(s_netm, &s.netmask.addr);
} else {
goto out;
}
} else {
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_pool_start, nxt);
if (s_pool_start && atoi(s_pool_start)) {
pool_start = atoi(s_pool_start);
} else {
goto out;
}
} else {
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_pool_end, nxt);
if (s_pool_end && atoi(s_pool_end)) {
pool_end = atoi(s_pool_end);
} else {
goto out;
}
} else {
goto out;
}
dev = (struct pico_device *)pico_get_device(s_name);
if (dev == NULL) {
fprintf(stderr, "No device with name %s found\n", s_name);
exit(255);
}
s.dev = dev;
s.pool_start = (s.server_ip.addr & s.netmask.addr) | long_be(pool_start);
s.pool_end = (s.server_ip.addr & s.netmask.addr) | long_be(pool_end);
pico_dhcp_server_initiate(&s);
}
return;
out:
fprintf(stderr, "dhcpserver expects the following format: dhcpserver:dev_name:dev_addr:dev_netm:pool_start:pool_end\n");
exit(255);
}
#endif
/*** END DHCP Server ***/

View File

@ -0,0 +1,112 @@
#include "utils.h"
#include <pico_dns_sd.h>
#include <pico_ipv4.h>
#include <pico_addressing.h>
#include <pico_device.h>
#include <pico_ipv4.h>
/*** START DNS_SD ***/
#ifdef PICO_SUPPORT_DNS_SD
#define TTL 30
#define SECONDS 10
static int fully_initialized = 0;
static char *service_name = NULL;
void dns_sd_claimed_callback( pico_mdns_rtree *tree,
char *str,
void *arg )
{
printf("DONE - Registering DNS-SD Service\n");
IGNORE_PARAMETER(tree);
IGNORE_PARAMETER(str);
IGNORE_PARAMETER(arg);
}
void dns_sd_init_callback( pico_mdns_rtree *tree,
char *str,
void *arg )
{
PICO_DNS_SD_KV_VECTOR_DECLARE(key_value_pair_vector);
IGNORE_PARAMETER(str);
IGNORE_PARAMETER(arg);
IGNORE_PARAMETER(tree);
pico_dns_sd_kv_vector_add(&key_value_pair_vector, "key", "value");
printf("DONE - Initialising DNS Service Discovery module.\n");
if (pico_dns_sd_register_service(service_name,
"_http._tcp", 80,
&key_value_pair_vector,
TTL, dns_sd_claimed_callback, NULL) < 0) {
printf("Registering service failed!\n");
}
fully_initialized = 1;
}
void app_dns_sd(char *arg, struct pico_ip4 address)
{
char *hostname;
char *nxt = arg;
uint64_t starttime = 0;
int once = 0;
if (!nxt) {
exit(255);
}
nxt = cpy_arg(&hostname, nxt);
if(!hostname) {
exit(255);
}
if(!nxt) {
printf("Not enough args supplied!\n");
exit(255);
}
nxt = cpy_arg(&service_name, nxt);
if(!service_name) {
exit(255);
}
printf("\nStarting DNS Service Discovery module...\n");
if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL) != 0) {
printf("Initialisation returned with Error!\n");
exit(255);
}
printf("\nTry reinitialising DNS-SD\n");
if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL)) {
printf("Initialisation returned with Error!\n");
exit(255);
}
printf("DONE - Re-initialising DNS-SD module.\n");
starttime = PICO_TIME_MS();
printf("Starting time: %d\n", starttime);
while(1) {
pico_stack_tick();
usleep(2000);
if (((PICO_TIME_MS() - starttime) > SECONDS * 1000) && fully_initialized && !once) {
printf("\nTry reinitialising DNS-SD (a second time)\n");
if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL)) {
printf("Initialisation returned with Error!\n");
exit(255);
}
once = 1;
printf("DONE - Re-initialising mDNS module. (a second time)\n");
}
}
}
#endif
/*** END DNS_SD ***/

View File

@ -0,0 +1,120 @@
#include <stdint.h>
#include <pico_stack.h>
#include <pico_ipv4.h>
#include <pico_dns_client.h>
#include "utils.h"
extern int IPV6_MODE;
/*** START UDP DNS CLIENT ***/
/*
./test/vde_sock_start.sh
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
iptables -A FORWARD -i pic0 -o wlan0 -j ACCEPT
iptables -A FORWARD -i wlan0 -o pic0 -j ACCEPT
./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1: -a udpdnsclient:www.google.be:173.194.67.94
*/
void cb_udpdnsclient_getaddr(char *ip, void *arg)
{
uint8_t *id = (uint8_t *) arg;
if (!ip) {
picoapp_dbg("%s: ERROR occured! (id: %u)\n", __FUNCTION__, *id);
return;
}
picoapp_dbg("%s: ip %s (id: %u)\n", __FUNCTION__, ip, *id);
if (arg)
PICO_FREE(arg);
}
void cb_udpdnsclient_getname(char *name, void *arg)
{
uint8_t *id = (uint8_t *) arg;
if (!name) {
picoapp_dbg("%s: ERROR occured! (id: %u)\n", __FUNCTION__, *id);
return;
}
picoapp_dbg("%s: name %s (id: %u)\n", __FUNCTION__, name, *id);
if (arg)
PICO_FREE(arg);
}
void app_udpdnsclient(char *arg)
{
struct pico_ip4 nameserver;
char *dname, *daddr;
char *nxt;
char *ipver;
int v = 4;
uint8_t *getaddr_id, *getname_id, *getaddr6_id, *getname6_id;
nxt = cpy_arg(&dname, arg);
if (!dname || !nxt) {
picoapp_dbg(" udpdnsclient expects the following format: udpdnsclient:dest_name:dest_ip:[ipv6]\n");
exit(255);
}
nxt = cpy_arg(&daddr, nxt);
if (!daddr || !nxt) {
picoapp_dbg(" udpdnsclient expects the following format: udpdnsclient:dest_name:dest_ip:[ipv6]\n");
exit(255);
}
nxt = cpy_arg(&ipver, nxt);
if (!ipver || strcmp("ipv6", ipver) != 0)
v = 4;
else
v = 6;
picoapp_dbg("UDP DNS client started.\n");
picoapp_dbg("----- Deleting non existant nameserver -----\n");
pico_string_to_ipv4("127.0.0.1", &nameserver.addr);
pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_DEL);
picoapp_dbg("----- Adding 8.8.8.8 nameserver -----\n");
pico_string_to_ipv4("8.8.8.8", &nameserver.addr);
pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD);
picoapp_dbg("----- Deleting 8.8.8.8 nameserver -----\n");
pico_string_to_ipv4("8.8.8.8", &nameserver.addr);
pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_DEL);
picoapp_dbg("----- Adding 8.8.8.8 nameserver -----\n");
pico_string_to_ipv4("8.8.8.8", &nameserver.addr);
pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD);
picoapp_dbg("----- Adding 8.8.4.4 nameserver -----\n");
pico_string_to_ipv4("8.8.4.4", &nameserver.addr);
pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD);
if (!IPV6_MODE) {
if (v == 4) {
picoapp_dbg("Mode: IPv4\n");
getaddr_id = calloc(1, sizeof(uint8_t));
*getaddr_id = 1;
picoapp_dbg(">>>>> DNS GET ADDR OF %s\n", dname);
pico_dns_client_getaddr(dname, &cb_udpdnsclient_getaddr, getaddr_id);
getname_id = calloc(1, sizeof(uint8_t));
*getname_id = 2;
picoapp_dbg(">>>>> DNS GET NAME OF %s\n", daddr);
pico_dns_client_getname(daddr, &cb_udpdnsclient_getname, getname_id);
return;
}
picoapp_dbg("Mode: IPv6\n");
#ifdef PICO_SUPPORT_IPV6
getaddr6_id = calloc(1, sizeof(uint8_t));
*getaddr6_id = 3;
picoapp_dbg(">>>>> DNS GET ADDR6 OF %s\n", dname);
pico_dns_client_getaddr6(dname, &cb_udpdnsclient_getaddr, getaddr6_id);
getname6_id = calloc(1, sizeof(uint8_t));
*getname6_id = 4;
picoapp_dbg(">>>>> DNS GET NAME OF ipv6 addr 2a00:1450:400c:c06::64\n");
pico_dns_client_getname6("2a00:1450:400c:c06::64", &cb_udpdnsclient_getname, getname6_id);
#endif
}
return;
}
/*** END UDP DNS CLIENT ***/

View File

@ -0,0 +1,142 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "pico_ipv6.h"
#include "pico_stack.h"
#include "pico_socket.h"
#include "utils.h"
#define DURATION 30
struct iperf_hdr {
int32_t flags; /* 0 */
int32_t numThreads; /* 1 */
int32_t mPort; /* 5001 */
int32_t bufferlen; /* 0 */
int32_t mWinBand; /* 0 */
int32_t mAmount; /* 0xfffffc18 */
};
#define IPERF_PORT 5001
#define MTU 1444
#define SEND_BUF_SIZ (1024 * 2048)
char *cpy_arg(char **dst, char *str);
extern int IPV6_MODE;
static pico_time deadline;
static void panic(void)
{
for(;; ) ;
}
static char buf[MTU] = {};
static void buf_paint(void)
{
char paint[11] = "0123456789";
int i;
for (i = 0; i < MTU; i++) {
buf[i] = paint[i % 10];
}
}
static void send_hdr(struct pico_socket *s)
{
struct iperf_hdr hdr = {};
hdr.numThreads = long_be(1);
hdr.mPort = long_be(5001);
hdr.mAmount = long_be(0xfffffc18);
pico_socket_write(s, &hdr, sizeof(hdr));
deadline = PICO_TIME_MS() + DURATION * 1000;
}
static void iperf_cb(uint16_t ev, struct pico_socket *s)
{
int r;
static int end = 0;
if (ev & PICO_SOCK_EV_CONN) {
send_hdr(s);
return;
}
if ((!end) && (ev & PICO_SOCK_EV_WR)) {
if (PICO_TIME_MS() > deadline) {
pico_socket_close(s);
if (!pico_timer_add(2000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
end++;
}
pico_socket_write(s, buf, MTU);
}
if (!(end) && (ev & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE))) {
if (!pico_timer_add(2000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
end++;
}
}
static void iperfc_socket_setup(union pico_address *addr, uint16_t family)
{
int yes = 1;
uint16_t send_port = 0;
struct pico_socket *s = NULL;
uint32_t bufsize = SEND_BUF_SIZ;
send_port = short_be(5001);
s = pico_socket_open(family, PICO_PROTO_TCP, &iperf_cb);
pico_socket_setoption(s, PICO_SOCKET_OPT_SNDBUF, &bufsize);
pico_socket_connect(s, addr, send_port);
}
void app_iperfc(char *arg)
{
struct pico_ip4 my_eth_addr, netmask;
struct pico_device *pico_dev_eth;
char *daddr = NULL, *dport = NULL;
char *nxt = arg;
uint16_t send_port = 0, listen_port = short_be(5001);
int i = 0, ret = 0, yes = 1;
struct pico_socket *s = NULL;
uint16_t family = PICO_PROTO_IPV4;
union pico_address dst = {
.ip4 = {0}, .ip6 = {{0}}
};
union pico_address inaddr_any = {
.ip4 = {0}, .ip6 = {{0}}
};
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&daddr, arg);
if (daddr) {
if (!IPV6_MODE)
pico_string_to_ipv4(daddr, &dst.ip4.addr);
#ifdef PICO_SUPPORT_IPV6
else {
pico_string_to_ipv6(daddr, dst.ip6.addr);
family = PICO_PROTO_IPV6;
}
#endif
} else {
goto out;
}
} else {
/* missing dest_addr */
goto out;
}
iperfc_socket_setup(&dst, family);
return;
out:
dbg("Error parsing options!\n");
exit(1);
}

View File

@ -0,0 +1,83 @@
#include "utils.h"
#include "pico_dns_common.h"
#include "pico_mdns.h"
#include "pico_ipv4.h"
#include "pico_addressing.h"
/*** START MDNS ***/
#ifdef PICO_SUPPORT_MDNS
#define SECONDS 10
static int fully_initialized = 0;
void mdns_init_callback( pico_mdns_rtree *rtree,
char *str,
void *arg )
{
printf("\nInitialised with hostname: %s\n\n", str);
fully_initialized = 1;
}
void app_mdns(char *arg, struct pico_ip4 address)
{
char *hostname, *peername;
char *nxt = arg;
uint64_t starttime = 0;
int once = 0;
if (!nxt)
exit(255);
nxt = cpy_arg(&hostname, nxt);
if(!hostname) {
exit(255);
}
if(!nxt) {
printf("Not enough args supplied!\n");
exit(255);
}
nxt = cpy_arg(&peername, nxt);
if(!peername) {
exit(255);
}
printf("\nStarting mDNS module...\n");
if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) {
printf("Initialisation returned with Error!\n");
exit(255);
}
printf("\nTry reinitialising mDNS\n");
if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) {
printf("Initialisation returned with Error!\n");
exit(255);
}
printf("DONE - Re-initialising mDNS module.\n");
starttime = PICO_TIME_MS();
printf("Starting time: %d\n", starttime);
while(1) {
pico_stack_tick();
usleep(2000);
if (((PICO_TIME_MS() - starttime) > SECONDS * 1000) && fully_initialized && !once) {
printf("\nTry reinitialising mDNS (a second time)\n");
if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) {
printf("Initialisation returned with Error!\n");
exit(255);
}
once = 1;
printf("DONE - Re-initialising mDNS module. (a second time)\n");
}
}
}
#endif
/*** END MDNS ***/

View File

@ -0,0 +1,182 @@
#include "utils.h"
#include <pico_ipv6.h>
#include <pico_socket.h>
extern void app_udpecho(char *arg);
/*** START Multicast RECEIVE + ECHO ***/
/*
* multicast receive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port:sendto_port
* link_addr: mcastreceive picoapp IP address
* mcast_addr: multicast IP address to receive
* listen_port: port number on which the mcastreceive listens
* sendto_port: port number to echo multicast traffic to (echo to originating IP address)
*
* f.e.: ./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667
*/
extern struct udpclient_pas *udpclient_pas;
extern struct udpecho_pas *udpecho_pas;
#ifdef PICO_SUPPORT_MCAST
void app_mcastreceive_ipv6(char *arg)
{
char *new_arg = NULL, *p = NULL, *nxt = arg;
char *laddr = NULL, *maddr = NULL, *lport = NULL, *sport = NULL;
uint16_t listen_port = 0;
union pico_address inaddr_link = {
0
}, inaddr_mcast = {
0
}, src[5] = {
{.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0 }},
{.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0x10}},
{.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0x01 }},
{.ip6 = { 0xff, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xe0, 0x01, 0x01, 0x01 }},
};
struct pico_ip_mreq mreq = ZERO_MREQ_IP6;
struct pico_ip_mreq_source mreq_source = ZERO_MREQ_SRC_IP6;
/* start of parameter parsing */
if (nxt) {
nxt = cpy_arg(&laddr, nxt);
if (laddr) {
pico_string_to_ipv6(laddr, &inaddr_link.ip6.addr[0]);
} else {
goto out;
}
} else {
/* no arguments */
goto out;
}
if (nxt) {
nxt = cpy_arg(&maddr, nxt);
if (maddr) {
pico_string_to_ipv6(maddr, &inaddr_mcast.ip6.addr[0]);
} else {
goto out;
}
} else {
/* missing multicast address */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
listen_port = short_be(atoi(lport));
} else {
/* incorrect listen_port */
goto out;
}
} else {
/* missing listen_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
/* unused at this moment */
/* send_port = short_be(atoi(sport)); */
} else {
/* incorrect send_port */
goto out;
}
} else {
/* missing send_port */
goto out;
}
/* end of parameter parsing */
printf("\n%s: multicast receive started. Receiving packets on [%s]:%d\n\n", __FUNCTION__, maddr, short_be(listen_port));
/* udpecho:bind_addr:listen_port[:sendto_port:datasize] */
new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(",64:") + 1);
p = strcat(new_arg, laddr);
p = strcat(p + strlen(laddr), ",");
p = strcat(p + 1, lport);
p = strcat(p + strlen(lport), ",");
p = strcat(p + 1, sport);
p = strcat(p + strlen(sport), ",64,");
/* DAD needs to verify the link address before we can continue */
while(!pico_ipv6_link_get(&inaddr_link.ip6)) {
pico_stack_tick();
usleep(2000);
}
app_udpecho(new_arg);
memcpy(&mreq.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6));
memcpy( &mreq_source.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6));
memcpy(&mreq.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6));
memcpy(&mreq_source.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6));
memcpy(&mreq_source.mcast_source_addr, &src[0], sizeof(struct pico_ip6));
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_BLOCK_SOURCE, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_BLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_UNBLOCK_SOURCE, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_UNBLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
memcpy(&mreq_source.mcast_source_addr, &src[1], sizeof(struct pico_ip6));
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
memcpy(&mreq_source.mcast_source_addr, &src[2], sizeof(struct pico_ip6));
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
memcpy(&mreq_source.mcast_group_addr, &src[3], sizeof(struct pico_ip6));
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
return;
out:
fprintf(stderr, "mcastreceive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port[:send_port]\n");
exit(255);
}
#else
void app_mcastreceive_ipv6(char *arg)
{
printf("ERROR: PICO_SUPPORT_MCAST disabled\n");
return;
}
#endif
/*** END Multicast RECEIVE + ECHO ***/

View File

@ -0,0 +1,140 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_socket.h>
extern void app_udpclient(char *arg);
/*** START Multicast SEND ***/
/*
* multicast send expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port
* link_addr: mcastsend picoapp IP address
* mcast_addr: multicast IP address to send to
* sendto_port: port number to send multicast traffic to
* listen_port: port number on which the mcastsend can receive data
*
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667
*/
extern struct udpclient_pas *udpclient_pas;
#ifdef PICO_SUPPORT_MCAST
void app_mcastsend_ipv6(char *arg)
{
int retval = 0;
char *maddr = NULL, *laddr = NULL, *lport = NULL, *sport = NULL;
uint16_t sendto_port = 0;
struct pico_ip6 inaddr_link = {
0
}, inaddr_mcast = {
0
};
char *new_arg = NULL, *p = NULL, *nxt = arg;
struct pico_ip_mreq mreq = ZERO_MREQ_IP6;
/* start of parameter parsing */
if (nxt) {
nxt = cpy_arg(&laddr, nxt);
if (laddr) {
pico_string_to_ipv6(laddr, &inaddr_link.addr[0]);
} else {
goto out;
}
} else {
/* no arguments */
goto out;
}
if (nxt) {
nxt = cpy_arg(&maddr, nxt);
if (maddr) {
pico_string_to_ipv6(maddr, &inaddr_mcast.addr[0]);
} else {
goto out;
}
} else {
/* missing multicast address */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
sendto_port = short_be(atoi(sport));
} else {
/* incorrect send_port */
goto out;
}
} else {
/* missing send_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
/* unused at this moment */
/* listen_port = short_be(atoi(lport)); */
} else {
/* incorrect listen_port */
goto out;
}
} else {
/* missing listen_port */
goto out;
}
picoapp_dbg("\n%s: mcastsend started. Sending packets to %s:%u\n\n", __FUNCTION__, maddr, short_be(sendto_port));
/* udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] */
new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(",64,10,5,") + 1);
p = strcat(new_arg, maddr);
p = strcat(p + strlen(maddr), ",");
p = strcat(p + 1, sport);
p = strcat(p + strlen(sport), ",");
p = strcat(p + 1, lport);
p = strcat(p + strlen(lport), ",64,10,5,");
/* DAD needs to verify the link address before we can continue */
while(!pico_ipv6_link_get(&inaddr_link)) {
pico_stack_tick();
usleep(2000);
}
app_udpclient(new_arg);
memcpy(&mreq.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6));
memcpy(&mreq.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6));
if(pico_socket_setoption(udpclient_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
picoapp_dbg("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
retval = 1;
}
if (new_arg)
free(new_arg);
if (lport)
free(lport);
if (maddr)
free(maddr);
if (sport)
free(sport);
if (laddr)
free(laddr);
if (retval)
exit(retval);
return;
out:
picoapp_dbg("mcastsend expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port\n");
exit(255);
}
#else
void app_mcastsend_ipv6(char *arg)
{
picoapp_dbg("ERROR: PICO_SUPPORT_MCAST disabled\n");
return;
}
#endif
/*** END Multicast SEND ***/

View File

@ -0,0 +1,171 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_socket.h>
extern void app_udpecho(char *arg);
/*** START Multicast RECEIVE + ECHO ***/
/*
* multicast receive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port:sendto_port
* link_addr: mcastreceive picoapp IP address
* mcast_addr: multicast IP address to receive
* listen_port: port number on which the mcastreceive listens
* sendto_port: port number to echo multicast traffic to (echo to originating IP address)
*
* f.e.: ./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667
*/
extern struct udpclient_pas *udpclient_pas;
extern struct udpecho_pas *udpecho_pas;
#ifdef PICO_SUPPORT_MCAST
void app_mcastreceive(char *arg)
{
char *new_arg = NULL, *p = NULL, *nxt = arg;
char *laddr = NULL, *maddr = NULL, *lport = NULL, *sport = NULL;
uint16_t listen_port = 0;
union pico_address inaddr_link = {
0
}, inaddr_mcast = {
0
};
struct pico_ip_mreq mreq = ZERO_MREQ;
struct pico_ip_mreq_source mreq_source = ZERO_MREQ_SRC;
/* start of parameter parsing */
if (nxt) {
nxt = cpy_arg(&laddr, nxt);
if (laddr) {
pico_string_to_ipv4(laddr, &inaddr_link.ip4.addr);
} else {
goto out;
}
} else {
/* no arguments */
goto out;
}
if (nxt) {
nxt = cpy_arg(&maddr, nxt);
if (maddr) {
pico_string_to_ipv4(maddr, &inaddr_mcast.ip4.addr);
} else {
goto out;
}
} else {
/* missing multicast address */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
listen_port = short_be(atoi(lport));
} else {
/* incorrect listen_port */
goto out;
}
} else {
/* missing listen_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
/* unused at this moment */
/* send_port = short_be(atoi(sport)); */
} else {
/* incorrect send_port */
goto out;
}
} else {
/* missing send_port */
goto out;
}
/* end of parameter parsing */
printf("\n%s: multicast receive started. Receiving packets on %s:%d\n\n", __FUNCTION__, maddr, short_be(listen_port));
/* udpecho:bind_addr:listen_port[:sendto_port:datasize] */
new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(":64:") + 1);
p = strcat(new_arg, laddr);
p = strcat(p + strlen(laddr), ":");
p = strcat(p + 1, lport);
p = strcat(p + strlen(lport), ":");
p = strcat(p + 1, sport);
p = strcat(p + strlen(sport), ":64:");
app_udpecho(new_arg);
mreq.mcast_group_addr = mreq_source.mcast_group_addr = inaddr_mcast;
mreq.mcast_link_addr = mreq_source.mcast_link_addr = inaddr_link;
mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101);
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_BLOCK_SOURCE, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_BLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_UNBLOCK_SOURCE, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_UNBLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC10010A);
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
}
mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101);
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
mreq_source.mcast_group_addr.ip4.addr = long_be(0XE0010101);
if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
}
return;
out:
fprintf(stderr, "mcastreceive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port[:send_port]\n");
exit(255);
}
#else
void app_mcastreceive(char *arg)
{
printf("ERROR: PICO_SUPPORT_MCAST disabled\n");
return;
}
#endif
/*** END Multicast RECEIVE + ECHO ***/

View File

@ -0,0 +1,129 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_socket.h>
extern void app_udpclient(char *arg);
/*** START Multicast SEND ***/
/*
* multicast send expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port
* link_addr: mcastsend picoapp IP address
* mcast_addr: multicast IP address to send to
* sendto_port: port number to send multicast traffic to
* listen_port: port number on which the mcastsend can receive data
*
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667
*/
extern struct udpclient_pas *udpclient_pas;
#ifdef PICO_SUPPORT_MCAST
void app_mcastsend(char *arg)
{
char *maddr = NULL, *laddr = NULL, *lport = NULL, *sport = NULL;
uint16_t sendto_port = 0;
union pico_address inaddr_link = {
0
}, inaddr_mcast = {
0
};
char *new_arg = NULL, *p = NULL, *nxt = arg;
struct pico_ip_mreq mreq = ZERO_MREQ;
/* start of parameter parsing */
if (nxt) {
nxt = cpy_arg(&laddr, nxt);
if (laddr) {
pico_string_to_ipv4(laddr, &inaddr_link.ip4.addr);
} else {
goto out;
}
} else {
/* no arguments */
goto out;
}
if (nxt) {
nxt = cpy_arg(&maddr, nxt);
if (maddr) {
pico_string_to_ipv4(maddr, &inaddr_mcast.ip4.addr);
} else {
goto out;
}
} else {
/* missing multicast address */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
sendto_port = short_be(atoi(sport));
} else {
/* incorrect send_port */
goto out;
}
} else {
/* missing send_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
/* unused at this moment */
/* listen_port = short_be(atoi(lport)); */
} else {
/* incorrect listen_port */
goto out;
}
} else {
/* missing listen_port */
goto out;
}
picoapp_dbg("\n%s: mcastsend started. Sending packets to %08X:%u\n\n", __FUNCTION__, long_be(inaddr_mcast.addr), short_be(sendto_port));
/* udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] */
new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(":64:10:5:") + 1);
p = strcat(new_arg, maddr);
p = strcat(p + strlen(maddr), ":");
p = strcat(p + 1, sport);
p = strcat(p + strlen(sport), ":");
p = strcat(p + 1, lport);
p = strcat(p + strlen(lport), ":64:10:5:");
app_udpclient(new_arg);
free(new_arg);
mreq.mcast_group_addr = inaddr_mcast;
mreq.mcast_link_addr = inaddr_link;
if(pico_socket_setoption(udpclient_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
picoapp_dbg("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
exit(1);
}
/* free strdups */
if (maddr)
free(maddr);
if (laddr)
free(laddr);
if (lport)
free(lport);
if (sport)
free(sport);
return;
out:
picoapp_dbg("mcastsend expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port\n");
exit(255);
}
#else
void app_mcastsend(char *arg)
{
picoapp_dbg("ERROR: PICO_SUPPORT_MCAST disabled\n");
return;
}
#endif
/*** END Multicast SEND ***/

View File

@ -0,0 +1,31 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_nat.h>
/*** START NATBOX ***/
void app_natbox(char *arg)
{
char *dest = NULL;
struct pico_ip4 ipdst, pub_addr, priv_addr;
struct pico_ipv4_link *link;
cpy_arg(&dest, arg);
if (!dest) {
fprintf(stderr, "natbox needs the following format: natbox:dst_addr\n");
exit(255);
}
pico_string_to_ipv4(dest, &ipdst.addr);
link = pico_ipv4_link_get(&ipdst);
if (!link) {
fprintf(stderr, "natbox: Destination not found.\n");
exit(255);
}
pico_ipv4_nat_enable(link);
pico_string_to_ipv4("10.50.0.10", &pub_addr.addr);
pico_string_to_ipv4("10.40.0.08", &priv_addr.addr);
pico_ipv4_port_forward(pub_addr, short_be(5555), priv_addr, short_be(6667), PICO_PROTO_UDP, PICO_NAT_PORT_FORWARD_ADD);
fprintf(stderr, "natbox: started.\n");
}
/*** END NATBOX ***/

View File

@ -0,0 +1,11 @@
/* NOOP */
#include <pico_stack.h>
void app_noop(void)
{
while(1) {
pico_stack_tick();
usleep(2000);
}
}
/* END NOOP */

View File

@ -0,0 +1,138 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_icmp4.h>
#include <pico_icmp6.h>
/*** START PING ***/
#ifdef PICO_SUPPORT_PING
#define NUM_PING 10
void cb_ping(struct pico_icmp4_stats *s)
{
char host[30];
pico_ipv4_to_string(host, s->dst.addr);
if (s->err == 0) {
dbg("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size, host, s->seq,
s->ttl, (long unsigned int)s->time);
if (s->seq >= NUM_PING)
exit(0);
} else {
dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err);
exit(1);
}
}
#ifdef PICO_SUPPORT_IPV6
void cb_ping6(struct pico_icmp6_stats *s)
{
char host[50];
pico_ipv6_to_string(host, s->dst.addr);
if (s->err == 0) {
dbg("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size, host, s->seq,
s->ttl, (long unsigned int)s->time);
if (s->seq >= NUM_PING)
exit(0);
} else {
dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err);
exit(1);
}
}
#endif
void ping_abort_timer(pico_time now, void *_id)
{
int *id = (int *) _id;
printf("Ping: aborting...\n");
if (!IPV6_MODE)
pico_icmp4_ping_abort(*id);
#ifdef PICO_SUPPORT_IPV6
else
pico_icmp6_ping_abort(*id);
#endif
}
void app_ping(char *arg)
{
char *dest = NULL;
char *next = NULL;
char *abort = NULL;
char *delay = NULL;
char *asize = NULL;
int initial_delay = 0;
struct pico_ip6 dst;
static int id;
int timeout = 0;
int size = 64;
next = cpy_arg(&dest, arg);
if (!dest) {
fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n");
exit(255);
}
pico_string_to_ipv6(dest, dst.addr);
if (next) {
next = cpy_arg(&asize, next);
size = atoi(asize);
free(asize);
if (size <= 0) {
size = 64; /* Default */
}
}
if (next) {
next = cpy_arg(&abort, next);
if (strlen(abort) > 0) {
printf("Got arg: '%s'\n", abort);
timeout = atoi(abort);
if (timeout < 0) {
fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n");
exit(255);
}
printf("Aborting ping after %d seconds\n", timeout);
}
}
if (next) {
next = cpy_arg(&delay, next);
if (strlen(delay) > 0) {
initial_delay = atoi(delay);
if (initial_delay > 0) {
printf("Initial delay: %d seconds\n", initial_delay);
initial_delay = PICO_TIME_MS() + initial_delay * 1000;
while (PICO_TIME_MS() < initial_delay) {
pico_stack_tick();
usleep(10000);
}
}
}
free(delay);
}
printf("Starting ping.\n");
if (!IPV6_MODE)
id = pico_icmp4_ping(dest, NUM_PING, 1000, 10000, size, cb_ping);
#ifdef PICO_SUPPORT_IPV6
else
id = pico_icmp6_ping(dest, NUM_PING, 1000, 10000, size, cb_ping6, pico_ipv6_source_dev_find(&dst));
#endif
if (timeout > 0) {
printf("Adding abort timer after %d seconds for id %d\n", timeout, id);
if (!pico_timer_add(timeout * 1000, ping_abort_timer, &id)) {
printf("Failed to set ping abort timeout, aborting ping\n");
ping_abort_timer((pico_time)0, &id);
exit(1);
}
}
/* free copied args */
if (dest)
free(dest);
if (abort)
free(abort);
}
#endif
/*** END PING ***/

View File

@ -0,0 +1,72 @@
#include "utils.h"
#include <pico_slaacv4.h>
#include <pico_icmp4.h>
/*** START SLAACV4 ***/
void ping_callback_slaacv4(struct pico_icmp4_stats *s)
{
char host[30] = { };
pico_ipv4_to_string(host, s->dst.addr);
if (s->err == 0) {
dbg("SLAACV4: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", s->size, host,
s->seq, (long unsigned int)s->time);
if (s->seq >= 3) {
dbg("SLAACV4: TEST SUCCESS!\n");
pico_slaacv4_unregisterip();
exit(0);
}
} else {
dbg("SLAACV4: ping %lu to %s error %d\n", s->seq, host, s->err);
dbg("SLAACV4: TEST FAILED!\n");
exit(1);
}
}
void slaacv4_cb(struct pico_ip4 *ip, uint8_t code)
{
char dst[16] = "169.254.22.5";
printf("SLAACV4 CALLBACK ip:0x%X code:%d \n", ip->addr, code);
if (code == 0)
{
#ifdef PICO_SUPPORT_PING
pico_icmp4_ping(dst, 3, 1000, 5000, 32, ping_callback_slaacv4);
#else
exit(0);
#endif
}
else
{
exit(255);
}
}
void app_slaacv4(char *arg)
{
char *sdev = NULL;
char *nxt = arg;
struct pico_device *dev = NULL;
if (!nxt)
exit(255);
while (nxt) {
if (nxt) {
nxt = cpy_arg(&sdev, nxt);
if(!sdev) {
exit(255);
}
}
}
dev = pico_get_device(sdev);
free(sdev);
if(dev == NULL) {
printf("%s: error getting device %s: %s\n", __FUNCTION__, dev->name, strerror(pico_err));
exit(255);
}
pico_slaacv4_claimip(dev, slaacv4_cb);
}
/*** END SLAACv4 ***/

View File

@ -0,0 +1,59 @@
#include "utils.h"
#include <pico_sntp_client.h>
/*** START SNTP ***/
#ifdef PICO_SUPPORT_SNTP_CLIENT
void sntp_timeout(pico_time __attribute__((unused)) now, void *arg)
{
struct pico_timeval ptv;
struct timeval tv;
pico_sntp_gettimeofday(&ptv);
gettimeofday(&tv, NULL);
printf("Linux sec: %u, msec: %u\n", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec / 1000);
printf("Picotcp sec: %u, msec: %u\n", (unsigned int)ptv.tv_sec, (unsigned int)ptv.tv_msec);
printf("SNTP test succesfull!\n");
exit(0);
}
void cb_synced(pico_err_t status)
{
if(status == PICO_ERR_ENETDOWN) {
printf("SNTP: Cannot resolve ntp server name\n");
exit(1);
} else if (status == PICO_ERR_ETIMEDOUT) {
printf("SNTP: Timed out, did not receive ntp packet from server\n");
exit(1);
} else if (status == PICO_ERR_EINVAL) {
printf("SNTP: Conversion error\n");
exit(1);
} else if (status == PICO_ERR_ENOTCONN) {
printf("SNTP: Socket error\n");
exit(1);
} else if (status == PICO_ERR_NOERR) {
if (!pico_timer_add(2000, sntp_timeout, NULL)) {
printf("SNTP: Failed to start timeout timer, exiting program \n");
exit(1);
}
} else {
printf("SNTP: Invalid status received in cb_synced\n");
exit(1);
}
}
void app_sntp(char *servername)
{
struct pico_timeval tv;
printf("Starting SNTP query towards %s\n", servername);
if(pico_sntp_gettimeofday(&tv) == 0)
printf("Wrongly succesfull gettimeofday\n");
else
printf("Unsuccesfull gettimeofday (not synced)\n");
if(pico_sntp_sync(servername, &cb_synced) == 0)
printf("Succesfull sync call!\n");
else
printf("Error in sync\n");
}
#endif
/*** END SNTP ***/

View File

@ -0,0 +1,320 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_socket.h>
/*** START TCP BENCH ***/
#define TCP_BENCH_TX 1
#define TCP_BENCH_RX 2
#define TCP_BENCH_TX_FOREVER 3
static char *buffer1;
static char *buffer0;
int tcpbench_mode = 0;
struct pico_socket *tcpbench_sock = NULL;
static pico_time tcpbench_time_start, tcpbench_time_end;
void cb_tcpbench(uint16_t ev, struct pico_socket *s)
{
static int closed = 0;
static unsigned long count = 0;
uint8_t recvbuf[1500];
uint16_t port;
char peer[200];
/* struct pico_socket *sock_a; */
static int tcpbench_wr_size = 0;
static int tcpbench_rd_size = 0;
int tcpbench_w = 0;
int tcpbench_r = 0;
double tcpbench_time = 0;
count++;
if (ev & PICO_SOCK_EV_RD) {
do {
/* read data, but discard */
tcpbench_r = pico_socket_read(s, recvbuf, 1500);
if (tcpbench_r > 0) {
tcpbench_rd_size += tcpbench_r;
}
} while (tcpbench_r > 0);
if (tcpbench_time_start == 0)
tcpbench_time_start = PICO_TIME_MS();
printf("tcpbench_rd_size = %d \r", tcpbench_rd_size);
}
if (ev & PICO_SOCK_EV_CONN) {
if (!IPV6_MODE) {
struct pico_ip4 orig;
if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) {
printf("tcpbench> Connection established with server.\n");
} else if (tcpbench_mode == TCP_BENCH_RX) {
/* sock_a = pico_socket_accept(s, &orig, &port); */
pico_socket_accept(s, &orig, &port);
pico_ipv4_to_string(peer, orig.addr);
printf("tcpbench> Connection established with %s:%d.\n", peer, short_be(port));
}
} else {
struct pico_ip6 orig;
if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) {
printf("tcpbench> Connection established with server.\n");
} else if (tcpbench_mode == TCP_BENCH_RX) {
/* sock_a = pico_socket_accept(s, &orig, &port); */
pico_socket_accept(s, &orig, &port);
#ifdef PICO_SUPPORT_IPV6
pico_ipv6_to_string(peer, orig.addr);
printf("tcpbench> Connection established with [%s]:%d.\n", peer, short_be(port));
#endif
}
}
}
if (ev & PICO_SOCK_EV_FIN) {
printf("tcpbench> Socket closed. Exit normally. \n");
if (tcpbench_mode == TCP_BENCH_RX) {
tcpbench_time_end = PICO_TIME_MS();
tcpbench_time = (tcpbench_time_end - tcpbench_time_start) / 1000.0; /* get number of seconds */
printf("tcpbench> received %d bytes in %lf seconds\n", tcpbench_rd_size, tcpbench_time);
printf("tcpbench> average read throughput %lf kbit/sec\n", ((tcpbench_rd_size * 8.0) / tcpbench_time) / 1000);
pico_socket_shutdown(s, PICO_SHUT_WR);
printf("tcpbench> Called shutdown write, ev = %d\n", ev);
}
if (!pico_timer_add(5000, deferred_exit, NULL)) {
printf("tcpbench> Failed to start exit timer, exiting now\n");
exit(1);
}
}
if (ev & PICO_SOCK_EV_ERR) {
printf("tcpbench> ---- Socket Error received: %s. Bailing out.\n", strerror(pico_err));
if (!pico_err == PICO_ERR_ECONNRESET) {
if (pico_timer_add(5000, deferred_exit, NULL)) {
printf("tcpbench> Failed to start exit timer, exiting now\n");
exit(1);
}
}
else {
printf("tcpbench> ---- Socket Error: '%s'. Was unexpected! Something went wrong.\n", strerror(pico_err));
exit(2);
}
}
if (ev & PICO_SOCK_EV_CLOSE) {
printf("tcpbench> event close\n");
if (tcpbench_mode == TCP_BENCH_RX) {
pico_socket_close(s);
printf("tcpbench> Called shutdown write, ev = %d\n", ev);
} else if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) {
pico_socket_close(s);
return;
}
}
if (ev & PICO_SOCK_EV_WR) {
if (((tcpbench_wr_size < TCPSIZ) && (tcpbench_mode == TCP_BENCH_TX)) || tcpbench_mode == TCP_BENCH_TX_FOREVER) {
do {
tcpbench_w = pico_socket_write(tcpbench_sock, buffer0 + (tcpbench_wr_size % TCPSIZ), TCPSIZ - (tcpbench_wr_size % TCPSIZ));
if (tcpbench_w > 0) {
tcpbench_wr_size += tcpbench_w;
/* printf("tcpbench> SOCKET WRITTEN - %d\n",tcpbench_w); */
} else {
/* printf("pico_socket_write returned %d\n", tcpbench_w); */
}
if (tcpbench_time_start == 0)
tcpbench_time_start = PICO_TIME_MS();
} while(tcpbench_w > 0);
printf("tcpbench_wr_size = %d \r", tcpbench_wr_size);
} else {
if (!closed && tcpbench_mode == TCP_BENCH_TX) {
tcpbench_time_end = PICO_TIME_MS();
pico_socket_shutdown(s, PICO_SHUT_WR);
printf("tcpbench> TCPSIZ written\n");
printf("tcpbench> Called shutdown()\n");
tcpbench_time = (tcpbench_time_end - tcpbench_time_start) / 1000.0; /* get number of seconds */
printf("tcpbench> Transmitted %u bytes in %lf seconds\n", TCPSIZ, tcpbench_time);
printf("tcpbench> average write throughput %lf kbit/sec\n", ((TCPSIZ * 8.0) / tcpbench_time) / 1000);
closed = 1;
}
}
}
}
void app_tcpbench(char *arg)
{
struct pico_socket *s;
char *dport = NULL;
char *dest = NULL;
char *mode = NULL;
char *nagle = NULL;
int port = 0, i;
uint16_t port_be = 0;
char *nxt;
char *sport = NULL;
int nagle_off = 1;
union {
struct pico_ip4 ip4;
struct pico_ip6 ip6;
} inaddr_any = {
.ip4 = {0}, .ip6 = {{0}}
};
nxt = cpy_arg(&mode, arg);
if ((*mode == 't') || (*mode == 'f')) { /* TEST BENCH SEND MODE */
if (*mode == 't')
tcpbench_mode = TCP_BENCH_TX;
else
tcpbench_mode = TCP_BENCH_TX_FOREVER;
printf("tcpbench> TX\n");
nxt = cpy_arg(&dest, nxt);
if (!dest) {
fprintf(stderr, "tcpbench send needs the following format: tcpbench:tx:dst_addr[:dport][:n] -- 'n' is for nagle\n");
exit(255);
}
printf ("+++ Dest is %s\n", dest);
if (nxt) {
printf("Next arg: %s\n", nxt);
nxt = cpy_arg(&dport, nxt);
printf("Dport: %s\n", dport);
}
if (nxt) {
printf("Next arg: %s\n", nxt);
nxt = cpy_arg(&nagle, nxt);
printf("nagle: %s\n", nagle);
if (strlen(nagle) == 1 && nagle[0] == 'n') {
nagle_off = 0;
printf("Nagle algorithm enabled\n");
}
}
if (dport) {
port = atoi(dport);
port_be = short_be((uint16_t)port);
}
if (port == 0) {
port_be = short_be(5555);
}
buffer0 = malloc(TCPSIZ);
buffer1 = malloc(TCPSIZ);
printf("Buffer1 (%p)\n", buffer1);
for (i = 0; i < TCPSIZ; i++) {
char c = (i % 26) + 'a';
buffer0[i] = c;
}
memset(buffer1, 'a', TCPSIZ);
printf("tcpbench> Connecting to: %s:%d\n", dest, short_be(port_be));
if (!IPV6_MODE) {
struct pico_ip4 server_addr;
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpbench);
if (!s)
exit(1);
pico_socket_setoption(s, PICO_TCP_NODELAY, &nagle_off);
/* NOTE: used to set a fixed local port and address
local_port = short_be(6666);
pico_string_to_ipv4("10.40.0.11", &local_addr.addr);
pico_socket_bind(s, &local_addr, &local_port);*/
pico_string_to_ipv4(dest, &server_addr.addr);
pico_socket_connect(s, &server_addr, port_be);
} else {
struct pico_ip6 server_addr;
s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpbench);
if (!s)
exit(1);
pico_socket_setoption(s, PICO_TCP_NODELAY, &nagle_off);
/* NOTE: used to set a fixed local port and address
local_port = short_be(6666);
pico_string_to_ipv4("10.40.0.11", &local_addr.addr);
pico_socket_bind(s, &local_addr, &local_port);*/
#ifdef PICO_SUPPORT_IPV6
pico_string_to_ipv6(dest, server_addr.addr);
pico_socket_connect(s, &server_addr, port_be);
#endif
}
} else if (*mode == 'r') { /* TEST BENCH RECEIVE MODE */
int ret;
tcpbench_mode = TCP_BENCH_RX;
printf("tcpbench> RX\n");
cpy_arg(&sport, nxt);
if (!sport) {
fprintf(stderr, "tcpbench receive needs the following format: tcpbench:rx[:dport]\n");
exit(255);
}
if (sport) {
printf("s-port is %s\n", sport);
port = atoi(sport);
port_be = short_be((uint16_t)port);
printf("tcpbench> Got port %d\n", port);
free(sport);
}
if (port == 0) {
port_be = short_be(5555);
}
printf("tcpbench> OPEN\n");
if (!IPV6_MODE)
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpbench);
else
s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpbench);
if (!s)
exit(1);
printf("tcpbench> BIND\n");
if (!IPV6_MODE)
ret = pico_socket_bind(s, &inaddr_any.ip4, &port_be);
else
ret = pico_socket_bind(s, &inaddr_any.ip6, &port_be);
if (ret < 0) {
printf("tcpbench> BIND failed because %s\n", strerror(pico_err));
exit(1);
}
printf("tcpbench> LISTEN\n");
if (pico_socket_listen(s, 40) != 0)
exit(1);
printf("tcpbench> listening port %u ...\n", short_be(port_be));
} else {
printf("tcpbench> wrong mode argument\n");
exit(1);
}
tcpbench_sock = s;
/* free strdups */
if (dport)
free(dport);
if (dest)
free (dest);
if (mode)
free (mode);
if (nagle)
free (nagle);
return;
}
/*** END TCP BENCH ***/

View File

@ -0,0 +1,197 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_socket.h>
/*** START TCP CLIENT ***/
static char *buffer1;
static char *buffer0;
void compare_results(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg)
{
#ifdef CONSISTENCY_CHECK /* TODO: Enable */
int i;
printf("Calculating result.... (%p)\n", buffer1);
if (memcmp(buffer0, buffer1, TCPSIZ) == 0)
exit(0);
for (i = 0; i < TCPSIZ; i++) {
if (buffer0[i] != buffer1[i]) {
fprintf(stderr, "Error at byte %d - %c!=%c\n", i, buffer0[i], buffer1[i]);
exit(115);
}
}
#endif
exit(0);
}
void cb_tcpclient(uint16_t ev, struct pico_socket *s)
{
static int w_size = 0;
static int r_size = 0;
static int closed = 0;
int r, w;
static unsigned long count = 0;
count++;
picoapp_dbg("tcpclient> wakeup %lu, event %u\n", count, ev);
if (ev & PICO_SOCK_EV_RD) {
do {
r = pico_socket_read(s, buffer1 + r_size, TCPSIZ - r_size);
if (r > 0) {
r_size += r;
picoapp_dbg("SOCKET READ - %d\n", r_size);
}
if (r < 0)
exit(5);
} while(r > 0);
}
if (ev & PICO_SOCK_EV_CONN) {
printf("Connection established with server.\n");
}
if (ev & PICO_SOCK_EV_FIN) {
printf("Socket closed. Exit normally. \n");
if (!pico_timer_add(2000, compare_results, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
}
if (ev & PICO_SOCK_EV_ERR) {
printf("Socket error received: %s. Bailing out.\n", strerror(pico_err));
exit(1);
}
if (ev & PICO_SOCK_EV_CLOSE) {
printf("Socket received close from peer - Wrong case if not all client data sent!\n");
pico_socket_close(s);
return;
}
if (ev & PICO_SOCK_EV_WR) {
if (w_size < TCPSIZ) {
do {
w = pico_socket_write(s, buffer0 + w_size, TCPSIZ - w_size);
if (w > 0) {
w_size += w;
picoapp_dbg("SOCKET WRITTEN - %d\n", w_size);
if (w < 0)
exit(5);
}
} while(w > 0);
} else {
#ifdef INFINITE_TCPTEST
w_size = 0;
return;
#endif
if (!closed) {
pico_socket_shutdown(s, PICO_SHUT_WR);
printf("Called shutdown()\n");
closed = 1;
}
}
}
}
void app_tcpclient(char *arg)
{
char *daddr = NULL, *dport = NULL;
char *nxt = arg;
uint16_t send_port = 0, listen_port = short_be(5555);
int i = 0, ret = 0, yes = 1;
struct pico_socket *s = NULL;
union pico_address dst = {
.ip4 = {0}, .ip6 = {{0}}
};
union pico_address inaddr_any = {
.ip4 = {0}, .ip6 = {{0}}
};
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&daddr, arg);
if (daddr) {
if (!IPV6_MODE)
pico_string_to_ipv4(daddr, &dst.ip4.addr);
#ifdef PICO_SUPPORT_IPV6
else
pico_string_to_ipv6(daddr, dst.ip6.addr);
#endif
} else {
goto out;
}
} else {
/* missing dest_addr */
goto out;
}
if (nxt) {
nxt = cpy_arg(&dport, nxt);
if (dport && atoi(dport)) {
send_port = short_be(atoi(dport));
} else {
goto out;
}
} else {
/* missing send_port */
goto out;
}
/* end of argument parsing */
buffer0 = malloc(TCPSIZ);
buffer1 = malloc(TCPSIZ);
printf("Buffer1 (%p)\n", buffer1);
for (i = 0; i < TCPSIZ; i++) {
char c = (i % 26) + 'a';
buffer0[i] = c;
}
memset(buffer1, 'a', TCPSIZ);
printf("Connecting to: %s:%d\n", daddr, short_be(send_port));
if (!IPV6_MODE)
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpclient);
else
s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpclient);
if (!s) {
printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err));
exit(1);
}
pico_socket_setoption(s, PICO_TCP_NODELAY, &yes);
if (!IPV6_MODE)
ret = pico_socket_bind(s, &inaddr_any.ip4, &listen_port);
else
ret = pico_socket_bind(s, &inaddr_any.ip6, &listen_port);
if (ret < 0) {
printf("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
exit(1);
}
if (!IPV6_MODE)
ret = pico_socket_connect(s, &dst.ip4, send_port);
else
ret = pico_socket_connect(s, &dst.ip6, send_port);
if (ret < 0) {
printf("%s: error connecting to %s:%u: %s\n", __FUNCTION__, daddr, short_be(send_port), strerror(pico_err));
exit(1);
}
return;
out:
fprintf(stderr, "tcpclient expects the following format: tcpclient:dest_addr:dest_port\n");
exit(255);
}
/*** END TCP CLIENT ***/

View File

@ -0,0 +1,178 @@
#include "utils.h"
#include <pico_socket.h>
#include <pico_ipv4.h>
/*** START TCP ECHO ***/
#define BSIZE (1024 * 10)
static char recvbuf[BSIZE];
static int pos = 0, len = 0;
static int flag = 0;
int send_tcpecho(struct pico_socket *s)
{
int w, ww = 0;
if (len > pos) {
do {
w = pico_socket_write(s, recvbuf + pos, len - pos);
if (w > 0) {
pos += w;
ww += w;
if (pos >= len) {
pos = 0;
len = 0;
}
}
} while((w > 0) && (pos < len));
}
return ww;
}
void cb_tcpecho(uint16_t ev, struct pico_socket *s)
{
int r = 0;
picoapp_dbg("tcpecho> wakeup ev=%u\n", ev);
if (ev & PICO_SOCK_EV_RD) {
if (flag & PICO_SOCK_EV_CLOSE)
printf("SOCKET> EV_RD, FIN RECEIVED\n");
while (len < BSIZE) {
r = pico_socket_read(s, recvbuf + len, BSIZE - len);
if (r > 0) {
len += r;
flag &= ~(PICO_SOCK_EV_RD);
} else {
flag |= PICO_SOCK_EV_RD;
break;
}
}
if (flag & PICO_SOCK_EV_WR) {
flag &= ~PICO_SOCK_EV_WR;
send_tcpecho(s);
}
}
if (ev & PICO_SOCK_EV_CONN) {
uint32_t ka_val = 0;
struct pico_socket *sock_a = {
0
};
struct pico_ip4 orig = {
0
};
uint16_t port = 0;
char peer[30] = {
0
};
int yes = 1;
sock_a = pico_socket_accept(s, &orig, &port);
pico_ipv4_to_string(peer, orig.addr);
printf("Connection established with %s:%d.\n", peer, short_be(port));
pico_socket_setoption(sock_a, PICO_TCP_NODELAY, &yes);
/* Set keepalive options */
ka_val = 5;
pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPCNT, &ka_val);
ka_val = 30000;
pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPIDLE, &ka_val);
ka_val = 5000;
pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPINTVL, &ka_val);
}
if (ev & PICO_SOCK_EV_FIN) {
printf("Socket closed. Exit normally. \n");
if (!pico_timer_add(2000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
}
if (ev & PICO_SOCK_EV_ERR) {
printf("Socket error received: %s. Bailing out.\n", strerror(pico_err));
exit(1);
}
if (ev & PICO_SOCK_EV_CLOSE) {
printf("Socket received close from peer.\n");
if (flag & PICO_SOCK_EV_RD) {
pico_socket_shutdown(s, PICO_SHUT_WR);
printf("SOCKET> Called shutdown write, ev = %d\n", ev);
}
}
if (ev & PICO_SOCK_EV_WR) {
r = send_tcpecho(s);
if (r == 0)
flag |= PICO_SOCK_EV_WR;
else
flag &= (~PICO_SOCK_EV_WR);
}
}
void app_tcpecho(char *arg)
{
char *nxt = arg;
char *lport = NULL;
uint16_t listen_port = 0;
int ret = 0, yes = 1;
struct pico_socket *s = NULL;
union {
struct pico_ip4 ip4;
struct pico_ip6 ip6;
} inaddr_any = {
.ip4 = {0}, .ip6 = {{0}}
};
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
listen_port = short_be(atoi(lport));
} else {
goto out;
}
} else {
/* missing listen_port */
goto out;
}
/* end of argument parsing */
if (!IPV6_MODE)
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpecho);
else
s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpecho);
if (!s) {
printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err));
exit(1);
}
pico_socket_setoption(s, PICO_TCP_NODELAY, &yes);
if (!IPV6_MODE)
ret = pico_socket_bind(s, &inaddr_any.ip4, &listen_port);
else
ret = pico_socket_bind(s, &inaddr_any.ip6, &listen_port);
if (ret < 0) {
printf("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
exit(1);
}
if (pico_socket_listen(s, 40) != 0) {
printf("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port));
exit(1);
}
printf("Launching PicoTCP echo server\n");
return;
out:
fprintf(stderr, "tcpecho expects the following format: tcpecho:listen_port\n");
exit(255);
}
/*** END TCP ECHO ***/

View File

@ -0,0 +1,485 @@
#include "utils.h"
#include <pico_stack.h>
#include <pico_tftp.h>
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
/* Let's use linux fs */
#include <fcntl.h>
#include <ctype.h>
/*** START TFTP ***/
#ifdef PICO_SUPPORT_TFTP
#define TFTP_MODE_SRV 0
#define TFTP_MODE_CLI 1
#define TFTP_MODE_PSH 2
#define TFTP_TX_COUNT 2000
#define TFTP_PAYLOAD_SIZE 512
unsigned char tftp_txbuf[TFTP_PAYLOAD_SIZE];
static uint16_t family;
struct command_t {
char operation;
char *filename;
union pico_address server_address;
struct command_t *next;
};
struct note_t {
char *filename;
int fd;
char direction;
int32_t filesize;
struct note_t *next;
};
struct note_t *clipboard = NULL;
struct note_t *add_note(const char *filename, int fd, char direction)
{
struct note_t *note = PICO_ZALLOC(sizeof(struct note_t));
note->filename = strdup(filename);
note->fd = fd;
note->direction = direction;
note->filesize = 0;
note->next = clipboard;
clipboard = note;
return note;
}
void del_note(struct note_t *note)
{
struct note_t *prev;
if (note == clipboard)
{
clipboard = clipboard->next;
if (note->filename)
free (note->filename);
PICO_FREE(note);
} else {
for (prev = clipboard; prev->next; prev = prev->next)
if (prev->next == note) {
prev->next = note->next;
if (note->filename)
free (note->filename);
PICO_FREE(note);
break;
}
}
}
struct command_t *add_command(struct command_t *commands, char operation,
char *filename, union pico_address *server_address)
{
struct command_t *command = PICO_ZALLOC(sizeof(struct command_t));
command->operation = operation;
command->filename = filename;
memcpy(&command->server_address, server_address, sizeof(union pico_address));
command->next = commands;
return command;
}
int32_t get_filesize(const char *filename)
{
int ret;
struct stat buf;
ret = stat(filename, &buf);
if (ret)
return -1;
return buf.st_size;
}
struct note_t *setup_transfer(char operation, const char *filename)
{
int fd;
printf("operation %c\n", operation);
fd = open(filename, (toupper(operation) == 'T') ? O_RDONLY : O_WRONLY | O_EXCL | O_CREAT, 0666);
if (fd < 0) {
perror("open");
fprintf(stderr, "Unable to handle file %s\n", filename);
return NULL;
}
return add_note(filename, fd, operation);
}
int cb_tftp_tx(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg)
{
struct note_t *note = (struct note_t *) arg;
if (event != PICO_TFTP_EV_OK) {
fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block);
exit(1);
}
len = read(note->fd, tftp_txbuf, PICO_TFTP_PAYLOAD_SIZE);
if (len >= 0) {
note->filesize += len;
pico_tftp_send(session, tftp_txbuf, len);
if (len < PICO_TFTP_PAYLOAD_SIZE) {
printf("TFTP: file %s (%" PRId32 " bytes) TX transfer complete!\n", note->filename, note->filesize);
close(note->fd);
del_note(note);
}
} else {
perror("read");
fprintf(stderr, "Filesystem error reading file %s, cancelling current transfer\n", note->filename);
pico_tftp_abort(session, TFTP_ERR_EACC, "Error on read");
del_note(note);
}
if (!clipboard) {
if (!pico_timer_add(3000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
}
return len;
}
int cb_tftp_tx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg)
{
int ret;
int32_t filesize;
if (event == PICO_TFTP_EV_OPT) {
ret = pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, &filesize);
if (ret)
printf("TFTP: Option filesize is not used\n");
else
printf("TFTP: We expect to transmit %" PRId32 " bytes\n", filesize);
event = PICO_TFTP_EV_OK;
}
return cb_tftp_tx(session, event, block, len, arg);
}
int cb_tftp_rx(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg)
{
struct note_t *note = (struct note_t *) arg;
int ret;
if (event != PICO_TFTP_EV_OK) {
fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block);
exit(1);
}
if (!note)
return 0;
note->filesize += len;
if (write(note->fd, block, len) < 0) {
perror("write");
fprintf(stderr, "Filesystem error writing file %s, cancelling current transfer\n", note->filename);
pico_tftp_abort(session, TFTP_ERR_EACC, "Error on write");
del_note(note);
} else {
if (len != PICO_TFTP_PAYLOAD_SIZE) {
printf("TFTP: file %s (%" PRId32 " bytes) RX transfer complete!\n", note->filename, note->filesize);
close(note->fd);
del_note(note);
}
}
if (!clipboard) {
if (!pico_timer_add(3000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
}
return len;
}
int cb_tftp_rx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg)
{
int ret;
int32_t filesize;
if (event == PICO_TFTP_EV_OPT) {
ret = pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, &filesize);
if (ret)
printf("TFTP: Option filesize is not used\n");
else
printf("TFTP: We expect to receive %" PRId32 " bytes\n", filesize);
return 0;
}
return cb_tftp_rx(session, event, block, len, arg);
}
struct pico_tftp_session *make_session_or_die(union pico_address *addr, uint16_t family)
{
struct pico_tftp_session *session;
session = pico_tftp_session_setup(addr, family);
if (!session) {
fprintf(stderr, "TFTP: Error in session setup\n");
exit(3);
}
return session;
}
struct note_t *transfer_prepare(struct pico_tftp_session **psession, char operation, const char *filename, union pico_address *addr, uint16_t family)
{
struct note_t *note;
note = setup_transfer(operation, filename);
*psession = make_session_or_die(addr, family);
return note;
}
void start_rx(struct pico_tftp_session *session, const char *filename, uint16_t port,
int (*rx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg),
struct note_t *note)
{
if (pico_tftp_start_rx(session, port, filename, rx_callback, note)) {
fprintf(stderr, "TFTP: Error in initialization\n");
exit(1);
}
}
void start_tx(struct pico_tftp_session *session, const char *filename, uint16_t port,
int (*tx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg),
struct note_t *note)
{
if (pico_tftp_start_tx(session, port, filename, tx_callback, note)) {
fprintf(stderr, "TFTP: Error in initialization\n");
exit(1);
}
}
void tftp_listen_cb(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len)
{
struct note_t *note;
struct pico_tftp_session *session;
printf("TFTP listen callback (BASIC) from remote port %" PRIu16 ".\n", short_be(port));
if (opcode == PICO_TFTP_RRQ) {
printf("Received TFTP get request for %s\n", filename);
note = transfer_prepare(&session, 't', filename, addr, family);
start_tx(session, filename, port, cb_tftp_tx, note);
} else if (opcode == PICO_TFTP_WRQ) {
printf("Received TFTP put request for %s\n", filename);
note = transfer_prepare(&session, 'r', filename, addr, family);
start_rx(session, filename, port, cb_tftp_rx, note);
}
}
void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len)
{
struct note_t *note;
struct pico_tftp_session *session;
int options;
uint8_t timeout;
int32_t filesize;
int ret;
printf("TFTP listen callback (OPTIONS) from remote port %" PRIu16 ".\n", short_be(port));
/* declare the options we want to support */
ret = pico_tftp_parse_request_args(filename, len, &options, &timeout, &filesize);
if (ret)
pico_tftp_reject_request(addr, port, TFTP_ERR_EOPT, "Malformed request");
if (opcode == PICO_TFTP_RRQ) {
printf("Received TFTP get request for %s\n", filename);
note = transfer_prepare(&session, 'T', filename, addr, family);
if (options & PICO_TFTP_OPTION_TIME)
pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout);
if (options & PICO_TFTP_OPTION_FILE) {
ret = get_filesize(filename);
if (ret < 0) {
pico_tftp_reject_request(addr, port, TFTP_ERR_ENOENT, "File not found");
return;
}
pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret);
}
start_tx(session, filename, port, cb_tftp_tx_opt, note);
} else { /* opcode == PICO_TFTP_WRQ */
printf("Received TFTP put request for %s\n", filename);
note = transfer_prepare(&session, 'R', filename, addr, family);
if (options & PICO_TFTP_OPTION_TIME)
pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout);
if (options & PICO_TFTP_OPTION_FILE)
pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize);
start_rx(session, filename, port, cb_tftp_rx_opt, note);
}
}
void print_usage(int exit_code)
{
printf("\nUsage: tftp:OPTION:[OPTION]...\n"
"\nOtions can be repeated. Every option may be one of the following:\n"
"\ts\t\t\t starts the basic server (RFC1350)\n"
"\tS\t\t\t starts the server with option handling capability\n"
"\tt:file:ip\t\t PUT request (without options) for file to server ip\n"
"\tT:file:ip\t\t PUT request for file to server ip\n"
"\tr:file:ip\t\t GET request (without options) for file to server ip\n"
"\tR:file:ip\t\t GET request for file to server ip\n"
"Example:\n"
"\t\t tftp:S:T:firstFile:10.40.0.2:R:another.file:10.40.0.5:T:secondFile:10.40.0.2\n\n");
exit(exit_code);
}
struct command_t *parse_arguments_recursive(struct command_t *commands, char *arg)
{
char *next;
char *operation;
char *filename;
char *address;
static union pico_address remote_address;
int ret;
struct command_t *new_cmd = NULL;
if (!arg)
return commands;
next = cpy_arg(&operation, arg);
switch (*operation) {
case 'S':
case 's':
filename = address = NULL;
break;
case 'T':
case 'R':
case 't':
case 'r':
if (!next) {
fprintf(stderr, "Incomplete client command %s (filename componet is missing)\n", arg);
return NULL;
}
next = cpy_arg(&filename, next);
if (!next) {
fprintf(stderr, "Incomplete client command %s (address component is missing)\n", arg);
return NULL;
}
next = cpy_arg(&address, next);
if (!IPV6_MODE)
ret = pico_string_to_ipv4(address, &remote_address.ip4.addr);
else
ret = pico_string_to_ipv6(address, remote_address.ip6.addr);
if (ret < 0) {
fprintf(stderr, "Invalid IP address %s\n", address);
print_usage(2);
}
if (address)
free(address);
break;
default:
fprintf(stderr, "Invalid command %s\n", operation);
return NULL;
};
new_cmd = add_command(commands, *operation, filename, &remote_address);
free(operation);
return parse_arguments_recursive(new_cmd, next);
}
struct command_t *parse_arguments(char *arg)
{
struct command_t *reversed = parse_arguments_recursive(NULL, arg);
struct command_t *commands = NULL;
struct command_t *current;
if (!reversed) {
fprintf(stderr, "Wrong command line!\n");
print_usage(1);
}
while (reversed) {
current = reversed;
reversed = reversed->next;
current->next = commands;
commands = current;
}
return commands;
}
void app_tftp(char *arg)
{
struct command_t *commands, *old_cmd;
struct note_t *note;
struct pico_tftp_session *session;
int is_server_enabled = 0;
int filesize;
family = IPV6_MODE ? PICO_PROTO_IPV6 : PICO_PROTO_IPV4;
commands = parse_arguments(arg);
while (commands) {
if (toupper(commands->operation) != 'S')
note = transfer_prepare(&session, commands->operation, commands->filename, &commands->server_address, family);
switch (commands->operation) {
case 'S':
case 's':
if (!is_server_enabled) {
pico_tftp_listen(PICO_PROTO_IPV4, (commands->operation == 'S') ? tftp_listen_cb_opt : tftp_listen_cb);
is_server_enabled = 1;
}
break;
case 'T':
filesize = get_filesize(commands->filename);
if (filesize < 0) {
fprintf(stderr, "TFTP: unable to read size of file %s\n", commands->filename);
exit(3);
}
pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize);
start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_tx_opt, note);
break;
case 't':
start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_tx, note);
break;
case 'R':
pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0);
start_rx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_rx_opt, note);
break;
case 'r':
start_rx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_rx, note);
}
old_cmd = commands;
commands = commands->next;
if (old_cmd->filename)
free(old_cmd->filename);
/* commands are allocated using PICO_ZALLOC, so use PICO_FREE */
PICO_FREE(old_cmd);
}
}
#endif
/* END TFTP */

View File

@ -0,0 +1,290 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_socket.h>
/*** START UDP CLIENT ***/
/*
* udpclient expects the following format: udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops]
* dest_addr: IP address to send datagrams to
* sendto_port: port number to send datagrams to
* listen_port [OPTIONAL]: port number on which the udpclient listens
* datasize [OPTIONAL]: size of the data given to the socket in one go
* loops [OPTIONAL]: number of intervals in which data is send
* subloops [OPTIONAL]: number of sends in one interval
*
* REMARK: once an optional parameter is given, all optional parameters need a value!
*
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a udpclient:10.40.0.3:6667:6667:1400:100:10
*/
struct udpclient_pas *udpclient_pas;
static int exit_retry = 0;
static void request_exit_echo(pico_time now, void *arg)
{
struct pico_socket *s = (struct pico_socket *)arg;
char end[4] = "end";
pico_socket_send(s, end, 4);
if (exit_retry++ > 3) {
if (!pico_timer_add(1000, deferred_exit, udpclient_pas)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
} else {
if (!pico_timer_add(1000, request_exit_echo, s)) {
printf("Failed to start request_exit_echo timer, sending request now\n");
request_exit_echo((pico_time)0, NULL);
exit(1);
}
printf("%s: requested exit of echo\n", __FUNCTION__);
}
}
void udpclient_send(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg)
{
struct pico_socket *s = udpclient_pas->s;
char *buf = NULL;
int i = 0, w = 0;
static uint16_t loop = 0;
if (++loop > udpclient_pas->loops) {
if (!pico_timer_add(1000, request_exit_echo, s)) {
printf("Failed to start request_exit_echo timer, sending request now\n");
request_exit_echo((pico_time)0, NULL);
exit(1);
}
return;
} else {
buf = calloc(1, udpclient_pas->datasize);
if (!buf) {
printf("%s: no memory available\n", __FUNCTION__);
return;
}
memset(buf, '1', udpclient_pas->datasize);
picoapp_dbg("%s: performing loop %u\n", __FUNCTION__, loop);
for (i = 0; i < udpclient_pas->subloops; i++) {
w = pico_socket_send(s, buf, udpclient_pas->datasize);
if (w <= 0)
break;
}
picoapp_dbg("%s: written %u byte(s) in each of %u subloops\n", __FUNCTION__, udpclient_pas->datasize, i);
free(buf);
}
if (!pico_timer_add(100, udpclient_send, NULL)) {
printf("Failed to start send timer, sending exit request to echo and exiting\n");
request_exit_echo((pico_time)0, NULL);
exit(1);
}
}
void cb_udpclient(uint16_t ev, struct pico_socket *s)
{
char *recvbuf = NULL;
int r = 0;
if (ev & PICO_SOCK_EV_RD) {
recvbuf = calloc(1, udpclient_pas->datasize);
if (!recvbuf) {
printf("%s: no memory available\n", __FUNCTION__);
return;
}
do {
r = pico_socket_recv(s, recvbuf, udpclient_pas->datasize);
} while ( r > 0);
free(recvbuf);
}
if (ev == PICO_SOCK_EV_ERR) {
printf("Socket Error received. Bailing out.\n");
free(udpclient_pas);
exit(7);
}
}
void app_udpclient(char *arg)
{
char *daddr = NULL, *lport = NULL, *sport = NULL, *s_datasize = NULL, *s_loops = NULL, *s_subloops = NULL;
char *nxt = arg;
char sinaddr_any[40] = {
0
};
uint16_t listen_port = 0;
int ret = 0;
udpclient_pas = calloc(1, sizeof(struct udpclient_pas));
if (!udpclient_pas) {
printf("%s: no memory available\n", __FUNCTION__);
exit(255);
}
udpclient_pas->s = NULL;
udpclient_pas->loops = 100;
udpclient_pas->subloops = 10;
udpclient_pas->datasize = 1400;
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&daddr, arg);
if (daddr) {
if (!IPV6_MODE)
pico_string_to_ipv4(daddr, &udpclient_pas->dst.ip4.addr);
#ifdef PICO_SUPPORT_IPV6
else
pico_string_to_ipv6(daddr, udpclient_pas->dst.ip6.addr);
#endif
} else {
goto out;
}
} else {
/* missing dest_addr */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
udpclient_pas->sport = short_be(atoi(sport));
} else {
goto out;
}
} else {
/* missing send_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
listen_port = short_be(atoi(lport));
} else {
goto out;
}
} else {
/* missing listen_port, use default */
listen_port = 0;
}
if (nxt) {
nxt = cpy_arg(&s_datasize, nxt);
if (s_datasize && atoi(s_datasize)) {
udpclient_pas->datasize = atoi(s_datasize);
} else {
goto out;
}
} else {
/* missing datasize, incomplete optional parameters? -> exit */
if (lport)
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_loops, nxt);
if (s_loops && atoi(s_loops)) {
udpclient_pas->loops = atoi(s_loops);
} else {
goto out;
}
} else {
/* missing loops, incomplete optional parameters? -> exit */
if (s_datasize)
goto out;
}
if (nxt) {
nxt = cpy_arg(&s_subloops, nxt);
if (s_subloops && atoi(s_subloops)) {
udpclient_pas->subloops = atoi(s_subloops);
} else {
goto out;
}
} else {
/* missing subloops, incomplete optional parameters? -> exit */
if (s_loops)
goto out;
}
/* end of argument parsing */
if (!IPV6_MODE)
pico_ipv4_to_string(sinaddr_any, inaddr_any.addr);
#ifdef PICO_SUPPORT_IPV6
else
pico_ipv6_to_string(sinaddr_any, inaddr6_any.addr);
#endif
if (!IPV6_MODE)
udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpclient);
else
udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &cb_udpclient);
if (!udpclient_pas->s) {
printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err));
free(udpclient_pas);
exit(1);
}
if (!IPV6_MODE)
ret = pico_socket_bind(udpclient_pas->s, &inaddr_any, &listen_port);
else
ret = pico_socket_bind(udpclient_pas->s, &inaddr6_any, &listen_port);
if (ret < 0) {
free(udpclient_pas);
printf("%s: error binding socket to %s:%u: %s\n", __FUNCTION__, sinaddr_any, short_be(listen_port), strerror(pico_err));
exit(1);
}
if (!IPV6_MODE)
ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip4, udpclient_pas->sport);
else
ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip6, udpclient_pas->sport);
if (ret < 0) {
printf("%s: error connecting to [%s]:%u: %s\n", __FUNCTION__, daddr, short_be(udpclient_pas->sport), strerror(pico_err));
free(udpclient_pas);
exit(1);
}
printf("\n%s: UDP client launched. Sending packets of %u bytes in %u loops and %u subloops to %s:%u\n\n",
__FUNCTION__, udpclient_pas->datasize, udpclient_pas->loops, udpclient_pas->subloops, daddr, short_be(udpclient_pas->sport));
if (!pico_timer_add(100, udpclient_send, NULL)) {
printf("Failed to start send timer, sending exit request to echo and exiting\n");
request_exit_echo((pico_time)0, NULL);
exit(1);
}
/* free strdups */
if (daddr)
free (daddr);
if (lport)
free (lport);
if (sport)
free (sport);
if (s_datasize)
free (s_datasize);
if (s_loops)
free (s_loops);
if (s_subloops)
free (s_subloops);
return;
out:
fprintf(stderr, "udpclient expects the following format: udpclient:dest_addr:dest_port[:listen_port:datasize:loops:subloops]\n");
free(udpclient_pas);
exit(255);
}
/*** END UDP CLIENT ***/

View File

@ -0,0 +1,216 @@
#include "utils.h"
#include <pico_ipv4.h>
#include <pico_ipv6.h>
#include <pico_socket.h>
/**** START UDP ECHO ****/
/*
* udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize]
* bind_addr: IP address to bind to
* listen_port: port number on which the udpecho listens
* sendto_port [OPTIONAL]: port number to echo datagrams to (echo to originating IP address)
* datasize [OPTIONAL]: max size of the data red from the socket in one go
*
* REMARK: once an optional parameter is given, all optional parameters need a value!
*
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.3:255.255.255.0: -a udpecho:10.40.0.3:6667:6667:1400
*/
static int udpecho_exit = 0;
struct udpecho_pas *udpecho_pas;
void cb_udpecho(uint16_t ev, struct pico_socket *s)
{
char *recvbuf = NULL;
uint16_t port = 0;
int r = 0;
union {
struct pico_ip4 ip4;
struct pico_ip6 ip6;
} peer;
if (udpecho_exit)
return;
if (ev == PICO_SOCK_EV_RD) {
recvbuf = calloc(1, udpecho_pas->datasize);
if (!recvbuf) {
printf("%s: no memory available\n", __FUNCTION__);
return;
}
do {
r = pico_socket_recvfrom(s, recvbuf, udpecho_pas->datasize, IPV6_MODE ? (void *)peer.ip6.addr : (void *)&peer.ip4.addr, &port);
/* printf("UDP recvfrom returned %d\n", r); */
if (r > 0) {
if (strncmp(recvbuf, "end", 3) == 0) {
printf("Client requested to exit... test successful.\n");
if (!pico_timer_add(1000, deferred_exit, udpecho_pas)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
udpecho_exit++;
}
pico_socket_sendto(s, recvbuf, r, IPV6_MODE ? (void *)peer.ip6.addr : (void *)&peer.ip4.addr, port);
}
} while (r > 0);
free(recvbuf);
}
if (ev == PICO_SOCK_EV_ERR) {
printf("Socket Error received. Bailing out.\n");
free(udpecho_pas);
exit(7);
}
picoapp_dbg("%s: received packet from %08X:%u\n", __FUNCTION__, long_be(peer), short_be(port));
}
void app_udpecho(char *arg)
{
char *baddr = NULL, *lport = NULL, *sport = NULL, *s_datasize = NULL;
char *nxt = arg;
uint16_t listen_port = 0;
struct pico_ip4 inaddr_bind = { };
struct pico_ip6 inaddr_bind6 = { };
int ret = 0;
udpecho_pas = calloc(1, sizeof(struct udpecho_pas));
if (!udpecho_pas) {
printf("%s: no memory available\n", __FUNCTION__);
exit(255);
}
udpecho_pas->s = NULL;
udpecho_pas->sendto_port = 0;
udpecho_pas->datasize = 5000;
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&baddr, nxt);
if (baddr) {
if (!IPV6_MODE)
pico_string_to_ipv4(baddr, &inaddr_bind.addr);
#ifdef PICO_SUPPORT_IPV6
else
pico_string_to_ipv6(baddr, inaddr_bind6.addr);
#endif
} else {
goto out;
}
} else {
/* missing bind_addr */
goto out;
}
if (nxt) {
nxt = cpy_arg(&lport, nxt);
if (lport && atoi(lport)) {
listen_port = short_be(atoi(lport));
} else {
listen_port = short_be(5555);
}
} else {
/* missing listen_port */
goto out;
}
if (nxt) {
nxt = cpy_arg(&sport, nxt);
if (sport && atoi(sport)) {
udpecho_pas->sendto_port = atoi(sport);
} else {
/* incorrect send_port */
goto out;
}
} else {
/* missing send_port, use default */
}
if (nxt) {
nxt = cpy_arg(&s_datasize, nxt);
if (s_datasize && atoi(s_datasize)) {
udpecho_pas->datasize = atoi(s_datasize);
} else {
/* incorrect datasize */
goto out;
}
} else {
/* missing datasize, incomplete optional parameters? -> exit */
if (sport)
goto out;
}
/* end of argument parsing */
if (!IPV6_MODE)
udpecho_pas->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpecho);
else
udpecho_pas->s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &cb_udpecho);
if (!udpecho_pas->s) {
printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err));
free(udpecho_pas);
exit(1);
}
if (!IPV6_MODE)
ret = pico_socket_bind(udpecho_pas->s, &inaddr_bind, &listen_port);
else {
ret = pico_socket_bind(udpecho_pas->s, &inaddr_bind6, &listen_port);
printf("udpecho> Bound to [%s]:%d.\n", baddr, short_be(listen_port));
}
if (ret != 0) {
free(udpecho_pas);
if (!IPV6_MODE)
printf("%s: error binding socket to %08X:%u: %s\n", __FUNCTION__, long_be(inaddr_bind.addr), short_be(listen_port), strerror(pico_err));
else
printf("%s: error binding socket to [%s]:%u: %s\n", __FUNCTION__, baddr, short_be(listen_port), strerror(pico_err));
exit(1);
}
#ifdef PICOAPP_IPFILTER
{
struct pico_ip4 address, in_addr_netmask, in_addr;
/* struct pico_ipv4_link *link; */
int ret = 0;
address.addr = 0x0800280a;
in_addr_netmask.addr = 0x00FFFFFF;
in_addr.addr = 0x0000320a;
/* link = pico_ipv4_link_get(&address); */
printf("udpecho> IPFILTER ENABLED\n");
/*Adjust your IPFILTER*/
ret |= pico_ipv4_filter_add(NULL, 17, NULL, NULL, &in_addr, &in_addr_netmask, 0, 5555, 0, 0, FILTER_DROP);
if (ret < 0)
printf("Filter_add invalid argument\n");
}
#endif
printf("\n%s: UDP echo launched. Receiving packets of %u bytes on port %u\n\n", __FUNCTION__, udpecho_pas->datasize, short_be(listen_port));
/* free strdups */
if (baddr)
free (baddr);
if (lport)
free (lport);
if (sport)
free (sport);
if (s_datasize)
free (s_datasize);
return;
out:
fprintf(stderr, "udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize]\n");
free(udpecho_pas);
exit(255);
}
/*** END UDP ECHO ***/

View File

@ -0,0 +1,88 @@
#include "utils.h"
#include <pico_ipv6.h>
#include <pico_socket.h>
/**** START UDP ECHO ****/
/*
* udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize]
* bind_addr: IP address to bind to
* listen_port: port number on which the udpecho listens
* sendto_port [OPTIONAL]: port number to echo datagrams to (echo to originating IP address)
* datasize [OPTIONAL]: max size of the data red from the socket in one go
*
* REMARK: once an optional parameter is given, all optional parameters need a value!
*
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.3:255.255.255.0: -a udpecho:10.40.0.3:6667:6667:1400
*/
void dummy_cb(uint16_t __attribute__((unused)) ev, struct pico_socket __attribute__((unused)) *s)
{
}
void app_sendto_test(char *arg)
{
char *nxt = arg;
char *dstaddr = NULL;
char *dstport = NULL;
struct pico_ip4 inaddr_dst = {};
struct pico_ip6 inaddr_dst6 = {};
uint16_t dport;
struct pico_socket *sock;
int ret;
/* start of argument parsing */
if (nxt) {
nxt = cpy_arg(&dstaddr, nxt);
if (dstaddr) {
if (!IPV6_MODE)
pico_string_to_ipv4(dstaddr, &inaddr_dst.addr);
#ifdef PICO_SUPPORT_IPV6
else
pico_string_to_ipv6(dstaddr, inaddr_dst6.addr);
#endif
} else {
goto out;
}
} else {
/* missing bind_addr */
goto out;
}
if (nxt) {
nxt = cpy_arg(&dstport, nxt);
if (dstport && atoi(dstport)) {
dport = short_be(atoi(dstport));
} else {
dport = short_be(5555);
}
} else {
/* missing listen_port */
goto out;
}
if (!IPV6_MODE)
sock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &dummy_cb);
else
sock = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &dummy_cb);
ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport);
if (ret < 0)
printf("Failure in first pico_socket_send\n");
ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport);
if (ret < 0)
printf("Failure in second pico_socket_send\n");
ret = pico_socket_close(sock);
if (ret)
printf("Failure in pico_socket_close\n");
printf("\n%s: UDP sendto test launched. Sending packets to ip %s port %u\n\n", __FUNCTION__, dstaddr, short_be(dport));
return;
out:
fprintf(stderr, "udp_sendto_test expects the following format: udp_sendto_test:dest_addr:[dest_por]t\n");
exit(255);
}

View File

@ -0,0 +1,151 @@
#include "utils.h"
#include <pico_ipv6.h>
#include <pico_socket.h>
/*** START UDP NAT CLIENT ***/
/* ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10: -a udpnatclient:10.50.0.8:6667: */
static struct pico_ip4 udpnatclient_inaddr_dst;
static uint16_t udpnatclient_port_be;
void udpnatclient_send(pico_time __attribute__((unused)) now, void *arg)
{
int i, w;
struct pico_socket *s = (struct pico_socket *)arg;
char buf[1400] = { };
char end[4] = "end";
static int loop = 0;
for ( i = 0; i < 3; i++) {
w = pico_socket_send(s, buf, 1400);
}
if (++loop > 1000) {
udpnatclient_port_be = 0;
for (i = 0; i < 3; i++) {
w = pico_socket_send(s, end, 4);
if (w <= 0)
break;
printf("End!\n");
}
if (!pico_timer_add(1000, deferred_exit, NULL)) {
printf("Failed to start exit timer, exiting now\n");
exit(1);
}
return;
}
}
void cb_udpnatclient(uint16_t ev, struct pico_socket *s)
{
char recvbuf[1400];
int r = 0;
if (ev & PICO_SOCK_EV_RD) {
do {
r = pico_socket_recv(s, recvbuf, 1400);
} while(r > 0);
}
if (ev == PICO_SOCK_EV_ERR) {
printf("Socket Error received. Bailing out.\n");
exit(7);
}
/* Not closing to test port check */
/* pico_socket_close(s); */
}
void udpnatclient_open_socket(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg)
{
struct pico_socket *s = NULL;
static int loop;
if (!udpnatclient_port_be)
return;
loop++;
picoapp_dbg(">>>>> Loop %d\n", loop);
if (!(loop % 100))
printf("Created %d sockets\n", loop);
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpnatclient);
if (!s)
exit(1);
if (pico_socket_connect(s, &udpnatclient_inaddr_dst, udpnatclient_port_be) != 0)
{
printf("Error connecting\n");
exit(1);
}
picoapp_dbg("New socket with port %u\n", s->local_port);
if (!pico_timer_add(25, udpnatclient_send, s)) {
printf("Failed to start send timer, exiting now\n");
exit(1);
}
if (!pico_timer_add(25, udpnatclient_open_socket, 0)) {
printf("Failed to start open_socket timer, exiting now\n");
exit(1);
}
}
void app_udpnatclient(char *arg)
{
struct pico_socket *s;
char *daddr, *dport;
int port = 0;
uint16_t port_be = 0;
struct pico_ip4 inaddr_dst = ZERO_IP4;
char *nxt;
nxt = cpy_arg(&daddr, arg);
if (!daddr) {
fprintf(stderr, " udpnatclient expects the following format: udpnatclient:dest_addr[:dest_port]\n");
exit(255);
}
if (nxt) {
nxt = cpy_arg(&dport, nxt);
if (dport) {
port = atoi(dport);
if (port > 0)
port_be = short_be(port);
}
}
if (port == 0) {
port_be = short_be(5555);
}
printf("UDP NAT client started. Sending packets to %s:%d\n", daddr, short_be(port_be));
s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpnatclient);
if (!s)
exit(1);
pico_string_to_ipv4(daddr, &inaddr_dst.addr);
if (pico_socket_connect(s, &inaddr_dst, port_be) != 0)
{
printf("Error binding the port \n");
exit(1);
}
picoapp_dbg("New socket with port %u\n", s->local_port);
udpnatclient_inaddr_dst = inaddr_dst;
udpnatclient_port_be = port_be;
if (!pico_timer_add(100, udpnatclient_send, s)) {
printf("Failed to start send timer, exiting now\n");
exit(1);
}
if (!pico_timer_add(1000, udpnatclient_open_socket, 0)) {
printf("Failed to start open_socket timer, exiting now\n");
exit(1);
}
}
/*** END UDP NAT CLIENT ***/

View File

@ -0,0 +1,39 @@
#ifndef PICO_EXAMPLES_UTILS_H
#define PICO_EXAMPLES_UTILS_H
#include <pico_stack.h>
#define TCPSIZ (1024 * 1024 * 5)
extern struct pico_ip4 ZERO_IP4;
extern struct pico_ip_mreq ZERO_MREQ;
extern struct pico_ip_mreq_source ZERO_MREQ_SRC;
extern struct pico_ip6 ZERO_IP6;
extern struct pico_ip_mreq ZERO_MREQ_IP6;
extern struct pico_ip_mreq_source ZERO_MREQ_SRC_IP6;
#define picoapp_dbg(...) do {} while(0)
/* #define picoapp_dbg printf */
extern int IPV6_MODE;
extern struct pico_ip4 inaddr_any;
extern struct pico_ip6 inaddr6_any;
extern char *cpy_arg(char **dst, char *str);
extern void deferred_exit(pico_time now, void *arg);
struct udpclient_pas {
struct pico_socket *s;
uint8_t loops;
uint8_t subloops;
uint16_t datasize;
uint16_t sport;
union pico_address dst;
}; /* per application struct */
struct udpecho_pas {
struct pico_socket *s;
uint16_t sendto_port; /* big-endian */
uint16_t datasize;
}; /* per application struct */
#endif