1 /* udp.c - UDP specific code for echo client */
2 
3 /*
4  * Copyright (c) 2017 Intel Corporation.
5  * Copyright (c) 2018 Nordic Semiconductor ASA.
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <logging/log.h>
11 LOG_MODULE_DECLARE(net_echo_client_sample, LOG_LEVEL_DBG);
12 
13 #include <zephyr.h>
14 #include <errno.h>
15 #include <stdio.h>
16 
17 #include <net/socket.h>
18 #include <net/tls_credentials.h>
19 #include <random/rand32.h>
20 
21 #include "common.h"
22 #include "ca_certificate.h"
23 
24 #define RECV_BUF_SIZE 1280
25 #define UDP_SLEEP K_MSEC(150)
26 #define UDP_WAIT K_SECONDS(10)
27 
28 static APP_BMEM char recv_buf[RECV_BUF_SIZE];
29 
send_udp_data(struct data * data)30 static int send_udp_data(struct data *data)
31 {
32 	int ret;
33 
34 	do {
35 		data->udp.expecting = sys_rand32_get() % ipsum_len;
36 	} while (data->udp.expecting == 0U ||
37 		 data->udp.expecting > data->udp.mtu);
38 
39 	ret = send(data->udp.sock, lorem_ipsum, data->udp.expecting, 0);
40 
41 	LOG_DBG("%s UDP: Sent %d bytes", data->proto, data->udp.expecting);
42 
43 	k_work_reschedule(&data->udp.recv, UDP_WAIT);
44 
45 	return ret < 0 ? -EIO : 0;
46 }
47 
compare_udp_data(struct data * data,const char * buf,uint32_t received)48 static int compare_udp_data(struct data *data, const char *buf, uint32_t received)
49 {
50 	if (received != data->udp.expecting) {
51 		LOG_ERR("Invalid amount of data received: UDP %s", data->proto);
52 		return -EIO;
53 	}
54 
55 	if (memcmp(buf, lorem_ipsum, received) != 0) {
56 		LOG_ERR("Invalid data received: UDP %s", data->proto);
57 		return -EIO;
58 	}
59 
60 	return 0;
61 }
62 
wait_reply(struct k_work * work)63 static void wait_reply(struct k_work *work)
64 {
65 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
66 	/* This means that we did not receive response in time. */
67 	struct data *data = CONTAINER_OF(dwork, struct data, udp.recv);
68 
69 	LOG_ERR("UDP %s: Data packet not received", data->proto);
70 
71 	/* Send a new packet at this point */
72 	send_udp_data(data);
73 }
74 
wait_transmit(struct k_work * work)75 static void wait_transmit(struct k_work *work)
76 {
77 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
78 	struct data *data = CONTAINER_OF(dwork, struct data, udp.transmit);
79 
80 	send_udp_data(data);
81 }
82 
start_udp_proto(struct data * data,struct sockaddr * addr,socklen_t addrlen)83 static int start_udp_proto(struct data *data, struct sockaddr *addr,
84 			   socklen_t addrlen)
85 {
86 	int ret;
87 
88 	k_work_init_delayable(&data->udp.recv, wait_reply);
89 	k_work_init_delayable(&data->udp.transmit, wait_transmit);
90 
91 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
92 	data->udp.sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_DTLS_1_2);
93 #else
94 	data->udp.sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
95 #endif
96 	if (data->udp.sock < 0) {
97 		LOG_ERR("Failed to create UDP socket (%s): %d", data->proto,
98 			errno);
99 		return -errno;
100 	}
101 
102 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
103 	sec_tag_t sec_tag_list[] = {
104 		CA_CERTIFICATE_TAG,
105 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
106 		PSK_TAG,
107 #endif
108 	};
109 
110 	ret = setsockopt(data->udp.sock, SOL_TLS, TLS_SEC_TAG_LIST,
111 			 sec_tag_list, sizeof(sec_tag_list));
112 	if (ret < 0) {
113 		LOG_ERR("Failed to set TLS_SEC_TAG_LIST option (%s): %d",
114 			data->proto, errno);
115 		ret = -errno;
116 	}
117 
118 	ret = setsockopt(data->udp.sock, SOL_TLS, TLS_HOSTNAME,
119 			 TLS_PEER_HOSTNAME, sizeof(TLS_PEER_HOSTNAME));
120 	if (ret < 0) {
121 		LOG_ERR("Failed to set TLS_HOSTNAME option (%s): %d",
122 			data->proto, errno);
123 		ret = -errno;
124 	}
125 #endif
126 
127 	/* Call connect so we can use send and recv. */
128 	ret = connect(data->udp.sock, addr, addrlen);
129 	if (ret < 0) {
130 		LOG_ERR("Cannot connect to UDP remote (%s): %d", data->proto,
131 			errno);
132 		ret = -errno;
133 	}
134 
135 	return ret;
136 }
137 
process_udp_proto(struct data * data)138 static int process_udp_proto(struct data *data)
139 {
140 	int ret, received;
141 
142 	received = recv(data->udp.sock, recv_buf, sizeof(recv_buf),
143 			MSG_DONTWAIT);
144 
145 	if (received == 0) {
146 		return -EIO;
147 	}
148 	if (received < 0) {
149 		if (errno == EAGAIN || errno == EWOULDBLOCK) {
150 			ret = 0;
151 		} else {
152 			ret = -errno;
153 		}
154 		return ret;
155 	}
156 
157 	ret = compare_udp_data(data, recv_buf, received);
158 	if (ret != 0) {
159 		LOG_WRN("%s UDP: Received and compared %d bytes, data "
160 			"mismatch", data->proto, received);
161 		return 0;
162 	}
163 
164 	/* Correct response received */
165 	LOG_DBG("%s UDP: Received and compared %d bytes, all ok",
166 		data->proto, received);
167 
168 	if (++data->udp.counter % 1000 == 0U) {
169 		LOG_INF("%s UDP: Exchanged %u packets", data->proto,
170 			data->udp.counter);
171 	}
172 
173 	k_work_cancel_delayable(&data->udp.recv);
174 
175 	/* Do not flood the link if we have also TCP configured */
176 	if (IS_ENABLED(CONFIG_NET_TCP)) {
177 		k_work_reschedule(&data->udp.transmit, UDP_SLEEP);
178 		ret = 0;
179 	} else {
180 		ret = send_udp_data(data);
181 	}
182 
183 	return ret;
184 }
185 
start_udp(void)186 int start_udp(void)
187 {
188 	int ret = 0;
189 	struct sockaddr_in addr4;
190 	struct sockaddr_in6 addr6;
191 
192 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
193 		addr6.sin6_family = AF_INET6;
194 		addr6.sin6_port = htons(PEER_PORT);
195 		inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR,
196 			  &addr6.sin6_addr);
197 
198 		ret = start_udp_proto(&conf.ipv6, (struct sockaddr *)&addr6,
199 				      sizeof(addr6));
200 		if (ret < 0) {
201 			return ret;
202 		}
203 	}
204 
205 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
206 		addr4.sin_family = AF_INET;
207 		addr4.sin_port = htons(PEER_PORT);
208 		inet_pton(AF_INET, CONFIG_NET_CONFIG_PEER_IPV4_ADDR,
209 			  &addr4.sin_addr);
210 
211 		ret = start_udp_proto(&conf.ipv4, (struct sockaddr *)&addr4,
212 				      sizeof(addr4));
213 		if (ret < 0) {
214 			return ret;
215 		}
216 	}
217 
218 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
219 		ret = send_udp_data(&conf.ipv6);
220 		if (ret < 0) {
221 			return ret;
222 		}
223 	}
224 
225 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
226 		ret = send_udp_data(&conf.ipv4);
227 	}
228 
229 	return ret;
230 }
231 
process_udp(void)232 int process_udp(void)
233 {
234 	int ret = 0;
235 
236 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
237 		ret = process_udp_proto(&conf.ipv6);
238 		if (ret < 0) {
239 			return ret;
240 		}
241 	}
242 
243 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
244 		ret = process_udp_proto(&conf.ipv4);
245 		if (ret < 0) {
246 			return ret;
247 		}
248 	}
249 
250 	return ret;
251 }
252 
stop_udp(void)253 void stop_udp(void)
254 {
255 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
256 		k_work_cancel_delayable(&conf.ipv6.udp.recv);
257 		k_work_cancel_delayable(&conf.ipv6.udp.transmit);
258 
259 		if (conf.ipv6.udp.sock >= 0) {
260 			(void)close(conf.ipv6.udp.sock);
261 		}
262 	}
263 
264 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
265 		k_work_cancel_delayable(&conf.ipv4.udp.recv);
266 		k_work_cancel_delayable(&conf.ipv4.udp.transmit);
267 
268 		if (conf.ipv4.udp.sock >= 0) {
269 			(void)close(conf.ipv4.udp.sock);
270 		}
271 	}
272 }
273