Files
my-os-project2/kernel/picotcp/test/picoapp.c
2025-10-29 14:29:06 +01:00

758 lines
22 KiB
C

/* PicoTCP Test application */
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/types.h>
#include <unistd.h>
#include "utils.h"
#include "pico_stack.h"
#include "pico_config.h"
#include "pico_dev_vde.h"
#include "pico_ipv4.h"
#include "pico_ipv6.h"
#include "pico_socket.h"
#include "pico_dev_tun.h"
#include "pico_dev_tap.h"
#include "pico_nat.h"
#include "pico_icmp4.h"
#include "pico_icmp6.h"
#include "pico_dns_client.h"
#include "pico_dev_loop.h"
#include "pico_dhcp_client.h"
#include "pico_dhcp_server.h"
#include "pico_ipfilter.h"
#include "pico_olsr.h"
#include "pico_sntp_client.h"
#include "pico_mdns.h"
#include "pico_tftp.h"
#include "pico_dev_radiotest.h"
#include "pico_dev_radio_mgr.h"
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#ifdef FAULTY
#include "pico_faulty.h"
#endif
void app_udpecho(char *args);
void app_tcpecho(char *args);
void app_udpclient(char *args);
void app_tcpclient(char *args);
void app_tcpbench(char *args);
void app_natbox(char *args);
void app_udpdnsclient(char *args);
void app_udpnatclient(char *args);
void app_mcastsend(char *args);
void app_mcastreceive_ipv6(char *args);
void app_mcastsend_ipv6(char *args);
void app_mcastreceive(char *args);
void app_ping(char *args);
void app_dhcp_server(char *args);
void app_dhcp_client(char *args);
void app_dns_sd(char *arg, struct pico_ip4 addr);
void app_mdns(char *arg, struct pico_ip4 addr);
void app_sntp(char *args);
void app_tftp(char *args);
void app_slaacv4(char *args);
void app_udpecho(char *args);
void app_sendto_test(char *args);
void app_noop(void);
struct pico_ip4 ZERO_IP4 = {
0
};
struct pico_ip_mreq ZERO_MREQ = {
.mcast_group_addr = {{0}},
.mcast_link_addr = {{0}}
};
struct pico_ip_mreq_source ZERO_MREQ_SRC = {
.mcast_group_addr.ip4 = {0},
.mcast_link_addr.ip4 = {0},
.mcast_source_addr.ip4 = {0}
};
struct pico_ip6 ZERO_IP6 = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
struct pico_ip_mreq ZERO_MREQ_IP6 = {
.mcast_group_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
.mcast_link_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
};
struct pico_ip_mreq_source ZERO_MREQ_SRC_IP6 = {
.mcast_group_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
.mcast_link_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
.mcast_source_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
};
/* #define INFINITE_TCPTEST */
#define picoapp_dbg(...) do {} while(0)
/* #define picoapp_dbg printf */
/* #define PICOAPP_IPFILTER 1 */
int IPV6_MODE;
struct pico_ip4 inaddr_any = {
0
};
struct pico_ip6 inaddr6_any = {{0}};
char *cpy_arg(char **dst, char *str);
void deferred_exit(pico_time __attribute__((unused)) now, void *arg)
{
if (arg) {
free(arg);
arg = NULL;
}
printf("%s: quitting\n", __FUNCTION__);
exit(0);
}
/** From now on, parsing the command line **/
#define NXT_MAC(x) ++ x[5]
/* Copy a string until the separator,
terminate it and return the next index,
or NULL if it encounters a EOS */
char *cpy_arg(char **dst, char *str)
{
char *p, *nxt = NULL;
char *start = str;
char *end = start + strlen(start);
char sep = ':';
if (IPV6_MODE)
sep = ',';
p = str;
while (p) {
if ((*p == sep) || (*p == '\0')) {
*p = (char)0;
nxt = p + 1;
if ((*nxt == 0) || (nxt >= end))
nxt = 0;
printf("dup'ing %s\n", start);
*dst = strdup(start);
break;
}
p++;
}
return nxt;
}
static void __wakeup(uint16_t __attribute__((unused)) ev, struct pico_socket __attribute__((unused)) *s)
{
}
static void usage(char *arg0)
{
printf("Usage: %s [--vde name:sock:address:netmask[:gateway]] [--vde ...] [--tun name:address:netmask[:gateway]] [--tun ...] [--app name[:args]]\n\n\n", arg0);
printf("\tall arguments can be repeated, e.g. to run on multiple links or applications\n");
printf("\t* --app arguments must be at the end *\n");
exit(255);
}
#define IF_APPNAME(x) if(strcmp(x, name) == 0)
int main(int argc, char **argv)
{
unsigned char macaddr[6] = {
0, 0, 0, 0xa, 0xb, 0x0
};
uint16_t *macaddr_low = (uint16_t *) (macaddr + 2);
struct pico_device *dev = NULL;
struct pico_ip4 addr4 = {
0
};
struct pico_ip4 bcastAddr = ZERO_IP4;
struct option long_options[] = {
{"help", 0, 0, 'h'},
{"vde", 1, 0, 'v'},
{"barevde", 1, 0, 'b'},
{"tun", 1, 0, 't'},
{"tap", 1, 0, 'T'},
{"route", 1, 0, 'r'},
{"app", 1, 0, 'a'},
{"dns", 1, 0, 'd'},
{"loop", 0, 0, 'l'},
{0, 0, 0, 0}
};
int option_idx = 0;
int c;
char *app = NULL, *p = argv[0];
/* parse till we find the name of the executable */
while (p) {
if (*p == '/')
app = p + 1;
else if (*p == '\0')
break;
else
{} /* do nothing */
p++;
}
if (strcmp(app, "picoapp6.elf") == 0)
IPV6_MODE = 1;
*macaddr_low = (uint16_t)(*macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU));
printf("My macaddr base is: %02x %02x\n", macaddr[2], macaddr[3]);
printf("My macaddr is: %02x %02x %02x %02x %02x %02x\n", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
#ifdef PICO_SUPPORT_MM
pico_mem_init(128 * 1024);
#endif
pico_stack_init();
/* Parse args */
while(1) {
c = getopt_long(argc, argv, "6:v:b:t:T:a:r:hl", long_options, &option_idx);
if (c < 0)
break;
switch(c) {
case 'h':
usage(argv[0]);
break;
case 'T':
{
char *nxt, *name = NULL, *addr = NULL, *nm = NULL, *gw = NULL;
struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4;
do {
nxt = cpy_arg(&name, optarg);
if (!nxt) break;
nxt = cpy_arg(&addr, nxt);
if (!nxt) break;
nxt = cpy_arg(&nm, nxt);
if (!nxt) break;
cpy_arg(&gw, nxt);
} while(0);
if (!nm) {
fprintf(stderr, "Tun: bad configuration...\n");
exit(1);
}
dev = pico_tap_create(name);
if (!dev) {
perror("Creating tap");
exit(1);
}
pico_string_to_ipv4(addr, &ipaddr.addr);
pico_string_to_ipv4(nm, &netmask.addr);
pico_ipv4_link_add(dev, ipaddr, netmask);
bcastAddr.addr = (ipaddr.addr) | (~netmask.addr);
if (gw && *gw) {
pico_string_to_ipv4(gw, &gateway.addr);
printf("Adding default route via %08x\n", gateway.addr);
pico_ipv4_route_add(zero, zero, gateway, 1, NULL);
}
#ifdef PICO_SUPPORT_IPV6
if (IPV6_MODE) {
struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}};
pico_string_to_ipv6(addr, ipaddr6.addr);
pico_string_to_ipv6(nm, netmask6.addr);
pico_ipv6_link_add(dev, ipaddr6, netmask6);
if (gw && *gw) {
pico_string_to_ipv6(gw, gateway6.addr);
pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL);
}
pico_ipv6_dev_routing_enable(dev);
}
#endif
}
break;
case 't':
{
char *nxt, *name = NULL, *addr = NULL, *nm = NULL, *gw = NULL;
struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4;
do {
nxt = cpy_arg(&name, optarg);
if (!nxt) break;
nxt = cpy_arg(&addr, nxt);
if (!nxt) break;
nxt = cpy_arg(&nm, nxt);
if (!nxt) break;
cpy_arg(&gw, nxt);
} while(0);
if (!nm) {
fprintf(stderr, "Tun: bad configuration...\n");
exit(1);
}
dev = pico_tun_create(name);
if (!dev) {
perror("Creating tun");
exit(1);
}
pico_string_to_ipv4(addr, &ipaddr.addr);
pico_string_to_ipv4(nm, &netmask.addr);
pico_ipv4_link_add(dev, ipaddr, netmask);
bcastAddr.addr = (ipaddr.addr) | (~netmask.addr);
if (gw && *gw) {
pico_string_to_ipv4(gw, &gateway.addr);
printf("Adding default route via %08x\n", gateway.addr);
pico_ipv4_route_add(zero, zero, gateway, 1, NULL);
}
#ifdef PICO_SUPPORT_IPV6
if (IPV6_MODE) {
struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}};
pico_string_to_ipv6(addr, ipaddr6.addr);
pico_string_to_ipv6(nm, netmask6.addr);
pico_ipv6_link_add(dev, ipaddr6, netmask6);
if (gw && *gw) {
pico_string_to_ipv6(gw, gateway6.addr);
pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL);
}
pico_ipv6_dev_routing_enable(dev);
}
#endif
}
break;
case 'v':
{
char *nxt, *name = NULL, *sock = NULL, *addr = NULL, *nm = NULL, *gw = NULL, *addr6 = NULL, *nm6 = NULL, *gw6 = NULL, *loss_in = NULL, *loss_out = NULL;
struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4;
uint32_t i_pc = 0, o_pc = 0;
printf("+++ OPTARG %s\n", optarg);
do {
nxt = cpy_arg(&name, optarg);
if (!nxt) break;
nxt = cpy_arg(&sock, nxt);
if (!nxt) break;
if (!IPV6_MODE) {
nxt = cpy_arg(&addr, nxt);
if (!nxt) break;
nxt = cpy_arg(&nm, nxt);
if (!nxt) break;
nxt = cpy_arg(&gw, nxt);
if (!nxt) break;
nxt = cpy_arg(&loss_in, nxt);
if (!nxt) break;
nxt = cpy_arg(&loss_out, nxt);
if (!nxt) break;
} else {
nxt = cpy_arg(&addr6, nxt);
if (!nxt) break;
printf("addr6: %s\n", addr6);
nxt = cpy_arg(&nm6, nxt);
if (!nxt) break;
nxt = cpy_arg(&gw6, nxt);
if (!nxt) break;
nxt = cpy_arg(&loss_in, nxt);
if (!nxt) break;
nxt = cpy_arg(&loss_out, nxt);
if (!nxt) break;
}
} while(0);
if (!nm && !nm6) {
fprintf(stderr, "Vde: bad configuration...\n");
exit(1);
}
macaddr[4] ^= (uint8_t)(getpid() >> 8);
macaddr[5] ^= (uint8_t) (getpid() & 0xFF);
dev = pico_vde_create(sock, name, macaddr);
NXT_MAC(macaddr);
if (!dev) {
perror("Creating vde");
exit(1);
}
printf("Vde created.\n");
if (!IPV6_MODE) {
pico_string_to_ipv4(addr, &ipaddr.addr);
pico_string_to_ipv4(nm, &netmask.addr);
pico_ipv4_link_add(dev, ipaddr, netmask);
addr4 = ipaddr;
bcastAddr.addr = (ipaddr.addr) | (~netmask.addr);
if (gw && *gw) {
pico_string_to_ipv4(gw, &gateway.addr);
pico_ipv4_route_add(zero, zero, gateway, 1, NULL);
}
}
#ifdef PICO_SUPPORT_IPV6
if (IPV6_MODE) {
struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}};
printf("SETTING UP IPV6 ADDRESS\n");
pico_string_to_ipv6(addr6, ipaddr6.addr);
pico_string_to_ipv6(nm6, netmask6.addr);
pico_ipv6_link_add(dev, ipaddr6, netmask6);
if (gw6 && *gw6) {
pico_string_to_ipv6(gw6, gateway6.addr);
pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL);
}
pico_ipv6_dev_routing_enable(dev);
}
#endif
if (loss_in && (strlen(loss_in) > 0)) {
i_pc = (uint32_t)atoi(loss_in);
}
if (loss_out && (strlen(loss_out) > 0)) {
o_pc = (uint32_t)atoi(loss_out);
}
if (i_pc || o_pc) {
printf(" ---------- >Setting vde packet loss %u:%u\n", i_pc, o_pc);
pico_vde_set_packetloss(dev, i_pc, o_pc);
}
}
break;
case '6':
{
char *nxt, *name = NULL, *area0 = NULL, *area1 = NULL, *dump = NULL;
const char pan_addr[] = "2aaa:abcd::0";
uint8_t n_id, n_area0, n_area1;
struct pico_ip6 pan;
/* Copy required command line arguments */
nxt = cpy_arg(&name, optarg);
if (!nxt)
goto check;
nxt = cpy_arg(&area0, nxt);
if (!nxt)
goto check;
nxt = cpy_arg(&area1, nxt);
if (!nxt)
goto check;
/* Check required arguments */
check: if (!name || !area0 || !area1) {
fprintf(stderr, "Usage: -6,id,area\n");
exit(1);
}
n_id = (uint8_t) atoi(name);
n_area0 = (uint8_t) atoi(area0);
n_area1 = (uint8_t) atoi(area1);
if (nxt) {
nxt = cpy_arg(&dump, nxt);
}
printf("%d:%d:%d\n", n_id, n_area0, n_area1);
if (!n_id) {
printf("Starting radio-network...\n");
pico_radio_mgr_start();
} else {
dev = pico_radiotest_create(n_id, n_area0, n_area1, 0, dump);
if (!dev) {
exit(1);
}
printf("Radiotest created.\n");
/* Add a routable link */
pico_string_to_ipv6(pan_addr, pan.addr);
pico_ipv6_link_add_local(dev, &pan);
/* Enable routing on first device */
if (n_id == 1) {
pico_ipv6_dev_routing_enable(dev);
}
}
break;
}
case 'b':
{
char *nxt, *name = NULL, *sock = NULL;
printf("+++ OPTARG %s\n", optarg);
do {
nxt = cpy_arg(&name, optarg);
if (!nxt) break;
nxt = cpy_arg(&sock, nxt);
} while(0);
if (!sock) {
fprintf(stderr, "Vde: bad configuration...\n");
exit(1);
}
macaddr[4] ^= (uint8_t)(getpid() >> 8);
macaddr[5] ^= (uint8_t)(getpid() & 0xFF);
dev = pico_vde_create(sock, name, macaddr);
NXT_MAC(macaddr);
if (!dev) {
if (sock)
free(sock);
if (name)
free(name);
perror("Creating vde");
exit(1);
}
if (sock)
free(sock);
if (name)
free(name);
printf("Vde created.\n");
}
break;
case 'l':
{
struct pico_ip4 ipaddr, netmask;
dev = pico_loop_create();
if (!dev) {
perror("Creating loop");
exit(1);
}
pico_string_to_ipv4("127.0.0.1", &ipaddr.addr);
pico_string_to_ipv4("255.0.0.0", &netmask.addr);
pico_ipv4_link_add(dev, ipaddr, netmask);
printf("Loopback created\n");
#ifdef PICO_SUPPORT_IPV6
if (IPV6_MODE) {
struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}};
pico_string_to_ipv6("::1", ipaddr6.addr);
pico_string_to_ipv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", netmask6.addr);
pico_ipv6_link_add(dev, ipaddr6, netmask6);
}
pico_ipv6_dev_routing_enable(dev);
#endif
}
break;
case 'r':
{
char *nxt, *addr, *nm, *gw;
struct pico_ip4 ipaddr, netmask, gateway;
/* XXX adjust for IPv6 */
addr = NULL, nm = NULL, gw = NULL;
printf("+++ ROUTEOPTARG %s\n", optarg);
do {
nxt = cpy_arg(&addr, optarg);
if (!nxt) break;
nxt = cpy_arg(&nm, nxt);
if (!nxt) break;
nxt = cpy_arg(&gw, nxt);
} while(0);
if (!addr || !nm || !gw) {
fprintf(stderr, "--route expects addr:nm:gw:\n");
usage(argv[0]);
}
pico_string_to_ipv4(addr, &ipaddr.addr);
pico_string_to_ipv4(nm, &netmask.addr);
pico_string_to_ipv4(gw, &gateway.addr);
if (pico_ipv4_route_add(ipaddr, netmask, gateway, 1, NULL) == 0)
fprintf(stderr, "ROUTE ADDED *** to %s via %s\n", addr, gw);
else
fprintf(stderr, "ROUTE ADD: ERROR %s \n", strerror(pico_err));
break;
}
case 'd':
{
/* Add a DNS nameserver IP address */
char *straddr;
struct pico_ip4 ipaddr;
printf("DNS nameserver address = %s\n", optarg);
cpy_arg(&straddr, optarg);
pico_string_to_ipv4(straddr, &ipaddr.addr);
pico_dns_client_nameserver(&ipaddr, PICO_DNS_NS_ADD);
break;
}
case 'a':
{
char *name = NULL, *args = NULL;
printf("+++ OPTARG %s\n", optarg);
args = cpy_arg(&name, optarg);
printf("+++ NAME: %s ARGS: %s\n", name, args);
IF_APPNAME("udpecho") {
app_udpecho(args);
} else IF_APPNAME("tcpecho") {
app_tcpecho(args);
} else IF_APPNAME("udpclient") {
app_udpclient(args);
} else IF_APPNAME("tcpclient") {
app_tcpclient(args);
} else IF_APPNAME("tcpbench") {
app_tcpbench(args);
} else IF_APPNAME("natbox") {
app_natbox(args);
} else IF_APPNAME("udpdnsclient") {
app_udpdnsclient(args);
} else IF_APPNAME("udpnatclient") {
app_udpnatclient(args);
} else IF_APPNAME("mcastsend") {
#ifndef PICO_SUPPORT_MCAST
return 0;
#endif
app_mcastsend(args);
} else IF_APPNAME("mcastreceive") {
#ifndef PICO_SUPPORT_MCAST
return 0;
#endif
app_mcastreceive(args);
}
else IF_APPNAME("mcastsend_ipv6") {
#ifndef PICO_SUPPORT_MCAST
return 0;
#endif
app_mcastsend_ipv6(args);
} else IF_APPNAME("mcastreceive_ipv6") {
#ifndef PICO_SUPPORT_MCAST
return 0;
#endif
app_mcastreceive_ipv6(args);
}
#ifdef PICO_SUPPORT_PING
else IF_APPNAME("ping") {
app_ping(args);
}
#endif
else IF_APPNAME("dhcpserver") {
#ifndef PICO_SUPPORT_DHCPD
return 0;
#else
app_dhcp_server(args);
#endif
} else IF_APPNAME("dhcpclient") {
#ifndef PICO_SUPPORT_DHCPC
return 0;
#else
app_dhcp_client(args);
#endif
} else IF_APPNAME("dns_sd") {
#ifndef PICO_SUPPORT_DNS_SD
return 0;
#else
app_dns_sd(args, addr4);
#endif
} else IF_APPNAME("mdns") {
#ifndef PICO_SUPPORT_MDNS
return 0;
#else
app_mdns(args, addr4);
#endif
#ifdef PICO_SUPPORT_SNTP_CLIENT
} else IF_APPNAME("sntp") {
app_sntp(args);
#endif
} else IF_APPNAME("bcast") {
struct pico_ip4 any = {
.addr = 0xFFFFFFFFu
};
struct pico_socket *s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &__wakeup);
pico_socket_sendto(s, "abcd", 5u, &any, 1000);
pico_socket_sendto(s, "abcd", 5u, &bcastAddr, 1000);
#ifdef PICO_SUPPORT_TFTP
} else IF_APPNAME("tftp") {
app_tftp(args);
#endif
} else IF_APPNAME("noop") {
app_noop();
#ifdef PICO_SUPPORT_OLSR
} else IF_APPNAME("olsr") {
dev = pico_get_device("pic0");
if(dev) {
pico_olsr_add(dev);
}
dev = pico_get_device("pic1");
if(dev) {
pico_olsr_add(dev);
}
app_noop();
#endif
} else IF_APPNAME("slaacv4") {
#ifndef PICO_SUPPORT_SLAACV4
return 0;
#else
app_slaacv4(args);
#endif
} else IF_APPNAME("udp_sendto_test") {
app_sendto_test(args);
} else {
fprintf(stderr, "Unknown application %s\n", name);
usage(argv[0]);
}
}
break;
}
}
if (!dev) {
printf("nodev");
usage(argv[0]);
}
#ifdef FAULTY
atexit(memory_stats);
#endif
printf("%s: launching PicoTCP loop\n", __FUNCTION__);
while(1) {
pico_stack_tick();
usleep(2000);
}
}