1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/init.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/net/socket.h>
10 
11 #include "zperf_internal.h"
12 #include "zperf_session.h"
13 
14 LOG_MODULE_REGISTER(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
15 
16 /* Get some useful debug routings from net_private.h, requires
17  * that NET_LOG_ENABLED is set.
18  */
19 #define NET_LOG_ENABLED 1
20 #include "net_private.h"
21 
22 #include "ipv6.h" /* to get infinite lifetime */
23 
24 static struct sockaddr_in6 in6_addr_my = {
25 	.sin6_family = AF_INET6,
26 	.sin6_port = htons(MY_SRC_PORT),
27 };
28 
29 static struct sockaddr_in in4_addr_my = {
30 	.sin_family = AF_INET,
31 	.sin_port = htons(MY_SRC_PORT),
32 };
33 
zperf_get_sin6(void)34 struct sockaddr_in6 *zperf_get_sin6(void)
35 {
36 	return &in6_addr_my;
37 }
38 
zperf_get_sin(void)39 struct sockaddr_in *zperf_get_sin(void)
40 {
41 	return &in4_addr_my;
42 }
43 
44 #define ZPERF_WORK_Q_THREAD_PRIORITY                                                               \
45 	CLAMP(CONFIG_ZPERF_WORK_Q_THREAD_PRIORITY, K_HIGHEST_APPLICATION_THREAD_PRIO,              \
46 	      K_LOWEST_APPLICATION_THREAD_PRIO)
47 K_THREAD_STACK_DEFINE(zperf_work_q_stack, CONFIG_ZPERF_WORK_Q_STACK_SIZE);
48 
49 static struct k_work_q zperf_work_q;
50 
zperf_get_ipv6_addr(char * host,char * prefix_str,struct in6_addr * addr)51 int zperf_get_ipv6_addr(char *host, char *prefix_str, struct in6_addr *addr)
52 {
53 	struct net_if_ipv6_prefix *prefix;
54 	struct net_if_addr *ifaddr;
55 	int prefix_len;
56 	int ret;
57 
58 	if (!host) {
59 		return -EINVAL;
60 	}
61 
62 	ret = net_addr_pton(AF_INET6, host, addr);
63 	if (ret < 0) {
64 		return -EINVAL;
65 	}
66 
67 	prefix_len = strtoul(prefix_str, NULL, 10);
68 
69 	ifaddr = net_if_ipv6_addr_add(net_if_get_default(),
70 				      addr, NET_ADDR_MANUAL, 0);
71 	if (!ifaddr) {
72 		NET_ERR("Cannot set IPv6 address %s", host);
73 		return -EINVAL;
74 	}
75 
76 	prefix = net_if_ipv6_prefix_add(net_if_get_default(),
77 					addr, prefix_len,
78 					NET_IPV6_ND_INFINITE_LIFETIME);
79 	if (!prefix) {
80 		NET_ERR("Cannot set IPv6 prefix %s", prefix_str);
81 		return -EINVAL;
82 	}
83 
84 	return 0;
85 }
86 
87 
zperf_get_ipv4_addr(char * host,struct in_addr * addr)88 int zperf_get_ipv4_addr(char *host, struct in_addr *addr)
89 {
90 	struct net_if_addr *ifaddr;
91 	int ret;
92 
93 	if (!host) {
94 		return -EINVAL;
95 	}
96 
97 	ret = net_addr_pton(AF_INET, host, addr);
98 	if (ret < 0) {
99 		return -EINVAL;
100 	}
101 
102 	ifaddr = net_if_ipv4_addr_add(net_if_get_default(),
103 				      addr, NET_ADDR_MANUAL, 0);
104 	if (!ifaddr) {
105 		NET_ERR("Cannot set IPv4 address %s", host);
106 		return -EINVAL;
107 	}
108 
109 	return 0;
110 }
111 
zperf_prepare_upload_sock(const struct sockaddr * peer_addr,uint8_t tos,int priority,int tcp_nodelay,int proto)112 int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, uint8_t tos,
113 			      int priority, int tcp_nodelay, int proto)
114 {
115 	socklen_t addrlen = peer_addr->sa_family == AF_INET6 ?
116 			    sizeof(struct sockaddr_in6) :
117 			    sizeof(struct sockaddr_in);
118 	int type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
119 	int sock = -1;
120 	int ret;
121 
122 	switch (peer_addr->sa_family) {
123 	case AF_INET:
124 		if (!IS_ENABLED(CONFIG_NET_IPV4)) {
125 			NET_ERR("IPv4 not available.");
126 			return -EINVAL;
127 		}
128 
129 		sock = zsock_socket(AF_INET, type, proto);
130 		if (sock < 0) {
131 			NET_ERR("Cannot create IPv4 network socket (%d)",
132 				errno);
133 			return -errno;
134 		}
135 
136 		if (tos > 0) {
137 			if (zsock_setsockopt(sock, IPPROTO_IP, IP_TOS,
138 					     &tos, sizeof(tos)) != 0) {
139 				NET_WARN("Failed to set IP_TOS socket option. "
140 					 "Please enable CONFIG_NET_CONTEXT_DSCP_ECN.");
141 			}
142 		}
143 
144 		break;
145 
146 	case AF_INET6:
147 		if (!IS_ENABLED(CONFIG_NET_IPV6)) {
148 			NET_ERR("IPv6 not available.");
149 			return -EINVAL;
150 		}
151 
152 		sock = zsock_socket(AF_INET6, type, proto);
153 		if (sock < 0) {
154 			NET_ERR("Cannot create IPv6 network socket (%d)",
155 				errno);
156 			return -errno;
157 		}
158 
159 		if (tos >= 0) {
160 			if (zsock_setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
161 					     &tos, sizeof(tos)) != 0) {
162 				NET_WARN("Failed to set IPV6_TCLASS socket option. "
163 					 "Please enable CONFIG_NET_CONTEXT_DSCP_ECN.");
164 			}
165 		}
166 
167 		break;
168 
169 	default:
170 		LOG_ERR("Invalid address family (%d)", peer_addr->sa_family);
171 		return -EINVAL;
172 	}
173 
174 	if (IS_ENABLED(CONFIG_NET_CONTEXT_PRIORITY) && priority >= 0) {
175 		uint8_t prio = priority;
176 
177 		if (!IS_ENABLED(CONFIG_NET_ALLOW_ANY_PRIORITY) &&
178 		    (prio >= NET_MAX_PRIORITIES)) {
179 			NET_ERR("Priority %d is too large, maximum allowed is %d",
180 				prio, NET_MAX_PRIORITIES - 1);
181 			ret = -EINVAL;
182 			goto error;
183 		}
184 
185 		if (zsock_setsockopt(sock, SOL_SOCKET, SO_PRIORITY,
186 				     &prio,
187 				     sizeof(prio)) != 0) {
188 			NET_WARN("Failed to set SOL_SOCKET - SO_PRIORITY socket option.");
189 			ret = -errno;
190 			goto error;
191 		}
192 	}
193 
194 	if (proto == IPPROTO_TCP && tcp_nodelay &&
195 	    zsock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
196 			     &tcp_nodelay,
197 			     sizeof(tcp_nodelay)) != 0) {
198 		NET_WARN("Failed to set IPPROTO_TCP - TCP_NODELAY socket option.");
199 		ret = -errno;
200 		goto error;
201 	}
202 
203 	ret = zsock_connect(sock, peer_addr, addrlen);
204 	if (ret < 0) {
205 		NET_ERR("Connect failed (%d)", errno);
206 		ret = -errno;
207 		goto error;
208 	}
209 
210 	return sock;
211 
212 error:
213 	zsock_close(sock);
214 	return ret;
215 }
216 
zperf_packet_duration(uint32_t packet_size,uint32_t rate_in_kbps)217 uint32_t zperf_packet_duration(uint32_t packet_size, uint32_t rate_in_kbps)
218 {
219 	return (uint32_t)(((uint64_t)packet_size * 8U * USEC_PER_SEC) /
220 			  (rate_in_kbps * 1024U));
221 }
222 
zperf_async_work_submit(struct k_work * work)223 void zperf_async_work_submit(struct k_work *work)
224 {
225 	k_work_submit_to_queue(&zperf_work_q, work);
226 }
227 
zperf_init(void)228 static int zperf_init(void)
229 {
230 
231 	k_work_queue_init(&zperf_work_q);
232 	k_work_queue_start(&zperf_work_q, zperf_work_q_stack,
233 			   K_THREAD_STACK_SIZEOF(zperf_work_q_stack), ZPERF_WORK_Q_THREAD_PRIORITY,
234 			   NULL);
235 	k_thread_name_set(&zperf_work_q.thread, "zperf_work_q");
236 
237 	zperf_udp_uploader_init();
238 	zperf_tcp_uploader_init();
239 
240 	zperf_session_init();
241 
242 	if (IS_ENABLED(CONFIG_NET_SHELL)) {
243 		zperf_shell_init();
244 	}
245 
246 	return 0;
247 }
248 
249 SYS_INIT(zperf_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
250