1 /*
2  * Copyright (c) 2019 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_pkt_sock_sample, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 #include <stdio.h>
13 
14 #include <zephyr/misc/lorem_ipsum.h>
15 #include <zephyr/net/socket.h>
16 #include <zephyr/net/ethernet.h>
17 #include <zephyr/net/net_mgmt.h>
18 
19 #include <zephyr/posix/sys/socket.h>
20 #include <zephyr/posix/unistd.h>
21 
22 #define STACK_SIZE 1024
23 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
24 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
25 #else
26 #define THREAD_PRIORITY K_PRIO_PREEMPT(8)
27 #endif
28 #define RECV_BUFFER_SIZE 1280
29 #define WAIT_TIME CONFIG_NET_SAMPLE_SEND_WAIT_TIME
30 
31 #define FLOOD (CONFIG_NET_SAMPLE_SEND_WAIT_TIME ? 0 : 1)
32 
33 static struct k_sem quit_lock;
34 
35 struct packet_data {
36 	int send_sock;
37 	int recv_sock;
38 	char recv_buffer[RECV_BUFFER_SIZE];
39 };
40 
41 static struct packet_data sock_packet;
42 static bool finish;
43 static K_SEM_DEFINE(iface_up, 0, 1);
44 
45 static void recv_packet(void);
46 static void send_packet(void);
47 
48 K_THREAD_DEFINE(receiver_thread_id, STACK_SIZE,
49 		recv_packet, NULL, NULL, NULL,
50 		THREAD_PRIORITY, 0, -1);
51 K_THREAD_DEFINE(sender_thread_id, STACK_SIZE,
52 		send_packet, NULL, NULL, NULL,
53 		THREAD_PRIORITY, 0, -1);
54 
55 const char lorem_ipsum[] = LOREM_IPSUM;
56 
quit(void)57 static void quit(void)
58 {
59 	k_sem_give(&quit_lock);
60 }
61 
start_socket(int * sock)62 static int start_socket(int *sock)
63 {
64 	struct sockaddr_ll dst = { 0 };
65 	int ret;
66 
67 	*sock = socket(AF_PACKET,
68 		       IS_ENABLED(CONFIG_NET_SAMPLE_ENABLE_PACKET_DGRAM) ?
69 							SOCK_DGRAM : SOCK_RAW,
70 		       htons(ETH_P_ALL));
71 	if (*sock < 0) {
72 		LOG_ERR("Failed to create %s socket : %d",
73 			IS_ENABLED(CONFIG_NET_SAMPLE_ENABLE_PACKET_DGRAM) ?
74 							"DGRAM" : "RAW",
75 			errno);
76 		return -errno;
77 	}
78 
79 	dst.sll_ifindex = net_if_get_by_iface(net_if_get_default());
80 	dst.sll_family = AF_PACKET;
81 
82 	ret = bind(*sock, (const struct sockaddr *)&dst,
83 		   sizeof(struct sockaddr_ll));
84 	if (ret < 0) {
85 		LOG_ERR("Failed to bind packet socket : %d", errno);
86 		return -errno;
87 	}
88 
89 	return 0;
90 }
91 
recv_packet_socket(struct packet_data * packet)92 static int recv_packet_socket(struct packet_data *packet)
93 {
94 	int ret = 0;
95 	int received;
96 
97 	LOG_INF("Waiting for packets ...");
98 
99 	do {
100 		if (finish) {
101 			ret = -1;
102 			break;
103 		}
104 
105 		received = recv(packet->recv_sock, packet->recv_buffer,
106 				sizeof(packet->recv_buffer), 0);
107 
108 		if (received < 0) {
109 			if (errno == EAGAIN) {
110 				continue;
111 			}
112 
113 			LOG_ERR("RAW : recv error %d", errno);
114 			ret = -errno;
115 			break;
116 		}
117 
118 		LOG_DBG("Received %d bytes", received);
119 	} while (true);
120 
121 	return ret;
122 }
123 
recv_packet(void)124 static void recv_packet(void)
125 {
126 	int ret;
127 	struct timeval timeo_optval = {
128 		.tv_sec = 1,
129 		.tv_usec = 0,
130 	};
131 
132 	ret = start_socket(&sock_packet.recv_sock);
133 	if (ret < 0) {
134 		quit();
135 		return;
136 	}
137 
138 	ret = setsockopt(sock_packet.recv_sock, SOL_SOCKET, SO_RCVTIMEO,
139 			 &timeo_optval, sizeof(timeo_optval));
140 	if (ret < 0) {
141 		quit();
142 		return;
143 	}
144 
145 	while (ret == 0) {
146 		ret = recv_packet_socket(&sock_packet);
147 		if (ret < 0) {
148 			quit();
149 			return;
150 		}
151 	}
152 }
153 
send_packet_socket(struct packet_data * packet)154 static int send_packet_socket(struct packet_data *packet)
155 {
156 	struct sockaddr_ll dst = { 0 };
157 	size_t send = 100U;
158 	int ret;
159 
160 	dst.sll_ifindex = net_if_get_by_iface(net_if_get_default());
161 
162 	if (IS_ENABLED(CONFIG_NET_SAMPLE_ENABLE_PACKET_DGRAM)) {
163 		dst.sll_halen = sizeof(struct net_eth_addr);
164 
165 		/* FIXME: assume IP data atm */
166 		dst.sll_protocol = htons(ETH_P_IP);
167 
168 		ret = net_bytes_from_str(
169 			dst.sll_addr,
170 			dst.sll_halen,
171 			CONFIG_NET_SAMPLE_DESTINATION_ADDR);
172 		if (ret < 0) {
173 			LOG_ERR("Invalid MAC address '%s'",
174 				CONFIG_NET_SAMPLE_DESTINATION_ADDR);
175 		}
176 	}
177 
178 	do {
179 		if (finish) {
180 			ret = -1;
181 			break;
182 		}
183 
184 		/* Sending dummy data */
185 		ret = sendto(packet->send_sock, lorem_ipsum, send, 0,
186 			     (const struct sockaddr *)&dst,
187 			     sizeof(struct sockaddr_ll));
188 		if (ret < 0) {
189 			LOG_ERR("Failed to send, errno %d", errno);
190 			break;
191 		} else {
192 			if (!FLOOD) {
193 				LOG_DBG("Sent %zd bytes", send);
194 			}
195 		}
196 
197 		/* If we have received any data, flush it here in order to
198 		 * not to leak memory in IP stack.
199 		 */
200 		do {
201 			static char recv_buffer[RECV_BUFFER_SIZE];
202 
203 			ret = recv(packet->send_sock, recv_buffer,
204 				   sizeof(recv_buffer), MSG_DONTWAIT);
205 		} while (ret > 0);
206 
207 		if (!FLOOD) {
208 			k_msleep(WAIT_TIME);
209 		}
210 	} while (true);
211 
212 	return ret;
213 }
214 
send_packet(void)215 static void send_packet(void)
216 {
217 	int ret;
218 
219 	ret = start_socket(&sock_packet.send_sock);
220 	if (ret < 0) {
221 		quit();
222 		return;
223 	}
224 
225 	while (ret == 0) {
226 		ret = send_packet_socket(&sock_packet);
227 		if (ret < 0) {
228 			quit();
229 			return;
230 		}
231 	}
232 }
233 
iface_up_handler(struct net_mgmt_event_callback * cb,uint64_t mgmt_event,struct net_if * iface)234 static void iface_up_handler(struct net_mgmt_event_callback *cb,
235 			     uint64_t mgmt_event, struct net_if *iface)
236 {
237 	if (mgmt_event == NET_EVENT_IF_UP) {
238 		k_sem_give(&iface_up);
239 	}
240 }
241 
wait_for_interface(void)242 static void wait_for_interface(void)
243 {
244 	struct net_if *iface = net_if_get_default();
245 	struct net_mgmt_event_callback iface_up_cb;
246 
247 	if (net_if_is_up(iface)) {
248 		return;
249 	}
250 
251 	net_mgmt_init_event_callback(&iface_up_cb, iface_up_handler,
252 				     NET_EVENT_IF_UP);
253 	net_mgmt_add_event_callback(&iface_up_cb);
254 
255 	/* Wait for the interface to come up. */
256 	k_sem_take(&iface_up, K_FOREVER);
257 
258 	net_mgmt_del_event_callback(&iface_up_cb);
259 }
260 
main(void)261 int main(void)
262 {
263 	k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT);
264 
265 	wait_for_interface();
266 
267 	LOG_INF("Packet socket sample is running");
268 
269 	k_thread_start(receiver_thread_id);
270 	k_thread_start(sender_thread_id);
271 
272 	k_sem_take(&quit_lock, K_FOREVER);
273 
274 	LOG_INF("Stopping...");
275 
276 	finish = true;
277 
278 	k_thread_join(receiver_thread_id, K_FOREVER);
279 	k_thread_join(sender_thread_id, K_FOREVER);
280 
281 	if (sock_packet.recv_sock >= 0) {
282 		(void)close(sock_packet.recv_sock);
283 	}
284 
285 	if (sock_packet.send_sock >= 0) {
286 		(void)close(sock_packet.send_sock);
287 	}
288 	return 0;
289 }
290