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