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 <kernel.h>
14 #include <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,
23 				    struct modem_socket *sock)
24 {
25 	uint16_t total = 0U;
26 
27 	k_sem_take(&cfg->sem_lock, K_FOREVER);
28 
29 	if (!sock || !sock->packet_count) {
30 		goto exit;
31 	}
32 
33 	total = sock->packet_sizes[0];
34 
35 exit:
36 	k_sem_give(&cfg->sem_lock);
37 	return total;
38 }
39 
modem_socket_packet_get_total(struct modem_socket * sock)40 static uint16_t modem_socket_packet_get_total(struct modem_socket *sock)
41 {
42 	int i;
43 	uint16_t total = 0U;
44 
45 	if (!sock || !sock->packet_count) {
46 		return 0U;
47 	}
48 
49 	for (i = 0; i < sock->packet_count; i++) {
50 		total += sock->packet_sizes[i];
51 	}
52 
53 	return total;
54 }
55 
modem_socket_packet_drop_first(struct modem_socket * sock)56 static int modem_socket_packet_drop_first(struct modem_socket *sock)
57 {
58 	int i;
59 
60 	if (!sock || !sock->packet_count) {
61 		return -EINVAL;
62 	}
63 
64 	sock->packet_count--;
65 	for (i = 0; i < sock->packet_count; i++) {
66 		sock->packet_sizes[i] =
67 			sock->packet_sizes[i + 1];
68 	}
69 
70 	sock->packet_sizes[sock->packet_count] = 0U;
71 	return 0;
72 }
73 
modem_socket_packet_size_update(struct modem_socket_config * cfg,struct modem_socket * sock,int new_total)74 int modem_socket_packet_size_update(struct modem_socket_config *cfg,
75 				    struct modem_socket *sock, int new_total)
76 {
77 	uint16_t old_total = 0U;
78 
79 	if (!sock) {
80 		return -EINVAL;
81 	}
82 
83 	k_sem_take(&cfg->sem_lock, K_FOREVER);
84 
85 	if (new_total < 0) {
86 		new_total += modem_socket_packet_get_total(sock);
87 	}
88 
89 	if (new_total <= 0) {
90 		/* reset outstanding value here */
91 		sock->packet_count = 0U;
92 		sock->packet_sizes[0] = 0U;
93 		k_sem_give(&cfg->sem_lock);
94 		return 0;
95 	}
96 
97 	old_total = modem_socket_packet_get_total(sock);
98 	if (new_total == old_total) {
99 		goto data_ready;
100 	}
101 
102 	/* remove sent packets */
103 	if (new_total < old_total) {
104 		/* remove packets that are not included in new_size */
105 		while (old_total > new_total && sock->packet_count > 0) {
106 			/* handle partial read */
107 			if (old_total - new_total < sock->packet_sizes[0]) {
108 				sock->packet_sizes[0] -= old_total - new_total;
109 				break;
110 			}
111 
112 			old_total -= sock->packet_sizes[0];
113 			modem_socket_packet_drop_first(sock);
114 		}
115 
116 		goto data_ready;
117 	}
118 
119 	/* new packet to add */
120 	if (sock->packet_count >= CONFIG_MODEM_SOCKET_PACKET_COUNT) {
121 		k_sem_give(&cfg->sem_lock);
122 		return -ENOMEM;
123 	}
124 
125 	if (new_total - old_total > 0) {
126 		sock->packet_sizes[sock->packet_count] = new_total - old_total;
127 		sock->packet_count++;
128 	} else {
129 		k_sem_give(&cfg->sem_lock);
130 		return -EINVAL;
131 	}
132 
133 data_ready:
134 	k_sem_give(&cfg->sem_lock);
135 	return new_total;
136 }
137 
138 /*
139  * Socket Support Functions
140  */
141 
modem_socket_get(struct modem_socket_config * cfg,int family,int type,int proto)142 int modem_socket_get(struct modem_socket_config *cfg,
143 		     int family, int type, int proto)
144 {
145 	int i;
146 
147 	k_sem_take(&cfg->sem_lock, K_FOREVER);
148 
149 	for (i = 0; i < cfg->sockets_len; i++) {
150 		if (cfg->sockets[i].id < cfg->base_socket_num) {
151 			break;
152 		}
153 	}
154 
155 	if (i >= cfg->sockets_len) {
156 		k_sem_give(&cfg->sem_lock);
157 		return -ENOMEM;
158 	}
159 
160 	/* FIXME: 4 fds max now due to POSIX_OS conflict */
161 	cfg->sockets[i].sock_fd = z_reserve_fd();
162 	if (cfg->sockets[i].sock_fd < 0) {
163 		k_sem_give(&cfg->sem_lock);
164 		return -errno;
165 	}
166 
167 	cfg->sockets[i].family = family;
168 	cfg->sockets[i].type = type;
169 	cfg->sockets[i].ip_proto = proto;
170 	/* socket # needs assigning */
171 	cfg->sockets[i].id = cfg->sockets_len + 1;
172 	z_finalize_fd(cfg->sockets[i].sock_fd, &cfg->sockets[i],
173 		      (const struct fd_op_vtable *)cfg->vtable);
174 
175 	k_sem_give(&cfg->sem_lock);
176 	return cfg->sockets[i].sock_fd;
177 }
178 
modem_socket_from_fd(struct modem_socket_config * cfg,int sock_fd)179 struct modem_socket *modem_socket_from_fd(struct modem_socket_config *cfg,
180 					  int sock_fd)
181 {
182 	int i;
183 
184 	k_sem_take(&cfg->sem_lock, K_FOREVER);
185 
186 	for (i = 0; i < cfg->sockets_len; i++) {
187 		if (cfg->sockets[i].sock_fd == sock_fd) {
188 			k_sem_give(&cfg->sem_lock);
189 			return &cfg->sockets[i];
190 		}
191 	}
192 
193 	k_sem_give(&cfg->sem_lock);
194 
195 	return NULL;
196 }
197 
modem_socket_from_id(struct modem_socket_config * cfg,int id)198 struct modem_socket *modem_socket_from_id(struct modem_socket_config *cfg,
199 					  int id)
200 {
201 	int i;
202 
203 	if (id < cfg->base_socket_num) {
204 		return NULL;
205 	}
206 
207 	k_sem_take(&cfg->sem_lock, K_FOREVER);
208 
209 	for (i = 0; i < cfg->sockets_len; i++) {
210 		if (cfg->sockets[i].id == id) {
211 			k_sem_give(&cfg->sem_lock);
212 			return &cfg->sockets[i];
213 		}
214 	}
215 
216 	k_sem_give(&cfg->sem_lock);
217 
218 	return NULL;
219 }
220 
modem_socket_from_newid(struct modem_socket_config * cfg)221 struct modem_socket *modem_socket_from_newid(struct modem_socket_config *cfg)
222 {
223 	return modem_socket_from_id(cfg, cfg->sockets_len + 1);
224 }
225 
modem_socket_put(struct modem_socket_config * cfg,int sock_fd)226 void modem_socket_put(struct modem_socket_config *cfg, int sock_fd)
227 {
228 	struct modem_socket *sock = modem_socket_from_fd(cfg, sock_fd);
229 
230 	if (!sock) {
231 		return;
232 	}
233 
234 	k_sem_take(&cfg->sem_lock, K_FOREVER);
235 
236 	sock->id = cfg->base_socket_num - 1;
237 	sock->sock_fd = -1;
238 	sock->is_waiting = false;
239 	sock->is_polled = false;
240 	sock->is_connected = false;
241 	(void)memset(&sock->src, 0, sizeof(struct sockaddr));
242 	(void)memset(&sock->dst, 0, sizeof(struct sockaddr));
243 	memset(&sock->packet_sizes, 0, sizeof(sock->packet_sizes));
244 	sock->packet_count = 0;
245 	k_sem_reset(&sock->sem_data_ready);
246 
247 	k_sem_give(&cfg->sem_lock);
248 }
249 
250 /*
251  * Generic Poll Function
252  */
253 
254 /*
255  * FIXME: The design here makes the poll function non-reentrant. If two
256  * different threads poll on two different sockets we'll end up with unexpected
257  * behavior - the higher priority thread will be unblocked, regardless on which
258  * socket it polled. I think we could live with such limitation though in the
259  * initial implementation, but this should be improved in the future.
260  */
modem_socket_poll(struct modem_socket_config * cfg,struct zsock_pollfd * fds,int nfds,int msecs)261 int modem_socket_poll(struct modem_socket_config *cfg,
262 		      struct zsock_pollfd *fds, int nfds, int msecs)
263 {
264 	struct modem_socket *sock;
265 	int ret, i;
266 	uint8_t found_count = 0;
267 
268 	if (!cfg) {
269 		return -EINVAL;
270 	}
271 
272 	k_sem_reset(&cfg->sem_poll);
273 
274 	for (i = 0; i < nfds; i++) {
275 		sock = modem_socket_from_fd(cfg, fds[i].fd);
276 		if (sock) {
277 			/*
278 			 * Handle user check for POLLOUT events:
279 			 * we consider the socket to always be writable.
280 			 */
281 			if (fds[i].events & ZSOCK_POLLOUT) {
282 				found_count++;
283 				break;
284 			} else if (fds[i].events & ZSOCK_POLLIN) {
285 				sock->is_polled = true;
286 
287 				/*
288 				 * Handle check done after data reception on
289 				 * the socket. In this case that was received
290 				 * but as the socket wasn't polled, no sem_poll
291 				 * semaphore was given at that time. Therefore
292 				 * if there is a polled socket with data,
293 				 * increment found_count to escape the
294 				 * k_sem_take().
295 				 */
296 				if (sock->packet_sizes[0] > 0U) {
297 					found_count++;
298 					break;
299 				}
300 			}
301 		}
302 	}
303 
304 	/* Avoid waiting on semaphore if we have already found an event */
305 	ret = 0;
306 	if (!found_count) {
307 		ret = k_sem_take(&cfg->sem_poll, K_MSEC(msecs));
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) &&
326 			   (sock->packet_sizes[0] > 0U)) {
327 			fds[i].revents |= ZSOCK_POLLIN;
328 			found_count++;
329 		}
330 
331 		sock->is_polled = false;
332 	}
333 
334 	/* EBUSY, EAGAIN and ETIMEDOUT aren't true errors */
335 	if (ret < 0 && ret != -EBUSY && ret != -EAGAIN && ret != -ETIMEDOUT) {
336 		errno = ret;
337 		return -1;
338 	}
339 
340 	errno = 0;
341 	return found_count;
342 }
343 
modem_socket_wait_data(struct modem_socket_config * cfg,struct modem_socket * sock)344 void modem_socket_wait_data(struct modem_socket_config *cfg,
345 			    struct modem_socket *sock)
346 {
347 	k_sem_take(&cfg->sem_lock, K_FOREVER);
348 	sock->is_waiting = true;
349 	k_sem_give(&cfg->sem_lock);
350 
351 	k_sem_take(&sock->sem_data_ready, K_FOREVER);
352 }
353 
modem_socket_data_ready(struct modem_socket_config * cfg,struct modem_socket * sock)354 void modem_socket_data_ready(struct modem_socket_config *cfg,
355 			     struct modem_socket *sock)
356 {
357 	k_sem_take(&cfg->sem_lock, K_FOREVER);
358 
359 	if (sock->is_waiting) {
360 		/* unblock sockets waiting on recv() */
361 		sock->is_waiting = false;
362 		k_sem_give(&sock->sem_data_ready);
363 	}
364 
365 	if (sock->is_polled) {
366 		/* unblock poll() */
367 		k_sem_give(&cfg->sem_poll);
368 	}
369 
370 	k_sem_give(&cfg->sem_lock);
371 }
372 
modem_socket_init(struct modem_socket_config * cfg,const struct socket_op_vtable * vtable)373 int modem_socket_init(struct modem_socket_config *cfg,
374 		      const struct socket_op_vtable *vtable)
375 {
376 	int i;
377 
378 	k_sem_init(&cfg->sem_poll, 0, 1);
379 	k_sem_init(&cfg->sem_lock, 1, 1);
380 	for (i = 0; i < cfg->sockets_len; i++) {
381 		k_sem_init(&cfg->sockets[i].sem_data_ready, 0, 1);
382 		cfg->sockets[i].id = cfg->base_socket_num - 1;
383 	}
384 
385 	cfg->vtable = vtable;
386 
387 	return 0;
388 }
389