1 /** @file
2  * @brief Modem socket / packet size handler
3  *
4  * Generic modem socket and packet size implementation for modem context
5  */
6 
7 /*
8  * Copyright (c) 2019-2020 Foundries.io
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/fdtable.h>
15 
16 #include "modem_socket.h"
17 
18 /*
19  * Packet Size Support Functions
20  */
21 
modem_socket_next_packet_size(struct modem_socket_config * cfg,struct modem_socket * sock)22 uint16_t modem_socket_next_packet_size(struct modem_socket_config *cfg, struct modem_socket *sock)
23 {
24 	uint16_t total = 0U;
25 
26 	k_sem_take(&cfg->sem_lock, K_FOREVER);
27 
28 	if (!sock || !sock->packet_count) {
29 		goto exit;
30 	}
31 
32 	total = sock->packet_sizes[0];
33 
34 exit:
35 	k_sem_give(&cfg->sem_lock);
36 	return total;
37 }
38 
modem_socket_packet_get_total(struct modem_socket * sock)39 static uint16_t modem_socket_packet_get_total(struct modem_socket *sock)
40 {
41 	int i;
42 	uint16_t total = 0U;
43 
44 	if (!sock || !sock->packet_count) {
45 		return 0U;
46 	}
47 
48 	for (i = 0; i < sock->packet_count; i++) {
49 		total += sock->packet_sizes[i];
50 	}
51 
52 	return total;
53 }
54 
modem_socket_packet_drop_first(struct modem_socket * sock)55 static int modem_socket_packet_drop_first(struct modem_socket *sock)
56 {
57 	int i;
58 
59 	if (!sock || !sock->packet_count) {
60 		return -EINVAL;
61 	}
62 
63 	sock->packet_count--;
64 	for (i = 0; i < sock->packet_count; i++) {
65 		sock->packet_sizes[i] = sock->packet_sizes[i + 1];
66 	}
67 
68 	sock->packet_sizes[sock->packet_count] = 0U;
69 	return 0;
70 }
71 
modem_socket_packet_size_update(struct modem_socket_config * cfg,struct modem_socket * sock,int new_total)72 int modem_socket_packet_size_update(struct modem_socket_config *cfg, struct modem_socket *sock,
73 				    int new_total)
74 {
75 	uint16_t old_total = 0U;
76 
77 	if (!sock) {
78 		return -EINVAL;
79 	}
80 
81 	k_sem_take(&cfg->sem_lock, K_FOREVER);
82 
83 	if (new_total < 0) {
84 		new_total += modem_socket_packet_get_total(sock);
85 	}
86 
87 	if (new_total <= 0) {
88 		/* reset outstanding value here */
89 		sock->packet_count = 0U;
90 		sock->packet_sizes[0] = 0U;
91 		k_poll_signal_reset(&sock->sig_data_ready);
92 		k_sem_give(&cfg->sem_lock);
93 		return 0;
94 	}
95 
96 	old_total = modem_socket_packet_get_total(sock);
97 	if (new_total == old_total) {
98 		goto data_ready;
99 	}
100 
101 	/* remove sent packets */
102 	if (new_total < old_total) {
103 		/* remove packets that are not included in new_size */
104 		while (old_total > new_total && sock->packet_count > 0) {
105 			/* handle partial read */
106 			if (old_total - new_total < sock->packet_sizes[0]) {
107 				sock->packet_sizes[0] -= old_total - new_total;
108 				break;
109 			}
110 
111 			old_total -= sock->packet_sizes[0];
112 			modem_socket_packet_drop_first(sock);
113 		}
114 
115 		goto data_ready;
116 	}
117 
118 	/* new packet to add */
119 	if (sock->packet_count >= CONFIG_MODEM_SOCKET_PACKET_COUNT) {
120 		k_sem_give(&cfg->sem_lock);
121 		return -ENOMEM;
122 	}
123 
124 	if (new_total - old_total > 0) {
125 		sock->packet_sizes[sock->packet_count] = new_total - old_total;
126 		sock->packet_count++;
127 	} else {
128 		k_sem_give(&cfg->sem_lock);
129 		return -EINVAL;
130 	}
131 
132 data_ready:
133 	if (sock->packet_sizes[0]) {
134 		k_poll_signal_raise(&sock->sig_data_ready, 0);
135 	} else {
136 		k_poll_signal_reset(&sock->sig_data_ready);
137 	}
138 	k_sem_give(&cfg->sem_lock);
139 	return new_total;
140 }
141 
142 /*
143  * Socket Support Functions
144  */
145 
146 /*
147  * This function reserves a file descriptor from the fdtable, make sure to update the
148  * POSIX_FDS_MAX Kconfig option to support at minimum the required amount of sockets
149  */
modem_socket_get(struct modem_socket_config * cfg,int family,int type,int proto)150 int modem_socket_get(struct modem_socket_config *cfg, int family, int type, int proto)
151 {
152 	int i;
153 
154 	k_sem_take(&cfg->sem_lock, K_FOREVER);
155 
156 	for (i = 0; i < cfg->sockets_len; i++) {
157 		if (cfg->sockets[i].id < cfg->base_socket_id) {
158 			break;
159 		}
160 	}
161 
162 	if (i >= cfg->sockets_len) {
163 		k_sem_give(&cfg->sem_lock);
164 		return -ENOMEM;
165 	}
166 
167 	cfg->sockets[i].sock_fd = z_reserve_fd();
168 	if (cfg->sockets[i].sock_fd < 0) {
169 		k_sem_give(&cfg->sem_lock);
170 		return -errno;
171 	}
172 
173 	cfg->sockets[i].family = family;
174 	cfg->sockets[i].type = type;
175 	cfg->sockets[i].ip_proto = proto;
176 	cfg->sockets[i].id = (cfg->assign_id) ? (i + cfg->base_socket_id) :
177 		(cfg->base_socket_id + cfg->sockets_len);
178 	z_finalize_fd(cfg->sockets[i].sock_fd, &cfg->sockets[i],
179 		      (const struct fd_op_vtable *)cfg->vtable);
180 
181 	k_sem_give(&cfg->sem_lock);
182 	return cfg->sockets[i].sock_fd;
183 }
184 
modem_socket_from_fd(struct modem_socket_config * cfg,int sock_fd)185 struct modem_socket *modem_socket_from_fd(struct modem_socket_config *cfg, int sock_fd)
186 {
187 	int i;
188 
189 	k_sem_take(&cfg->sem_lock, K_FOREVER);
190 
191 	for (i = 0; i < cfg->sockets_len; i++) {
192 		if (cfg->sockets[i].sock_fd == sock_fd) {
193 			k_sem_give(&cfg->sem_lock);
194 			return &cfg->sockets[i];
195 		}
196 	}
197 
198 	k_sem_give(&cfg->sem_lock);
199 
200 	return NULL;
201 }
202 
modem_socket_from_id(struct modem_socket_config * cfg,int id)203 struct modem_socket *modem_socket_from_id(struct modem_socket_config *cfg, int id)
204 {
205 	int i;
206 
207 	if (id < cfg->base_socket_id) {
208 		return NULL;
209 	}
210 
211 	k_sem_take(&cfg->sem_lock, K_FOREVER);
212 
213 	for (i = 0; i < cfg->sockets_len; i++) {
214 		if (cfg->sockets[i].id == id) {
215 			k_sem_give(&cfg->sem_lock);
216 			return &cfg->sockets[i];
217 		}
218 	}
219 
220 	k_sem_give(&cfg->sem_lock);
221 
222 	return NULL;
223 }
224 
modem_socket_from_newid(struct modem_socket_config * cfg)225 struct modem_socket *modem_socket_from_newid(struct modem_socket_config *cfg)
226 {
227 	return modem_socket_from_id(cfg, cfg->base_socket_id + cfg->sockets_len);
228 }
229 
modem_socket_put(struct modem_socket_config * cfg,int sock_fd)230 void modem_socket_put(struct modem_socket_config *cfg, int sock_fd)
231 {
232 	struct modem_socket *sock = modem_socket_from_fd(cfg, sock_fd);
233 
234 	if (!sock) {
235 		return;
236 	}
237 
238 	k_sem_take(&cfg->sem_lock, K_FOREVER);
239 
240 	sock->id = cfg->base_socket_id - 1;
241 	sock->sock_fd = -1;
242 	sock->is_waiting = false;
243 	sock->is_connected = false;
244 	(void)memset(&sock->src, 0, sizeof(struct sockaddr));
245 	(void)memset(&sock->dst, 0, sizeof(struct sockaddr));
246 	memset(&sock->packet_sizes, 0, sizeof(sock->packet_sizes));
247 	sock->packet_count = 0;
248 	k_sem_reset(&sock->sem_data_ready);
249 	k_poll_signal_reset(&sock->sig_data_ready);
250 
251 	k_sem_give(&cfg->sem_lock);
252 }
253 
254 /*
255  * Generic Poll Function
256  */
257 
258 /*
259  * FIXME: The design here makes the poll function non-reentrant for same sockets.
260  * If two different threads poll on two identical sockets we'll end up with unexpected
261  * behavior - the higher priority thread will be unblocked, regardless on which
262  * socket it polled. I think we could live with such limitation though in the
263  * initial implementation, but this should be improved in the future.
264  */
modem_socket_poll(struct modem_socket_config * cfg,struct zsock_pollfd * fds,int nfds,int msecs)265 int modem_socket_poll(struct modem_socket_config *cfg, struct zsock_pollfd *fds, int nfds,
266 		      int msecs)
267 {
268 	struct modem_socket *sock;
269 	int ret, i;
270 	uint8_t found_count = 0;
271 
272 	if (!cfg || nfds > CONFIG_NET_SOCKETS_POLL_MAX) {
273 		return -EINVAL;
274 	}
275 	struct k_poll_event events[nfds];
276 	int eventcount = 0;
277 
278 	for (i = 0; i < nfds; i++) {
279 		sock = modem_socket_from_fd(cfg, fds[i].fd);
280 		if (sock) {
281 			/*
282 			 * Handle user check for POLLOUT events:
283 			 * we consider the socket to always be writable.
284 			 */
285 			if (fds[i].events & ZSOCK_POLLOUT) {
286 				found_count++;
287 				break;
288 			} else if (fds[i].events & ZSOCK_POLLIN) {
289 				k_poll_event_init(&events[eventcount++], K_POLL_TYPE_SIGNAL,
290 						  K_POLL_MODE_NOTIFY_ONLY, &sock->sig_data_ready);
291 				if (sock->packet_sizes[0] > 0U) {
292 					found_count++;
293 					break;
294 				}
295 			}
296 		}
297 	}
298 
299 	/* Avoid waiting on semaphore if we have already found an event */
300 	ret = 0;
301 	if (!found_count) {
302 		k_timeout_t timeout = K_FOREVER;
303 
304 		if (msecs >= 0) {
305 			timeout = K_MSEC(msecs);
306 		}
307 		ret = k_poll(events, eventcount, timeout);
308 	}
309 	/* Reset counter as we reiterate on all polled sockets */
310 	found_count = 0;
311 
312 	for (i = 0; i < nfds; i++) {
313 		sock = modem_socket_from_fd(cfg, fds[i].fd);
314 		if (!sock) {
315 			continue;
316 		}
317 
318 		/*
319 		 * Handle user check for ZSOCK_POLLOUT events:
320 		 * we consider the socket to always be writable.
321 		 */
322 		if (fds[i].events & ZSOCK_POLLOUT) {
323 			fds[i].revents |= ZSOCK_POLLOUT;
324 			found_count++;
325 		} else if ((fds[i].events & ZSOCK_POLLIN) && (sock->packet_sizes[0] > 0U)) {
326 			fds[i].revents |= ZSOCK_POLLIN;
327 			found_count++;
328 		}
329 	}
330 
331 	/* EBUSY, EAGAIN and ETIMEDOUT aren't true errors */
332 	if (ret < 0 && ret != -EBUSY && ret != -EAGAIN && ret != -ETIMEDOUT) {
333 		errno = ret;
334 		return -1;
335 	}
336 
337 	errno = 0;
338 	return found_count;
339 }
340 
modem_socket_poll_prepare(struct modem_socket_config * cfg,struct modem_socket * sock,struct zsock_pollfd * pfd,struct k_poll_event ** pev,struct k_poll_event * pev_end)341 int modem_socket_poll_prepare(struct modem_socket_config *cfg, struct modem_socket *sock,
342 			      struct zsock_pollfd *pfd, struct k_poll_event **pev,
343 			      struct k_poll_event *pev_end)
344 {
345 	if (pfd->events & ZSOCK_POLLIN) {
346 		if (*pev == pev_end) {
347 			errno = ENOMEM;
348 			return -1;
349 		}
350 
351 		k_poll_event_init(*pev, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY,
352 				  &sock->sig_data_ready);
353 		(*pev)++;
354 	}
355 
356 	if (pfd->events & ZSOCK_POLLOUT) {
357 		if (*pev == pev_end) {
358 			errno = ENOMEM;
359 			return -1;
360 		}
361 		/* Not Implemented */
362 		errno = ENOTSUP;
363 		return -1;
364 	}
365 
366 	return 0;
367 }
368 
modem_socket_poll_update(struct modem_socket * sock,struct zsock_pollfd * pfd,struct k_poll_event ** pev)369 int modem_socket_poll_update(struct modem_socket *sock, struct zsock_pollfd *pfd,
370 			     struct k_poll_event **pev)
371 {
372 	ARG_UNUSED(sock);
373 
374 	if (pfd->events & ZSOCK_POLLIN) {
375 		if ((*pev)->state != K_POLL_STATE_NOT_READY) {
376 			pfd->revents |= ZSOCK_POLLIN;
377 		}
378 		(*pev)++;
379 	}
380 
381 	if (pfd->events & ZSOCK_POLLOUT) {
382 		/* Not implemented, but the modem socket is always ready to transmit,
383 		 * so set the revents
384 		 */
385 		pfd->revents |= ZSOCK_POLLOUT;
386 		(*pev)++;
387 	}
388 
389 	return 0;
390 }
391 
modem_socket_wait_data(struct modem_socket_config * cfg,struct modem_socket * sock)392 void modem_socket_wait_data(struct modem_socket_config *cfg, struct modem_socket *sock)
393 {
394 	k_sem_take(&cfg->sem_lock, K_FOREVER);
395 	sock->is_waiting = true;
396 	k_sem_give(&cfg->sem_lock);
397 
398 	k_sem_take(&sock->sem_data_ready, K_FOREVER);
399 }
400 
modem_socket_data_ready(struct modem_socket_config * cfg,struct modem_socket * sock)401 void modem_socket_data_ready(struct modem_socket_config *cfg, struct modem_socket *sock)
402 {
403 	k_sem_take(&cfg->sem_lock, K_FOREVER);
404 
405 	if (sock->is_waiting) {
406 		/* unblock sockets waiting on recv() */
407 		sock->is_waiting = false;
408 		k_sem_give(&sock->sem_data_ready);
409 	}
410 
411 	k_sem_give(&cfg->sem_lock);
412 }
413 
modem_socket_init(struct modem_socket_config * cfg,struct modem_socket * sockets,size_t sockets_len,int base_socket_id,bool assign_id,const struct socket_op_vtable * vtable)414 int modem_socket_init(struct modem_socket_config *cfg, struct modem_socket *sockets,
415 		      size_t sockets_len, int base_socket_id, bool assign_id,
416 		      const struct socket_op_vtable *vtable)
417 {
418 	/* Verify arguments */
419 	if (cfg == NULL || sockets == NULL || sockets_len < 1 || vtable == NULL) {
420 		return -EINVAL;
421 	}
422 
423 	/* Initialize config */
424 	cfg->sockets = sockets;
425 	cfg->sockets_len = sockets_len;
426 	cfg->base_socket_id = base_socket_id;
427 	cfg->assign_id = assign_id;
428 	k_sem_init(&cfg->sem_lock, 1, 1);
429 	cfg->vtable = vtable;
430 
431 	/* Initialize associated sockets */
432 	for (int i = 0; i < cfg->sockets_len; i++) {
433 		/* Clear entire socket structure */
434 		memset(&cfg->sockets[i], 0, sizeof(cfg->sockets[i]));
435 
436 		/* Initialize socket members */
437 		k_sem_init(&cfg->sockets[i].sem_data_ready, 0, 1);
438 		k_poll_signal_init(&cfg->sockets[i].sig_data_ready);
439 		cfg->sockets[i].id = -1;
440 	}
441 	return 0;
442 }
443 
modem_socket_is_allocated(const struct modem_socket_config * cfg,const struct modem_socket * sock)444 bool modem_socket_is_allocated(const struct modem_socket_config *cfg,
445 			       const struct modem_socket *sock)
446 {
447 	/* Socket is allocated with a reserved id value if id is not dynamically assigned */
448 	if (cfg->assign_id == false && sock->id == (cfg->base_socket_id + cfg->sockets_len)) {
449 		return true;
450 	}
451 
452 	/* Socket must have been allocated if id is assigned */
453 	return modem_socket_id_is_assigned(cfg, sock);
454 }
455 
modem_socket_id_is_assigned(const struct modem_socket_config * cfg,const struct modem_socket * sock)456 bool modem_socket_id_is_assigned(const struct modem_socket_config *cfg,
457 				 const struct modem_socket *sock)
458 {
459 	/* Verify socket is assigned to a valid value */
460 	if ((cfg->base_socket_id <= sock->id) &&
461 		(sock->id < (cfg->base_socket_id + cfg->sockets_len))) {
462 		return true;
463 	}
464 	return false;
465 }
466 
modem_socket_id_assign(const struct modem_socket_config * cfg,struct modem_socket * sock,int id)467 int modem_socket_id_assign(const struct modem_socket_config *cfg,
468 			   struct modem_socket *sock, int id)
469 {
470 	/* Verify dynamically assigning id is disabled */
471 	if (cfg->assign_id) {
472 		return -EPERM;
473 	}
474 
475 	/* Verify id is currently not assigned */
476 	if (modem_socket_id_is_assigned(cfg, sock)) {
477 		return -EPERM;
478 	}
479 
480 	/* Verify id is valid */
481 	if (id < cfg->base_socket_id || (cfg->base_socket_id + cfg->sockets_len) <= id) {
482 		return -EINVAL;
483 	}
484 
485 	/* Assign id */
486 	sock->id = id;
487 	return 0;
488 }
489