1 /*
2 * Copyright (c) 2019-2020 Foundries.io
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT u_blox_sara_r4
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(modem_ublox_sara_r4, CONFIG_MODEM_LOG_LEVEL);
11
12 #include <zephyr/kernel.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/device.h>
17 #include <zephyr/init.h>
18 #include <zephyr/posix/fcntl.h>
19
20 #include <zephyr/net/net_if.h>
21 #include <zephyr/net/net_offload.h>
22 #include <zephyr/net/offloaded_netdev.h>
23 #include <zephyr/net/socket_offload.h>
24
25 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
26 #include <stdio.h>
27 #endif
28
29 #include "modem_context.h"
30 #include "modem_socket.h"
31 #include "modem_cmd_handler.h"
32 #include "modem_iface_uart.h"
33
34 #if !defined(CONFIG_MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO)
35 #define CONFIG_MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO ""
36 #endif
37
38
39 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
40 #include "tls_internal.h"
41 #include <zephyr/net/tls_credentials.h>
42 #endif
43
44 /* pin settings */
45 static const struct gpio_dt_spec power_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_power_gpios);
46 #if DT_INST_NODE_HAS_PROP(0, mdm_reset_gpios)
47 static const struct gpio_dt_spec reset_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_reset_gpios);
48 #endif
49 #if DT_INST_NODE_HAS_PROP(0, mdm_vint_gpios)
50 static const struct gpio_dt_spec vint_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_vint_gpios);
51 #endif
52
53 #define MDM_UART_NODE DT_INST_BUS(0)
54 #define MDM_UART_DEV DEVICE_DT_GET(MDM_UART_NODE)
55
56 #define MDM_RESET_NOT_ASSERTED 1
57 #define MDM_RESET_ASSERTED 0
58
59 #define MDM_CMD_TIMEOUT K_SECONDS(10)
60 #define MDM_DNS_TIMEOUT K_SECONDS(70)
61 #define MDM_CMD_CONN_TIMEOUT K_SECONDS(120)
62 #define MDM_REGISTRATION_TIMEOUT K_SECONDS(180)
63 #define MDM_PROMPT_CMD_DELAY K_MSEC(50)
64
65 #define MDM_MAX_DATA_LENGTH 1024
66 #define MDM_RECV_MAX_BUF 30
67 #define MDM_RECV_BUF_SIZE 128
68
69 #define MDM_MAX_SOCKETS 6
70 #define MDM_BASE_SOCKET_NUM 0
71
72 #define MDM_NETWORK_RETRY_COUNT 3
73 #define MDM_WAIT_FOR_RSSI_COUNT 10
74 #define MDM_WAIT_FOR_RSSI_DELAY K_SECONDS(2)
75
76 #define MDM_MANUFACTURER_LENGTH 10
77 #define MDM_MODEL_LENGTH 16
78 #define MDM_REVISION_LENGTH 64
79 #define MDM_IMEI_LENGTH 16
80 #define MDM_IMSI_LENGTH 16
81 #define MDM_APN_LENGTH 32
82 #define MDM_MAX_CERT_LENGTH 8192
83 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
84 #define MDM_VARIANT_UBLOX_R4 4
85 #define MDM_VARIANT_UBLOX_U2 2
86 #endif
87
88 NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE,
89 0, NULL);
90
91 /* RX thread structures */
92 K_KERNEL_STACK_DEFINE(modem_rx_stack,
93 CONFIG_MODEM_UBLOX_SARA_R4_RX_STACK_SIZE);
94 struct k_thread modem_rx_thread;
95
96 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
97 /* RX thread work queue */
98 K_KERNEL_STACK_DEFINE(modem_workq_stack,
99 CONFIG_MODEM_UBLOX_SARA_R4_RX_WORKQ_STACK_SIZE);
100 static struct k_work_q modem_workq;
101 #endif
102
103 /* socket read callback data */
104 struct socket_read_data {
105 char *recv_buf;
106 size_t recv_buf_len;
107 struct sockaddr *recv_addr;
108 uint16_t recv_read_len;
109 };
110
111 /* driver data */
112 struct modem_data {
113 struct net_if *net_iface;
114 uint8_t mac_addr[6];
115
116 /* modem interface */
117 struct modem_iface_uart_data iface_data;
118 uint8_t iface_rb_buf[MDM_MAX_DATA_LENGTH];
119
120 /* modem cmds */
121 struct modem_cmd_handler_data cmd_handler_data;
122 uint8_t cmd_match_buf[MDM_RECV_BUF_SIZE + 1];
123
124 /* socket data */
125 struct modem_socket_config socket_config;
126 struct modem_socket sockets[MDM_MAX_SOCKETS];
127
128 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
129 /* RSSI work */
130 struct k_work_delayable rssi_query_work;
131 #endif
132
133 /* modem data */
134 char mdm_manufacturer[MDM_MANUFACTURER_LENGTH];
135 char mdm_model[MDM_MODEL_LENGTH];
136 char mdm_revision[MDM_REVISION_LENGTH];
137 char mdm_imei[MDM_IMEI_LENGTH];
138 char mdm_imsi[MDM_IMSI_LENGTH];
139 int mdm_rssi;
140
141 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
142 /* modem variant */
143 int mdm_variant;
144 #endif
145 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
146 /* APN */
147 char mdm_apn[MDM_APN_LENGTH];
148 #endif
149
150 /* modem state */
151 int ev_creg;
152
153 /* bytes written to socket in last transaction */
154 int sock_written;
155
156 /* response semaphore */
157 struct k_sem sem_response;
158
159 /* prompt semaphore */
160 struct k_sem sem_prompt;
161 };
162
163 static struct modem_data mdata;
164 static struct modem_context mctx;
165
166 #if defined(CONFIG_DNS_RESOLVER)
167 static struct zsock_addrinfo result;
168 static struct sockaddr result_addr;
169 static char result_canonname[DNS_MAX_NAME_SIZE + 1];
170 #endif
171
172 /* helper macro to keep readability */
173 #define ATOI(s_, value_, desc_) modem_atoi(s_, value_, desc_, __func__)
174
175 /**
176 * @brief Convert string to long integer, but handle errors
177 *
178 * @param s: string with representation of integer number
179 * @param err_value: on error return this value instead
180 * @param desc: name the string being converted
181 * @param func: function where this is called (typically __func__)
182 *
183 * @retval return integer conversion on success, or err_value on error
184 */
modem_atoi(const char * s,const int err_value,const char * desc,const char * func)185 static int modem_atoi(const char *s, const int err_value,
186 const char *desc, const char *func)
187 {
188 int ret;
189 char *endptr;
190
191 ret = (int)strtol(s, &endptr, 10);
192 if (!endptr || *endptr != '\0') {
193 LOG_ERR("bad %s '%s' in %s", s, desc,
194 func);
195 return err_value;
196 }
197
198 return ret;
199 }
200
201 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
202
203 /* the list of SIM profiles. Global scope, so the app can change it */
204 const char *modem_sim_profiles =
205 CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN_PROFILES;
206
find_apn(char * apn,int apnlen,const char * profiles,const char * imsi)207 int find_apn(char *apn, int apnlen, const char *profiles, const char *imsi)
208 {
209 int rc = -1;
210
211 /* try to find a match */
212 char *s = strstr(profiles, imsi);
213
214 if (s) {
215 char *eos;
216
217 /* find the assignment operator preceding the match */
218 while (s >= profiles && !strchr("=", *s)) {
219 s--;
220 }
221 /* find the apn preceding the assignment operator */
222 while (s >= profiles && strchr(" =", *s)) {
223 s--;
224 }
225
226 /* mark end of apn string */
227 eos = s+1;
228
229 /* find first character of the apn */
230 while (s >= profiles && !strchr(" ,", *s)) {
231 s--;
232 }
233 s++;
234
235 /* copy the key */
236 if (s >= profiles) {
237 int len = eos - s;
238
239 if (len < apnlen) {
240 memcpy(apn, s, len);
241 apn[len] = '\0';
242 rc = 0;
243 } else {
244 LOG_ERR("buffer overflow");
245 }
246 }
247 }
248
249 return rc;
250 }
251
252 /* try to detect APN automatically, based on IMSI */
modem_detect_apn(const char * imsi)253 int modem_detect_apn(const char *imsi)
254 {
255 int rc = -1;
256
257 if (imsi != NULL && strlen(imsi) >= 5) {
258
259 /* extract MMC and MNC from IMSI */
260 char mmcmnc[6];
261 *mmcmnc = 0;
262 strncat(mmcmnc, imsi, sizeof(mmcmnc)-1);
263
264 /* try to find a matching IMSI, and assign the APN */
265 rc = find_apn(mdata.mdm_apn,
266 sizeof(mdata.mdm_apn),
267 modem_sim_profiles,
268 mmcmnc);
269 if (rc < 0) {
270 rc = find_apn(mdata.mdm_apn,
271 sizeof(mdata.mdm_apn),
272 modem_sim_profiles,
273 "*");
274 }
275 }
276
277 if (rc == 0) {
278 LOG_INF("Assign APN: \"%s\"", mdata.mdm_apn);
279 }
280
281 return rc;
282 }
283 #endif
284
285 /* Forward declaration */
286 MODEM_CMD_DEFINE(on_cmd_sockwrite);
287
288 /* send binary data via the +USO[ST/WR] commands */
send_socket_data(void * obj,const struct msghdr * msg,k_timeout_t timeout)289 static ssize_t send_socket_data(void *obj,
290 const struct msghdr *msg,
291 k_timeout_t timeout)
292 {
293 int ret;
294 char send_buf[sizeof("AT+USO**=###,"
295 "!####.####.####.####.####.####.####.####!,"
296 "#####,#########\r\n")];
297 uint16_t dst_port = 0U;
298 struct modem_socket *sock = (struct modem_socket *)obj;
299 const struct modem_cmd handler_cmds[] = {
300 MODEM_CMD("+USOST: ", on_cmd_sockwrite, 2U, ","),
301 MODEM_CMD("+USOWR: ", on_cmd_sockwrite, 2U, ","),
302 };
303 struct sockaddr *dst_addr = msg->msg_name;
304 size_t buf_len = 0;
305
306 if (!sock) {
307 return -EINVAL;
308 }
309
310 for (int i = 0; i < msg->msg_iovlen; i++) {
311 if (!msg->msg_iov[i].iov_base || msg->msg_iov[i].iov_len == 0) {
312 errno = EINVAL;
313 return -1;
314 }
315 buf_len += msg->msg_iov[i].iov_len;
316 }
317
318 if (!sock->is_connected && sock->ip_proto != IPPROTO_UDP) {
319 errno = ENOTCONN;
320 return -1;
321 }
322
323 if (!dst_addr && sock->ip_proto == IPPROTO_UDP) {
324 dst_addr = &sock->dst;
325 }
326
327 /*
328 * Binary and ASCII mode allows sending MDM_MAX_DATA_LENGTH bytes to
329 * the socket in one command
330 */
331 if (buf_len > MDM_MAX_DATA_LENGTH) {
332 if (sock->type == SOCK_DGRAM) {
333 errno = EMSGSIZE;
334 return -1;
335 }
336
337 buf_len = MDM_MAX_DATA_LENGTH;
338 }
339
340 /* The number of bytes written will be reported by the modem */
341 mdata.sock_written = 0;
342
343 if (sock->ip_proto == IPPROTO_UDP) {
344 char ip_str[NET_IPV6_ADDR_LEN];
345
346 ret = modem_context_sprint_ip_addr(dst_addr, ip_str, sizeof(ip_str));
347 if (ret != 0) {
348 LOG_ERR("Error formatting IP string %d", ret);
349 goto exit;
350 }
351
352 ret = modem_context_get_addr_port(dst_addr, &dst_port);
353 if (ret != 0) {
354 LOG_ERR("Error getting port from IP address %d", ret);
355 goto exit;
356 }
357
358 snprintk(send_buf, sizeof(send_buf),
359 "AT+USOST=%d,\"%s\",%u,%zu", sock->id,
360 ip_str,
361 dst_port, buf_len);
362 } else {
363 snprintk(send_buf, sizeof(send_buf), "AT+USOWR=%d,%zu",
364 sock->id, buf_len);
365 }
366
367 k_sem_take(&mdata.cmd_handler_data.sem_tx_lock, K_FOREVER);
368
369 /* Reset prompt '@' semaphore */
370 k_sem_reset(&mdata.sem_prompt);
371
372 ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler,
373 NULL, 0U, send_buf, NULL, K_NO_WAIT);
374 if (ret < 0) {
375 goto exit;
376 }
377
378 /* set command handlers */
379 ret = modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
380 handler_cmds,
381 ARRAY_SIZE(handler_cmds),
382 true);
383 if (ret < 0) {
384 goto exit;
385 }
386
387 /* Wait for prompt '@' */
388 ret = k_sem_take(&mdata.sem_prompt, K_SECONDS(1));
389 if (ret != 0) {
390 ret = -ETIMEDOUT;
391 LOG_ERR("No @ prompt received");
392 goto exit;
393 }
394
395 /*
396 * The AT commands manual requires a 50 ms wait
397 * after '@' prompt if using AT+USOWR, but not
398 * if using AT+USOST. This if condition is matched with
399 * the command selection above.
400 */
401 if (sock->ip_proto != IPPROTO_UDP) {
402 k_sleep(MDM_PROMPT_CMD_DELAY);
403 }
404
405 /* Reset response semaphore before sending data
406 * So that we are sure that we won't use a previously pending one
407 * And we won't miss the one that is going to be freed
408 */
409 k_sem_reset(&mdata.sem_response);
410
411 /* Send data directly on modem iface */
412 for (int i = 0; i < msg->msg_iovlen; i++) {
413 int len = MIN(buf_len, msg->msg_iov[i].iov_len);
414
415 if (len == 0) {
416 break;
417 }
418 mctx.iface.write(&mctx.iface, msg->msg_iov[i].iov_base, len);
419 buf_len -= len;
420 }
421
422 if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
423 ret = 0;
424 goto exit;
425 }
426 ret = k_sem_take(&mdata.sem_response, timeout);
427
428 if (ret == 0) {
429 ret = modem_cmd_handler_get_error(&mdata.cmd_handler_data);
430 } else if (ret == -EAGAIN) {
431 ret = -ETIMEDOUT;
432 }
433
434 exit:
435 /* unset handler commands and ignore any errors */
436 (void)modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
437 NULL, 0U, false);
438 k_sem_give(&mdata.cmd_handler_data.sem_tx_lock);
439
440 if (ret < 0) {
441 return ret;
442 }
443
444 return mdata.sock_written;
445 }
446
447 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
448 /* send binary data via the +USO[ST/WR] commands */
send_cert(struct modem_socket * sock,struct modem_cmd * handler_cmds,size_t handler_cmds_len,const char * cert_data,size_t cert_len,int cert_type)449 static ssize_t send_cert(struct modem_socket *sock,
450 struct modem_cmd *handler_cmds,
451 size_t handler_cmds_len,
452 const char *cert_data, size_t cert_len,
453 int cert_type)
454 {
455 int ret;
456 char *filename = "ca";
457 char send_buf[sizeof("AT+USECMNG=#,#,!####!,####\r\n")];
458
459 /* TODO support other cert types as well */
460 if (cert_type != 0) {
461 return -EINVAL;
462 }
463
464 if (!sock) {
465 return -EINVAL;
466 }
467
468 __ASSERT_NO_MSG(cert_len <= MDM_MAX_CERT_LENGTH);
469
470 snprintk(send_buf, sizeof(send_buf),
471 "AT+USECMNG=0,%d,\"%s\",%d", cert_type, filename, cert_len);
472
473 k_sem_take(&mdata.cmd_handler_data.sem_tx_lock, K_FOREVER);
474
475 ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler,
476 NULL, 0U, send_buf, NULL, K_NO_WAIT);
477 if (ret < 0) {
478 goto exit;
479 }
480
481 /* set command handlers */
482 ret = modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
483 handler_cmds, handler_cmds_len,
484 true);
485 if (ret < 0) {
486 goto exit;
487 }
488
489 /* slight pause per spec so that @ prompt is received */
490 k_sleep(MDM_PROMPT_CMD_DELAY);
491 mctx.iface.write(&mctx.iface, cert_data, cert_len);
492
493 k_sem_reset(&mdata.sem_response);
494 ret = k_sem_take(&mdata.sem_response, K_MSEC(1000));
495
496 if (ret == 0) {
497 ret = modem_cmd_handler_get_error(&mdata.cmd_handler_data);
498 } else if (ret == -EAGAIN) {
499 ret = -ETIMEDOUT;
500 }
501
502 exit:
503 /* unset handler commands and ignore any errors */
504 (void)modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
505 NULL, 0U, false);
506 k_sem_give(&mdata.cmd_handler_data.sem_tx_lock);
507
508 return ret;
509 }
510 #endif
511
512 /*
513 * Modem Response Command Handlers
514 */
515
516 /* Handler: OK */
MODEM_CMD_DEFINE(on_cmd_ok)517 MODEM_CMD_DEFINE(on_cmd_ok)
518 {
519 modem_cmd_handler_set_error(data, 0);
520 k_sem_give(&mdata.sem_response);
521 return 0;
522 }
523
524 /* Handler: @ */
MODEM_CMD_DEFINE(on_prompt)525 MODEM_CMD_DEFINE(on_prompt)
526 {
527 k_sem_give(&mdata.sem_prompt);
528
529 /* A direct cmd should return the number of byte processed.
530 * Therefore, here we always return 1
531 */
532 return 1;
533 }
534
535 /* Handler: ERROR */
MODEM_CMD_DEFINE(on_cmd_error)536 MODEM_CMD_DEFINE(on_cmd_error)
537 {
538 modem_cmd_handler_set_error(data, -EIO);
539 k_sem_give(&mdata.sem_response);
540 return 0;
541 }
542
543 /* Handler: +CME Error: <err>[0] */
MODEM_CMD_DEFINE(on_cmd_exterror)544 MODEM_CMD_DEFINE(on_cmd_exterror)
545 {
546 /* TODO: map extended error codes to values */
547 modem_cmd_handler_set_error(data, -EIO);
548 k_sem_give(&mdata.sem_response);
549 return 0;
550 }
551
552 /*
553 * Modem Info Command Handlers
554 */
555
556 /* Handler: <manufacturer> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_manufacturer)557 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_manufacturer)
558 {
559 size_t out_len;
560
561 out_len = net_buf_linearize(mdata.mdm_manufacturer,
562 sizeof(mdata.mdm_manufacturer) - 1,
563 data->rx_buf, 0, len);
564 mdata.mdm_manufacturer[out_len] = '\0';
565 LOG_INF("Manufacturer: %s", mdata.mdm_manufacturer);
566 return 0;
567 }
568
569 /* Handler: <model> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_model)570 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_model)
571 {
572 size_t out_len;
573
574 out_len = net_buf_linearize(mdata.mdm_model,
575 sizeof(mdata.mdm_model) - 1,
576 data->rx_buf, 0, len);
577 mdata.mdm_model[out_len] = '\0';
578 LOG_INF("Model: %s", mdata.mdm_model);
579
580 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
581 /* Set modem type */
582 if (strstr(mdata.mdm_model, "R4")) {
583 mdata.mdm_variant = MDM_VARIANT_UBLOX_R4;
584 } else {
585 if (strstr(mdata.mdm_model, "U2")) {
586 mdata.mdm_variant = MDM_VARIANT_UBLOX_U2;
587 }
588 }
589 LOG_INF("Variant: %d", mdata.mdm_variant);
590 #endif
591
592 return 0;
593 }
594
595 /* Handler: <rev> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_revision)596 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_revision)
597 {
598 size_t out_len;
599
600 out_len = net_buf_linearize(mdata.mdm_revision,
601 sizeof(mdata.mdm_revision) - 1,
602 data->rx_buf, 0, len);
603 mdata.mdm_revision[out_len] = '\0';
604 LOG_INF("Revision: %s", mdata.mdm_revision);
605 return 0;
606 }
607
608 /* Handler: <IMEI> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imei)609 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imei)
610 {
611 size_t out_len;
612
613 out_len = net_buf_linearize(mdata.mdm_imei, sizeof(mdata.mdm_imei) - 1,
614 data->rx_buf, 0, len);
615 mdata.mdm_imei[out_len] = '\0';
616 LOG_INF("IMEI: %s", mdata.mdm_imei);
617 return 0;
618 }
619
620 /* Handler: <IMSI> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imsi)621 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imsi)
622 {
623 size_t out_len;
624
625 out_len = net_buf_linearize(mdata.mdm_imsi, sizeof(mdata.mdm_imsi) - 1,
626 data->rx_buf, 0, len);
627 mdata.mdm_imsi[out_len] = '\0';
628 LOG_INF("IMSI: %s", mdata.mdm_imsi);
629
630 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
631 /* set the APN automatically */
632 modem_detect_apn(mdata.mdm_imsi);
633 #endif
634
635 return 0;
636 }
637
638 #if !defined(CONFIG_MODEM_UBLOX_SARA_U2)
639 /*
640 * Handler: +CESQ: <rxlev>[0],<ber>[1],<rscp>[2],<ecn0>[3],<rsrq>[4],<rsrp>[5]
641 */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_rssi_cesq)642 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_rssi_cesq)
643 {
644 int rsrp, rxlev;
645
646 rsrp = ATOI(argv[5], 0, "rsrp");
647 rxlev = ATOI(argv[0], 0, "rxlev");
648 if (rsrp >= 0 && rsrp <= 97) {
649 mdata.mdm_rssi = -140 + (rsrp - 1);
650 LOG_INF("RSRP: %d", mdata.mdm_rssi);
651 } else if (rxlev >= 0 && rxlev <= 63) {
652 mdata.mdm_rssi = -110 + (rxlev - 1);
653 LOG_INF("RSSI: %d", mdata.mdm_rssi);
654 } else {
655 mdata.mdm_rssi = -1000;
656 LOG_INF("RSRP/RSSI not known");
657 }
658
659 return 0;
660 }
661 #endif
662
663 #if defined(CONFIG_MODEM_UBLOX_SARA_U2) \
664 || defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
665 /* Handler: +CSQ: <signal_power>[0],<qual>[1] */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_rssi_csq)666 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_rssi_csq)
667 {
668 int rssi;
669
670 rssi = ATOI(argv[0], 0, "signal_power");
671 if (rssi == 31) {
672 mdata.mdm_rssi = -46;
673 } else if (rssi >= 0 && rssi <= 31) {
674 /* FIXME: This value depends on the RAT */
675 mdata.mdm_rssi = -110 + ((rssi * 2) + 1);
676 } else {
677 mdata.mdm_rssi = -1000;
678 }
679
680 LOG_INF("RSSI: %d", mdata.mdm_rssi);
681 return 0;
682 }
683 #endif
684
685 #if defined(CONFIG_MODEM_CELL_INFO)
unquoted_atoi(const char * s,int base)686 static int unquoted_atoi(const char *s, int base)
687 {
688 if (*s == '"') {
689 s++;
690 }
691
692 return strtol(s, NULL, base);
693 }
694
695 /*
696 * Handler: +COPS: <mode>[0],<format>[1],<oper>[2]
697 */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_cops)698 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_cops)
699 {
700 if (argc >= 3) {
701 mctx.data_operator = unquoted_atoi(argv[2], 10);
702 LOG_INF("operator: %u",
703 mctx.data_operator);
704 }
705
706 return 0;
707 }
708
709 /*
710 * Handler: +CEREG: <n>[0],<stat>[1],<tac>[2],<ci>[3],<AcT>[4]
711 */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_cereg)712 MODEM_CMD_DEFINE(on_cmd_atcmdinfo_cereg)
713 {
714 if (argc >= 4) {
715 mctx.data_lac = unquoted_atoi(argv[2], 16);
716 mctx.data_cellid = unquoted_atoi(argv[3], 16);
717 LOG_INF("lac: %u, cellid: %u",
718 mctx.data_lac,
719 mctx.data_cellid);
720 }
721
722 return 0;
723 }
724
725 static const struct setup_cmd query_cellinfo_cmds[] = {
726 SETUP_CMD_NOHANDLE("AT+CEREG=2"),
727 SETUP_CMD("AT+CEREG?", "", on_cmd_atcmdinfo_cereg, 5U, ","),
728 SETUP_CMD_NOHANDLE("AT+COPS=3,2"),
729 SETUP_CMD("AT+COPS?", "", on_cmd_atcmdinfo_cops, 3U, ","),
730 };
731 #endif /* CONFIG_MODEM_CELL_INFO */
732
733 /*
734 * Modem Socket Command Handlers
735 */
736
737 /* Handler: +USOCR: <socket_id>[0] */
MODEM_CMD_DEFINE(on_cmd_sockcreate)738 MODEM_CMD_DEFINE(on_cmd_sockcreate)
739 {
740 struct modem_socket *sock = NULL;
741 int id;
742
743 /* look up new socket by special id */
744 sock = modem_socket_from_newid(&mdata.socket_config);
745 if (sock) {
746 id = ATOI(argv[0], -1, "socket_id");
747
748 /* on error give up modem socket */
749 if (modem_socket_id_assign(&mdata.socket_config, sock, id) < 0) {
750 modem_socket_put(&mdata.socket_config, sock->sock_fd);
751 }
752 }
753
754 /* don't give back semaphore -- OK to follow */
755 return 0;
756 }
757
758 /* Handler: +USO[WR|ST]: <socket_id>[0],<length>[1] */
MODEM_CMD_DEFINE(on_cmd_sockwrite)759 MODEM_CMD_DEFINE(on_cmd_sockwrite)
760 {
761 mdata.sock_written = ATOI(argv[1], 0, "length");
762 LOG_DBG("bytes written: %d", mdata.sock_written);
763 return 0;
764 }
765
766 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
767 /* Handler: +USECMNG: 0,<type>[0],<internal_name>[1],<md5_string>[2] */
MODEM_CMD_DEFINE(on_cmd_cert_write)768 MODEM_CMD_DEFINE(on_cmd_cert_write)
769 {
770 LOG_DBG("cert md5: %s", argv[2]);
771 return 0;
772 }
773 #endif
774
775 /* Common code for +USOR[D|F]: "<data>" */
on_cmd_sockread_common(int socket_id,struct modem_cmd_handler_data * data,int socket_data_length,uint16_t len)776 static int on_cmd_sockread_common(int socket_id,
777 struct modem_cmd_handler_data *data,
778 int socket_data_length, uint16_t len)
779 {
780 struct modem_socket *sock = NULL;
781 struct socket_read_data *sock_data;
782 int ret;
783
784 if (!len) {
785 LOG_ERR("Short +USOR[D|F] value. Aborting!");
786 return -EAGAIN;
787 }
788
789 /*
790 * make sure we still have buf data and next char in the buffer is a
791 * quote.
792 */
793 if (!data->rx_buf || *data->rx_buf->data != '\"') {
794 LOG_ERR("Incorrect format! Ignoring data!");
795 return -EINVAL;
796 }
797
798 /* zero length */
799 if (socket_data_length <= 0) {
800 LOG_ERR("Length problem (%d). Aborting!", socket_data_length);
801 return -EAGAIN;
802 }
803
804 /* check to make sure we have all of the data (minus quotes) */
805 if ((net_buf_frags_len(data->rx_buf) - 2) < socket_data_length) {
806 LOG_DBG("Not enough data -- wait!");
807 return -EAGAIN;
808 }
809
810 /* skip quote */
811 len--;
812 net_buf_pull_u8(data->rx_buf);
813 if (!data->rx_buf->len) {
814 data->rx_buf = net_buf_frag_del(NULL, data->rx_buf);
815 }
816
817 sock = modem_socket_from_id(&mdata.socket_config, socket_id);
818 if (!sock) {
819 LOG_ERR("Socket not found! (%d)", socket_id);
820 ret = -EINVAL;
821 goto exit;
822 }
823
824 sock_data = (struct socket_read_data *)sock->data;
825 if (!sock_data) {
826 LOG_ERR("Socket data not found! Skip handling (%d)", socket_id);
827 ret = -EINVAL;
828 goto exit;
829 }
830
831 ret = net_buf_linearize(sock_data->recv_buf, sock_data->recv_buf_len,
832 data->rx_buf, 0, (uint16_t)socket_data_length);
833 data->rx_buf = net_buf_skip(data->rx_buf, ret);
834 sock_data->recv_read_len = ret;
835 if (ret != socket_data_length) {
836 LOG_ERR("Total copied data is different then received data!"
837 " copied:%d vs. received:%d", ret, socket_data_length);
838 ret = -EINVAL;
839 }
840
841 exit:
842 /* remove packet from list (ignore errors) */
843 (void)modem_socket_packet_size_update(&mdata.socket_config, sock,
844 -socket_data_length);
845
846 /* don't give back semaphore -- OK to follow */
847 return ret;
848 }
849
850 /*
851 * Handler: +USORF: <socket_id>[0],<remote_ip_addr>[1],<remote_port>[2],
852 * <length>[3],"<data>"
853 */
MODEM_CMD_DEFINE(on_cmd_sockreadfrom)854 MODEM_CMD_DEFINE(on_cmd_sockreadfrom)
855 {
856 /* TODO: handle remote_ip_addr */
857
858 return on_cmd_sockread_common(ATOI(argv[0], 0, "socket_id"), data,
859 ATOI(argv[3], 0, "length"), len);
860 }
861
862 /* Handler: +USORD: <socket_id>[0],<length>[1],"<data>" */
MODEM_CMD_DEFINE(on_cmd_sockread)863 MODEM_CMD_DEFINE(on_cmd_sockread)
864 {
865 return on_cmd_sockread_common(ATOI(argv[0], 0, "socket_id"), data,
866 ATOI(argv[1], 0, "length"), len);
867 }
868
869 #if defined(CONFIG_DNS_RESOLVER)
870 /* Handler: +UDNSRN: "<resolved_ip_address>"[0], "<resolved_ip_address>"[1] */
MODEM_CMD_DEFINE(on_cmd_dns)871 MODEM_CMD_DEFINE(on_cmd_dns)
872 {
873 /* chop off end quote */
874 argv[0][strlen(argv[0]) - 1] = '\0';
875
876 /* FIXME: Hard-code DNS on SARA-R4 to return IPv4 */
877 result_addr.sa_family = AF_INET;
878 /* skip beginning quote when parsing */
879 (void)net_addr_pton(result.ai_family, &argv[0][1],
880 &((struct sockaddr_in *)&result_addr)->sin_addr);
881 return 0;
882 }
883 #endif
884
885 /*
886 * MODEM UNSOLICITED NOTIFICATION HANDLERS
887 */
888
889 /* Handler: +UUSOCL: <socket_id>[0] */
MODEM_CMD_DEFINE(on_cmd_socknotifyclose)890 MODEM_CMD_DEFINE(on_cmd_socknotifyclose)
891 {
892 struct modem_socket *sock;
893
894 sock = modem_socket_from_id(&mdata.socket_config,
895 ATOI(argv[0], 0, "socket_id"));
896 if (sock) {
897 sock->is_connected = false;
898 }
899
900 return 0;
901 }
902
903 /* Handler: +UUSOR[D|F]: <socket_id>[0],<length>[1] */
MODEM_CMD_DEFINE(on_cmd_socknotifydata)904 MODEM_CMD_DEFINE(on_cmd_socknotifydata)
905 {
906 int ret, socket_id, new_total;
907 struct modem_socket *sock;
908
909 socket_id = ATOI(argv[0], 0, "socket_id");
910 new_total = ATOI(argv[1], 0, "length");
911 sock = modem_socket_from_id(&mdata.socket_config, socket_id);
912 if (!sock) {
913 return 0;
914 }
915
916 ret = modem_socket_packet_size_update(&mdata.socket_config, sock,
917 new_total);
918 if (ret < 0) {
919 LOG_ERR("socket_id:%d left_bytes:%d err: %d", socket_id,
920 new_total, ret);
921 }
922
923 if (new_total > 0) {
924 modem_socket_data_ready(&mdata.socket_config, sock);
925 }
926
927 return 0;
928 }
929
930 /* Handler: +CREG: <stat>[0] */
MODEM_CMD_DEFINE(on_cmd_socknotifycreg)931 MODEM_CMD_DEFINE(on_cmd_socknotifycreg)
932 {
933 mdata.ev_creg = ATOI(argv[0], 0, "stat");
934 LOG_DBG("CREG:%d", mdata.ev_creg);
935 return 0;
936 }
937
938 /* RX thread */
modem_rx(void)939 static void modem_rx(void)
940 {
941 while (true) {
942 /* wait for incoming data */
943 modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
944
945 modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
946
947 /* give up time if we have a solid stream of data */
948 k_yield();
949 }
950 }
951
pin_init(void)952 static int pin_init(void)
953 {
954 LOG_INF("Setting Modem Pins");
955
956 #if DT_INST_NODE_HAS_PROP(0, mdm_reset_gpios)
957 LOG_DBG("MDM_RESET_PIN -> NOT_ASSERTED");
958 gpio_pin_set_dt(&reset_gpio, MDM_RESET_NOT_ASSERTED);
959 #endif
960
961 LOG_DBG("MDM_POWER_PIN -> ENABLE");
962 gpio_pin_set_dt(&power_gpio, 1);
963 k_sleep(K_SECONDS(4));
964
965 LOG_DBG("MDM_POWER_PIN -> DISABLE");
966 gpio_pin_set_dt(&power_gpio, 0);
967 #if defined(CONFIG_MODEM_UBLOX_SARA_U2)
968 k_sleep(K_SECONDS(1));
969 #else
970 k_sleep(K_SECONDS(4));
971 #endif
972 LOG_DBG("MDM_POWER_PIN -> ENABLE");
973 gpio_pin_set_dt(&power_gpio, 1);
974 k_sleep(K_SECONDS(1));
975
976 /* make sure module is powered off */
977 #if DT_INST_NODE_HAS_PROP(0, mdm_vint_gpios)
978 LOG_DBG("Waiting for MDM_VINT_PIN = 0");
979
980 while (gpio_pin_get_dt(&vint_gpio) > 0) {
981 #if defined(CONFIG_MODEM_UBLOX_SARA_U2)
982 /* try to power off again */
983 LOG_DBG("MDM_POWER_PIN -> DISABLE");
984 gpio_pin_set_dt(&power_gpio, 0);
985 k_sleep(K_SECONDS(1));
986 LOG_DBG("MDM_POWER_PIN -> ENABLE");
987 gpio_pin_set_dt(&power_gpio, 1);
988 #endif
989 k_sleep(K_MSEC(100));
990 }
991 #else
992 k_sleep(K_SECONDS(8));
993 #endif
994
995 LOG_DBG("MDM_POWER_PIN -> DISABLE");
996
997 unsigned int irq_lock_key = irq_lock();
998
999 gpio_pin_set_dt(&power_gpio, 0);
1000 #if defined(CONFIG_MODEM_UBLOX_SARA_U2)
1001 k_usleep(50); /* 50-80 microseconds */
1002 #else
1003 k_sleep(K_SECONDS(1));
1004 #endif
1005 gpio_pin_set_dt(&power_gpio, 1);
1006
1007 irq_unlock(irq_lock_key);
1008
1009 LOG_DBG("MDM_POWER_PIN -> ENABLE");
1010
1011 #if DT_INST_NODE_HAS_PROP(0, mdm_vint_gpios)
1012 LOG_DBG("Waiting for MDM_VINT_PIN = 1");
1013 do {
1014 k_sleep(K_MSEC(100));
1015 } while (gpio_pin_get_dt(&vint_gpio) == 0);
1016 #else
1017 k_sleep(K_SECONDS(10));
1018 #endif
1019
1020 gpio_pin_configure_dt(&power_gpio, GPIO_INPUT);
1021
1022 LOG_INF("... Done!");
1023
1024 return 0;
1025 }
1026
1027 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
modem_rssi_query_work(struct k_work * work)1028 static void modem_rssi_query_work(struct k_work *work)
1029 {
1030 static const struct modem_cmd cmds[] = {
1031 MODEM_CMD("+CSQ: ", on_cmd_atcmdinfo_rssi_csq, 2U, ","),
1032 MODEM_CMD("+CESQ: ", on_cmd_atcmdinfo_rssi_cesq, 6U, ","),
1033 };
1034 const char *send_cmd_u2 = "AT+CSQ";
1035 const char *send_cmd_r4 = "AT+CESQ";
1036 int ret;
1037
1038 /* choose cmd according to variant */
1039 const char *send_cmd = send_cmd_r4;
1040
1041 if (mdata.mdm_variant == MDM_VARIANT_UBLOX_U2) {
1042 send_cmd = send_cmd_u2;
1043 }
1044
1045 /* query modem RSSI */
1046 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1047 cmds, ARRAY_SIZE(cmds),
1048 send_cmd,
1049 &mdata.sem_response,
1050 MDM_CMD_TIMEOUT);
1051 if (ret < 0) {
1052 LOG_ERR("AT+C[E]SQ ret:%d", ret);
1053 }
1054
1055 #if defined(CONFIG_MODEM_CELL_INFO)
1056 /* query cell info */
1057 ret = modem_cmd_handler_setup_cmds_nolock(&mctx.iface,
1058 &mctx.cmd_handler,
1059 query_cellinfo_cmds,
1060 ARRAY_SIZE(query_cellinfo_cmds),
1061 &mdata.sem_response,
1062 MDM_CMD_TIMEOUT);
1063 if (ret < 0) {
1064 LOG_WRN("modem query for cell info returned %d", ret);
1065 }
1066 #endif
1067
1068 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
1069 /* re-start RSSI query work */
1070 if (work) {
1071 k_work_reschedule_for_queue(
1072 &modem_workq, &mdata.rssi_query_work,
1073 K_SECONDS(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK_PERIOD));
1074 }
1075 #endif
1076 }
1077 #else
modem_rssi_query_work(struct k_work * work)1078 static void modem_rssi_query_work(struct k_work *work)
1079 {
1080 static const struct modem_cmd cmd =
1081 #if defined(CONFIG_MODEM_UBLOX_SARA_U2)
1082 MODEM_CMD("+CSQ: ", on_cmd_atcmdinfo_rssi_csq, 2U, ",");
1083 static char *send_cmd = "AT+CSQ";
1084 #else
1085 MODEM_CMD("+CESQ: ", on_cmd_atcmdinfo_rssi_cesq, 6U, ",");
1086 static char *send_cmd = "AT+CESQ";
1087 #endif
1088 int ret;
1089
1090 /* query modem RSSI */
1091 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1092 &cmd, 1U, send_cmd, &mdata.sem_response,
1093 MDM_CMD_TIMEOUT);
1094 if (ret < 0) {
1095 LOG_ERR("AT+C[E]SQ ret:%d", ret);
1096 }
1097
1098 #if defined(CONFIG_MODEM_CELL_INFO)
1099 /* query cell info */
1100 ret = modem_cmd_handler_setup_cmds_nolock(&mctx.iface,
1101 &mctx.cmd_handler,
1102 query_cellinfo_cmds,
1103 ARRAY_SIZE(query_cellinfo_cmds),
1104 &mdata.sem_response,
1105 MDM_CMD_TIMEOUT);
1106 if (ret < 0) {
1107 LOG_WRN("modem query for cell info returned %d", ret);
1108 }
1109 #endif
1110
1111 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
1112 /* re-start RSSI query work */
1113 if (work) {
1114 k_work_reschedule_for_queue(
1115 &modem_workq, &mdata.rssi_query_work,
1116 K_SECONDS(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK_PERIOD));
1117 }
1118 #endif
1119 }
1120 #endif
1121
modem_reset(void)1122 static void modem_reset(void)
1123 {
1124 int ret = 0, retry_count = 0, counter = 0;
1125 static const struct setup_cmd setup_cmds[] = {
1126 /* turn off echo */
1127 SETUP_CMD_NOHANDLE("ATE0"),
1128 /* stop functionality */
1129 SETUP_CMD_NOHANDLE("AT+CFUN=0"),
1130 /* extended error numbers */
1131 SETUP_CMD_NOHANDLE("AT+CMEE=1"),
1132 #if defined(CONFIG_BOARD_PARTICLE_BORON)
1133 /* use external SIM */
1134 SETUP_CMD_NOHANDLE("AT+UGPIOC=23,0,0"),
1135 #endif
1136 #if defined(CONFIG_MODEM_UBLOX_SARA_R4_NET_STATUS_PIN)
1137 /* enable the network status indication */
1138 SETUP_CMD_NOHANDLE("AT+UGPIOC="
1139 STRINGIFY(CONFIG_MODEM_UBLOX_SARA_R4_NET_STATUS_PIN)
1140 ",2"),
1141 #endif
1142 /* UNC messages for registration */
1143 SETUP_CMD_NOHANDLE("AT+CREG=1"),
1144 /* query modem info */
1145 SETUP_CMD("AT+CGMI", "", on_cmd_atcmdinfo_manufacturer, 0U, ""),
1146 SETUP_CMD("AT+CGMM", "", on_cmd_atcmdinfo_model, 0U, ""),
1147 SETUP_CMD("AT+CGMR", "", on_cmd_atcmdinfo_revision, 0U, ""),
1148 SETUP_CMD("AT+CGSN", "", on_cmd_atcmdinfo_imei, 0U, ""),
1149 SETUP_CMD("AT+CIMI", "", on_cmd_atcmdinfo_imsi, 0U, ""),
1150 #if !defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
1151 /* setup PDP context definition */
1152 SETUP_CMD_NOHANDLE("AT+CGDCONT=1,\"IP\",\""
1153 CONFIG_MODEM_UBLOX_SARA_R4_APN "\""),
1154 /* start functionality */
1155 SETUP_CMD_NOHANDLE("AT+CFUN=1"),
1156 #endif
1157 };
1158
1159 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
1160 static const struct setup_cmd post_setup_cmds_u2[] = {
1161 #if !defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
1162 /* set the APN */
1163 SETUP_CMD_NOHANDLE("AT+UPSD=0,1,\""
1164 CONFIG_MODEM_UBLOX_SARA_R4_APN "\""),
1165 #endif
1166 /* set dynamic IP */
1167 SETUP_CMD_NOHANDLE("AT+UPSD=0,7,\"0.0.0.0\""),
1168 /* activate the GPRS connection */
1169 SETUP_CMD_NOHANDLE("AT+UPSDA=0,3"),
1170 };
1171 #endif
1172
1173 static const struct setup_cmd post_setup_cmds[] = {
1174 #if defined(CONFIG_MODEM_UBLOX_SARA_U2)
1175 /* set the APN */
1176 SETUP_CMD_NOHANDLE("AT+UPSD=0,1,\""
1177 CONFIG_MODEM_UBLOX_SARA_R4_APN "\""),
1178 /* set dynamic IP */
1179 SETUP_CMD_NOHANDLE("AT+UPSD=0,7,\"0.0.0.0\""),
1180 /* activate the GPRS connection */
1181 SETUP_CMD_NOHANDLE("AT+UPSDA=0,3"),
1182 #else
1183 /* activate the PDP context */
1184 SETUP_CMD_NOHANDLE("AT+CGACT=1,1"),
1185 #endif
1186 };
1187
1188 restart:
1189
1190 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
1191 mdata.mdm_apn[0] = '\0';
1192 strncat(mdata.mdm_apn,
1193 CONFIG_MODEM_UBLOX_SARA_R4_APN,
1194 sizeof(mdata.mdm_apn)-1);
1195 #endif
1196
1197 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
1198 /* stop RSSI delay work */
1199 k_work_cancel_delayable(&mdata.rssi_query_work);
1200 #endif
1201
1202 pin_init();
1203
1204 LOG_INF("Waiting for modem to respond");
1205
1206 /* Give the modem a while to start responding to simple 'AT' commands.
1207 * Also wait for CSPS=1 or RRCSTATE=1 notification
1208 */
1209 ret = -1;
1210 while (counter++ < 50 && ret < 0) {
1211 k_sleep(K_SECONDS(2));
1212 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1213 NULL, 0, "AT", &mdata.sem_response,
1214 MDM_CMD_TIMEOUT);
1215 if (ret < 0 && ret != -ETIMEDOUT) {
1216 break;
1217 }
1218 }
1219
1220 if (ret < 0) {
1221 LOG_ERR("MODEM WAIT LOOP ERROR: %d", ret);
1222 goto error;
1223 }
1224
1225 ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler,
1226 setup_cmds, ARRAY_SIZE(setup_cmds),
1227 &mdata.sem_response,
1228 MDM_REGISTRATION_TIMEOUT);
1229 if (ret < 0) {
1230 goto error;
1231 }
1232
1233 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
1234 /* autodetect APN from IMSI */
1235 char cmd[sizeof("AT+CGDCONT=1,\"IP\",\"\"")+MDM_APN_LENGTH];
1236
1237 snprintk(cmd, sizeof(cmd), "AT+CGDCONT=1,\"IP\",\"%s\"", mdata.mdm_apn);
1238
1239 /* setup PDP context definition */
1240 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1241 NULL, 0,
1242 (const char *)cmd,
1243 &mdata.sem_response,
1244 MDM_REGISTRATION_TIMEOUT);
1245
1246 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1247 NULL, 0,
1248 "AT+CFUN=1",
1249 &mdata.sem_response,
1250 MDM_REGISTRATION_TIMEOUT);
1251 #endif
1252
1253 if (strlen(CONFIG_MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO) > 0) {
1254 /* use manual MCC/MNO entry */
1255 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1256 NULL, 0,
1257 "AT+COPS=1,2,\""
1258 CONFIG_MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO
1259 "\"",
1260 &mdata.sem_response,
1261 MDM_REGISTRATION_TIMEOUT);
1262 } else {
1263 /* register operator automatically */
1264 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1265 NULL, 0, "AT+COPS=0,0",
1266 &mdata.sem_response,
1267 MDM_REGISTRATION_TIMEOUT);
1268 }
1269
1270 if (ret < 0) {
1271 LOG_ERR("AT+COPS ret:%d", ret);
1272 goto error;
1273 }
1274
1275 LOG_INF("Waiting for network");
1276
1277 /*
1278 * TODO: A lot of this should be setup as a 3GPP module to handle
1279 * basic connection to the network commands / polling
1280 */
1281
1282 /* wait for +CREG: 1(normal) or 5(roaming) */
1283 counter = 0;
1284 while (counter++ < 40 && mdata.ev_creg != 1 && mdata.ev_creg != 5) {
1285 if (counter == 20) {
1286 LOG_WRN("Force restart of RF functionality");
1287
1288 /* Disable RF temporarily */
1289 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1290 NULL, 0, "AT+CFUN=0", &mdata.sem_response,
1291 MDM_CMD_TIMEOUT);
1292
1293 k_sleep(K_SECONDS(1));
1294
1295 /* Enable RF */
1296 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1297 NULL, 0, "AT+CFUN=1", &mdata.sem_response,
1298 MDM_CMD_TIMEOUT);
1299 }
1300
1301 k_sleep(K_SECONDS(1));
1302 }
1303
1304 /* query modem RSSI */
1305 modem_rssi_query_work(NULL);
1306 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
1307
1308 counter = 0;
1309 /* wait for RSSI < 0 and > -1000 */
1310 while (counter++ < MDM_WAIT_FOR_RSSI_COUNT &&
1311 (mdata.mdm_rssi >= 0 ||
1312 mdata.mdm_rssi <= -1000)) {
1313 modem_rssi_query_work(NULL);
1314 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
1315 }
1316
1317 if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) {
1318 retry_count++;
1319 if (retry_count >= MDM_NETWORK_RETRY_COUNT) {
1320 LOG_ERR("Failed network init. Too many attempts!");
1321 ret = -ENETUNREACH;
1322 goto error;
1323 }
1324
1325 LOG_ERR("Failed network init. Restarting process.");
1326 goto restart;
1327 }
1328
1329 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
1330 if (mdata.mdm_variant == MDM_VARIANT_UBLOX_U2) {
1331
1332 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
1333 /* setup PDP context definition */
1334 char cmd[sizeof("AT+UPSD=0,1,\"%s\"")+MDM_APN_LENGTH];
1335
1336 snprintk(cmd, sizeof(cmd), "AT+UPSD=0,1,\"%s\"", mdata.mdm_apn);
1337 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1338 NULL, 0,
1339 (const char *)cmd,
1340 &mdata.sem_response,
1341 MDM_REGISTRATION_TIMEOUT);
1342 #endif
1343 ret = modem_cmd_handler_setup_cmds(&mctx.iface,
1344 &mctx.cmd_handler,
1345 post_setup_cmds_u2,
1346 ARRAY_SIZE(post_setup_cmds_u2),
1347 &mdata.sem_response,
1348 MDM_REGISTRATION_TIMEOUT);
1349 } else {
1350 #endif
1351 ret = modem_cmd_handler_setup_cmds(&mctx.iface,
1352 &mctx.cmd_handler,
1353 post_setup_cmds,
1354 ARRAY_SIZE(post_setup_cmds),
1355 &mdata.sem_response,
1356 MDM_REGISTRATION_TIMEOUT);
1357 #if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
1358 }
1359 #endif
1360 if (ret < 0) {
1361 goto error;
1362 }
1363
1364 LOG_INF("Network is ready.");
1365
1366 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
1367 /* start RSSI query */
1368 k_work_reschedule_for_queue(
1369 &modem_workq, &mdata.rssi_query_work,
1370 K_SECONDS(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK_PERIOD));
1371 #endif
1372
1373 error:
1374 return;
1375 }
1376
1377 /*
1378 * generic socket creation function
1379 * which can be called in bind() or connect()
1380 */
create_socket(struct modem_socket * sock,const struct sockaddr * addr)1381 static int create_socket(struct modem_socket *sock, const struct sockaddr *addr)
1382 {
1383 int ret;
1384 static const struct modem_cmd cmd =
1385 MODEM_CMD("+USOCR: ", on_cmd_sockcreate, 1U, "");
1386 char buf[sizeof("AT+USOCR=#,#####\r")];
1387 uint16_t local_port = 0U, proto = 6U;
1388
1389 if (addr) {
1390 if (addr->sa_family == AF_INET6) {
1391 local_port = ntohs(net_sin6(addr)->sin6_port);
1392 } else if (addr->sa_family == AF_INET) {
1393 local_port = ntohs(net_sin(addr)->sin_port);
1394 }
1395 }
1396
1397 if (sock->ip_proto == IPPROTO_UDP) {
1398 proto = 17U;
1399 }
1400
1401 if (local_port > 0U) {
1402 snprintk(buf, sizeof(buf), "AT+USOCR=%d,%u", proto, local_port);
1403 } else {
1404 snprintk(buf, sizeof(buf), "AT+USOCR=%d", proto);
1405 }
1406
1407 /* create socket */
1408 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1409 &cmd, 1U, buf,
1410 &mdata.sem_response, MDM_CMD_TIMEOUT);
1411 if (ret < 0) {
1412 goto error;
1413 }
1414
1415 if (sock->ip_proto == IPPROTO_TLS_1_2) {
1416 char atbuf[sizeof("AT+USECPRF=#,#,#######\r")];
1417
1418 /* Enable socket security */
1419 snprintk(atbuf, sizeof(atbuf), "AT+USOSEC=%d,1,%d", sock->id, sock->id);
1420 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, atbuf,
1421 &mdata.sem_response, MDM_CMD_TIMEOUT);
1422 if (ret < 0) {
1423 goto error;
1424 }
1425 /* Reset the security profile */
1426 snprintk(atbuf, sizeof(atbuf), "AT+USECPRF=%d", sock->id);
1427 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, atbuf,
1428 &mdata.sem_response, MDM_CMD_TIMEOUT);
1429 if (ret < 0) {
1430 goto error;
1431 }
1432 /* Validate server cert against the CA. */
1433 snprintk(atbuf, sizeof(atbuf), "AT+USECPRF=%d,0,1", sock->id);
1434 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, atbuf,
1435 &mdata.sem_response, MDM_CMD_TIMEOUT);
1436 if (ret < 0) {
1437 goto error;
1438 }
1439 /* Use TLSv1.2 only */
1440 snprintk(atbuf, sizeof(atbuf), "AT+USECPRF=%d,1,3", sock->id);
1441 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, atbuf,
1442 &mdata.sem_response, MDM_CMD_TIMEOUT);
1443 if (ret < 0) {
1444 goto error;
1445 }
1446 /* Set root CA filename */
1447 snprintk(atbuf, sizeof(atbuf), "AT+USECPRF=%d,3,\"ca\"", sock->id);
1448 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, atbuf,
1449 &mdata.sem_response, MDM_CMD_TIMEOUT);
1450 if (ret < 0) {
1451 goto error;
1452 }
1453 }
1454
1455 errno = 0;
1456 return 0;
1457
1458 error:
1459 LOG_ERR("%s ret:%d", buf, ret);
1460 modem_socket_put(&mdata.socket_config, sock->sock_fd);
1461 errno = -ret;
1462 return -1;
1463 }
1464
1465 /*
1466 * Socket Offload OPS
1467 */
1468
1469 static const struct socket_op_vtable offload_socket_fd_op_vtable;
1470
offload_socket(int family,int type,int proto)1471 static int offload_socket(int family, int type, int proto)
1472 {
1473 int ret;
1474
1475 /* defer modem's socket create call to bind() */
1476 ret = modem_socket_get(&mdata.socket_config, family, type, proto);
1477 if (ret < 0) {
1478 errno = -ret;
1479 return -1;
1480 }
1481
1482 errno = 0;
1483 return ret;
1484 }
1485
offload_close(void * obj)1486 static int offload_close(void *obj)
1487 {
1488 struct modem_socket *sock = (struct modem_socket *)obj;
1489 char buf[sizeof("AT+USOCL=#\r")];
1490 int ret;
1491
1492 /* make sure socket is allocated and assigned an id */
1493 if (modem_socket_id_is_assigned(&mdata.socket_config, sock) == false) {
1494 return 0;
1495 }
1496
1497 if (sock->is_connected || sock->ip_proto == IPPROTO_UDP) {
1498 snprintk(buf, sizeof(buf), "AT+USOCL=%d", sock->id);
1499
1500 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1501 NULL, 0U, buf,
1502 &mdata.sem_response, MDM_CMD_TIMEOUT);
1503 if (ret < 0) {
1504 LOG_ERR("%s ret:%d", buf, ret);
1505 }
1506 }
1507
1508 modem_socket_put(&mdata.socket_config, sock->sock_fd);
1509 return 0;
1510 }
1511
offload_bind(void * obj,const struct sockaddr * addr,socklen_t addrlen)1512 static int offload_bind(void *obj, const struct sockaddr *addr,
1513 socklen_t addrlen)
1514 {
1515 struct modem_socket *sock = (struct modem_socket *)obj;
1516
1517 /* save bind address information */
1518 memcpy(&sock->src, addr, sizeof(*addr));
1519
1520 /* make sure we've created the socket */
1521 if (modem_socket_is_allocated(&mdata.socket_config, sock) == true) {
1522 if (create_socket(sock, addr) < 0) {
1523 return -1;
1524 }
1525 }
1526
1527 return 0;
1528 }
1529
offload_connect(void * obj,const struct sockaddr * addr,socklen_t addrlen)1530 static int offload_connect(void *obj, const struct sockaddr *addr,
1531 socklen_t addrlen)
1532 {
1533 struct modem_socket *sock = (struct modem_socket *)obj;
1534 int ret;
1535 char buf[sizeof("AT+USOCO=###,!####.####.####.####.####.####.####.####!,#####,#\r")];
1536 uint16_t dst_port = 0U;
1537 char ip_str[NET_IPV6_ADDR_LEN];
1538
1539 if (!addr) {
1540 errno = EINVAL;
1541 return -1;
1542 }
1543
1544 /* make sure socket has been allocated */
1545 if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) {
1546 LOG_ERR("Invalid socket_id(%d) from fd:%d",
1547 sock->id, sock->sock_fd);
1548 errno = EINVAL;
1549 return -1;
1550 }
1551
1552 /* make sure we've created the socket */
1553 if (modem_socket_id_is_assigned(&mdata.socket_config, sock) == false) {
1554 if (create_socket(sock, NULL) < 0) {
1555 return -1;
1556 }
1557 }
1558
1559 memcpy(&sock->dst, addr, sizeof(*addr));
1560 if (addr->sa_family == AF_INET6) {
1561 dst_port = ntohs(net_sin6(addr)->sin6_port);
1562 } else if (addr->sa_family == AF_INET) {
1563 dst_port = ntohs(net_sin(addr)->sin_port);
1564 } else {
1565 errno = EAFNOSUPPORT;
1566 return -1;
1567 }
1568
1569 /* skip socket connect if UDP */
1570 if (sock->ip_proto == IPPROTO_UDP) {
1571 errno = 0;
1572 return 0;
1573 }
1574
1575 ret = modem_context_sprint_ip_addr(addr, ip_str, sizeof(ip_str));
1576 if (ret != 0) {
1577 errno = -ret;
1578 LOG_ERR("Error formatting IP string %d", ret);
1579 return -1;
1580 }
1581
1582 snprintk(buf, sizeof(buf), "AT+USOCO=%d,\"%s\",%d", sock->id,
1583 ip_str, dst_port);
1584 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1585 NULL, 0U, buf,
1586 &mdata.sem_response, MDM_CMD_CONN_TIMEOUT);
1587 if (ret < 0) {
1588 LOG_ERR("%s ret:%d", buf, ret);
1589 errno = -ret;
1590 return -1;
1591 }
1592
1593 sock->is_connected = true;
1594 errno = 0;
1595 return 0;
1596 }
1597
offload_recvfrom(void * obj,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)1598 static ssize_t offload_recvfrom(void *obj, void *buf, size_t len,
1599 int flags, struct sockaddr *from,
1600 socklen_t *fromlen)
1601 {
1602 struct modem_socket *sock = (struct modem_socket *)obj;
1603 int ret, next_packet_size;
1604 static const struct modem_cmd cmd[] = {
1605 MODEM_CMD("+USORF: ", on_cmd_sockreadfrom, 4U, ","),
1606 MODEM_CMD("+USORD: ", on_cmd_sockread, 2U, ","),
1607 };
1608 char sendbuf[sizeof("AT+USORF=#,#####\r")];
1609 struct socket_read_data sock_data;
1610
1611 if (!buf || len == 0) {
1612 errno = EINVAL;
1613 return -1;
1614 }
1615
1616 if (flags & ZSOCK_MSG_PEEK) {
1617 errno = ENOTSUP;
1618 return -1;
1619 }
1620
1621 next_packet_size = modem_socket_next_packet_size(&mdata.socket_config,
1622 sock);
1623 if (!next_packet_size) {
1624 if (flags & ZSOCK_MSG_DONTWAIT) {
1625 errno = EAGAIN;
1626 return -1;
1627 }
1628
1629 if (!sock->is_connected && sock->ip_proto != IPPROTO_UDP) {
1630 errno = 0;
1631 return 0;
1632 }
1633
1634 modem_socket_wait_data(&mdata.socket_config, sock);
1635 next_packet_size = modem_socket_next_packet_size(
1636 &mdata.socket_config, sock);
1637 }
1638
1639 /*
1640 * Binary and ASCII mode allows sending MDM_MAX_DATA_LENGTH bytes to
1641 * the socket in one command
1642 */
1643 if (next_packet_size > MDM_MAX_DATA_LENGTH) {
1644 next_packet_size = MDM_MAX_DATA_LENGTH;
1645 }
1646
1647 snprintk(sendbuf, sizeof(sendbuf), "AT+USO%s=%d,%zd",
1648 sock->ip_proto == IPPROTO_UDP ? "RF" : "RD", sock->id,
1649 len < next_packet_size ? len : next_packet_size);
1650
1651 /* socket read settings */
1652 (void)memset(&sock_data, 0, sizeof(sock_data));
1653 sock_data.recv_buf = buf;
1654 sock_data.recv_buf_len = len;
1655 sock_data.recv_addr = from;
1656 sock->data = &sock_data;
1657
1658 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
1659 cmd, ARRAY_SIZE(cmd), sendbuf, &mdata.sem_response,
1660 MDM_CMD_TIMEOUT);
1661 if (ret < 0) {
1662 errno = -ret;
1663 ret = -1;
1664 goto exit;
1665 }
1666
1667 /* HACK: use dst address as from */
1668 if (from && fromlen) {
1669 *fromlen = sizeof(sock->dst);
1670 memcpy(from, &sock->dst, *fromlen);
1671 }
1672
1673 /* return length of received data */
1674 errno = 0;
1675 ret = sock_data.recv_read_len;
1676
1677 exit:
1678 /* clear socket data */
1679 sock->data = NULL;
1680 return ret;
1681 }
1682
offload_sendto(void * obj,const void * buf,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)1683 static ssize_t offload_sendto(void *obj, const void *buf, size_t len,
1684 int flags, const struct sockaddr *to,
1685 socklen_t tolen)
1686 {
1687 struct iovec msg_iov = {
1688 .iov_base = (void *)buf,
1689 .iov_len = len,
1690 };
1691 struct msghdr msg = {
1692 .msg_iovlen = 1,
1693 .msg_name = (struct sockaddr *)to,
1694 .msg_namelen = tolen,
1695 .msg_iov = &msg_iov,
1696 };
1697
1698 int ret = send_socket_data(obj, &msg, MDM_CMD_TIMEOUT);
1699 if (ret < 0) {
1700 errno = -ret;
1701 return -1;
1702 }
1703
1704 errno = 0;
1705 return ret;
1706 }
1707
offload_ioctl(void * obj,unsigned int request,va_list args)1708 static int offload_ioctl(void *obj, unsigned int request, va_list args)
1709 {
1710 switch (request) {
1711 case ZFD_IOCTL_POLL_PREPARE: {
1712 struct zsock_pollfd *pfd;
1713 struct k_poll_event **pev;
1714 struct k_poll_event *pev_end;
1715
1716 pfd = va_arg(args, struct zsock_pollfd *);
1717 pev = va_arg(args, struct k_poll_event **);
1718 pev_end = va_arg(args, struct k_poll_event *);
1719
1720 return modem_socket_poll_prepare(&mdata.socket_config, obj, pfd, pev, pev_end);
1721 }
1722 case ZFD_IOCTL_POLL_UPDATE: {
1723 struct zsock_pollfd *pfd;
1724 struct k_poll_event **pev;
1725
1726 pfd = va_arg(args, struct zsock_pollfd *);
1727 pev = va_arg(args, struct k_poll_event **);
1728
1729 return modem_socket_poll_update(obj, pfd, pev);
1730 }
1731
1732 case F_GETFL:
1733 return 0;
1734
1735 default:
1736 errno = EINVAL;
1737 return -1;
1738 }
1739 }
1740
offload_read(void * obj,void * buffer,size_t count)1741 static ssize_t offload_read(void *obj, void *buffer, size_t count)
1742 {
1743 return offload_recvfrom(obj, buffer, count, 0, NULL, 0);
1744 }
1745
offload_write(void * obj,const void * buffer,size_t count)1746 static ssize_t offload_write(void *obj, const void *buffer, size_t count)
1747 {
1748 return offload_sendto(obj, buffer, count, 0, NULL, 0);
1749 }
1750
offload_sendmsg(void * obj,const struct msghdr * msg,int flags)1751 static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags)
1752 {
1753 ssize_t sent = 0;
1754 int bkp_iovec_idx;
1755 struct iovec bkp_iovec = {0};
1756 struct msghdr crafted_msg = {
1757 .msg_name = msg->msg_name,
1758 .msg_namelen = msg->msg_namelen,
1759 };
1760 size_t full_len = 0;
1761 int ret;
1762
1763 /* Compute the full length to be send and check for invalid values */
1764 for (int i = 0; i < msg->msg_iovlen; i++) {
1765 if (!msg->msg_iov[i].iov_base || msg->msg_iov[i].iov_len == 0) {
1766 errno = EINVAL;
1767 return -1;
1768 }
1769 full_len += msg->msg_iov[i].iov_len;
1770 }
1771
1772 LOG_DBG("msg_iovlen:%zd flags:%d, full_len:%zd",
1773 msg->msg_iovlen, flags, full_len);
1774
1775 while (full_len > sent) {
1776 int removed = 0;
1777 int i = 0;
1778
1779 crafted_msg.msg_iovlen = msg->msg_iovlen;
1780 crafted_msg.msg_iov = &msg->msg_iov[0];
1781
1782 bkp_iovec_idx = -1;
1783 /* Iterate on iovec to remove the bytes already sent */
1784 while (removed < sent) {
1785 int to_removed = sent - removed;
1786
1787 if (to_removed >= msg->msg_iov[i].iov_len) {
1788 crafted_msg.msg_iovlen -= 1;
1789 crafted_msg.msg_iov = &msg->msg_iov[i + 1];
1790
1791 removed += msg->msg_iov[i].iov_len;
1792 } else {
1793 /* Backup msg->msg_iov[i] before "removing"
1794 * starting bytes already send.
1795 */
1796 bkp_iovec_idx = i;
1797 bkp_iovec.iov_len = msg->msg_iov[i].iov_len;
1798 bkp_iovec.iov_base = msg->msg_iov[i].iov_base;
1799
1800 /* Update msg->msg_iov[i] to "remove"
1801 * starting bytes already send.
1802 */
1803 msg->msg_iov[i].iov_len -= to_removed;
1804 msg->msg_iov[i].iov_base = &(((uint8_t *)msg->msg_iov[i].iov_base)[to_removed]);
1805
1806 removed += to_removed;
1807 }
1808
1809 i++;
1810 }
1811
1812 ret = send_socket_data(obj, &crafted_msg, MDM_CMD_TIMEOUT);
1813
1814 /* Restore backup iovec when necessary */
1815 if (bkp_iovec_idx != -1) {
1816 msg->msg_iov[bkp_iovec_idx].iov_len = bkp_iovec.iov_len;
1817 msg->msg_iov[bkp_iovec_idx].iov_base = bkp_iovec.iov_base;
1818 }
1819
1820 /* Handle send_socket_data() returned value */
1821 if (ret < 0) {
1822 errno = -ret;
1823 return -1;
1824 }
1825
1826 sent += ret;
1827 }
1828
1829 return (ssize_t)sent;
1830 }
1831
1832 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
map_credentials(struct modem_socket * sock,const void * optval,socklen_t optlen)1833 static int map_credentials(struct modem_socket *sock, const void *optval, socklen_t optlen)
1834 {
1835 sec_tag_t *sec_tags = (sec_tag_t *)optval;
1836 int ret = 0;
1837 int tags_len;
1838 sec_tag_t tag;
1839 int id;
1840 int i;
1841 struct tls_credential *cert;
1842
1843 if ((optlen % sizeof(sec_tag_t)) != 0 || (optlen == 0)) {
1844 return -EINVAL;
1845 }
1846
1847 tags_len = optlen / sizeof(sec_tag_t);
1848 /* For each tag, retrieve the credentials value and type: */
1849 for (i = 0; i < tags_len; i++) {
1850 tag = sec_tags[i];
1851 cert = credential_next_get(tag, NULL);
1852 while (cert != NULL) {
1853 switch (cert->type) {
1854 case TLS_CREDENTIAL_CA_CERTIFICATE:
1855 id = 0;
1856 break;
1857 case TLS_CREDENTIAL_NONE:
1858 case TLS_CREDENTIAL_PSK:
1859 case TLS_CREDENTIAL_PSK_ID:
1860 default:
1861 /* Not handled */
1862 return -EINVAL;
1863 }
1864 struct modem_cmd cmd[] = {
1865 MODEM_CMD("+USECMNG: ", on_cmd_cert_write, 3U, ","),
1866 };
1867 ret = send_cert(sock, cmd, 1, cert->buf, cert->len, id);
1868 if (ret < 0) {
1869 return ret;
1870 }
1871
1872 cert = credential_next_get(tag, cert);
1873 }
1874 }
1875
1876 return 0;
1877 }
1878 #else
map_credentials(struct modem_socket * sock,const void * optval,socklen_t optlen)1879 static int map_credentials(struct modem_socket *sock, const void *optval, socklen_t optlen)
1880 {
1881 return -EINVAL;
1882 }
1883 #endif
1884
offload_setsockopt(void * obj,int level,int optname,const void * optval,socklen_t optlen)1885 static int offload_setsockopt(void *obj, int level, int optname,
1886 const void *optval, socklen_t optlen)
1887 {
1888 struct modem_socket *sock = (struct modem_socket *)obj;
1889
1890 int ret;
1891
1892 if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) && level == SOL_TLS) {
1893 switch (optname) {
1894 case TLS_SEC_TAG_LIST:
1895 ret = map_credentials(sock, optval, optlen);
1896 break;
1897 case TLS_HOSTNAME:
1898 LOG_WRN("TLS_HOSTNAME option is not supported");
1899 return -EINVAL;
1900 case TLS_PEER_VERIFY:
1901 if (*(uint32_t *)optval != TLS_PEER_VERIFY_REQUIRED) {
1902 LOG_WRN("Disabling peer verification is not supported");
1903 return -EINVAL;
1904 }
1905 ret = 0;
1906 break;
1907 default:
1908 return -EINVAL;
1909 }
1910 } else {
1911 return -EINVAL;
1912 }
1913
1914 return ret;
1915 }
1916
1917
1918 static const struct socket_op_vtable offload_socket_fd_op_vtable = {
1919 .fd_vtable = {
1920 .read = offload_read,
1921 .write = offload_write,
1922 .close = offload_close,
1923 .ioctl = offload_ioctl,
1924 },
1925 .bind = offload_bind,
1926 .connect = offload_connect,
1927 .sendto = offload_sendto,
1928 .recvfrom = offload_recvfrom,
1929 .listen = NULL,
1930 .accept = NULL,
1931 .sendmsg = offload_sendmsg,
1932 .getsockopt = NULL,
1933 .setsockopt = offload_setsockopt,
1934 };
1935
offload_is_supported(int family,int type,int proto)1936 static bool offload_is_supported(int family, int type, int proto)
1937 {
1938 if (family != AF_INET &&
1939 family != AF_INET6) {
1940 return false;
1941 }
1942
1943 if (type != SOCK_DGRAM &&
1944 type != SOCK_STREAM) {
1945 return false;
1946 }
1947
1948 if (proto != IPPROTO_TCP &&
1949 proto != IPPROTO_UDP &&
1950 proto != IPPROTO_TLS_1_2) {
1951 return false;
1952 }
1953
1954 return true;
1955 }
1956
1957 NET_SOCKET_OFFLOAD_REGISTER(ublox_sara_r4, CONFIG_NET_SOCKETS_OFFLOAD_PRIORITY,
1958 AF_UNSPEC, offload_is_supported, offload_socket);
1959
1960 #if defined(CONFIG_DNS_RESOLVER)
1961 /* TODO: This is a bare-bones implementation of DNS handling
1962 * We ignore most of the hints like ai_family, ai_protocol and ai_socktype.
1963 * Later, we can add additional handling if it makes sense.
1964 */
offload_getaddrinfo(const char * node,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo ** res)1965 static int offload_getaddrinfo(const char *node, const char *service,
1966 const struct zsock_addrinfo *hints,
1967 struct zsock_addrinfo **res)
1968 {
1969 static const struct modem_cmd cmd =
1970 MODEM_CMD("+UDNSRN: ", on_cmd_dns, 1U, ",");
1971 uint32_t port = 0U;
1972 int ret;
1973 /* DNS command + 128 bytes for domain name parameter */
1974 char sendbuf[sizeof("AT+UDNSRN=#,'[]'\r") + 128];
1975
1976 /* init result */
1977 (void)memset(&result, 0, sizeof(result));
1978 (void)memset(&result_addr, 0, sizeof(result_addr));
1979 /* FIXME: Hard-code DNS to return only IPv4 */
1980 result.ai_family = AF_INET;
1981 result_addr.sa_family = AF_INET;
1982 result.ai_addr = &result_addr;
1983 result.ai_addrlen = sizeof(result_addr);
1984 result.ai_canonname = result_canonname;
1985 result_canonname[0] = '\0';
1986
1987 if (service) {
1988 port = ATOI(service, 0U, "port");
1989 if (port < 1 || port > USHRT_MAX) {
1990 return DNS_EAI_SERVICE;
1991 }
1992 }
1993
1994 if (port > 0U) {
1995 /* FIXME: DNS is hard-coded to return only IPv4 */
1996 if (result.ai_family == AF_INET) {
1997 net_sin(&result_addr)->sin_port = htons(port);
1998 }
1999 }
2000
2001 /* check to see if node is an IP address */
2002 if (net_addr_pton(result.ai_family, node,
2003 &((struct sockaddr_in *)&result_addr)->sin_addr)
2004 == 0) {
2005 *res = &result;
2006 return 0;
2007 }
2008
2009 /* user flagged node as numeric host, but we failed net_addr_pton */
2010 if (hints && hints->ai_flags & AI_NUMERICHOST) {
2011 return DNS_EAI_NONAME;
2012 }
2013
2014 snprintk(sendbuf, sizeof(sendbuf), "AT+UDNSRN=0,\"%s\"", node);
2015 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
2016 &cmd, 1U, sendbuf, &mdata.sem_response,
2017 MDM_DNS_TIMEOUT);
2018 if (ret < 0) {
2019 return ret;
2020 }
2021
2022 LOG_DBG("DNS RESULT: %s",
2023 net_addr_ntop(result.ai_family,
2024 &net_sin(&result_addr)->sin_addr,
2025 sendbuf, NET_IPV4_ADDR_LEN));
2026
2027 *res = (struct zsock_addrinfo *)&result;
2028 return 0;
2029 }
2030
offload_freeaddrinfo(struct zsock_addrinfo * res)2031 static void offload_freeaddrinfo(struct zsock_addrinfo *res)
2032 {
2033 /* using static result from offload_getaddrinfo() -- no need to free */
2034 res = NULL;
2035 }
2036
2037 static const struct socket_dns_offload offload_dns_ops = {
2038 .getaddrinfo = offload_getaddrinfo,
2039 .freeaddrinfo = offload_freeaddrinfo,
2040 };
2041 #endif
2042
net_offload_dummy_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)2043 static int net_offload_dummy_get(sa_family_t family,
2044 enum net_sock_type type,
2045 enum net_ip_protocol ip_proto,
2046 struct net_context **context)
2047 {
2048
2049 LOG_ERR("CONFIG_NET_SOCKETS_OFFLOAD must be enabled for this driver");
2050
2051 return -ENOTSUP;
2052 }
2053
2054 /* placeholders, until Zephyr IP stack updated to handle a NULL net_offload */
2055 static struct net_offload modem_net_offload = {
2056 .get = net_offload_dummy_get,
2057 };
2058
2059 #define HASH_MULTIPLIER 37
hash32(char * str,int len)2060 static uint32_t hash32(char *str, int len)
2061 {
2062 uint32_t h = 0;
2063 int i;
2064
2065 for (i = 0; i < len; ++i) {
2066 h = (h * HASH_MULTIPLIER) + str[i];
2067 }
2068
2069 return h;
2070 }
2071
modem_get_mac(const struct device * dev)2072 static inline uint8_t *modem_get_mac(const struct device *dev)
2073 {
2074 struct modem_data *data = dev->data;
2075 uint32_t hash_value;
2076
2077 data->mac_addr[0] = 0x00;
2078 data->mac_addr[1] = 0x10;
2079
2080 /* use IMEI for mac_addr */
2081 hash_value = hash32(mdata.mdm_imei, strlen(mdata.mdm_imei));
2082
2083 UNALIGNED_PUT(hash_value, (uint32_t *)(data->mac_addr + 2));
2084
2085 return data->mac_addr;
2086 }
2087
2088 static int offload_socket(int family, int type, int proto);
2089
modem_net_iface_init(struct net_if * iface)2090 static void modem_net_iface_init(struct net_if *iface)
2091 {
2092 const struct device *dev = net_if_get_device(iface);
2093 struct modem_data *data = dev->data;
2094
2095 /* Direct socket offload used instead of net offload: */
2096 iface->if_dev->offload = &modem_net_offload;
2097 net_if_set_link_addr(iface, modem_get_mac(dev),
2098 sizeof(data->mac_addr),
2099 NET_LINK_ETHERNET);
2100 data->net_iface = iface;
2101 #ifdef CONFIG_DNS_RESOLVER
2102 socket_offload_dns_register(&offload_dns_ops);
2103 #endif
2104
2105 net_if_socket_offload_set(iface, offload_socket);
2106 }
2107
2108 static struct offloaded_if_api api_funcs = {
2109 .iface_api.init = modem_net_iface_init,
2110 };
2111
2112 static const struct modem_cmd response_cmds[] = {
2113 MODEM_CMD("OK", on_cmd_ok, 0U, ""), /* 3GPP */
2114 MODEM_CMD("ERROR", on_cmd_error, 0U, ""), /* 3GPP */
2115 MODEM_CMD("+CME ERROR: ", on_cmd_exterror, 1U, ""),
2116 MODEM_CMD_DIRECT("@", on_prompt),
2117 };
2118
2119 static const struct modem_cmd unsol_cmds[] = {
2120 MODEM_CMD("+UUSOCL: ", on_cmd_socknotifyclose, 1U, ""),
2121 MODEM_CMD("+UUSORD: ", on_cmd_socknotifydata, 2U, ","),
2122 MODEM_CMD("+UUSORF: ", on_cmd_socknotifydata, 2U, ","),
2123 MODEM_CMD("+CREG: ", on_cmd_socknotifycreg, 1U, ""),
2124 };
2125
modem_init(const struct device * dev)2126 static int modem_init(const struct device *dev)
2127 {
2128 int ret = 0;
2129
2130 ARG_UNUSED(dev);
2131
2132 k_sem_init(&mdata.sem_response, 0, 1);
2133 k_sem_init(&mdata.sem_prompt, 0, 1);
2134
2135 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
2136 /* initialize the work queue */
2137 k_work_queue_start(&modem_workq, modem_workq_stack,
2138 K_KERNEL_STACK_SIZEOF(modem_workq_stack),
2139 K_PRIO_COOP(7), NULL);
2140 #endif
2141
2142 /* socket config */
2143 ret = modem_socket_init(&mdata.socket_config, &mdata.sockets[0], ARRAY_SIZE(mdata.sockets),
2144 MDM_BASE_SOCKET_NUM, false, &offload_socket_fd_op_vtable);
2145 if (ret < 0) {
2146 goto error;
2147 }
2148
2149 /* cmd handler */
2150 const struct modem_cmd_handler_config cmd_handler_config = {
2151 .match_buf = &mdata.cmd_match_buf[0],
2152 .match_buf_len = sizeof(mdata.cmd_match_buf),
2153 .buf_pool = &mdm_recv_pool,
2154 .alloc_timeout = K_NO_WAIT,
2155 .eol = "\r",
2156 .user_data = NULL,
2157 .response_cmds = response_cmds,
2158 .response_cmds_len = ARRAY_SIZE(response_cmds),
2159 .unsol_cmds = unsol_cmds,
2160 .unsol_cmds_len = ARRAY_SIZE(unsol_cmds),
2161 };
2162
2163 ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
2164 &cmd_handler_config);
2165 if (ret < 0) {
2166 goto error;
2167 }
2168
2169 /* modem interface */
2170 const struct modem_iface_uart_config uart_config = {
2171 .rx_rb_buf = &mdata.iface_rb_buf[0],
2172 .rx_rb_buf_len = sizeof(mdata.iface_rb_buf),
2173 .dev = MDM_UART_DEV,
2174 .hw_flow_control = DT_PROP(MDM_UART_NODE, hw_flow_control),
2175 };
2176
2177 ret = modem_iface_uart_init(&mctx.iface, &mdata.iface_data, &uart_config);
2178 if (ret < 0) {
2179 goto error;
2180 }
2181
2182 /* modem data storage */
2183 mctx.data_manufacturer = mdata.mdm_manufacturer;
2184 mctx.data_model = mdata.mdm_model;
2185 mctx.data_revision = mdata.mdm_revision;
2186 mctx.data_imei = mdata.mdm_imei;
2187 mctx.data_rssi = &mdata.mdm_rssi;
2188
2189 /* pin setup */
2190 ret = gpio_pin_configure_dt(&power_gpio, GPIO_OUTPUT);
2191 if (ret < 0) {
2192 LOG_ERR("Failed to configure %s pin", "power");
2193 goto error;
2194 }
2195
2196 #if DT_INST_NODE_HAS_PROP(0, mdm_reset_gpios)
2197 ret = gpio_pin_configure_dt(&reset_gpio, GPIO_OUTPUT);
2198 if (ret < 0) {
2199 LOG_ERR("Failed to configure %s pin", "reset");
2200 goto error;
2201 }
2202 #endif
2203
2204 #if DT_INST_NODE_HAS_PROP(0, mdm_vint_gpios)
2205 ret = gpio_pin_configure_dt(&vint_gpio, GPIO_INPUT);
2206 if (ret < 0) {
2207 LOG_ERR("Failed to configure %s pin", "vint");
2208 goto error;
2209 }
2210 #endif
2211
2212 mctx.driver_data = &mdata;
2213
2214 ret = modem_context_register(&mctx);
2215 if (ret < 0) {
2216 LOG_ERR("Error registering modem context: %d", ret);
2217 goto error;
2218 }
2219
2220 /* start RX thread */
2221 k_thread_create(&modem_rx_thread, modem_rx_stack,
2222 K_KERNEL_STACK_SIZEOF(modem_rx_stack),
2223 (k_thread_entry_t) modem_rx,
2224 NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
2225
2226 #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK)
2227 /* init RSSI query */
2228 k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work);
2229 #endif
2230
2231 modem_reset();
2232
2233 error:
2234 return ret;
2235 }
2236
2237 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, modem_init, NULL,
2238 &mdata, NULL,
2239 CONFIG_MODEM_UBLOX_SARA_R4_INIT_PRIORITY,
2240 &api_funcs,
2241 MDM_MAX_DATA_LENGTH);
2242