1#include <stdlib.h>
2#include <string.h>
3#include <stdint.h>
4#include "pico_ipv6.h"
5#include "pico_stack.h"
6#include "pico_socket.h"
7#include "utils.h"
8
9#define DURATION 30
10
11struct iperf_hdr {
12    int32_t flags;          /* 0 */
13    int32_t numThreads;     /* 1 */
14    int32_t mPort;          /* 5001  */
15    int32_t bufferlen;      /* 0 */
16    int32_t mWinBand;       /* 0 */
17    int32_t mAmount;        /* 0xfffffc18 */
18};
19
20#define IPERF_PORT 5001
21#define MTU 1444
22#define SEND_BUF_SIZ (1024 * 2048)
23
24char *cpy_arg(char **dst, char *str);
25extern int IPV6_MODE;
26
27static pico_time deadline;
28
29static void panic(void)
30{
31    for(;; ) ;
32}
33
34static char buf[MTU] = {};
35
36static void buf_paint(void)
37{
38    char paint[11] = "0123456789";
39    int i;
40    for (i = 0; i < MTU; i++) {
41        buf[i] = paint[i % 10];
42    }
43}
44
45static void send_hdr(struct pico_socket *s)
46{
47    struct iperf_hdr hdr = {};
48    hdr.numThreads = long_be(1);
49    hdr.mPort = long_be(5001);
50    hdr.mAmount = long_be(0xfffffc18);
51    pico_socket_write(s, &hdr, sizeof(hdr));
52    deadline = PICO_TIME_MS() + DURATION * 1000;
53}
54
55static void iperf_cb(uint16_t ev, struct pico_socket *s)
56{
57    int r;
58    static int end = 0;
59    if (ev & PICO_SOCK_EV_CONN) {
60        send_hdr(s);
61        return;
62    }
63
64    if ((!end) && (ev & PICO_SOCK_EV_WR)) {
65        if (PICO_TIME_MS() > deadline) {
66            pico_socket_close(s);
67            if (!pico_timer_add(2000, deferred_exit, NULL)) {
68                printf("Failed to start exit timer, exiting now\n");
69                exit(1);
70            }
71            end++;
72        }
73
74        pico_socket_write(s, buf, MTU);
75    }
76
77    if (!(end) && (ev & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE))) {
78        if (!pico_timer_add(2000, deferred_exit, NULL)) {
79            printf("Failed to start exit timer, exiting now\n");
80            exit(1);
81        }
82        end++;
83    }
84}
85
86static void iperfc_socket_setup(union pico_address *addr, uint16_t family)
87{
88    int yes = 1;
89    uint16_t send_port = 0;
90    struct pico_socket *s = NULL;
91    uint32_t bufsize = SEND_BUF_SIZ;
92    send_port = short_be(5001);
93    s = pico_socket_open(family, PICO_PROTO_TCP, &iperf_cb);
94    pico_socket_setoption(s, PICO_SOCKET_OPT_SNDBUF, &bufsize);
95    pico_socket_connect(s, addr, send_port);
96}
97
98void app_iperfc(char *arg)
99{
100    struct pico_ip4 my_eth_addr, netmask;
101    struct pico_device *pico_dev_eth;
102    char *daddr = NULL, *dport = NULL;
103    char *nxt = arg;
104    uint16_t send_port = 0, listen_port = short_be(5001);
105    int i = 0, ret = 0, yes = 1;
106    struct pico_socket *s = NULL;
107    uint16_t family = PICO_PROTO_IPV4;
108    union pico_address dst = {
109        .ip4 = {0}, .ip6 = {{0}}
110    };
111    union pico_address inaddr_any = {
112        .ip4 = {0}, .ip6 = {{0}}
113    };
114
115    /* start of argument parsing */
116    if (nxt) {
117        nxt = cpy_arg(&daddr, arg);
118        if (daddr) {
119            if (!IPV6_MODE)
120                pico_string_to_ipv4(daddr, &dst.ip4.addr);
121
122      #ifdef PICO_SUPPORT_IPV6
123            else {
124                pico_string_to_ipv6(daddr, dst.ip6.addr);
125                family = PICO_PROTO_IPV6;
126            }
127      #endif
128        } else {
129            goto out;
130        }
131    } else {
132        /* missing dest_addr */
133        goto out;
134    }
135
136    iperfc_socket_setup(&dst, family);
137    return;
138out:
139    dbg("Error parsing options!\n");
140    exit(1);
141}
142
143