blob: 7d7d5645465018fecffd7c626f7b7f59e2658404 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define SYS_LOG_DOMAIN "net/zperf"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <zephyr.h>
#include <misc/printk.h>
#include <shell/shell.h>
#include <net/net_ip.h>
#include <net/net_core.h>
#include "zperf.h"
#include "zperf_internal.h"
#include "shell_utils.h"
#include "zperf_session.h"
/* Get some useful debug routings from net_private.h, requires
* that NET_LOG_ENABLED is set.
*/
#define NET_LOG_ENABLED 1
#include "net_private.h"
#include "ipv6.h" /* to get infinite lifetime */
#if defined(CONFIG_NET_L2_BLUETOOTH)
#include <bluetooth/bluetooth.h>
#include <gatt/ipss.h>
#endif
#if defined(CONFIG_NET_L2_IEEE802154)
#include <ieee802154_settings.h>
#endif
#define DEVICE_NAME "zperf shell"
static const char *CONFIG =
"unified"
#if defined(CONFIG_WLAN)
" wlan"
#endif
#if defined(CONFIG_ETHERNET)
" ethernet"
#endif
#if defined(CONFIG_NET_IPV4)
" ipv4"
#endif
#if defined(CONFIG_NET_IPV6)
" ipv6"
#endif
"";
#if defined(PROFILER)
#include "profiler.h"
#endif
#define MY_SRC_PORT 50000
#define DEF_PORT 5001
#define WAIT_CONNECT (2 * 1000) /* in ms */
#if defined(CONFIG_NET_IPV6)
static struct in6_addr ipv6;
#endif
static struct sockaddr_in6 in6_addr_my = {
.sin6_family = AF_INET6,
.sin6_port = htons(MY_SRC_PORT),
};
static struct sockaddr_in6 in6_addr_dst = {
.sin6_family = AF_INET6,
.sin6_port = htons(DEF_PORT),
};
struct sockaddr_in6 *zperf_get_sin6(void)
{
return &in6_addr_my;
}
#if defined(CONFIG_NET_IPV4)
static struct in_addr ipv4;
#endif
static struct sockaddr_in in4_addr_my = {
.sin_family = AF_INET,
.sin_port = htons(MY_SRC_PORT),
};
static struct sockaddr_in in4_addr_dst = {
.sin_family = AF_INET,
.sin_port = htons(DEF_PORT),
};
struct sockaddr_in *zperf_get_sin(void)
{
return &in4_addr_my;
}
#if defined(CONFIG_NET_IPV6)
static int parse_ipv6_addr(char *host, char *port,
struct sockaddr_in6 *addr,
const char *str)
{
int ret;
if (!host) {
return -EINVAL;
}
ret = net_addr_pton(AF_INET6, host, &addr->sin6_addr);
if (ret < 0) {
printk("[%s] Error! Invalid IPv6 address %s\n", str, host);
return -EINVAL;
}
addr->sin6_port = htons(strtoul(port, NULL, 10));
if (!addr->sin6_port) {
printk("[%s] Error! Invalid port %s\n", str, port);
return -EINVAL;
}
return 0;
}
int zperf_get_ipv6_addr(char *host, char *prefix_str, struct in6_addr *addr,
const char *str)
{
struct net_if_ipv6_prefix *prefix;
struct net_if_addr *ifaddr;
int prefix_len;
int ret;
if (!host) {
return -EINVAL;
}
ret = net_addr_pton(AF_INET6, host, addr);
if (ret < 0) {
return -EINVAL;
}
prefix_len = strtoul(prefix_str, NULL, 10);
ifaddr = net_if_ipv6_addr_add(net_if_get_default(),
addr, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
printk("[%s] Error! Cannot set IPv6 address\n", str);
return -EINVAL;
}
prefix = net_if_ipv6_prefix_add(net_if_get_default(),
addr, prefix_len,
NET_IPV6_ND_INFINITE_LIFETIME);
if (!prefix) {
printk("[%s] Error! Cannot set IPv6 prefix\n", str);
return -EINVAL;
}
return 0;
}
#endif
#if defined(CONFIG_NET_IPV4)
static int parse_ipv4_addr(char *host, char *port,
struct sockaddr_in *addr,
const char *str)
{
int ret;
if (!host) {
return -EINVAL;
}
ret = net_addr_pton(AF_INET, host, &addr->sin_addr);
if (ret < 0) {
printk("[%s] Error! Invalid IPv4 address %s\n", str, host);
return -EINVAL;
}
addr->sin_port = htons(strtoul(port, NULL, 10));
if (!addr->sin_port) {
printk("[%s] Error! Invalid port %s\n", str, port);
return -EINVAL;
}
return 0;
}
int zperf_get_ipv4_addr(char *host, struct in_addr *addr, const char *str)
{
struct net_if_addr *ifaddr;
int ret;
if (!host) {
return -EINVAL;
}
ret = net_addr_pton(AF_INET, host, addr);
if (ret < 0) {
return -EINVAL;
}
ifaddr = net_if_ipv4_addr_add(net_if_get_default(),
addr, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
printk("[%s] Error! Cannot set IPv4 address\n", str);
return -EINVAL;
}
return 0;
}
#endif
static int shell_cmd_setip(int argc, char *argv[])
{
int start = 0;
if (!strcmp(argv[0], "zperf")) {
start++;
argc--;
}
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
if (argc != 3) {
/* Print usage */
printk("\n%s:\n", CMD_STR_SETIP);
printk("Usage:\t%s <my ip> <prefix len>\n", CMD_STR_SETIP);
printk("\nExample %s 2001:db8::2 64\n", CMD_STR_SETIP);
return -1;
}
if (zperf_get_ipv6_addr(argv[start + 1], argv[start + 2], &ipv6,
CMD_STR_SETIP) < 0) {
printk("[%s] ERROR! Unable to set IP\n", CMD_STR_SETIP);
return 0;
}
printk("[%s] Setting IP address %s\n", CMD_STR_SETIP,
net_sprint_ipv6_addr(&ipv6));
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
if (argc != 2) {
/* Print usage */
printk("\n%s:\n", CMD_STR_SETIP);
printk("Usage:\t%s <my ip>\n", CMD_STR_SETIP);
printk("\nExample %s 10.237.164.178\n", CMD_STR_SETIP);
return -1;
}
if (zperf_get_ipv4_addr(argv[start + 1], &ipv4, CMD_STR_SETIP) < 0) {
printk("[%s] ERROR! Unable to set IP\n", CMD_STR_SETIP);
return 0;
}
printk("[%s] Setting IP address %s\n", CMD_STR_SETIP,
net_sprint_ipv4_addr(&ipv4));
#endif
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
if (net_addr_pton(AF_INET6, argv[start + 1],
&ipv6) < 0) {
if (argc != 2) {
/* Print usage */
printk("\n%s:\n", CMD_STR_SETIP);
printk("Usage:\t%s <my ip>\n", CMD_STR_SETIP);
printk("\nExample %s 10.237.164.178\n", CMD_STR_SETIP);
printk("Example %s 2001:db8::1 64\n", CMD_STR_SETIP);
return -1;
}
if (zperf_get_ipv4_addr(argv[start + 1], &ipv4,
CMD_STR_SETIP) < 0) {
printk("[%s] ERROR! Unable to set IP\n", CMD_STR_SETIP);
return 0;
}
printk("[%s] Setting IP address %s\n", CMD_STR_SETIP,
net_sprint_ipv4_addr(&ipv4));
} else {
if (argc != 3) {
/* Print usage */
printk("\n%s:\n", CMD_STR_SETIP);
printk("Usage:\t%s <my ip> <prefix len>\n",
CMD_STR_SETIP);
printk("\nExample %s 2001:db8::2 64\n", CMD_STR_SETIP);
printk("Example %s 10.237.164.178\n", CMD_STR_SETIP);
return -1;
}
if (zperf_get_ipv6_addr(argv[start + 1], argv[start + 2], &ipv6,
CMD_STR_SETIP) < 0) {
printk("[%s] ERROR! Unable to set IP\n", CMD_STR_SETIP);
return 0;
}
printk("[%s] Setting IP address %s\n", CMD_STR_SETIP,
net_sprint_ipv6_addr(&ipv6));
}
#endif
return 0;
}
#if defined(CONFIG_NET_UDP)
static int shell_cmd_udp_download(int argc, char *argv[])
{
static bool udp_stopped = true;
int port, start = 0;
if (!strcmp(argv[0], "zperf")) {
start++;
argc--;
}
if (argc == 1) {
/* Print usage */
printk("\n%s:\n", CMD_STR_UDP_DOWNLOAD);
printk("Usage:\t%s <port>\n", CMD_STR_UDP_DOWNLOAD);
printk("\nExample %s 5001\n", CMD_STR_UDP_DOWNLOAD);
return -1;
}
if (argc > 1) {
port = strtoul(argv[start + 1], NULL, 10);
} else {
port = DEF_PORT;
}
if (!udp_stopped) {
printk("[%s] ERROR! UDP server already started!\n",
CMD_STR_UDP_DOWNLOAD);
return -1;
}
zperf_receiver_init(port);
k_yield();
udp_stopped = false;
printk("[%s] UDP server started on port %u\n", CMD_STR_UDP_DOWNLOAD,
port);
return 0;
}
#endif
#if defined(CONFIG_NET_UDP)
static void shell_udp_upload_usage(void)
{
/* Print usage */
printk("\n%s:\n", CMD_STR_UDP_UPLOAD);
printk("Usage:\t%s <dest ip> <dest port> <duration> <packet "
"size>[K] <baud rate>[K|M]\n", CMD_STR_UDP_UPLOAD);
printk("\t<dest ip>:\tIP destination\n");
printk("\t<dest port>:\tUDP destination port\n");
printk("\t<duration>:\tDuration of the test in seconds\n");
printk("\t<packet size>:\tSize of the packet in byte or kilobyte "
"(with suffix K)\n");
printk("\t<baud rate>:\tBaudrate in kilobyte or megabyte\n");
printk("\nExample %s 10.237.164.178 1111 1 1K 1M\n",
CMD_STR_UDP_UPLOAD);
}
static void shell_udp_upload2_usage(void)
{
/* Print usage */
printk("\n%s:\n", CMD_STR_UDP_UPLOAD2);
printk("Usage:\t%s v6|v4 <duration> <packet "
"size>[K] <baud rate>[K|M]\n", CMD_STR_UDP_UPLOAD2);
printk("\t<v6|v4>:\tUse either IPv6 or IPv4\n");
printk("\t<duration>:\tDuration of the test in seconds\n");
printk("\t<packet size>:\tSize of the packet in byte or kilobyte "
"(with suffix K)\n");
printk("\t<baud rate>:\tBaudrate in kilobyte or megabyte\n");
printk("\nExample %s v6 1 1K 1M\n",
CMD_STR_UDP_UPLOAD2);
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
printk("\nDefault IPv6 address is %s, destination [%s]:%d\n",
MY_IP6ADDR, DST_IP6ADDR, DEF_PORT);
#endif
#if defined(CONFIG_NET_IPV4) && defined(MY_IP4ADDR)
printk("\nDefault IPv4 address is %s, destination %s:%d\n",
MY_IP4ADDR, DST_IP4ADDR, DEF_PORT);
#endif
}
#endif
#if defined(CONFIG_NET_TCP)
static void shell_tcp_upload_usage(void)
{
/* Print usage */
printk("\n%s:\n", CMD_STR_TCP_UPLOAD);
printk("Usage:\t%s <dest ip> <dest port> <duration> <packet "
"size>[K]\n", CMD_STR_TCP_UPLOAD);
printk("\t<dest ip>:\tIP destination\n");
printk("\t<dest port>:\tport destination\n");
printk("\t<duration>:\t of the test in seconds\n");
printk("\t<packet size>:\tSize of the packet in byte or kilobyte "
"(with suffix K)\n");
printk("\nExample %s 10.237.164.178 1111 1 1K 1M\n",
CMD_STR_TCP_UPLOAD);
}
static void shell_tcp_upload2_usage(void)
{
/* Print usage */
printk("\n%s:\n", CMD_STR_TCP_UPLOAD2);
printk("Usage:\t%s v6|v4 <duration> <packet "
"size>[K] <baud rate>[K|M]\n", CMD_STR_TCP_UPLOAD2);
printk("\t<v6|v4>:\tUse either IPv6 or IPv4\n");
printk("\t<duration>:\tDuration of the test in seconds\n");
printk("\t<packet size>:\tSize of the packet in byte or kilobyte "
"(with suffix K)\n");
printk("\t<baud rate>:\tBaudrate in kilobyte or megabyte\n");
printk("\nExample %s v6 1 1K 1M\n",
CMD_STR_TCP_UPLOAD2);
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
printk("\nDefault IPv6 address is %s, destination [%s]:%d\n",
MY_IP6ADDR, DST_IP6ADDR, DEF_PORT);
#endif
#if defined(CONFIG_NET_IPV4) && defined(MY_IP4ADDR)
printk("\nDefault IPv4 address is %s, destination %s:%d\n",
MY_IP4ADDR, DST_IP4ADDR, DEF_PORT);
#endif
}
#endif
#if defined(CONFIG_NET_UDP)
static void shell_udp_upload_print_stats(struct zperf_results *results)
{
unsigned int rate_in_kbps, client_rate_in_kbps;
printk("[%s] Upload completed!\n", CMD_STR_UDP_UPLOAD);
if (results->time_in_us != 0) {
rate_in_kbps = (uint32_t)
(((uint64_t)results->nb_bytes_sent *
(uint64_t)8 * (uint64_t)USEC_PER_SEC) /
((uint64_t)results->time_in_us * 1024));
} else {
rate_in_kbps = 0;
}
if (results->client_time_in_us != 0) {
client_rate_in_kbps = (uint32_t)
(((uint64_t)results->nb_packets_sent *
(uint64_t)results->packet_size * (uint64_t)8 *
(uint64_t)USEC_PER_SEC) /
((uint64_t)results->client_time_in_us * 1024));
} else {
client_rate_in_kbps = 0;
}
if (!rate_in_kbps) {
printk("[%s] LAST PACKET NOT RECEIVED!!!\n",
CMD_STR_UDP_UPLOAD);
}
printk("[%s] statistics:\t\tserver\t(client)\n", CMD_STR_UDP_UPLOAD);
printk("[%s] duration:\t\t\t", CMD_STR_UDP_UPLOAD);
print_number(results->time_in_us, TIME_US, TIME_US_UNIT);
printk("\t(");
print_number(results->client_time_in_us, TIME_US, TIME_US_UNIT);
printk(")\n");
printk("[%s] nb packets:\t\t%u\t(%u)\n", CMD_STR_UDP_UPLOAD,
results->nb_packets_rcvd,
results->nb_packets_sent);
printk("[%s] nb packets outorder:\t%u\n", CMD_STR_UDP_UPLOAD,
results->nb_packets_outorder);
printk("[%s] nb packets lost:\t\t%u\n", CMD_STR_UDP_UPLOAD,
results->nb_packets_lost);
printk("[%s] jitter:\t\t\t", CMD_STR_UDP_UPLOAD);
print_number(results->jitter_in_us, TIME_US, TIME_US_UNIT);
printk("\n");
printk("[%s] rate:\t\t\t", CMD_STR_UDP_UPLOAD);
print_number(rate_in_kbps, KBPS, KBPS_UNIT);
printk("\t(");
print_number(client_rate_in_kbps, KBPS, KBPS_UNIT);
printk(")\n");
}
#endif
#if defined(CONFIG_NET_TCP)
static void shell_tcp_upload_print_stats(struct zperf_results *results)
{
unsigned int client_rate_in_kbps;
printk("[%s] Upload completed!\n", CMD_STR_TCP_UPLOAD);
if (results->client_time_in_us != 0) {
client_rate_in_kbps = (uint32_t)
(((uint64_t)results->nb_packets_sent *
(uint64_t)results->packet_size * (uint64_t)8 *
(uint64_t)USEC_PER_SEC) /
((uint64_t)results->client_time_in_us * 1024));
} else {
client_rate_in_kbps = 0;
}
printk("[%s] duration:\t", CMD_STR_TCP_UPLOAD);
print_number(results->client_time_in_us, TIME_US, TIME_US_UNIT);
printk("\n");
printk("[%s] nb packets:\t%u\n", CMD_STR_TCP_UPLOAD,
results->nb_packets_sent);
printk("[%s] nb sending errors (retry or fail):\t%u\n",
CMD_STR_TCP_UPLOAD, results->nb_packets_errors);
printk("[%s] rate:\t", CMD_STR_TCP_UPLOAD);
print_number(client_rate_in_kbps, KBPS, KBPS_UNIT);
printk("\n");
}
#endif
static int setup_contexts(struct net_context **context6,
struct net_context **context4,
sa_family_t family,
struct sockaddr_in6 *ipv6,
struct sockaddr_in *ipv4,
int port,
bool is_udp,
char *argv0)
{
int ret;
#if defined(CONFIG_NET_IPV6)
ret = net_context_get(AF_INET6,
is_udp ? SOCK_DGRAM : SOCK_STREAM,
is_udp ? IPPROTO_UDP : IPPROTO_TCP,
context6);
if (ret < 0) {
printk("[%s] Cannot get IPv6 network context (%d)\n",
argv0, ret);
return -1;
}
ipv6->sin6_port = htons(port);
ipv6->sin6_family = AF_INET6;
#endif
#if defined(CONFIG_NET_IPV4)
ret = net_context_get(AF_INET,
is_udp ? SOCK_DGRAM : SOCK_STREAM,
is_udp ? IPPROTO_UDP : IPPROTO_TCP,
context4);
if (ret < 0) {
printk("[%s] Cannot get IPv4 network context (%d)\n",
argv0, ret);
return -1;
}
ipv4->sin_port = htons(port);
ipv4->sin_family = AF_INET;
#endif
if (family == AF_INET6 && *context6) {
ret = net_context_bind(*context6,
(struct sockaddr *)ipv6,
sizeof(struct sockaddr_in6));
if (ret < 0) {
printk("[%s] Cannot bind IPv6 port %d (%d)",
argv0, ntohs(ipv6->sin6_port), ret);
return -1;
}
}
if (family == AF_INET && *context4) {
ret = net_context_bind(*context4,
(struct sockaddr *)ipv4,
sizeof(struct sockaddr_in));
if (ret < 0) {
printk("[%s] Cannot bind IPv4 port %d (%d)",
argv0, ntohs(ipv4->sin_port), ret);
return -1;
}
}
if (!(*context6) && !(*context4)) {
printk("[%s] ERROR! Fail to retrieve network context(s)\n",
argv0);
return -1;
}
return 0;
}
static int execute_upload(struct net_context *context6,
struct net_context *context4,
sa_family_t family,
struct sockaddr_in6 *ipv6,
struct sockaddr_in *ipv4,
bool is_udp,
char *argv0,
unsigned int duration_in_ms,
unsigned int packet_size,
unsigned int rate_in_kbps)
{
struct zperf_results results = { };
int ret;
printk("[%s] duration:\t\t", argv0);
print_number(duration_in_ms * USEC_PER_MSEC, TIME_US, TIME_US_UNIT);
printk("\n");
printk("[%s] packet size:\t%u bytes\n", argv0, packet_size);
printk("[%s] start...\n", argv0);
#if defined(CONFIG_NET_IPV6)
if (family == AF_INET6 && context6) {
/* For IPv6, we should make sure that neighbor discovery
* has been done for the peer. So send ping here, wait
* some time and start the test after that.
*/
net_icmpv6_send_echo_request(net_if_get_default(),
&ipv6->sin6_addr, 0, 0);
k_sleep(1 * MSEC_PER_SEC);
}
#endif
if (is_udp) {
#if defined(CONFIG_NET_UDP)
printk("[%s] rate:\t\t", argv0);
print_number(rate_in_kbps, KBPS, KBPS_UNIT);
printk("\n");
if (family == AF_INET6 && context6) {
ret = net_context_connect(context6,
(struct sockaddr *)ipv6,
sizeof(*ipv6),
NULL,
K_NO_WAIT,
NULL);
if (ret < 0) {
printk("[%s] IPv6 connect failed (%d)\n",
argv0, ret);
goto out;
}
zperf_udp_upload(context6, duration_in_ms, packet_size,
rate_in_kbps, &results);
shell_udp_upload_print_stats(&results);
}
if (family == AF_INET && context4) {
ret = net_context_connect(context4,
(struct sockaddr *)ipv4,
sizeof(*ipv4),
NULL,
K_NO_WAIT,
NULL);
if (ret < 0) {
printk("[%s] IPv4 connect failed (%d)\n",
argv0, ret);
goto out;
}
zperf_udp_upload(context4, duration_in_ms, packet_size,
rate_in_kbps, &results);
shell_udp_upload_print_stats(&results);
}
#else
printk("[%s] UDP not supported\n", argv0);
#endif
} else {
#if defined(CONFIG_NET_TCP)
if (family == AF_INET6 && context6) {
ret = net_context_connect(context6,
(struct sockaddr *)ipv6,
sizeof(*ipv6),
NULL,
WAIT_CONNECT,
NULL);
if (ret < 0) {
printk("[%s] IPv6 connect failed (%d)\n",
argv0, ret);
goto out;
}
/* We either upload using IPv4 or IPv6, not both at
* the same time.
*/
net_context_put(context4);
zperf_tcp_upload(context6, duration_in_ms,
packet_size, &results);
shell_tcp_upload_print_stats(&results);
return 0;
}
if (family == AF_INET && context4) {
ret = net_context_connect(context4,
(struct sockaddr *)ipv4,
sizeof(*ipv4),
NULL,
WAIT_CONNECT,
NULL);
if (ret < 0) {
printk("[%s] IPv4 connect failed (%d)\n",
argv0, ret);
goto out;
}
net_context_put(context6);
zperf_tcp_upload(context4, duration_in_ms,
packet_size, &results);
shell_tcp_upload_print_stats(&results);
return 0;
}
#else
printk("[%s] TCP not supported\n", argv0);
#endif
}
out:
net_context_put(context6);
net_context_put(context4);
return 0;
}
static int shell_cmd_upload(int argc, char *argv[])
{
struct sockaddr_in6 ipv6 = { .sin6_family = AF_INET6 };
struct sockaddr_in ipv4 = { .sin_family = AF_INET };
struct net_context *context6 = NULL, *context4 = NULL;
sa_family_t family = AF_UNSPEC;
unsigned int duration_in_ms, packet_size, rate_in_kbps;
uint16_t port;
bool is_udp;
int start = 0;
if (!strcmp(argv[0], "zperf")) {
start++;
argc--;
}
is_udp = !strcmp(argv[start], CMD_STR_UDP_UPLOAD) ? 1 : 0;
if (argc == 1) {
if (is_udp) {
#if defined(CONFIG_NET_UDP)
shell_udp_upload_usage();
#endif
} else {
#if defined(CONFIG_NET_TCP)
shell_tcp_upload_usage();
#endif
}
return -1;
}
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
if (parse_ipv6_addr(argv[start + 1], argv[start + 2],
&ipv6, argv[start]) < 0) {
printk("[%s] ERROR! Please specify the IP address of the "
"remote server\n", argv[start]);
return -1;
}
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv6_addr(&ipv6.sin6_addr));
family = AF_INET6;
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
if (parse_ipv4_addr(argv[start + 1], argv[start + 2],
&ipv4, argv[start]) < 0) {
printk("[%s] ERROR! Please specify the IP address of the "
"remote server\n", argv[start]);
return -1;
}
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv4_addr(&ipv4.sin_addr));
family = AF_INET;
#endif
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
if (parse_ipv6_addr(argv[start + 1], argv[start + 2],
&ipv6, argv[start]) < 0) {
if (parse_ipv4_addr(argv[start + 1], argv[start + 2],
&ipv4, argv[start]) < 0) {
printk("[%s] ERROR! Please specify the IP address "
"of the remote server\n", argv[start]);
return -1;
}
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv4_addr(&ipv4.sin_addr));
family = AF_INET;
} else {
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv6_addr(&ipv6.sin6_addr));
family = AF_INET6;
}
#endif
if (argc > 2) {
port = strtoul(argv[start + 2], NULL, 10);
printk("[%s] Remote port is %u\n", argv[start], port);
} else {
port = DEF_PORT;
}
if (setup_contexts(&context6, &context4, family, &in6_addr_my,
&in4_addr_my, port, is_udp, argv[start]) < 0) {
return -1;
}
if (argc > 3) {
duration_in_ms = strtoul(argv[start + 3], NULL, 10) *
MSEC_PER_SEC;
} else {
duration_in_ms = 1000;
}
if (argc > 4) {
packet_size = parse_number(argv[start + 4], K, K_UNIT);
} else {
packet_size = 256;
}
if (argc > 5) {
rate_in_kbps =
(parse_number(argv[start + 5], K, K_UNIT) +
1023) / 1024;
} else {
rate_in_kbps = 10;
}
return execute_upload(context6, context4, family, &ipv6, &ipv4,
is_udp, argv[start], duration_in_ms,
packet_size, rate_in_kbps);
}
static int shell_cmd_upload2(int argc, char *argv[])
{
struct net_context *context6 = NULL, *context4 = NULL;
uint16_t port = DEF_PORT;
unsigned int duration_in_ms, packet_size, rate_in_kbps;
sa_family_t family;
uint8_t is_udp;
int start = 0;
if (!strcmp(argv[0], "zperf")) {
start++;
argc--;
}
is_udp = !strcmp(argv[start], CMD_STR_UDP_UPLOAD2) ? 1 : 0;
if (argc == 1) {
if (is_udp) {
#if defined(CONFIG_NET_UDP)
shell_udp_upload2_usage();
#endif
} else {
#if defined(CONFIG_NET_TCP)
shell_tcp_upload2_usage();
#endif
}
return -1;
}
family = !strcmp(argv[start + 1], "v4") ? AF_INET : AF_INET6;
#if defined(CONFIG_NET_IPV6)
in6_addr_my.sin6_port = htons(port);
#endif
#if defined(CONFIG_NET_IPV4)
in4_addr_my.sin_port = htons(port);
#endif
if (family == AF_INET6) {
if (net_is_ipv6_addr_unspecified(&in6_addr_my.sin6_addr)) {
printk("[%s] Invalid local IPv6 address\n",
argv[start]);
return -1;
}
if (net_is_ipv6_addr_unspecified(&in6_addr_dst.sin6_addr)) {
printk("[%s] Invalid destination IPv6 address\n",
argv[start]);
return -1;
}
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv6_addr(&in6_addr_dst.sin6_addr));
} else {
if (net_is_ipv4_addr_unspecified(&in4_addr_my.sin_addr)) {
printk("[%s] Invalid local IPv4 address\n",
argv[start]);
return -1;
}
if (net_is_ipv4_addr_unspecified(&in4_addr_dst.sin_addr)) {
printk("[%s] Invalid destination IPv4 address\n",
argv[start]);
return -1;
}
printk("[%s] Connecting to %s\n", argv[start],
net_sprint_ipv4_addr(&in4_addr_dst.sin_addr));
}
if (setup_contexts(&context6, &context4, family, &in6_addr_my,
&in4_addr_my, port, is_udp, argv[start]) < 0) {
return -1;
}
if (argc > 1) {
duration_in_ms = strtoul(argv[start + 2], NULL, 10) *
MSEC_PER_SEC;
} else {
duration_in_ms = 1000;
}
if (argc > 2) {
packet_size = parse_number(argv[start + 3], K, K_UNIT);
} else {
packet_size = 256;
}
if (argc > 3) {
rate_in_kbps =
(parse_number(argv[start + 4], K, K_UNIT) + 1023) /
1024;
} else {
rate_in_kbps = 10;
}
return execute_upload(context6, context4, family, &in6_addr_dst,
&in4_addr_dst, is_udp, argv[start],
duration_in_ms, packet_size, rate_in_kbps);
}
static int shell_cmd_connectap(int argc, char *argv[])
{
printk("[%s] Zephyr has not been built with Wi-Fi support.\n",
CMD_STR_CONNECTAP);
return 0;
}
#if defined(CONFIG_NET_TCP)
static int shell_cmd_tcp_download(int argc, char *argv[])
{
static bool tcp_stopped = true;
int port;
if (argc == 1) {
/* Print usage */
printk("\n[%s]:\n", CMD_STR_TCP_DOWNLOAD);
printk("Usage:\t%s <port>\n", CMD_STR_TCP_DOWNLOAD);
printk("\nExample %s 5001\n", CMD_STR_TCP_DOWNLOAD);
return -1;
}
if (argc > 1) {
port = strtoul(argv[1], NULL, 10);
} else {
port = DEF_PORT;
}
if (!tcp_stopped) {
printk("[%s] ERROR! TCP server already started!\n",
CMD_STR_TCP_DOWNLOAD);
return -1;
}
zperf_tcp_receiver_init(port);
tcp_stopped = false;
printk("[%s] TCP server started on port %u\n", CMD_STR_TCP_DOWNLOAD,
port);
return 0;
}
#endif
static int shell_cmd_version(int argc, char *argv[])
{
printk("\nzperf [%s]: %s config: %s\n", CMD_STR_VERSION, VERSION,
CONFIG);
return 0;
}
static void zperf_init(void)
{
#if defined(MY_IP6ADDR) || defined(MY_IP4ADDR)
int ret;
printk("\n");
#endif
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
if (zperf_get_ipv6_addr(MY_IP6ADDR, MY_PREFIX_LEN_STR,
&ipv6, __func__) < 0) {
printk("[%s] ERROR! Unable to set IP\n", __func__);
} else {
printk("[%s] Setting IP address %s\n", __func__,
net_sprint_ipv6_addr(&ipv6));
net_ipaddr_copy(&in6_addr_my.sin6_addr, &ipv6);
}
ret = net_addr_pton(AF_INET6, DST_IP6ADDR,
&in6_addr_dst.sin6_addr);
if (ret < 0) {
printk("[%s] ERROR! Unable to set IP %s\n", __func__,
DST_IP6ADDR);
} else {
printk("[%s] Setting destination IP address %s\n", __func__,
net_sprint_ipv6_addr(&in6_addr_dst.sin6_addr));
}
#endif
#if defined(CONFIG_NET_IPV4) && defined(MY_IP4ADDR)
if (zperf_get_ipv4_addr(MY_IP4ADDR, &ipv4, __func__) < 0) {
printk("[%s] ERROR! Unable to set IP\n", __func__);
} else {
printk("[%s] Setting IP address %s\n", __func__,
net_sprint_ipv4_addr(&ipv4));
net_ipaddr_copy(&in4_addr_my.sin_addr, &ipv4);
}
ret = net_addr_pton(AF_INET, DST_IP4ADDR,
&in4_addr_dst.sin_addr);
if (ret < 0) {
printk("[%s] ERROR! Unable to set IP %s\n", __func__,
DST_IP4ADDR);
} else {
printk("[%s] Setting destination IP address %s\n", __func__,
net_sprint_ipv4_addr(&in4_addr_dst.sin_addr));
}
#endif
zperf_session_init();
}
#define MY_SHELL_MODULE "zperf"
struct shell_cmd commands[] = {
{ CMD_STR_SETIP, shell_cmd_setip },
{ CMD_STR_CONNECTAP, shell_cmd_connectap },
{ CMD_STR_VERSION, shell_cmd_version },
#if defined(CONFIG_NET_UDP)
{ CMD_STR_UDP_UPLOAD, shell_cmd_upload },
/* Same as upload command but no need to specify the addresses */
{ CMD_STR_UDP_UPLOAD2, shell_cmd_upload2 },
{ CMD_STR_UDP_DOWNLOAD, shell_cmd_udp_download },
#endif
#if defined(CONFIG_NET_TCP)
{ CMD_STR_TCP_UPLOAD, shell_cmd_upload },
{ CMD_STR_TCP_UPLOAD2, shell_cmd_upload2 },
{ CMD_STR_TCP_DOWNLOAD, shell_cmd_tcp_download },
#endif
#if defined(PROFILER)
PROF_CMD,
#endif
{ NULL, NULL }
};
void main(void)
{
#if defined(CONFIG_NET_L2_BLUETOOTH)
if (bt_enable(NULL)) {
NET_ERR("Bluetooth init failed\n");
return;
}
#endif
#if defined(CONFIG_NET_L2_IEEE802154)
if (ieee802154_sample_setup()) {
NET_ERR("IEEE 802.15.4 setup failed");
return;
}
#endif
shell_cmd_version(0, NULL);
SHELL_REGISTER(MY_SHELL_MODULE, commands);
shell_register_default_module(MY_SHELL_MODULE);
zperf_init();
#if PROFILER
while (1) {
k_sleep(5 * MSEC_PER_SEC);
prof_flush();
}
#else
k_sleep(K_FOREVER);
#endif
}