1 /*
2  * Copyright (c) 2020 Laird Connectivity
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT swir_hl7800
8 
9 #include <zephyr/logging/log.h>
10 #include <zephyr/logging/log_ctrl.h>
11 #define LOG_MODULE_NAME modem_hl7800
12 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_MODEM_LOG_LEVEL);
13 
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/drivers/gpio.h>
21 #include <zephyr/device.h>
22 #include <zephyr/init.h>
23 
24 #include <zephyr/pm/device.h>
25 #include <zephyr/drivers/uart.h>
26 #include <zephyr/sys/util.h>
27 
28 #include <zephyr/net/net_context.h>
29 #include <zephyr/net/net_if.h>
30 #include <zephyr/net/net_offload.h>
31 #include <zephyr/net/net_pkt.h>
32 #include <zephyr/net/dns_resolve.h>
33 #include <zephyr/net/offloaded_netdev.h>
34 #if defined(CONFIG_NET_IPV6)
35 #include "ipv6.h"
36 #endif
37 #if defined(CONFIG_NET_IPV4)
38 #include "ipv4.h"
39 #endif
40 #if defined(CONFIG_NET_UDP)
41 #include "udp_internal.h"
42 #endif
43 
44 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
45 #include <zephyr/fs/fs.h>
46 #endif
47 
48 #include "modem_receiver.h"
49 #include <zephyr/drivers/modem/hl7800.h>
50 
51 #define PREFIXED_SWITCH_CASE_RETURN_STRING(prefix, val)                        \
52 	case prefix##_##val: {                                                 \
53 		return #val;                                                   \
54 	}
55 
56 /* Uncomment the #define below to enable a hexdump of all incoming
57  * data from the modem receiver
58  */
59 /* #define HL7800_ENABLE_VERBOSE_MODEM_RECV_HEXDUMP 1 */
60 
61 #define HL7800_LOG_UNHANDLED_RX_MSGS 1
62 
63 /* Uncomment the #define(s) below to enable extra debugging */
64 /* #define HL7800_RX_LOCK_LOG 1 */
65 /* #define HL7800_TX_LOCK_LOG 1 */
66 /* #define HL7800_IO_LOG 1 */
67 
68 #define HL7800_RX_LOCK_DBG_LOG(fmt, ...)                                       \
69 	do {                                                                   \
70 		if (IS_ENABLED(HL7800_RX_LOCK_LOG)) {                          \
71 			LOG_DBG(fmt, ##__VA_ARGS__);                           \
72 		}                                                              \
73 	} while (false)
74 
75 #define HL7800_TX_LOCK_DBG_LOG(fmt, ...)                                       \
76 	do {                                                                   \
77 		if (IS_ENABLED(HL7800_TX_LOCK_LOG)) {                          \
78 			LOG_DBG(fmt, ##__VA_ARGS__);                           \
79 		}                                                              \
80 	} while (false)
81 
82 #define HL7800_IO_DBG_LOG(fmt, ...)                                            \
83 	do {                                                                   \
84 		if (IS_ENABLED(HL7800_IO_LOG)) {                               \
85 			LOG_WRN(fmt, ##__VA_ARGS__);                           \
86 		}                                                              \
87 	} while (false)
88 
89 #if ((LOG_LEVEL == LOG_LEVEL_DBG) &&                                           \
90      defined(CONFIG_MODEM_HL7800_LOW_POWER_MODE))
91 #define PRINT_AWAKE_MSG LOG_WRN("awake")
92 #define PRINT_NOT_AWAKE_MSG LOG_WRN("NOT awake")
93 #else
94 #define PRINT_AWAKE_MSG
95 #define PRINT_NOT_AWAKE_MSG
96 #endif
97 
98 enum tcp_notif {
99 	HL7800_TCP_NET_ERR,
100 	HL7800_TCP_NO_SOCKS,
101 	HL7800_TCP_MEM,
102 	HL7800_TCP_DNS,
103 	HL7800_TCP_DISCON,
104 	HL7800_TCP_CONN,
105 	HL7800_TCP_ERR,
106 	HL7800_TCP_CLIENT_REQ,
107 	HL7800_TCP_DATA_SND,
108 	HL7800_TCP_ID,
109 	HL7800_TCP_RUNNING,
110 	HL7800_TCP_ALL_USED,
111 	HL7800_TCP_TIMEOUT,
112 	HL7800_TCP_SSL_CONN,
113 	HL7800_TCP_SSL_INIT
114 };
115 
116 enum udp_notif {
117 	HL7800_UDP_NET_ERR = 0,
118 	HL7800_UDP_NO_SOCKS = 1,
119 	HL7800_UDP_MEM = 2,
120 	HL7800_UDP_DNS = 3,
121 	HL7800_UDP_CONN = 5,
122 	HL7800_UDP_ERR = 6,
123 	HL7800_UDP_DATA_SND = 8, /* this matches TCP_DATA_SND */
124 	HL7800_UDP_ID = 9,
125 	HL7800_UDP_RUNNING = 10,
126 	HL7800_UDP_ALL_USED = 11
127 };
128 
129 enum socket_state {
130 	SOCK_IDLE,
131 	SOCK_RX,
132 	SOCK_TX,
133 	SOCK_CONNECTED,
134 };
135 
136 enum hl7800_lpm {
137 	HL7800_LPM_NONE,
138 	HL7800_LPM_EDRX,
139 	HL7800_LPM_PSM,
140 };
141 
142 /* pin settings */
143 enum mdm_control_pins {
144 	MDM_RESET = 0,
145 	MDM_WAKE,
146 	MDM_PWR_ON,
147 	MDM_FAST_SHUTD,
148 	MDM_VGPIO,
149 	MDM_UART_DSR,
150 	MDM_UART_CTS,
151 	MDM_GPIO6,
152 	MAX_MDM_CONTROL_PINS,
153 };
154 
155 enum net_operator_status { NO_OPERATOR, REGISTERED };
156 
157 enum device_service_indications {
158 	WDSI_PKG_DOWNLOADED = 3,
159 };
160 
161 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
162 enum XMODEM_CONTROL_CHARACTERS {
163 	XM_SOH = 0x01,
164 	XM_SOH_1K = 0x02,
165 	XM_EOT = 0x04,
166 	XM_ACK = 0x06, /* 'R' */
167 	XM_NACK = 0x15, /* 'N' */
168 	XM_ETB = 0x17,
169 	XM_CAN = 0x18,
170 	XM_C = 0x43
171 };
172 
173 #define XMODEM_DATA_SIZE 1024
174 #define XMODEM_PACKET_SIZE (XMODEM_DATA_SIZE + 4)
175 #define XMODEM_PAD_VALUE 26
176 
177 struct xmodem_packet {
178 	uint8_t preamble;
179 	uint8_t id;
180 	uint8_t id_complement;
181 	uint8_t data[XMODEM_DATA_SIZE];
182 	uint8_t crc;
183 };
184 #endif
185 
186 #define MDM_UART_DEV	DEVICE_DT_GET(DT_INST_BUS(0))
187 
188 #define MDM_SEND_OK_ENABLED 0
189 #define MDM_SEND_OK_DISABLED 1
190 
191 #define MDM_CMD_SEND_TIMEOUT K_SECONDS(6)
192 #define MDM_IP_SEND_RX_TIMEOUT K_SECONDS(62)
193 #define MDM_SOCK_NOTIF_DELAY K_MSEC(150)
194 #define MDM_CMD_CONN_TIMEOUT K_SECONDS(31)
195 
196 #define MDM_MAX_DATA_LENGTH 1500
197 #define MDM_MTU 1500
198 #define MDM_MAX_RESP_SIZE 128
199 #define MDM_IP_INFO_RESP_SIZE 256
200 #define MDM_EID_LENGTH	       33
201 #define MDM_CCID_RESP_MAX_SIZE (MDM_HL7800_ICCID_MAX_SIZE + MDM_EID_LENGTH)
202 
203 #define MDM_HANDLER_MATCH_MAX_LEN 100
204 
205 #define MDM_MAX_SOCKETS 6
206 
207 /* Special value used to indicate that a socket is being created
208  * and that its actual ID hasn't been assigned yet.
209  */
210 #define MDM_CREATE_SOCKET_ID (MDM_MAX_SOCKETS + 1)
211 #define MDM_INVALID_SOCKET_ID -1
212 
213 #define BUF_ALLOC_TIMEOUT K_SECONDS(1)
214 
215 #define SIZE_OF_NUL 1
216 
217 #define SIZE_WITHOUT_NUL(v) (sizeof(v) - SIZE_OF_NUL)
218 
219 #define CMD_HANDLER(cmd_, cb_)                                                 \
220 	{                                                                      \
221 		.cmd = cmd_, .cmd_len = (uint16_t)sizeof(cmd_) - 1,            \
222 		.func = on_cmd_##cb_                                           \
223 	}
224 
225 #define MDM_MANUFACTURER_LENGTH 16
226 #define MDM_MODEL_LENGTH 7
227 #define MDM_SN_RESPONSE_LENGTH (MDM_HL7800_SERIAL_NUMBER_SIZE + 7)
228 #define MDM_NETWORK_STATUS_LENGTH 45
229 
230 #define MDM_TOP_BAND_SIZE 4
231 #define MDM_MIDDLE_BAND_SIZE 8
232 #define MDM_BOTTOM_BAND_SIZE 8
233 #define MDM_TOP_BAND_START_POSITION 2
234 #define MDM_MIDDLE_BAND_START_POSITION 6
235 #define MDM_BOTTOM_BAND_START_POSITION 14
236 #define MDM_BAND_BITMAP_STR_LENGTH_MAX                                                             \
237 	(MDM_TOP_BAND_SIZE + MDM_MIDDLE_BAND_SIZE + MDM_BOTTOM_BAND_SIZE)
238 #define MDM_BAND_BITMAP_STR_LENGTH_MIN 1
239 
240 #define MDM_DEFAULT_AT_CMD_RETRIES 3
241 #define MDM_WAKEUP_TIME K_SECONDS(12)
242 #define MDM_BOOT_TIME K_SECONDS(12)
243 #define MDM_WAKE_TO_CHECK_CTS_DELAY_MS K_MSEC(20)
244 
245 #define MDM_WAIT_FOR_DATA_TIME K_MSEC(50)
246 #define MDM_RESET_LOW_TIME K_MSEC(50)
247 #define MDM_RESET_HIGH_TIME K_MSEC(10)
248 #define MDM_WAIT_FOR_DATA_RETRIES 3
249 
250 #define RSSI_UNKNOWN -999
251 
252 #define DNS_WORK_DELAY_SECS 1
253 #define IFACE_WORK_DELAY K_MSEC(500)
254 #define SOCKET_CLEANUP_WORK_DELAY K_MSEC(100)
255 #define WAIT_FOR_KSUP_RETRIES 5
256 
257 #define CGCONTRDP_RESPONSE_NUM_DELIMS 7
258 #define COPS_RESPONSE_NUM_DELIMS 2
259 #define KCELLMEAS_RESPONSE_NUM_DELIMS 4
260 
261 #define PROFILE_LINE_1                                                         \
262 	"E1 Q0 V1 X4 &C1 &D1 &R1 &S0 +IFC=2,2 &K3 +IPR=115200 +FCLASS0\r\n"
263 #define PROFILE_LINE_2                                                         \
264 	"S00:255 S01:255 S03:255 S04:255 S05:255 S07:255 S08:255 S10:255\r\n"
265 
266 #define ADDRESS_FAMILY_IP "IP"
267 #define ADDRESS_FAMILY_IPV4 "IPV4"
268 #if defined(CONFIG_MODEM_HL7800_ADDRESS_FAMILY_IPV4V6)
269 #define MODEM_HL7800_ADDRESS_FAMILY "IPV4V6"
270 #elif defined(CONFIG_MODEM_HL7800_ADDRESS_FAMILY_IPV4)
271 #define MODEM_HL7800_ADDRESS_FAMILY ADDRESS_FAMILY_IPV4
272 #else
273 #define MODEM_HL7800_ADDRESS_FAMILY "IPV6"
274 #endif
275 #define MDM_HL7800_SOCKET_AF_IPV4 0
276 #define MDM_HL7800_SOCKET_AF_IPV6 1
277 
278 #define SET_RAT_M1_CMD_LEGACY "AT+KSRAT=0"
279 #define SET_RAT_NB1_CMD_LEGACY "AT+KSRAT=1"
280 #define SET_RAT_M1_CMD "AT+KSRAT=0,1"
281 #define SET_RAT_NB1_CMD "AT+KSRAT=1,1"
282 #define NEW_RAT_CMD_MIN_VERSION "HL7800.4.5.4.0"
283 #define HL7800_VERSION_FORMAT "HL7800.%zu.%zu.%zu.%zu"
284 
285 #define MAX_PROFILE_LINE_LENGTH                                                \
286 	MAX(sizeof(PROFILE_LINE_1), sizeof(PROFILE_LINE_2))
287 
288 #define IPV6_ADDR_FORMAT "####:####:####:####:####:####:####:####"
289 #define HL7800_IPV6_ADDR_LEN                                                                       \
290 	sizeof("a01.a02.a03.a04.a05.a06.a07.a08.a09.a10.a11.a12.a13.a14.a15.a16")
291 
292 #define MDM_ADDR_FAM_MAX_LEN sizeof("IPV4V6")
293 
294 /* The ? can be a + or - */
295 static const char TIME_STRING_FORMAT[] = "\"yy/MM/dd,hh:mm:ss?zz\"";
296 #define TIME_STRING_DIGIT_STRLEN 2
297 #define TIME_STRING_SEPARATOR_STRLEN 1
298 #define TIME_STRING_PLUS_MINUS_INDEX (6 * 3)
299 #define TIME_STRING_FIRST_SEPARATOR_INDEX 0
300 #define TIME_STRING_FIRST_DIGIT_INDEX 1
301 #define TIME_STRING_TO_TM_STRUCT_YEAR_OFFSET (2000 - 1900)
302 
303 /* Time structure min, max */
304 #define TM_YEAR_RANGE 0, 99
305 #define TM_MONTH_RANGE_PLUS_1 1, 12
306 #define TM_DAY_RANGE 1, 31
307 #define TM_HOUR_RANGE 0, 23
308 #define TM_MIN_RANGE 0, 59
309 #define TM_SEC_RANGE 0, 60 /* leap second */
310 #define QUARTER_HOUR_RANGE 0, 96
311 #define SECONDS_PER_QUARTER_HOUR (15 * 60)
312 
313 #define SEND_AT_CMD_ONCE_EXPECT_OK(c)                                          \
314 	do {                                                                   \
315 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT, 0, false);  \
316 		if (ret < 0) {                                                 \
317 			LOG_ERR("%s result:%d", (c), ret);                     \
318 			goto error;                                            \
319 		}                                                              \
320 	} while (false)
321 
322 #define SEND_AT_CMD_IGNORE_ERROR(c)                                            \
323 	do {                                                                   \
324 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT, 0, false);  \
325 		if (ret < 0) {                                                 \
326 			LOG_ERR("%s result:%d", (c), ret);                     \
327 		}                                                              \
328 	} while (false)
329 
330 #define SEND_AT_CMD_EXPECT_OK(c)                                               \
331 	do {                                                                   \
332 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT,             \
333 				  MDM_DEFAULT_AT_CMD_RETRIES, false);          \
334 		if (ret < 0) {                                                 \
335 			LOG_ERR("%s result:%d", (c), ret);                     \
336 			goto error;                                            \
337 		}                                                              \
338 	} while (false)
339 
340 /* Complex has "no_id_resp" set to true because the sending command
341  * is the command used to process the response
342  */
343 #define SEND_COMPLEX_AT_CMD(c)                                                 \
344 	do {                                                                   \
345 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT,             \
346 				  MDM_DEFAULT_AT_CMD_RETRIES, true);           \
347 		if (ret < 0) {                                                 \
348 			LOG_ERR("%s result:%d", (c), ret);                     \
349 			goto error;                                            \
350 		}                                                              \
351 	} while (false)
352 
353 NET_BUF_POOL_DEFINE(mdm_recv_pool, CONFIG_MODEM_HL7800_RECV_BUF_CNT,
354 		    CONFIG_MODEM_HL7800_RECV_BUF_SIZE, 0, NULL);
355 
356 static uint8_t mdm_recv_buf[MDM_MAX_DATA_LENGTH];
357 
358 static K_SEM_DEFINE(hl7800_RX_lock_sem, 1, 1);
359 static K_SEM_DEFINE(hl7800_TX_lock_sem, 1, 1);
360 static K_SEM_DEFINE(cb_lock, 1, 1);
361 
362 /* RX thread structures */
363 K_THREAD_STACK_DEFINE(hl7800_rx_stack, CONFIG_MODEM_HL7800_RX_STACK_SIZE);
364 struct k_thread hl7800_rx_thread;
365 #define RX_THREAD_PRIORITY K_PRIO_COOP(7)
366 
367 /* RX thread work queue */
368 K_THREAD_STACK_DEFINE(hl7800_workq_stack,
369 		      CONFIG_MODEM_HL7800_RX_WORKQ_STACK_SIZE);
370 static struct k_work_q hl7800_workq;
371 #define WORKQ_PRIORITY K_PRIO_COOP(7)
372 
373 static const char EOF_PATTERN[] = "--EOF--Pattern--";
374 static const char CONNECT_STRING[] = "CONNECT";
375 static const char OK_STRING[] = "OK";
376 
377 struct hl7800_socket {
378 	struct net_context *context;
379 	sa_family_t family;
380 	enum net_sock_type type;
381 	enum net_ip_protocol ip_proto;
382 	struct sockaddr src;
383 	struct sockaddr dst;
384 
385 	bool created;
386 	bool reconfig;
387 	int socket_id;
388 	int rx_size;
389 	int error;
390 	enum socket_state state;
391 
392 	/** semaphore */
393 	struct k_sem sock_send_sem;
394 
395 	/** socket callbacks */
396 	struct k_work recv_cb_work;
397 	struct k_work rx_data_work;
398 	struct k_work_delayable notif_work;
399 	net_context_recv_cb_t recv_cb;
400 	struct net_pkt *recv_pkt;
401 	void *recv_user_data;
402 };
403 
404 struct stale_socket {
405 	int reserved; /* first word of queue data item reserved for the kernel */
406 	enum net_sock_type type;
407 	uint8_t id;
408 	bool allocated;
409 };
410 
411 #define NO_ID_RESP_CMD_MAX_LENGTH 32
412 
413 struct hl7800_config {
414 	struct gpio_dt_spec gpio[MAX_MDM_CONTROL_PINS];
415 };
416 
417 struct hl7800_iface_ctx {
418 	struct net_if *iface;
419 	uint8_t mac_addr[6];
420 	struct in_addr ipv4Addr, subnet, gateway, dns_v4;
421 #ifdef CONFIG_NET_IPV6
422 	struct in6_addr ipv6Addr, dns_v6;
423 	char dns_v6_string[HL7800_IPV6_ADDR_LEN];
424 #endif
425 	bool restarting;
426 	bool initialized;
427 	bool wait_for_KSUP;
428 	uint32_t wait_for_KSUP_tries;
429 	bool reconfig_IP_connection;
430 	char dns_v4_string[NET_IPV4_ADDR_LEN];
431 	char no_id_resp_cmd[NO_ID_RESP_CMD_MAX_LENGTH];
432 	bool search_no_id_resp;
433 
434 	/* GPIO PORT devices */
435 	struct gpio_callback mdm_vgpio_cb;
436 	struct gpio_callback mdm_uart_dsr_cb;
437 	struct gpio_callback mdm_gpio6_cb;
438 	struct gpio_callback mdm_uart_cts_cb;
439 	int vgpio_state;
440 	int dsr_state;
441 	int gpio6_state;
442 	int cts_state;
443 	int last_cts_state;
444 	int last_cts_time;
445 
446 	/* RX specific attributes */
447 	struct mdm_receiver_context mdm_ctx;
448 
449 	/* socket data */
450 	struct hl7800_socket sockets[MDM_MAX_SOCKETS];
451 	int last_socket_id;
452 	int last_error;
453 	struct stale_socket stale_sockets[MDM_MAX_SOCKETS];
454 	struct k_queue stale_socket_queue;
455 
456 	/* semaphores */
457 	struct k_sem response_sem;
458 	struct k_sem mdm_awake;
459 
460 	/* work */
461 	struct k_work_delayable rssi_query_work;
462 	struct k_work_delayable iface_status_work;
463 	struct k_work_delayable dns_work;
464 	struct k_work mdm_vgpio_work;
465 	struct k_work_delayable mdm_reset_work;
466 	struct k_work_delayable allow_sleep_work;
467 	struct k_work_delayable delete_untracked_socket_work;
468 	struct k_work mdm_pwr_off_work;
469 
470 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
471 	/* firmware update */
472 	enum mdm_hl7800_fota_state fw_update_state;
473 	struct fs_file_t fw_update_file;
474 	struct xmodem_packet fw_packet;
475 	uint32_t fw_packet_count;
476 	int file_pos;
477 	struct k_work finish_fw_update_work;
478 	bool fw_updated;
479 #endif
480 
481 	/* modem info */
482 	/* NOTE: make sure length is +1 for null char */
483 	char mdm_manufacturer[MDM_MANUFACTURER_LENGTH];
484 	char mdm_model[MDM_MODEL_LENGTH];
485 	char mdm_revision[MDM_HL7800_REVISION_MAX_SIZE];
486 	char mdm_imei[MDM_HL7800_IMEI_SIZE];
487 	char mdm_sn[MDM_HL7800_SERIAL_NUMBER_SIZE];
488 	char mdm_network_status[MDM_NETWORK_STATUS_LENGTH];
489 	char mdm_iccid[MDM_HL7800_ICCID_MAX_SIZE];
490 	enum mdm_hl7800_startup_state mdm_startup_state;
491 	enum mdm_hl7800_radio_mode mdm_rat;
492 	char mdm_active_bands_string[MDM_HL7800_LTE_BAND_STR_SIZE];
493 	char mdm_bands_string[MDM_HL7800_LTE_BAND_STR_SIZE];
494 	char mdm_imsi[MDM_HL7800_IMSI_MAX_STR_SIZE];
495 	int mdm_rssi;
496 	uint16_t mdm_bands_top;
497 	uint32_t mdm_bands_middle;
498 	uint32_t mdm_bands_bottom;
499 	int32_t mdm_sinr;
500 	bool mdm_echo_is_on;
501 	struct mdm_hl7800_apn mdm_apn;
502 	bool mdm_startup_reporting_on;
503 	int device_services_ind;
504 	bool new_rat_cmd_support;
505 	uint8_t operator_index;
506 	enum mdm_hl7800_functionality functionality;
507 	char mdm_pdp_addr_fam[MDM_ADDR_FAM_MAX_LEN];
508 
509 	/* modem state */
510 	bool busy;
511 	bool socket_cmd;
512 	bool allow_sleep;
513 	enum mdm_hl7800_sleep desired_sleep_level;
514 	enum mdm_hl7800_sleep sleep_state;
515 	enum hl7800_lpm low_power_mode;
516 	enum mdm_hl7800_network_state network_state;
517 	bool network_dropped;
518 	bool dns_ready;
519 	enum net_operator_status operator_status;
520 	struct tm local_time;
521 	int32_t local_time_offset;
522 	bool local_time_valid;
523 	bool configured;
524 	bool off;
525 	void (*wake_up_callback)(int state);
526 	void (*gpio6_callback)(int state);
527 	void (*cts_callback)(int state);
528 
529 #ifdef CONFIG_MODEM_HL7800_GPS
530 	struct k_work_delayable gps_work;
531 	uint32_t gps_query_location_rate_seconds;
532 #endif
533 };
534 
535 struct cmd_handler {
536 	const char *cmd;
537 	uint16_t cmd_len;
538 	bool (*func)(struct net_buf **buf, uint16_t len);
539 };
540 
541 static sys_slist_t hl7800_event_callback_list =
542 	SYS_SLIST_STATIC_INIT(&hl7800_event_callback_list);
543 
544 const static struct hl7800_config hl7800_cfg = {
545 	.gpio = {
546 		GPIO_DT_SPEC_INST_GET(0, mdm_reset_gpios),
547 		GPIO_DT_SPEC_INST_GET(0, mdm_wake_gpios),
548 		GPIO_DT_SPEC_INST_GET(0, mdm_pwr_on_gpios),
549 		GPIO_DT_SPEC_INST_GET(0, mdm_fast_shutd_gpios),
550 		GPIO_DT_SPEC_INST_GET(0, mdm_vgpio_gpios),
551 		GPIO_DT_SPEC_INST_GET(0, mdm_uart_dsr_gpios),
552 		GPIO_DT_SPEC_INST_GET(0, mdm_uart_cts_gpios),
553 		GPIO_DT_SPEC_INST_GET(0, mdm_gpio6_gpios),
554 	},
555 };
556 static struct hl7800_iface_ctx iface_ctx;
557 
558 static size_t hl7800_read_rx(struct net_buf **buf);
559 static char *get_network_state_string(enum mdm_hl7800_network_state state);
560 static char *get_startup_state_string(enum mdm_hl7800_startup_state state);
561 static char *get_sleep_state_string(enum mdm_hl7800_sleep state);
562 static void set_network_state(enum mdm_hl7800_network_state state);
563 static void set_startup_state(enum mdm_hl7800_startup_state state);
564 static void set_sleep_state(enum mdm_hl7800_sleep state);
565 static void generate_network_state_event(void);
566 static void generate_startup_state_event(void);
567 static void generate_sleep_state_event(void);
568 static int modem_boot_handler(char *reason);
569 static void mdm_vgpio_work_cb(struct k_work *item);
570 static void mdm_reset_work_callback(struct k_work *item);
571 static void mdm_power_off_work_callback(struct k_work *item);
572 static int write_apn(char *access_point_name);
573 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
574 static void mark_sockets_for_reconfig(void);
575 #endif
576 static void hl7800_build_mac(struct hl7800_iface_ctx *ictx);
577 static void rssi_query(void);
578 
579 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
580 static void initialize_sleep_level(void);
581 static int set_sleep_level(void);
582 #endif
583 
584 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
585 static char *get_fota_state_string(enum mdm_hl7800_fota_state state);
586 static void set_fota_state(enum mdm_hl7800_fota_state state);
587 static void generate_fota_state_event(void);
588 static void generate_fota_count_event(void);
589 #endif
590 
alloc_stale_socket(void)591 static struct stale_socket *alloc_stale_socket(void)
592 {
593 	struct stale_socket *sock = NULL;
594 
595 	for (int i = 0; i < MDM_MAX_SOCKETS; i++) {
596 		if (!iface_ctx.stale_sockets[i].allocated) {
597 			sock = &iface_ctx.stale_sockets[i];
598 			sock->allocated = true;
599 			break;
600 		}
601 	}
602 
603 	return sock;
604 }
605 
free_stale_socket(struct stale_socket * sock)606 static void free_stale_socket(struct stale_socket *sock)
607 {
608 	if (sock != NULL) {
609 		sock->allocated = false;
610 	}
611 }
612 
queue_stale_socket(enum net_sock_type type,uint8_t id)613 static int queue_stale_socket(enum net_sock_type type, uint8_t id)
614 {
615 	int ret = 0;
616 	struct stale_socket *sock = NULL;
617 
618 	sock = alloc_stale_socket();
619 	if (sock != NULL) {
620 		LOG_DBG("Queueing stale socket %d", id);
621 		sock->type = type;
622 		sock->id = id;
623 		k_queue_append(&iface_ctx.stale_socket_queue, (void *)sock);
624 	} else {
625 		LOG_ERR("Could not alloc stale socket");
626 		ret = -ENOMEM;
627 	}
628 
629 	return ret;
630 }
631 
dequeue_stale_socket(void)632 static struct stale_socket *dequeue_stale_socket(void)
633 {
634 	struct stale_socket *sock = NULL;
635 
636 	sock = (struct stale_socket *)k_queue_get(&iface_ctx.stale_socket_queue, K_NO_WAIT);
637 
638 	return sock;
639 }
640 
641 static bool convert_time_string_to_struct(struct tm *tm, int32_t *offset,
642 					  char *time_string);
643 static int modem_reset_and_configure(void);
644 
read_pin(int default_state,const struct gpio_dt_spec * spec)645 static int read_pin(int default_state, const struct gpio_dt_spec *spec)
646 {
647 	int state = gpio_pin_get_raw(spec->port, spec->pin);
648 
649 	if (state < 0) {
650 		LOG_ERR("Unable to read port: %s pin: %d status: %d",
651 			spec->port->name, spec->pin, state);
652 		state = default_state;
653 	}
654 
655 	return state;
656 }
657 
658 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
is_cmd_ready(void)659 static bool is_cmd_ready(void)
660 {
661 	iface_ctx.vgpio_state = read_pin(0, &hl7800_cfg.gpio[MDM_VGPIO]);
662 
663 	iface_ctx.gpio6_state = read_pin(0, &hl7800_cfg.gpio[MDM_GPIO6]);
664 
665 	iface_ctx.cts_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_CTS]);
666 
667 	return iface_ctx.vgpio_state && iface_ctx.gpio6_state && !iface_ctx.cts_state;
668 }
669 #endif
670 
671 /**
672  * The definition of awake is that the HL7800
673  * is ready to receive AT commands successfully
674  */
check_hl7800_awake(void)675 static void check_hl7800_awake(void)
676 {
677 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
678 	bool is_cmd_rdy = is_cmd_ready();
679 
680 	if (is_cmd_rdy && (iface_ctx.sleep_state != HL7800_SLEEP_AWAKE) &&
681 	    !iface_ctx.allow_sleep && !iface_ctx.wait_for_KSUP) {
682 		PRINT_AWAKE_MSG;
683 		set_sleep_state(HL7800_SLEEP_AWAKE);
684 		k_sem_give(&iface_ctx.mdm_awake);
685 	} else if (!is_cmd_rdy && iface_ctx.sleep_state == HL7800_SLEEP_AWAKE &&
686 		   iface_ctx.allow_sleep) {
687 		PRINT_NOT_AWAKE_MSG;
688 
689 		if (iface_ctx.desired_sleep_level == HL7800_SLEEP_HIBERNATE ||
690 		    iface_ctx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE) {
691 			/* If the device is sleeping (not ready to receive commands)
692 			 * then the device may send +KSUP when waking up.
693 			 * We should wait for it.
694 			 */
695 			iface_ctx.wait_for_KSUP = true;
696 			iface_ctx.wait_for_KSUP_tries = 0;
697 
698 			set_sleep_state(iface_ctx.desired_sleep_level);
699 
700 		} else if (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP) {
701 			set_sleep_state(HL7800_SLEEP_SLEEP);
702 		}
703 	}
704 #endif
705 }
706 
hl7800_RX_lock(void)707 static int hl7800_RX_lock(void)
708 {
709 	HL7800_RX_LOCK_DBG_LOG("Locking RX [%p]...", k_current_get());
710 	int rc = k_sem_take(&hl7800_RX_lock_sem, K_FOREVER);
711 
712 	if (rc != 0) {
713 		LOG_ERR("Unable to lock hl7800 (%d)", rc);
714 	} else {
715 		HL7800_RX_LOCK_DBG_LOG("Locked RX [%p]", k_current_get());
716 	}
717 
718 	return rc;
719 }
720 
hl7800_RX_unlock(void)721 static void hl7800_RX_unlock(void)
722 {
723 	HL7800_RX_LOCK_DBG_LOG("UNLocking RX [%p]...", k_current_get());
724 	k_sem_give(&hl7800_RX_lock_sem);
725 	HL7800_RX_LOCK_DBG_LOG("UNLocked RX [%p]", k_current_get());
726 }
727 
hl7800_RX_locked(void)728 static bool hl7800_RX_locked(void)
729 {
730 	if (k_sem_count_get(&hl7800_RX_lock_sem) == 0) {
731 		return true;
732 	} else {
733 		return false;
734 	}
735 }
736 
hl7800_TX_lock(void)737 static int hl7800_TX_lock(void)
738 {
739 	HL7800_TX_LOCK_DBG_LOG("Locking TX [%p]...", k_current_get());
740 	int rc = k_sem_take(&hl7800_TX_lock_sem, K_FOREVER);
741 
742 	if (rc != 0) {
743 		LOG_ERR("Unable to lock hl7800 (%d)", rc);
744 	} else {
745 		HL7800_TX_LOCK_DBG_LOG("Locked TX [%p]", k_current_get());
746 	}
747 
748 	return rc;
749 }
750 
hl7800_TX_unlock(void)751 static void hl7800_TX_unlock(void)
752 {
753 	HL7800_TX_LOCK_DBG_LOG("UNLocking TX [%p]...", k_current_get());
754 	k_sem_give(&hl7800_TX_lock_sem);
755 	HL7800_TX_LOCK_DBG_LOG("UNLocked TX [%p]", k_current_get());
756 }
757 
hl7800_TX_locked(void)758 static bool hl7800_TX_locked(void)
759 {
760 	if (k_sem_count_get(&hl7800_TX_lock_sem) == 0) {
761 		return true;
762 	} else {
763 		return false;
764 	}
765 }
766 
hl7800_lock(void)767 static void hl7800_lock(void)
768 {
769 	hl7800_TX_lock();
770 	hl7800_RX_lock();
771 }
772 
hl7800_unlock(void)773 static void hl7800_unlock(void)
774 {
775 	hl7800_RX_unlock();
776 	hl7800_TX_unlock();
777 }
778 
socket_get(void)779 static struct hl7800_socket *socket_get(void)
780 {
781 	int i;
782 	struct hl7800_socket *sock = NULL;
783 
784 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
785 		if (!iface_ctx.sockets[i].context) {
786 			sock = &iface_ctx.sockets[i];
787 			break;
788 		}
789 	}
790 
791 	return sock;
792 }
793 
socket_from_id(int socket_id)794 static struct hl7800_socket *socket_from_id(int socket_id)
795 {
796 	int i;
797 	struct hl7800_socket *sock = NULL;
798 
799 	if (socket_id < 1) {
800 		return NULL;
801 	}
802 
803 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
804 		if (iface_ctx.sockets[i].socket_id == socket_id) {
805 			sock = &iface_ctx.sockets[i];
806 			break;
807 		}
808 	}
809 
810 	return sock;
811 }
812 
set_busy(bool busy)813 static inline void set_busy(bool busy)
814 {
815 	iface_ctx.busy = busy;
816 }
817 
socket_put(struct hl7800_socket * sock)818 static void socket_put(struct hl7800_socket *sock)
819 {
820 	if (!sock) {
821 		return;
822 	}
823 
824 	sock->context = NULL;
825 	sock->socket_id = MDM_INVALID_SOCKET_ID;
826 	sock->created = false;
827 	sock->reconfig = false;
828 	sock->error = 0;
829 	sock->rx_size = 0;
830 	sock->state = SOCK_IDLE;
831 	(void)memset(&sock->src, 0, sizeof(struct sockaddr));
832 	(void)memset(&sock->dst, 0, sizeof(struct sockaddr));
833 }
834 
hl7800_sprint_ip_addr(const struct sockaddr * addr)835 char *hl7800_sprint_ip_addr(const struct sockaddr *addr)
836 {
837 	static char buf[NET_IPV6_ADDR_LEN];
838 
839 #if defined(CONFIG_NET_IPV6)
840 	if (addr->sa_family == AF_INET6) {
841 		return net_addr_ntop(AF_INET6, &net_sin6(addr)->sin6_addr, buf,
842 				     sizeof(buf));
843 	} else
844 #endif
845 #if defined(CONFIG_NET_IPV4)
846 		if (addr->sa_family == AF_INET) {
847 		return net_addr_ntop(AF_INET, &net_sin(addr)->sin_addr, buf,
848 				     sizeof(buf));
849 	} else
850 #endif
851 	{
852 		LOG_ERR("Unknown IP address family:%d", addr->sa_family);
853 		return NULL;
854 	}
855 }
856 
mdm_hl7800_register_wake_test_point_callback(void (* func)(int state))857 void mdm_hl7800_register_wake_test_point_callback(void (*func)(int state))
858 {
859 	iface_ctx.wake_up_callback = func;
860 }
861 
mdm_hl7800_register_gpio6_callback(void (* func)(int state))862 void mdm_hl7800_register_gpio6_callback(void (*func)(int state))
863 {
864 	iface_ctx.gpio6_callback = func;
865 }
866 
mdm_hl7800_register_cts_callback(void (* func)(int state))867 void mdm_hl7800_register_cts_callback(void (*func)(int state))
868 {
869 	iface_ctx.cts_callback = func;
870 }
871 
modem_assert_reset(bool assert)872 static void modem_assert_reset(bool assert)
873 {
874 	if (assert) {
875 		HL7800_IO_DBG_LOG("MDM_RESET -> ASSERTED");
876 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1);
877 	} else {
878 		HL7800_IO_DBG_LOG("MDM_RESET -> NOT_ASSERTED");
879 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0);
880 	}
881 }
882 
modem_assert_wake(bool assert)883 static void modem_assert_wake(bool assert)
884 {
885 	int state;
886 
887 	if (assert) {
888 		HL7800_IO_DBG_LOG("MDM_WAKE_PIN -> ASSERTED");
889 		state = 1;
890 	} else {
891 		HL7800_IO_DBG_LOG("MDM_WAKE_PIN -> NOT_ASSERTED");
892 		state = 0;
893 	}
894 
895 	gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_WAKE], state);
896 
897 	if (iface_ctx.wake_up_callback != NULL) {
898 		iface_ctx.wake_up_callback(state);
899 	}
900 }
901 
modem_assert_pwr_on(bool assert)902 static void modem_assert_pwr_on(bool assert)
903 {
904 	if (assert) {
905 		HL7800_IO_DBG_LOG("MDM_PWR_ON -> ASSERTED");
906 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_PWR_ON], 1);
907 	} else {
908 		HL7800_IO_DBG_LOG("MDM_PWR_ON -> NOT_ASSERTED");
909 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_PWR_ON], 0);
910 	}
911 }
912 
modem_assert_fast_shutd(bool assert)913 static void modem_assert_fast_shutd(bool assert)
914 {
915 	if (assert) {
916 		HL7800_IO_DBG_LOG("MDM_FAST_SHUTD -> ASSERTED");
917 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], 1);
918 	} else {
919 		HL7800_IO_DBG_LOG("MDM_FAST_SHUTD -> NOT_ASSERTED");
920 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], 0);
921 	}
922 }
923 
allow_sleep_work_callback(struct k_work * item)924 static void allow_sleep_work_callback(struct k_work *item)
925 {
926 	ARG_UNUSED(item);
927 	if (!iface_ctx.busy) {
928 		LOG_DBG("Allow sleep");
929 		iface_ctx.allow_sleep = true;
930 		set_sleep_state(iface_ctx.desired_sleep_level);
931 		modem_assert_wake(false);
932 	} else {
933 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.allow_sleep_work,
934 					    K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS));
935 	}
936 }
937 
allow_sleep(bool allow)938 static void allow_sleep(bool allow)
939 {
940 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
941 	if (allow) {
942 		if (!iface_ctx.restarting && !iface_ctx.busy) {
943 			k_work_reschedule_for_queue(
944 				&hl7800_workq, &iface_ctx.allow_sleep_work,
945 				K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS));
946 		} else {
947 			k_work_cancel_delayable(&iface_ctx.allow_sleep_work);
948 		}
949 	} else {
950 		LOG_DBG("Keep awake");
951 		k_work_cancel_delayable(&iface_ctx.allow_sleep_work);
952 		iface_ctx.allow_sleep = false;
953 		modem_assert_wake(true);
954 	}
955 #endif
956 }
957 
event_handler(enum mdm_hl7800_event event,void * event_data)958 static void event_handler(enum mdm_hl7800_event event, void *event_data)
959 {
960 	sys_snode_t *node;
961 	struct mdm_hl7800_callback_agent *agent;
962 	int ret;
963 
964 	ret = k_sem_take(&cb_lock, K_FOREVER);
965 	if (ret == 0) {
966 		SYS_SLIST_FOR_EACH_NODE(&hl7800_event_callback_list, node) {
967 			agent = CONTAINER_OF(node, struct mdm_hl7800_callback_agent, node);
968 			if (agent->event_callback != NULL) {
969 				agent->event_callback(event, event_data);
970 			}
971 		}
972 		k_sem_give(&cb_lock);
973 	}
974 }
975 
mdm_hl7800_get_signal_quality(int * rsrp,int * sinr)976 void mdm_hl7800_get_signal_quality(int *rsrp, int *sinr)
977 {
978 	if (CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS == 0) {
979 		rssi_query();
980 	}
981 
982 	*rsrp = iface_ctx.mdm_rssi;
983 	*sinr = iface_ctx.mdm_sinr;
984 }
985 
mdm_hl7800_wakeup(bool wakeup)986 void mdm_hl7800_wakeup(bool wakeup)
987 {
988 	allow_sleep(!wakeup);
989 }
990 
991 /* Send an AT command with a series of response handlers */
send_at_cmd(struct hl7800_socket * sock,const uint8_t * data,k_timeout_t timeout,int retries,bool no_id_resp)992 static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data,
993 		       k_timeout_t timeout, int retries, bool no_id_resp)
994 {
995 	int ret = 0;
996 
997 	iface_ctx.last_error = 0;
998 
999 	do {
1000 		if (!sock) {
1001 			k_sem_reset(&iface_ctx.response_sem);
1002 			iface_ctx.last_socket_id = 0;
1003 			iface_ctx.socket_cmd = false;
1004 		} else {
1005 			sock->error = 0;
1006 			iface_ctx.socket_cmd = true;
1007 			k_sem_reset(&sock->sock_send_sem);
1008 			iface_ctx.last_socket_id = sock->socket_id;
1009 		}
1010 		if (no_id_resp) {
1011 			strncpy(iface_ctx.no_id_resp_cmd, data,
1012 				sizeof(iface_ctx.no_id_resp_cmd) - 1);
1013 			iface_ctx.search_no_id_resp = true;
1014 		}
1015 
1016 		LOG_DBG("OUT: [%s]", (char *)data);
1017 		mdm_receiver_send(&iface_ctx.mdm_ctx, data, strlen(data));
1018 		mdm_receiver_send(&iface_ctx.mdm_ctx, "\r", 1);
1019 
1020 		if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
1021 			goto done;
1022 		}
1023 
1024 		if (!sock) {
1025 			ret = k_sem_take(&iface_ctx.response_sem, timeout);
1026 		} else {
1027 			ret = k_sem_take(&sock->sock_send_sem, timeout);
1028 		}
1029 
1030 		if (ret == 0) {
1031 			if (sock) {
1032 				ret = sock->error;
1033 			} else {
1034 				ret = iface_ctx.last_error;
1035 			}
1036 		} else if (ret == -EAGAIN) {
1037 			ret = -ETIMEDOUT;
1038 		}
1039 
1040 		retries--;
1041 		if (retries < 0) {
1042 			retries = 0;
1043 		}
1044 	} while (ret != 0 && retries > 0);
1045 done:
1046 	iface_ctx.search_no_id_resp = false;
1047 	return ret;
1048 }
1049 
wakeup_hl7800(void)1050 static int wakeup_hl7800(void)
1051 {
1052 	set_busy(true);
1053 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
1054 	int ret;
1055 
1056 	allow_sleep(false);
1057 
1058 	/* If modem is in sleep mode (not hibernate),
1059 	 * then it can respond in ~10 ms.
1060 	 */
1061 	if (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP) {
1062 		k_sleep(MDM_WAKE_TO_CHECK_CTS_DELAY_MS);
1063 	}
1064 
1065 	if (!is_cmd_ready()) {
1066 		LOG_DBG("Waiting to wakeup");
1067 		ret = k_sem_take(&iface_ctx.mdm_awake, MDM_WAKEUP_TIME);
1068 		if (ret) {
1069 			LOG_DBG("Err waiting for wakeup: %d", ret);
1070 		}
1071 	}
1072 #endif
1073 	return 0;
1074 }
1075 
mdm_hl7800_send_at_cmd(const uint8_t * data)1076 int32_t mdm_hl7800_send_at_cmd(const uint8_t *data)
1077 {
1078 	int ret;
1079 
1080 	if (!data) {
1081 		return -EINVAL;
1082 	}
1083 
1084 	hl7800_lock();
1085 	wakeup_hl7800();
1086 	iface_ctx.last_socket_id = 0;
1087 	ret = send_at_cmd(NULL, data, MDM_CMD_SEND_TIMEOUT, 0, false);
1088 	set_busy(false);
1089 	allow_sleep(true);
1090 	hl7800_unlock();
1091 	return ret;
1092 }
1093 
1094 /* The access point name (and username and password) are stored in the modem's
1095  * non-volatile memory.
1096  */
mdm_hl7800_update_apn(char * access_point_name)1097 int32_t mdm_hl7800_update_apn(char *access_point_name)
1098 {
1099 	int ret = -EINVAL;
1100 
1101 	hl7800_lock();
1102 	wakeup_hl7800();
1103 	iface_ctx.last_socket_id = 0;
1104 	ret = write_apn(access_point_name);
1105 	set_busy(false);
1106 	allow_sleep(true);
1107 	hl7800_unlock();
1108 
1109 	if (ret >= 0) {
1110 		/* After a reset the APN will be re-read from the modem
1111 		 * and an event will be generated.
1112 		 */
1113 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.mdm_reset_work,
1114 					    K_NO_WAIT);
1115 	}
1116 	return ret;
1117 }
1118 
mdm_hl7800_valid_rat(uint8_t value)1119 bool mdm_hl7800_valid_rat(uint8_t value)
1120 {
1121 	if ((value == MDM_RAT_CAT_M1) || (value == MDM_RAT_CAT_NB1)) {
1122 		return true;
1123 	}
1124 	return false;
1125 }
1126 
mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value)1127 int32_t mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value)
1128 {
1129 	int ret = -EINVAL;
1130 
1131 	if (value == iface_ctx.mdm_rat) {
1132 		/* The set command will fail (in the modem)
1133 		 * if the RAT isn't different.
1134 		 */
1135 		return 0;
1136 	} else if (!mdm_hl7800_valid_rat(value)) {
1137 		return ret;
1138 	}
1139 
1140 	hl7800_lock();
1141 	wakeup_hl7800();
1142 	iface_ctx.last_socket_id = 0;
1143 
1144 	if (value == MDM_RAT_CAT_M1) {
1145 		if (iface_ctx.new_rat_cmd_support) {
1146 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD);
1147 		} else {
1148 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD_LEGACY);
1149 		}
1150 	} else { /* MDM_RAT_CAT_NB1 */
1151 		if (iface_ctx.new_rat_cmd_support) {
1152 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD);
1153 		} else {
1154 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD_LEGACY);
1155 		}
1156 	}
1157 
1158 error:
1159 
1160 	set_busy(false);
1161 	allow_sleep(true);
1162 	hl7800_unlock();
1163 
1164 	/* Changing the RAT causes the modem to reset.
1165 	 * A reset and reconfigure ensures the modem configuration and
1166 	 * state are valid.
1167 	 */
1168 	if (ret >= 0) {
1169 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.mdm_reset_work, K_NO_WAIT);
1170 	}
1171 
1172 	return ret;
1173 }
1174 
mdm_hl7800_get_local_time(struct tm * tm,int32_t * offset)1175 int32_t mdm_hl7800_get_local_time(struct tm *tm, int32_t *offset)
1176 {
1177 	int ret;
1178 
1179 	iface_ctx.local_time_valid = false;
1180 
1181 	hl7800_lock();
1182 	wakeup_hl7800();
1183 	iface_ctx.last_socket_id = 0;
1184 	ret = send_at_cmd(NULL, "AT+CCLK?", MDM_CMD_SEND_TIMEOUT, 0, false);
1185 	set_busy(false);
1186 	allow_sleep(true);
1187 	if (iface_ctx.local_time_valid) {
1188 		memcpy(tm, &iface_ctx.local_time, sizeof(struct tm));
1189 		memcpy(offset, &iface_ctx.local_time_offset, sizeof(*offset));
1190 	} else {
1191 		ret = -EIO;
1192 	}
1193 	hl7800_unlock();
1194 	return ret;
1195 }
1196 
mdm_hl7800_get_operator_index(void)1197 int32_t mdm_hl7800_get_operator_index(void)
1198 {
1199 	int ret;
1200 
1201 	hl7800_lock();
1202 	wakeup_hl7800();
1203 	iface_ctx.last_socket_id = 0;
1204 	ret = send_at_cmd(NULL, "AT+KCARRIERCFG?", MDM_CMD_SEND_TIMEOUT, 0,
1205 			  false);
1206 	set_busy(false);
1207 	allow_sleep(true);
1208 	hl7800_unlock();
1209 	if (ret < 0) {
1210 		return ret;
1211 	} else {
1212 		return iface_ctx.operator_index;
1213 	}
1214 }
1215 
mdm_hl7800_get_functionality(void)1216 int32_t mdm_hl7800_get_functionality(void)
1217 {
1218 	int ret;
1219 
1220 	hl7800_lock();
1221 	wakeup_hl7800();
1222 	iface_ctx.last_socket_id = 0;
1223 	ret = send_at_cmd(NULL, "AT+CFUN?", MDM_CMD_SEND_TIMEOUT, 0, false);
1224 	set_busy(false);
1225 	allow_sleep(true);
1226 	hl7800_unlock();
1227 
1228 	if (ret < 0) {
1229 		return ret;
1230 	} else {
1231 		return iface_ctx.functionality;
1232 	}
1233 }
1234 
mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode)1235 int32_t mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode)
1236 {
1237 	int ret;
1238 	char buf[sizeof("AT+CFUN=###,0")] = { 0 };
1239 
1240 	hl7800_lock();
1241 	wakeup_hl7800();
1242 	snprintk(buf, sizeof(buf), "AT+CFUN=%u,0", mode);
1243 	iface_ctx.last_socket_id = 0;
1244 	ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT,
1245 			  MDM_DEFAULT_AT_CMD_RETRIES, false);
1246 	set_busy(false);
1247 	allow_sleep(true);
1248 	hl7800_unlock();
1249 
1250 	return ret;
1251 }
1252 
1253 #ifdef CONFIG_MODEM_HL7800_GPS
mdm_hl7800_set_gps_rate(uint32_t rate)1254 int32_t mdm_hl7800_set_gps_rate(uint32_t rate)
1255 {
1256 	int ret = -1;
1257 
1258 	hl7800_lock();
1259 	wakeup_hl7800();
1260 	iface_ctx.gps_query_location_rate_seconds = rate;
1261 
1262 	/* Stopping first allows changing the rate between two non-zero values.
1263 	 * Ignore error if GNSS isn't running.
1264 	 */
1265 	SEND_AT_CMD_IGNORE_ERROR("AT+GNSSSTOP");
1266 
1267 	if (rate == 0) {
1268 		SEND_AT_CMD_EXPECT_OK("AT+CFUN=1,0");
1269 	} else {
1270 		/* Navigation doesn't work when LTE is on. */
1271 		SEND_AT_CMD_EXPECT_OK("AT+CFUN=4,0");
1272 
1273 		SEND_AT_CMD_EXPECT_OK("AT+GNSSCONF=1,1");
1274 
1275 		if (IS_ENABLED(CONFIG_MODEM_HL7800_USE_GLONASS)) {
1276 			SEND_AT_CMD_EXPECT_OK("AT+GNSSCONF=10,1");
1277 		}
1278 		/* Enable all NMEA sentences */
1279 		SEND_AT_CMD_EXPECT_OK("AT+GNSSNMEA=0,1000,0,1FF");
1280 		/* Enable GPS */
1281 		SEND_AT_CMD_EXPECT_OK("AT+GNSSSTART=0");
1282 	}
1283 
1284 error:
1285 	if (rate && ret == 0) {
1286 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.gps_work,
1287 					    K_SECONDS(iface_ctx.gps_query_location_rate_seconds));
1288 	} else {
1289 		k_work_cancel_delayable(&iface_ctx.gps_work);
1290 	}
1291 	LOG_DBG("GPS status: %d rate: %u", ret, rate);
1292 
1293 	set_busy(false);
1294 	allow_sleep(true);
1295 	hl7800_unlock();
1296 	return ret;
1297 }
1298 #endif /* CONFIG_MODEM_HL7800_GPS */
1299 
1300 #ifdef CONFIG_MODEM_HL7800_POLTE
mdm_hl7800_polte_register(void)1301 int32_t mdm_hl7800_polte_register(void)
1302 {
1303 	int ret = -1;
1304 
1305 	hl7800_lock();
1306 	wakeup_hl7800();
1307 	/* register for events */
1308 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1");
1309 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1");
1310 	/* register with polte.io */
1311 	SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"REGISTER\"");
1312 error:
1313 	LOG_DBG("PoLTE register status: %d", ret);
1314 	set_busy(false);
1315 	allow_sleep(true);
1316 	hl7800_unlock();
1317 	return ret;
1318 }
1319 
mdm_hl7800_polte_enable(char * user,char * password)1320 int32_t mdm_hl7800_polte_enable(char *user, char *password)
1321 {
1322 	int ret = -1;
1323 	char buf[sizeof(MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR) +
1324 		 MDM_HL7800_MAX_POLTE_USER_ID_SIZE + MDM_HL7800_MAX_POLTE_PASSWORD_SIZE] = { 0 };
1325 
1326 	hl7800_lock();
1327 	wakeup_hl7800();
1328 
1329 	/* register for events */
1330 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1");
1331 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1");
1332 	/*  restore user and password (not saved in NV by modem) */
1333 	snprintk(buf, sizeof(buf), MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR, user, password);
1334 	ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false);
1335 
1336 error:
1337 	LOG_DBG("PoLTE register status: %d", ret);
1338 	set_busy(false);
1339 	allow_sleep(true);
1340 	hl7800_unlock();
1341 	return ret;
1342 }
1343 
mdm_hl7800_polte_locate(void)1344 int32_t mdm_hl7800_polte_locate(void)
1345 {
1346 	int ret = -1;
1347 
1348 	hl7800_lock();
1349 	wakeup_hl7800();
1350 	SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"LOCATE\",2,1");
1351 error:
1352 	LOG_DBG("PoLTE locate status: %d", ret);
1353 	set_busy(false);
1354 	allow_sleep(true);
1355 	hl7800_unlock();
1356 	return ret;
1357 }
1358 
1359 #endif /* CONFIG_MODEM_HL7800_POLTE */
1360 
1361 /**
1362  * @brief Perform a site survey.
1363  *
1364  */
mdm_hl7800_perform_site_survey(void)1365 int32_t mdm_hl7800_perform_site_survey(void)
1366 {
1367 	int ret;
1368 
1369 	hl7800_lock();
1370 	wakeup_hl7800();
1371 	ret = send_at_cmd(NULL, "at%meas=\"97\"", MDM_CMD_SEND_TIMEOUT, 0, false);
1372 	set_busy(false);
1373 	allow_sleep(true);
1374 	hl7800_unlock();
1375 	return ret;
1376 }
1377 
mdm_hl7800_generate_status_events(void)1378 void mdm_hl7800_generate_status_events(void)
1379 {
1380 	hl7800_lock();
1381 	generate_startup_state_event();
1382 	generate_network_state_event();
1383 	generate_sleep_state_event();
1384 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
1385 	generate_fota_state_event();
1386 #endif
1387 	event_handler(HL7800_EVENT_RSSI, &iface_ctx.mdm_rssi);
1388 	event_handler(HL7800_EVENT_SINR, &iface_ctx.mdm_sinr);
1389 	event_handler(HL7800_EVENT_APN_UPDATE, &iface_ctx.mdm_apn);
1390 	event_handler(HL7800_EVENT_RAT, &iface_ctx.mdm_rat);
1391 	event_handler(HL7800_EVENT_BANDS, iface_ctx.mdm_bands_string);
1392 	event_handler(HL7800_EVENT_ACTIVE_BANDS, iface_ctx.mdm_active_bands_string);
1393 	event_handler(HL7800_EVENT_REVISION, iface_ctx.mdm_revision);
1394 	hl7800_unlock();
1395 }
1396 
mdm_hl7800_log_filter_set(uint32_t level)1397 uint32_t mdm_hl7800_log_filter_set(uint32_t level)
1398 {
1399 	uint32_t new_log_level = 0;
1400 
1401 #ifdef CONFIG_LOG_RUNTIME_FILTERING
1402 	new_log_level =
1403 		log_filter_set(NULL, Z_LOG_LOCAL_DOMAIN_ID,
1404 			       log_source_id_get(STRINGIFY(LOG_MODULE_NAME)),
1405 			       level);
1406 #endif
1407 
1408 	return new_log_level;
1409 }
1410 
send_data(struct hl7800_socket * sock,struct net_pkt * pkt)1411 static int send_data(struct hl7800_socket *sock, struct net_pkt *pkt)
1412 {
1413 	int ret;
1414 	struct net_buf *frag;
1415 	char dst_addr[NET_IPV6_ADDR_LEN];
1416 	char buf[sizeof("AT+KUDPSND=##,\"" IPV6_ADDR_FORMAT "\",#####,####")];
1417 	size_t send_len, actual_send_len;
1418 
1419 	send_len = 0, actual_send_len = 0;
1420 
1421 	if (!sock) {
1422 		return -EINVAL;
1423 	}
1424 
1425 	sock->error = 0;
1426 	sock->state = SOCK_TX;
1427 
1428 	frag = pkt->frags;
1429 	send_len = net_buf_frags_len(frag);
1430 	/* start sending data */
1431 	k_sem_reset(&sock->sock_send_sem);
1432 	if (sock->type == SOCK_STREAM) {
1433 		snprintk(buf, sizeof(buf), "AT+KTCPSND=%d,%zu", sock->socket_id,
1434 			 send_len);
1435 	} else {
1436 		if (!net_addr_ntop(sock->family, &net_sin(&sock->dst)->sin_addr,
1437 				   dst_addr, sizeof(dst_addr))) {
1438 			LOG_ERR("Invalid dst addr");
1439 			return -EINVAL;
1440 		}
1441 		snprintk(buf, sizeof(buf), "AT+KUDPSND=%d,\"%s\",%u,%zu",
1442 			 sock->socket_id, dst_addr,
1443 			 net_sin(&sock->dst)->sin_port, send_len);
1444 	}
1445 	send_at_cmd(sock, buf, K_NO_WAIT, 0, false);
1446 
1447 	/* wait for CONNECT  or error */
1448 	ret = k_sem_take(&sock->sock_send_sem, MDM_IP_SEND_RX_TIMEOUT);
1449 	if (ret) {
1450 		LOG_ERR("Err waiting for CONNECT (%d)", ret);
1451 		goto done;
1452 	}
1453 	/* check for error */
1454 	if (sock->error != 0) {
1455 		ret = sock->error;
1456 		LOG_ERR("AT+K**PSND (%d)", ret);
1457 		goto done;
1458 	}
1459 
1460 	/* Loop through packet data and send */
1461 	while (frag) {
1462 		actual_send_len += frag->len;
1463 		mdm_receiver_send(&iface_ctx.mdm_ctx, frag->data, frag->len);
1464 		frag = frag->frags;
1465 	}
1466 	if (actual_send_len != send_len) {
1467 		LOG_WRN("AT+K**PSND act: %zd exp: %zd", actual_send_len,
1468 			send_len);
1469 	}
1470 	LOG_DBG("Sent %zu bytes", actual_send_len);
1471 
1472 	/* Send EOF pattern to terminate data */
1473 	k_sem_reset(&sock->sock_send_sem);
1474 	mdm_receiver_send(&iface_ctx.mdm_ctx, EOF_PATTERN, strlen(EOF_PATTERN));
1475 	ret = k_sem_take(&sock->sock_send_sem, MDM_IP_SEND_RX_TIMEOUT);
1476 	if (ret == 0) {
1477 		ret = sock->error;
1478 	} else if (ret == -EAGAIN) {
1479 		ret = -ETIMEDOUT;
1480 	}
1481 done:
1482 	if (sock->type == SOCK_STREAM) {
1483 		if (sock->error == 0) {
1484 			sock->state = SOCK_CONNECTED;
1485 		}
1486 	} else {
1487 		sock->state = SOCK_IDLE;
1488 	}
1489 
1490 	return ret;
1491 }
1492 
1493 /*** NET_BUF HELPERS ***/
1494 
is_crlf(uint8_t c)1495 static bool is_crlf(uint8_t c)
1496 {
1497 	if (c == '\n' || c == '\r') {
1498 		return true;
1499 	} else {
1500 		return false;
1501 	}
1502 }
1503 
net_buf_skipcrlf(struct net_buf ** buf)1504 static void net_buf_skipcrlf(struct net_buf **buf)
1505 {
1506 	/* chop off any /n or /r */
1507 	while (*buf && is_crlf(*(*buf)->data)) {
1508 		net_buf_pull_u8(*buf);
1509 		if (!(*buf)->len) {
1510 			*buf = net_buf_frag_del(NULL, *buf);
1511 		}
1512 	}
1513 }
1514 
net_buf_findcrlf(struct net_buf * buf,struct net_buf ** frag)1515 static uint16_t net_buf_findcrlf(struct net_buf *buf, struct net_buf **frag)
1516 {
1517 	uint16_t len = 0U, pos = 0U;
1518 
1519 	while (buf && !is_crlf(*(buf->data + pos))) {
1520 		if (pos + 1 >= buf->len) {
1521 			len += buf->len;
1522 			buf = buf->frags;
1523 			pos = 0U;
1524 		} else {
1525 			pos++;
1526 		}
1527 	}
1528 
1529 	if (buf && is_crlf(*(buf->data + pos))) {
1530 		len += pos;
1531 		*frag = buf;
1532 		return len;
1533 	}
1534 
1535 	return 0;
1536 }
1537 
net_buf_get_u8(struct net_buf ** buf)1538 static uint8_t net_buf_get_u8(struct net_buf **buf)
1539 {
1540 	uint8_t val = net_buf_pull_u8(*buf);
1541 
1542 	if (!(*buf)->len) {
1543 		*buf = net_buf_frag_del(NULL, *buf);
1544 	}
1545 	return val;
1546 }
1547 
net_buf_remove(struct net_buf ** buf,uint32_t len)1548 static uint32_t net_buf_remove(struct net_buf **buf, uint32_t len)
1549 {
1550 	uint32_t to_remove;
1551 	uint32_t removed = 0;
1552 
1553 	while (*buf && len > 0) {
1554 		to_remove = (*buf)->len;
1555 		if (to_remove > len) {
1556 			to_remove = len;
1557 		}
1558 		net_buf_pull(*buf, to_remove);
1559 		removed += to_remove;
1560 		len -= to_remove;
1561 		if (!(*buf)->len) {
1562 			*buf = net_buf_frag_del(NULL, *buf);
1563 		}
1564 	}
1565 	return removed;
1566 }
1567 
1568 /*** UDP / TCP Helper Function ***/
1569 
1570 /* Setup IP header data to be used by some network applications.
1571  * While much is dummy data, some fields such as dst, port and family are
1572  * important.
1573  * Return the IP + protocol header length.
1574  */
pkt_setup_ip_data(struct net_pkt * pkt,struct hl7800_socket * sock)1575 static int pkt_setup_ip_data(struct net_pkt *pkt, struct hl7800_socket *sock)
1576 {
1577 	int hdr_len = 0;
1578 	uint16_t src_port = 0U, dst_port = 0U;
1579 #if defined(CONFIG_NET_TCP)
1580 	struct net_tcp_hdr *tcp;
1581 #endif
1582 
1583 #if defined(CONFIG_NET_IPV6)
1584 	if (net_pkt_family(pkt) == AF_INET6) {
1585 		if (net_ipv6_create(
1586 			    pkt,
1587 			    &((struct sockaddr_in6 *)&sock->dst)->sin6_addr,
1588 			    &((struct sockaddr_in6 *)&sock->src)->sin6_addr)) {
1589 			return -1;
1590 		}
1591 		net_pkt_set_remote_address(pkt, &sock->dst, sizeof(struct sockaddr_in6));
1592 		pkt->remote.sa_family = AF_INET6;
1593 		src_port = ntohs(net_sin6(&sock->src)->sin6_port);
1594 		dst_port = ntohs(net_sin6(&sock->dst)->sin6_port);
1595 
1596 		hdr_len = sizeof(struct net_ipv6_hdr);
1597 	}
1598 #endif
1599 #if defined(CONFIG_NET_IPV4)
1600 	if (net_pkt_family(pkt) == AF_INET) {
1601 		if (net_ipv4_create(
1602 			    pkt, &((struct sockaddr_in *)&sock->dst)->sin_addr,
1603 			    &((struct sockaddr_in *)&sock->src)->sin_addr)) {
1604 			return -1;
1605 		}
1606 		net_pkt_set_remote_address(pkt, &sock->dst, sizeof(struct sockaddr_in));
1607 		pkt->remote.sa_family = AF_INET;
1608 		src_port = ntohs(net_sin(&sock->src)->sin_port);
1609 		dst_port = ntohs(net_sin(&sock->dst)->sin_port);
1610 
1611 		hdr_len = sizeof(struct net_ipv4_hdr);
1612 	}
1613 #endif
1614 
1615 #if defined(CONFIG_NET_UDP)
1616 	if (sock->ip_proto == IPPROTO_UDP) {
1617 		if (net_udp_create(pkt, dst_port, src_port)) {
1618 			return -1;
1619 		}
1620 
1621 		hdr_len += NET_UDPH_LEN;
1622 	}
1623 #endif
1624 #if defined(CONFIG_NET_TCP)
1625 	if (sock->ip_proto == IPPROTO_TCP) {
1626 		NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr);
1627 
1628 		tcp = (struct net_tcp_hdr *)net_pkt_get_data(pkt, &tcp_access);
1629 		if (!tcp) {
1630 			return -1;
1631 		}
1632 
1633 		(void)memset(tcp, 0, NET_TCPH_LEN);
1634 
1635 		/* Setup TCP header */
1636 		tcp->src_port = dst_port;
1637 		tcp->dst_port = src_port;
1638 
1639 		if (net_pkt_set_data(pkt, &tcp_access)) {
1640 			return -1;
1641 		}
1642 
1643 		hdr_len += NET_TCPH_LEN;
1644 	}
1645 #endif /* CONFIG_NET_TCP */
1646 
1647 	return hdr_len;
1648 }
1649 
1650 /*** MODEM RESPONSE HANDLERS ***/
1651 
wait_for_modem_data(struct net_buf ** buf,uint32_t current_len,uint32_t expected_len)1652 static uint32_t wait_for_modem_data(struct net_buf **buf, uint32_t current_len,
1653 				    uint32_t expected_len)
1654 {
1655 	uint32_t waitForDataTries = 0;
1656 
1657 	while ((current_len < expected_len) &&
1658 	       (waitForDataTries < MDM_WAIT_FOR_DATA_RETRIES)) {
1659 		LOG_DBG("cur:%d, exp:%d", current_len, expected_len);
1660 		k_sleep(MDM_WAIT_FOR_DATA_TIME);
1661 		current_len += hl7800_read_rx(buf);
1662 		waitForDataTries++;
1663 	}
1664 
1665 	return current_len;
1666 }
1667 
wait_for_modem_data_and_newline(struct net_buf ** buf,uint32_t current_len,uint32_t expected_len)1668 static uint32_t wait_for_modem_data_and_newline(struct net_buf **buf,
1669 						uint32_t current_len,
1670 						uint32_t expected_len)
1671 {
1672 	return wait_for_modem_data(buf, current_len,
1673 				   (expected_len + strlen("\r\n")));
1674 }
1675 
1676 /* Handler: AT+CGMI */
on_cmd_atcmdinfo_manufacturer(struct net_buf ** buf,uint16_t len)1677 static bool on_cmd_atcmdinfo_manufacturer(struct net_buf **buf, uint16_t len)
1678 {
1679 	struct net_buf *frag = NULL;
1680 	size_t out_len;
1681 	int len_no_null = MDM_MANUFACTURER_LENGTH - 1;
1682 
1683 	/* make sure revision data is received
1684 	 *  waiting for: Sierra Wireless\r\n
1685 	 */
1686 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1687 					MDM_MANUFACTURER_LENGTH);
1688 
1689 	frag = NULL;
1690 	len = net_buf_findcrlf(*buf, &frag);
1691 	if (!frag) {
1692 		LOG_ERR("Unable to find mfg end");
1693 		goto done;
1694 	}
1695 	if (len < len_no_null) {
1696 		LOG_WRN("mfg too short (len:%d)", len);
1697 	} else if (len > len_no_null) {
1698 		LOG_WRN("mfg too long (len:%d)", len);
1699 		len = MDM_MANUFACTURER_LENGTH;
1700 	}
1701 
1702 	out_len = net_buf_linearize(iface_ctx.mdm_manufacturer,
1703 				    sizeof(iface_ctx.mdm_manufacturer) - 1, *buf, 0,
1704 				    len);
1705 	iface_ctx.mdm_manufacturer[out_len] = 0;
1706 	LOG_INF("Manufacturer: %s", iface_ctx.mdm_manufacturer);
1707 done:
1708 	return true;
1709 }
1710 
1711 /* Handler: AT+CGMM */
on_cmd_atcmdinfo_model(struct net_buf ** buf,uint16_t len)1712 static bool on_cmd_atcmdinfo_model(struct net_buf **buf, uint16_t len)
1713 {
1714 	struct net_buf *frag = NULL;
1715 	size_t out_len;
1716 	int len_no_null = MDM_MODEL_LENGTH - 1;
1717 
1718 	/* make sure model data is received
1719 	 *  waiting for: HL7800\r\n
1720 	 */
1721 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1722 					MDM_MODEL_LENGTH);
1723 
1724 	frag = NULL;
1725 	len = net_buf_findcrlf(*buf, &frag);
1726 	if (!frag) {
1727 		LOG_ERR("Unable to find model end");
1728 		goto done;
1729 	}
1730 	if (len < len_no_null) {
1731 		LOG_WRN("model too short (len:%d)", len);
1732 	} else if (len > len_no_null) {
1733 		LOG_WRN("model too long (len:%d)", len);
1734 		len = MDM_MODEL_LENGTH;
1735 	}
1736 
1737 	out_len = net_buf_linearize(iface_ctx.mdm_model, sizeof(iface_ctx.mdm_model) - 1,
1738 				    *buf, 0, len);
1739 	iface_ctx.mdm_model[out_len] = 0;
1740 	LOG_INF("Model: %s", iface_ctx.mdm_model);
1741 done:
1742 	return true;
1743 }
1744 
1745 /* Handler: AT+CGMR */
on_cmd_atcmdinfo_revision(struct net_buf ** buf,uint16_t len)1746 static bool on_cmd_atcmdinfo_revision(struct net_buf **buf, uint16_t len)
1747 {
1748 	struct net_buf *frag = NULL;
1749 	size_t out_len;
1750 
1751 	/* make sure revision data is received
1752 	 *  waiting for something like: AHL7800.1.2.3.1.20171211\r\n
1753 	 */
1754 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1755 					MDM_HL7800_REVISION_MAX_SIZE);
1756 
1757 	frag = NULL;
1758 	len = net_buf_findcrlf(*buf, &frag);
1759 	if (!frag) {
1760 		LOG_ERR("Unable to find rev end");
1761 		goto done;
1762 	}
1763 	if (len == 0) {
1764 		LOG_WRN("revision not found");
1765 	} else if (len > MDM_HL7800_REVISION_MAX_STRLEN) {
1766 		LOG_WRN("revision too long (len:%d)", len);
1767 		len = MDM_HL7800_REVISION_MAX_STRLEN;
1768 	}
1769 
1770 	out_len = net_buf_linearize(
1771 		iface_ctx.mdm_revision, sizeof(iface_ctx.mdm_revision) - 1, *buf, 0, len);
1772 	iface_ctx.mdm_revision[out_len] = 0;
1773 	LOG_INF("Revision: %s", iface_ctx.mdm_revision);
1774 	event_handler(HL7800_EVENT_REVISION, iface_ctx.mdm_revision);
1775 done:
1776 	return true;
1777 }
1778 
1779 /* Handler: AT+CGSN */
on_cmd_atcmdinfo_imei(struct net_buf ** buf,uint16_t len)1780 static bool on_cmd_atcmdinfo_imei(struct net_buf **buf, uint16_t len)
1781 {
1782 	struct net_buf *frag = NULL;
1783 	size_t out_len;
1784 
1785 	/* make sure IMEI data is received
1786 	 *  waiting for: ###############\r\n
1787 	 */
1788 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1789 					MDM_HL7800_IMEI_SIZE);
1790 
1791 	frag = NULL;
1792 	len = net_buf_findcrlf(*buf, &frag);
1793 	if (!frag) {
1794 		LOG_ERR("Unable to find IMEI end");
1795 		goto done;
1796 	}
1797 	if (len < MDM_HL7800_IMEI_STRLEN) {
1798 		LOG_WRN("IMEI too short (len:%d)", len);
1799 	} else if (len > MDM_HL7800_IMEI_STRLEN) {
1800 		LOG_WRN("IMEI too long (len:%d)", len);
1801 		len = MDM_HL7800_IMEI_STRLEN;
1802 	}
1803 
1804 	out_len = net_buf_linearize(iface_ctx.mdm_imei, sizeof(iface_ctx.mdm_imei) - 1,
1805 				    *buf, 0, len);
1806 	iface_ctx.mdm_imei[out_len] = 0;
1807 
1808 	LOG_INF("IMEI: %s", iface_ctx.mdm_imei);
1809 done:
1810 	return true;
1811 }
1812 
1813 /* Handler: +CCID: <ICCID>,<EID>
1814  * NOTE: EID will only be present for eSIM
1815  */
on_cmd_atcmdinfo_iccid(struct net_buf ** buf,uint16_t len)1816 static bool on_cmd_atcmdinfo_iccid(struct net_buf **buf, uint16_t len)
1817 {
1818 	char value[MDM_CCID_RESP_MAX_SIZE];
1819 	char *delim;
1820 	int iccid_len;
1821 	size_t out_len;
1822 
1823 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
1824 	value[out_len] = 0;
1825 
1826 	LOG_DBG("+CCID: %s", value);
1827 
1828 	if (len > MDM_HL7800_ICCID_MAX_STRLEN) {
1829 		delim = strchr(value, ',');
1830 		if (!delim) {
1831 			LOG_ERR("Could not process +CCID");
1832 			return true;
1833 		}
1834 		/* Replace ',' with null so value contains two null terminated strings */
1835 		*delim = 0;
1836 		LOG_INF("EID: %s", delim + 1);
1837 	}
1838 
1839 	iccid_len = strlen(value);
1840 	strncpy(iface_ctx.mdm_iccid, value, sizeof(iface_ctx.mdm_iccid));
1841 	len = MIN(iccid_len, sizeof(iface_ctx.mdm_iccid) - 1);
1842 	iface_ctx.mdm_iccid[len] = '\0';
1843 
1844 	if (iccid_len > len) {
1845 		LOG_WRN("ICCID too long: %d (max %d)", iccid_len, len);
1846 	}
1847 
1848 	LOG_INF("ICCID: %s", iface_ctx.mdm_iccid);
1849 
1850 	return true;
1851 }
1852 
on_cmd_atcmdinfo_imsi(struct net_buf ** buf,uint16_t len)1853 static bool on_cmd_atcmdinfo_imsi(struct net_buf **buf, uint16_t len)
1854 {
1855 	struct net_buf *frag = NULL;
1856 	size_t out_len;
1857 
1858 	/* The handler for the IMSI is based on the command.
1859 	 *  waiting for: <IMSI>\r\n
1860 	 */
1861 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1862 					MDM_HL7800_IMSI_MIN_STR_SIZE);
1863 
1864 	frag = NULL;
1865 	len = net_buf_findcrlf(*buf, &frag);
1866 	if (!frag) {
1867 		LOG_ERR("Unable to find IMSI end");
1868 		goto done;
1869 	}
1870 	if (len > MDM_HL7800_IMSI_MAX_STRLEN) {
1871 		LOG_WRN("IMSI too long (len:%d)", len);
1872 		len = MDM_HL7800_IMSI_MAX_STRLEN;
1873 	}
1874 
1875 	out_len = net_buf_linearize(iface_ctx.mdm_imsi, MDM_HL7800_IMSI_MAX_STR_SIZE,
1876 				    *buf, 0, len);
1877 	iface_ctx.mdm_imsi[out_len] = 0;
1878 
1879 	if (strstr(iface_ctx.mdm_imsi, "ERROR") != NULL) {
1880 		LOG_ERR("Unable to read IMSI");
1881 		memset(iface_ctx.mdm_imsi, 0, sizeof(iface_ctx.mdm_imsi));
1882 	}
1883 
1884 	LOG_INF("IMSI: %s", iface_ctx.mdm_imsi);
1885 done:
1886 	return true;
1887 }
1888 
dns_work_cb(struct k_work * work)1889 static void dns_work_cb(struct k_work *work)
1890 {
1891 #if defined(CONFIG_DNS_RESOLVER) && !defined(CONFIG_DNS_SERVER_IP_ADDRESSES)
1892 	int ret;
1893 	struct dns_resolve_context *dnsCtx;
1894 	struct sockaddr temp_addr;
1895 	bool valid_address = false;
1896 	bool retry = false;
1897 	static const char *const dns_servers_str[] = {
1898 #ifdef CONFIG_NET_IPV6
1899 		iface_ctx.dns_v6_string,
1900 #endif
1901 #ifdef CONFIG_NET_IPV4
1902 		iface_ctx.dns_v4_string,
1903 #endif
1904 		NULL};
1905 
1906 #ifdef CONFIG_NET_IPV6
1907 	valid_address =
1908 		net_ipaddr_parse(iface_ctx.dns_v6_string, strlen(iface_ctx.dns_v6_string),
1909 				 &temp_addr);
1910 	if (!valid_address && IS_ENABLED(CONFIG_NET_IPV4)) {
1911 		/* IPv6 DNS string is not valid, replace it with IPv4 address and recheck */
1912 		strncpy(iface_ctx.dns_v6_string, iface_ctx.dns_v4_string,
1913 			sizeof(iface_ctx.dns_v6_string) - 1);
1914 		valid_address = net_ipaddr_parse(iface_ctx.dns_v6_string,
1915 						 strlen(iface_ctx.dns_v6_string), &temp_addr);
1916 	}
1917 #else
1918 	valid_address =
1919 		net_ipaddr_parse(iface_ctx.dns_v4_string, strlen(iface_ctx.dns_v4_string),
1920 				 &temp_addr);
1921 #endif
1922 
1923 	if (!valid_address) {
1924 		LOG_WRN("No valid DNS address!");
1925 	} else if (iface_ctx.iface && net_if_is_up(iface_ctx.iface) && !iface_ctx.dns_ready) {
1926 		/* set new DNS addr in DNS resolver */
1927 		LOG_DBG("Refresh DNS resolver");
1928 		dnsCtx = dns_resolve_get_default();
1929 		if (dnsCtx->state == DNS_RESOLVE_CONTEXT_INACTIVE) {
1930 			LOG_DBG("Initializing DNS resolver");
1931 			ret = dns_resolve_init(dnsCtx, (const char **)dns_servers_str, NULL);
1932 			if (ret < 0) {
1933 				LOG_ERR("dns_resolve_init fail (%d)", ret);
1934 				retry = true;
1935 			}
1936 		} else {
1937 			LOG_DBG("Reconfiguring DNS resolver");
1938 			ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL);
1939 			if (ret < 0) {
1940 				LOG_ERR("dns_resolve_reconfigure fail (%d)", ret);
1941 				retry = true;
1942 			}
1943 		}
1944 		if (!retry) {
1945 			LOG_DBG("DNS ready");
1946 			iface_ctx.dns_ready = true;
1947 		} else {
1948 			LOG_DBG("DNS not ready, schedule a retry");
1949 			k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.dns_work,
1950 						    K_SECONDS(DNS_WORK_DELAY_SECS * 2));
1951 		}
1952 	}
1953 #endif
1954 }
1955 
mdm_hl7800_get_iccid(void)1956 char *mdm_hl7800_get_iccid(void)
1957 {
1958 	return iface_ctx.mdm_iccid;
1959 }
1960 
mdm_hl7800_get_sn(void)1961 char *mdm_hl7800_get_sn(void)
1962 {
1963 	return iface_ctx.mdm_sn;
1964 }
1965 
mdm_hl7800_get_imei(void)1966 char *mdm_hl7800_get_imei(void)
1967 {
1968 	return iface_ctx.mdm_imei;
1969 }
1970 
mdm_hl7800_get_fw_version(void)1971 char *mdm_hl7800_get_fw_version(void)
1972 {
1973 	return iface_ctx.mdm_revision;
1974 }
1975 
mdm_hl7800_get_imsi(void)1976 char *mdm_hl7800_get_imsi(void)
1977 {
1978 	return iface_ctx.mdm_imsi;
1979 }
1980 
1981 /* Convert HL7800 IPv6 address string in format
1982  * a01.a02.a03.a04.a05.a06.a07.a08.a09.a10.a11.a12.a13.a14.a15.a16 to
1983  * an IPv6 address.
1984  */
hl7800_net_addr6_pton(const char * src,struct in6_addr * dst)1985 static int hl7800_net_addr6_pton(const char *src, struct in6_addr *dst)
1986 {
1987 	int num_sections = 8;
1988 	int i, len;
1989 	uint16_t ipv6_section;
1990 
1991 	len = strlen(src);
1992 	for (i = 0; i < len; i++) {
1993 		if (!(src[i] >= '0' && src[i] <= '9') && src[i] != '.') {
1994 			return -EINVAL;
1995 		}
1996 	}
1997 
1998 	for (i = 0; i < num_sections; i++) {
1999 		if (!src || *src == '\0') {
2000 			return -EINVAL;
2001 		}
2002 
2003 		ipv6_section = (uint16_t)strtol(src, NULL, 10);
2004 		src = strchr(src, '.');
2005 		if (!src) {
2006 			return -EINVAL;
2007 		}
2008 		src++;
2009 		if (*src == '\0') {
2010 			return -EINVAL;
2011 		}
2012 		ipv6_section = (ipv6_section << 8) | (uint16_t)strtol(src, NULL, 10);
2013 		UNALIGNED_PUT(htons(ipv6_section), &dst->s6_addr16[i]);
2014 
2015 		src = strchr(src, '.');
2016 		if (src) {
2017 			src++;
2018 		} else {
2019 			if (i < num_sections - 1) {
2020 				return -EINVAL;
2021 			}
2022 		}
2023 	}
2024 
2025 	return 0;
2026 }
2027 
2028 /* Handler: +CGCONTRDP: <cid>,<bearer_id>,<apn>,<local_addr and subnet_mask>,
2029  *			<gw_addr>,<DNS_prim_addr>,<DNS_sec_addr>
2030  */
on_cmd_atcmdinfo_ipaddr(struct net_buf ** buf,uint16_t len)2031 static bool on_cmd_atcmdinfo_ipaddr(struct net_buf **buf, uint16_t len)
2032 {
2033 	int ret;
2034 	int num_delims = CGCONTRDP_RESPONSE_NUM_DELIMS;
2035 	char *delims[CGCONTRDP_RESPONSE_NUM_DELIMS];
2036 	size_t out_len;
2037 	char value[MDM_IP_INFO_RESP_SIZE];
2038 	char *search_start, *addr_start, *sm_start;
2039 	struct in_addr new_ipv4_addr;
2040 	struct in6_addr new_ipv6_addr;
2041 	bool is_ipv4;
2042 	int addr_len;
2043 	char temp_addr_str[HL7800_IPV6_ADDR_LEN];
2044 	k_timeout_t delay;
2045 
2046 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2047 	value[out_len] = 0;
2048 	search_start = value;
2049 	LOG_DBG("IP info: %s", value);
2050 
2051 	/* find all delimiters (,) */
2052 	for (int i = 0; i < num_delims; i++) {
2053 		delims[i] = strchr(search_start, ',');
2054 		if (!delims[i]) {
2055 			LOG_ERR("Could not find delim %d, val: %s", i,
2056 				value);
2057 			return true;
2058 		}
2059 		/* Start next search after current delim location */
2060 		search_start = delims[i] + 1;
2061 	}
2062 
2063 	/* determine if IPv4 or IPv6 by checking length of ip address plus
2064 	 * gateway string.
2065 	 */
2066 	is_ipv4 = false;
2067 	addr_len = delims[3] - delims[2];
2068 	LOG_DBG("IP string len: %d", addr_len);
2069 	if (addr_len <= (NET_IPV4_ADDR_LEN * 2)) {
2070 		is_ipv4 = true;
2071 	}
2072 
2073 	/* Find start of subnet mask */
2074 	addr_start = delims[2] + 1;
2075 	if (is_ipv4) {
2076 		num_delims = 4;
2077 	} else {
2078 		num_delims = 16;
2079 	}
2080 	search_start = addr_start;
2081 	sm_start = addr_start;
2082 	for (int i = 0; i < num_delims; i++) {
2083 		sm_start = strchr(search_start, '.');
2084 		if (!sm_start) {
2085 			LOG_ERR("Could not find submask start");
2086 			return true;
2087 		}
2088 		/* Start next search after current delim location */
2089 		search_start = sm_start + 1;
2090 	}
2091 
2092 	/* get new IP addr */
2093 	addr_len = sm_start - addr_start;
2094 	strncpy(temp_addr_str, addr_start, addr_len);
2095 	temp_addr_str[addr_len] = 0;
2096 	LOG_DBG("IP addr: %s", temp_addr_str);
2097 	if (is_ipv4) {
2098 		ret = net_addr_pton(AF_INET, temp_addr_str, &new_ipv4_addr);
2099 	} else {
2100 		ret = hl7800_net_addr6_pton(temp_addr_str, &new_ipv6_addr);
2101 	}
2102 	if (ret < 0) {
2103 		LOG_ERR("Invalid IP addr");
2104 		return true;
2105 	}
2106 
2107 	if (is_ipv4) {
2108 		/* move past the '.' */
2109 		sm_start += 1;
2110 		/* store new subnet mask */
2111 		addr_len = delims[3] - sm_start;
2112 		strncpy(temp_addr_str, sm_start, addr_len);
2113 		temp_addr_str[addr_len] = 0;
2114 		ret = net_addr_pton(AF_INET, temp_addr_str, &iface_ctx.subnet);
2115 		if (ret < 0) {
2116 			LOG_ERR("Invalid subnet");
2117 			return true;
2118 		}
2119 
2120 		/* store new gateway */
2121 		addr_start = delims[3] + 1;
2122 		addr_len = delims[4] - addr_start;
2123 		strncpy(temp_addr_str, addr_start, addr_len);
2124 		temp_addr_str[addr_len] = 0;
2125 		ret = net_addr_pton(AF_INET, temp_addr_str, &iface_ctx.gateway);
2126 		if (ret < 0) {
2127 			LOG_ERR("Invalid gateway");
2128 			return true;
2129 		}
2130 	}
2131 
2132 	/* store new dns */
2133 	addr_start = delims[4] + 1;
2134 	addr_len = delims[5] - addr_start;
2135 	strncpy(temp_addr_str, addr_start, addr_len);
2136 	temp_addr_str[addr_len] = 0;
2137 	if (is_ipv4) {
2138 		ret = strncmp(temp_addr_str, iface_ctx.dns_v4_string, addr_len);
2139 		if (ret != 0) {
2140 			iface_ctx.dns_ready = false;
2141 		}
2142 		strncpy(iface_ctx.dns_v4_string, addr_start, addr_len);
2143 		iface_ctx.dns_v4_string[addr_len] = 0;
2144 		ret = net_addr_pton(AF_INET, iface_ctx.dns_v4_string, &iface_ctx.dns_v4);
2145 		LOG_DBG("IPv4 DNS addr: %s", iface_ctx.dns_v4_string);
2146 	}
2147 #ifdef CONFIG_NET_IPV6
2148 	else {
2149 		ret = strncmp(temp_addr_str, iface_ctx.dns_v6_string, addr_len);
2150 		if (ret != 0) {
2151 			iface_ctx.dns_ready = false;
2152 		}
2153 		/* store HL7800 formatted IPv6 DNS string temporarily */
2154 		strncpy(iface_ctx.dns_v6_string, addr_start, addr_len);
2155 
2156 		ret = hl7800_net_addr6_pton(iface_ctx.dns_v6_string, &iface_ctx.dns_v6);
2157 		net_addr_ntop(AF_INET6, &iface_ctx.dns_v6, iface_ctx.dns_v6_string,
2158 			      sizeof(iface_ctx.dns_v6_string));
2159 		LOG_DBG("IPv6 DNS addr: %s", iface_ctx.dns_v6_string);
2160 	}
2161 #endif
2162 	if (ret < 0) {
2163 		LOG_ERR("Invalid dns");
2164 		return true;
2165 	}
2166 
2167 	if (iface_ctx.iface) {
2168 		if (is_ipv4) {
2169 #ifdef CONFIG_NET_IPV4
2170 			/* remove the current IPv4 addr before adding a new one.
2171 			 * We dont care if it is successful or not.
2172 			 */
2173 			net_if_ipv4_addr_rm(iface_ctx.iface, &iface_ctx.ipv4Addr);
2174 
2175 			if (!net_if_ipv4_addr_add(iface_ctx.iface, &new_ipv4_addr,
2176 						  NET_ADDR_DHCP, 0)) {
2177 				LOG_ERR("Cannot set iface IPv4 addr");
2178 			}
2179 
2180 			net_if_ipv4_set_netmask_by_addr(iface_ctx.iface,
2181 							&new_ipv4_addr,
2182 							&iface_ctx.subnet);
2183 			net_if_ipv4_set_gw(iface_ctx.iface, &iface_ctx.gateway);
2184 #endif
2185 			/* store the new IP addr */
2186 			net_ipaddr_copy(&iface_ctx.ipv4Addr, &new_ipv4_addr);
2187 		} else {
2188 #if CONFIG_NET_IPV6
2189 			net_if_ipv6_addr_rm(iface_ctx.iface, &iface_ctx.ipv6Addr);
2190 			if (!net_if_ipv6_addr_add(iface_ctx.iface, &new_ipv6_addr,
2191 						  NET_ADDR_AUTOCONF, 0)) {
2192 				LOG_ERR("Cannot set iface IPv6 addr");
2193 			}
2194 #endif
2195 		}
2196 
2197 		/* start DNS update work */
2198 		delay = K_NO_WAIT;
2199 		if (!iface_ctx.initialized) {
2200 			/* Delay this in case the network
2201 			 * stack is still starting up
2202 			 */
2203 			delay = K_SECONDS(DNS_WORK_DELAY_SECS);
2204 		}
2205 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.dns_work,
2206 					    delay);
2207 	} else {
2208 		LOG_ERR("iface NULL");
2209 	}
2210 
2211 	return true;
2212 }
2213 
2214 /* Handler1: +COPS: <mode>[,<format>,<oper>[,<AcT>]]
2215  *
2216  * Handler2:
2217  * +COPS: [list of supported (<stat>, long alphanumeric <oper>, short
2218  * alphanumeric <oper>, numeric <oper>[,< AcT>])s][,,
2219  * (list of supported <mode>s),(list of supported <format>s)]
2220  */
on_cmd_atcmdinfo_operator_status(struct net_buf ** buf,uint16_t len)2221 static bool on_cmd_atcmdinfo_operator_status(struct net_buf **buf, uint16_t len)
2222 {
2223 	size_t out_len;
2224 	char value[MDM_MAX_RESP_SIZE];
2225 	int num_delims = COPS_RESPONSE_NUM_DELIMS;
2226 	char *delims[COPS_RESPONSE_NUM_DELIMS];
2227 	char *search_start;
2228 	int i;
2229 
2230 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2231 	value[out_len] = 0;
2232 
2233 	/* For AT+COPS=?, result is most likely longer than size of log string */
2234 	if (strchr(value, '(') != NULL) {
2235 		LOG_HEXDUMP_DBG(value, out_len, "Operator: ");
2236 		goto done;
2237 	} else {
2238 		LOG_INF("Operator: %s", value);
2239 	}
2240 
2241 	/* Process AT+COPS? */
2242 	if (len == 1) {
2243 		/* only mode was returned, there is no operator info */
2244 		iface_ctx.operator_status = NO_OPERATOR;
2245 		goto done;
2246 	}
2247 
2248 	search_start = value;
2249 
2250 	/* find all delimiters (,) */
2251 	for (i = 0; i < num_delims; i++) {
2252 		delims[i] = strchr(search_start, ',');
2253 		if (!delims[i]) {
2254 			LOG_ERR("Could not find delim %d, val: %s", i, value);
2255 			goto done;
2256 		}
2257 		/* Start next search after current delim location */
2258 		search_start = delims[i] + 1;
2259 	}
2260 
2261 	/* we found both delimiters, that means we have an operator */
2262 	iface_ctx.operator_status = REGISTERED;
2263 done:
2264 	return true;
2265 }
2266 
2267 /* Handler: +KGSN: T5640400011101 */
on_cmd_atcmdinfo_serial_number(struct net_buf ** buf,uint16_t len)2268 static bool on_cmd_atcmdinfo_serial_number(struct net_buf **buf, uint16_t len)
2269 {
2270 	struct net_buf *frag = NULL;
2271 	char value[MDM_SN_RESPONSE_LENGTH];
2272 	size_t out_len;
2273 	int sn_len;
2274 	char *val_start;
2275 
2276 	/* make sure SN# data is received.
2277 	 *  we are waiting for: +KGSN: ##############\r\n
2278 	 */
2279 	wait_for_modem_data(buf, net_buf_frags_len(*buf),
2280 			    MDM_SN_RESPONSE_LENGTH);
2281 
2282 	frag = NULL;
2283 	len = net_buf_findcrlf(*buf, &frag);
2284 	if (!frag) {
2285 		LOG_ERR("Unable to find sn end");
2286 		goto done;
2287 	}
2288 
2289 	/* get msg data */
2290 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2291 	value[out_len] = 0;
2292 
2293 	/* find ':' */
2294 	val_start = strchr(value, ':');
2295 	if (!val_start) {
2296 		LOG_ERR("Unable to find sn ':'");
2297 		goto done;
2298 	}
2299 	/* Remove ": " chars */
2300 	val_start += 2;
2301 
2302 	sn_len = len - (val_start - value);
2303 	if (sn_len < MDM_HL7800_SERIAL_NUMBER_STRLEN) {
2304 		LOG_WRN("sn too short (len:%d)", sn_len);
2305 	} else if (sn_len > MDM_HL7800_SERIAL_NUMBER_STRLEN) {
2306 		LOG_WRN("sn too long (len:%d)", sn_len);
2307 		sn_len = MDM_HL7800_SERIAL_NUMBER_STRLEN;
2308 	}
2309 
2310 	strncpy(iface_ctx.mdm_sn, val_start, sn_len);
2311 	iface_ctx.mdm_sn[sn_len] = 0;
2312 	LOG_INF("Serial #: %s", iface_ctx.mdm_sn);
2313 done:
2314 	return true;
2315 }
2316 
2317 /* Handler: +KSRAT: # */
on_cmd_radio_tech_status(struct net_buf ** buf,uint16_t len)2318 static bool on_cmd_radio_tech_status(struct net_buf **buf, uint16_t len)
2319 {
2320 	size_t out_len;
2321 	char value[MDM_MAX_RESP_SIZE];
2322 
2323 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2324 	value[out_len] = 0;
2325 	iface_ctx.mdm_rat = strtol(value, NULL, 10);
2326 	LOG_INF("+KSRAT: %d", iface_ctx.mdm_rat);
2327 	event_handler(HL7800_EVENT_RAT, &iface_ctx.mdm_rat);
2328 
2329 	return true;
2330 }
2331 
2332 /* Handler: +KBNDCFG: #,####################### */
on_cmd_radio_band_configuration(struct net_buf ** buf,uint16_t len)2333 static bool on_cmd_radio_band_configuration(struct net_buf **buf, uint16_t len)
2334 {
2335 	size_t out_len;
2336 	char value[MDM_MAX_RESP_SIZE];
2337 	char n_tmp[sizeof("#########")];
2338 
2339 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2340 	value[out_len] = 0;
2341 
2342 	if (value[0] != (iface_ctx.mdm_rat == MDM_RAT_CAT_M1 ? '0' : '1')) {
2343 		/* Invalid RAT */
2344 		return true;
2345 	} else if (strlen(value) < sizeof("#,###################")) {
2346 		/* String size too short */
2347 		return true;
2348 	}
2349 
2350 	memcpy(iface_ctx.mdm_bands_string, &value[MDM_TOP_BAND_START_POSITION],
2351 	       MDM_HL7800_LTE_BAND_STRLEN);
2352 
2353 	memcpy(n_tmp, &value[MDM_TOP_BAND_START_POSITION], MDM_TOP_BAND_SIZE);
2354 	n_tmp[MDM_TOP_BAND_SIZE] = 0;
2355 	iface_ctx.mdm_bands_top = strtoul(n_tmp, NULL, 16);
2356 
2357 	memcpy(n_tmp, &value[MDM_MIDDLE_BAND_START_POSITION],
2358 	       MDM_MIDDLE_BAND_SIZE);
2359 	n_tmp[MDM_MIDDLE_BAND_SIZE] = 0;
2360 	iface_ctx.mdm_bands_middle = strtoul(n_tmp, NULL, 16);
2361 
2362 	memcpy(n_tmp, &value[MDM_BOTTOM_BAND_START_POSITION],
2363 	       MDM_BOTTOM_BAND_SIZE);
2364 	n_tmp[MDM_BOTTOM_BAND_SIZE] = 0;
2365 	iface_ctx.mdm_bands_bottom = strtoul(n_tmp, NULL, 16);
2366 
2367 	LOG_INF("Current band configuration: %04x %08x %08x",
2368 		iface_ctx.mdm_bands_top, iface_ctx.mdm_bands_middle,
2369 		iface_ctx.mdm_bands_bottom);
2370 
2371 	event_handler(HL7800_EVENT_BANDS, iface_ctx.mdm_bands_string);
2372 
2373 	return true;
2374 }
2375 
2376 /* Handler: +KBND: #,####################### */
on_cmd_radio_active_bands(struct net_buf ** buf,uint16_t len)2377 static bool on_cmd_radio_active_bands(struct net_buf **buf, uint16_t len)
2378 {
2379 	size_t out_len;
2380 	char value[MDM_MAX_RESP_SIZE];
2381 
2382 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2383 	value[out_len] = 0;
2384 
2385 	if (strlen(value) < sizeof("#,###################")) {
2386 		/* String size too short */
2387 		return true;
2388 	}
2389 
2390 	memcpy(iface_ctx.mdm_active_bands_string,
2391 	       &value[MDM_TOP_BAND_START_POSITION], MDM_HL7800_LTE_BAND_STRLEN);
2392 	event_handler(HL7800_EVENT_ACTIVE_BANDS, iface_ctx.mdm_active_bands_string);
2393 
2394 	return true;
2395 }
2396 
get_startup_state_string(enum mdm_hl7800_startup_state state)2397 static char *get_startup_state_string(enum mdm_hl7800_startup_state state)
2398 {
2399 	/* clang-format off */
2400 	switch (state) {
2401 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, READY);
2402 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, WAITING_FOR_ACCESS_CODE);
2403 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, SIM_NOT_PRESENT);
2404 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, SIMLOCK);
2405 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, UNRECOVERABLE_ERROR);
2406 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, UNKNOWN);
2407 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, INACTIVE_SIM);
2408 	default:
2409 		return "UNKNOWN";
2410 	}
2411 	/* clang-format on */
2412 }
2413 
set_startup_state(enum mdm_hl7800_startup_state state)2414 static void set_startup_state(enum mdm_hl7800_startup_state state)
2415 {
2416 	iface_ctx.mdm_startup_state = state;
2417 	generate_startup_state_event();
2418 }
2419 
generate_startup_state_event(void)2420 static void generate_startup_state_event(void)
2421 {
2422 	struct mdm_hl7800_compound_event event;
2423 
2424 	event.code = iface_ctx.mdm_startup_state;
2425 	event.string = get_startup_state_string(iface_ctx.mdm_startup_state);
2426 	LOG_INF("Startup State: %s", event.string);
2427 	event_handler(HL7800_EVENT_STARTUP_STATE_CHANGE, &event);
2428 }
2429 
mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level)2430 int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level)
2431 {
2432 	int r = -EPERM;
2433 
2434 #if CONFIG_MODEM_HL7800_LOW_POWER_MODE
2435 	switch (level) {
2436 	case HL7800_SLEEP_AWAKE:
2437 	case HL7800_SLEEP_HIBERNATE:
2438 	case HL7800_SLEEP_LITE_HIBERNATE:
2439 	case HL7800_SLEEP_SLEEP:
2440 		iface_ctx.desired_sleep_level = level;
2441 		r = 0;
2442 		break;
2443 	default:
2444 		r = -EINVAL;
2445 	}
2446 
2447 	if (r == 0) {
2448 		hl7800_lock();
2449 		wakeup_hl7800();
2450 		r = set_sleep_level();
2451 		set_busy(false);
2452 		allow_sleep(true);
2453 		hl7800_unlock();
2454 	}
2455 #endif
2456 
2457 	return r;
2458 }
2459 
initialize_sleep_level(void)2460 static void initialize_sleep_level(void)
2461 {
2462 	if (iface_ctx.desired_sleep_level == HL7800_SLEEP_UNINITIALIZED) {
2463 		if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_HIBERNATE)) {
2464 			iface_ctx.desired_sleep_level = HL7800_SLEEP_HIBERNATE;
2465 		} else if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_LITE_HIBERNATE)) {
2466 			iface_ctx.desired_sleep_level = HL7800_SLEEP_LITE_HIBERNATE;
2467 		} else if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_SLEEP)) {
2468 			iface_ctx.desired_sleep_level = HL7800_SLEEP_SLEEP;
2469 		} else {
2470 			iface_ctx.desired_sleep_level = HL7800_SLEEP_AWAKE;
2471 		}
2472 	}
2473 }
2474 
2475 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
set_sleep_level(void)2476 static int set_sleep_level(void)
2477 {
2478 	char cmd[sizeof("AT+KSLEEP=#,#,##")];
2479 	static const char SLEEP_CMD_FMT[] = "AT+KSLEEP=%d,%d,%d";
2480 	int delay = CONFIG_MODEM_HL7800_SLEEP_DELAY_AFTER_REBOOT;
2481 	int ret = 0;
2482 
2483 	/* AT+KSLEEP= <management>[,<level>[,<delay to sleep after reboot>]]
2484 	 * management 1 means the HL7800 decides when it enters sleep mode
2485 	 */
2486 	switch (iface_ctx.desired_sleep_level) {
2487 	case HL7800_SLEEP_HIBERNATE:
2488 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 2, delay);
2489 		break;
2490 	case HL7800_SLEEP_LITE_HIBERNATE:
2491 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 1, delay);
2492 		break;
2493 	case HL7800_SLEEP_SLEEP:
2494 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 0, delay);
2495 		break;
2496 	default:
2497 		/* don't sleep */
2498 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 2, 0, delay);
2499 		break;
2500 	}
2501 
2502 	SEND_AT_CMD_EXPECT_OK(cmd);
2503 
2504 error:
2505 	return ret;
2506 }
2507 
2508 #endif /* CONFIG_MODEM_HL7800_LOW_POWER_MODE */
2509 
get_sleep_state_string(enum mdm_hl7800_sleep state)2510 static char *get_sleep_state_string(enum mdm_hl7800_sleep state)
2511 {
2512 	/* clang-format off */
2513 	switch (state) {
2514 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, UNINITIALIZED);
2515 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, HIBERNATE);
2516 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, LITE_HIBERNATE);
2517 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, SLEEP);
2518 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, AWAKE);
2519 	default:
2520 		return "UNKNOWN";
2521 	}
2522 	/* clang-format on */
2523 }
2524 
set_sleep_state(enum mdm_hl7800_sleep state)2525 static void set_sleep_state(enum mdm_hl7800_sleep state)
2526 {
2527 	iface_ctx.sleep_state = state;
2528 	if (iface_ctx.sleep_state != HL7800_SLEEP_AWAKE) {
2529 		k_sem_reset(&iface_ctx.mdm_awake);
2530 	}
2531 	generate_sleep_state_event();
2532 }
2533 
generate_sleep_state_event(void)2534 static void generate_sleep_state_event(void)
2535 {
2536 	struct mdm_hl7800_compound_event event;
2537 
2538 	event.code = iface_ctx.sleep_state;
2539 	event.string = get_sleep_state_string(iface_ctx.sleep_state);
2540 	LOG_INF("Sleep State: %s", event.string);
2541 	event_handler(HL7800_EVENT_SLEEP_STATE_CHANGE, &event);
2542 }
2543 
2544 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
get_fota_state_string(enum mdm_hl7800_fota_state state)2545 static char *get_fota_state_string(enum mdm_hl7800_fota_state state)
2546 {
2547 	/* clang-format off */
2548 	switch (state) {
2549 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, IDLE);
2550 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, START);
2551 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, WIP);
2552 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, PAD);
2553 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, SEND_EOT);
2554 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, FILE_ERROR);
2555 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, INSTALL);
2556 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, REBOOT_AND_RECONFIGURE);
2557 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, COMPLETE);
2558 	default:
2559 		return "UNKNOWN";
2560 	}
2561 	/* clang-format on */
2562 }
2563 
set_fota_state(enum mdm_hl7800_fota_state state)2564 static void set_fota_state(enum mdm_hl7800_fota_state state)
2565 {
2566 	LOG_INF("FOTA state: %s->%s",
2567 		get_fota_state_string(iface_ctx.fw_update_state),
2568 		get_fota_state_string(state));
2569 	iface_ctx.fw_update_state = state;
2570 	generate_fota_state_event();
2571 }
2572 
generate_fota_state_event(void)2573 static void generate_fota_state_event(void)
2574 {
2575 	struct mdm_hl7800_compound_event event;
2576 
2577 	event.code = iface_ctx.fw_update_state;
2578 	event.string = get_fota_state_string(iface_ctx.fw_update_state);
2579 	event_handler(HL7800_EVENT_FOTA_STATE, &event);
2580 }
2581 
generate_fota_count_event(void)2582 static void generate_fota_count_event(void)
2583 {
2584 	uint32_t count = iface_ctx.fw_packet_count * XMODEM_DATA_SIZE;
2585 
2586 	event_handler(HL7800_EVENT_FOTA_COUNT, &count);
2587 }
2588 #endif
2589 
2590 /* Handler: +KSUP: # */
on_cmd_startup_report(struct net_buf ** buf,uint16_t len)2591 static bool on_cmd_startup_report(struct net_buf **buf, uint16_t len)
2592 {
2593 	size_t out_len;
2594 	char value[MDM_MAX_RESP_SIZE];
2595 
2596 	memset(value, 0, sizeof(value));
2597 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2598 	if (out_len > 0) {
2599 		set_startup_state(strtol(value, NULL, 10));
2600 	} else {
2601 		set_startup_state(HL7800_STARTUP_STATE_UNKNOWN);
2602 	}
2603 
2604 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
2605 	if (iface_ctx.fw_updated) {
2606 		iface_ctx.fw_updated = false;
2607 		set_fota_state(HL7800_FOTA_REBOOT_AND_RECONFIGURE);
2608 		/* issue reset after a firmware update to reconfigure modem state */
2609 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.mdm_reset_work,
2610 					    K_NO_WAIT);
2611 	} else
2612 #endif
2613 	{
2614 		PRINT_AWAKE_MSG;
2615 		iface_ctx.wait_for_KSUP = false;
2616 		iface_ctx.mdm_startup_reporting_on = true;
2617 		iface_ctx.reconfig_IP_connection = true;
2618 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
2619 		mark_sockets_for_reconfig();
2620 #endif
2621 		set_sleep_state(HL7800_SLEEP_AWAKE);
2622 		k_sem_give(&iface_ctx.mdm_awake);
2623 	}
2624 
2625 	return true;
2626 }
2627 
profile_handler(struct net_buf ** buf,uint16_t len,bool active_profile)2628 static bool profile_handler(struct net_buf **buf, uint16_t len,
2629 			    bool active_profile)
2630 {
2631 	uint32_t size;
2632 	int echo_state = -1;
2633 	struct net_buf *frag = NULL;
2634 	uint16_t line_length;
2635 	char line[MAX_PROFILE_LINE_LENGTH];
2636 	size_t output_length;
2637 
2638 	/* Prepare net buffer for this parser. */
2639 	net_buf_remove(buf, len);
2640 	net_buf_skipcrlf(buf);
2641 
2642 	size = wait_for_modem_data(buf, net_buf_frags_len(*buf),
2643 				   sizeof(PROFILE_LINE_1));
2644 	net_buf_skipcrlf(buf); /* remove any \r\n that are in the front */
2645 
2646 	/* Parse configuration data to determine if echo is on/off. */
2647 	line_length = net_buf_findcrlf(*buf, &frag);
2648 	if (line_length) {
2649 		memset(line, 0, sizeof(line));
2650 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2651 						  *buf, 0, line_length);
2652 		LOG_DBG("length: %u: %s", line_length, line);
2653 
2654 		/* Echo on off is the first thing on the line: E0, E1 */
2655 		if (output_length >= SIZE_WITHOUT_NUL("E?")) {
2656 			echo_state = (line[1] == '1') ? 1 : 0;
2657 		}
2658 	}
2659 	LOG_DBG("echo: %d", echo_state);
2660 	net_buf_remove(buf, line_length);
2661 	net_buf_skipcrlf(buf);
2662 
2663 	if (active_profile) {
2664 		iface_ctx.mdm_echo_is_on = (echo_state != 0);
2665 	}
2666 
2667 	/* Discard next line.  This waits for the longest possible response even
2668 	 * though most registers won't have the value 0xFF. */
2669 	size = wait_for_modem_data(buf, net_buf_frags_len(*buf),
2670 				   sizeof(PROFILE_LINE_2));
2671 	net_buf_skipcrlf(buf);
2672 	len = net_buf_findcrlf(*buf, &frag);
2673 	net_buf_remove(buf, len);
2674 	net_buf_skipcrlf(buf);
2675 
2676 	return false;
2677 }
2678 
on_cmd_atcmdinfo_active_profile(struct net_buf ** buf,uint16_t len)2679 static bool on_cmd_atcmdinfo_active_profile(struct net_buf **buf, uint16_t len)
2680 {
2681 	return profile_handler(buf, len, true);
2682 }
2683 
on_cmd_atcmdinfo_stored_profile0(struct net_buf ** buf,uint16_t len)2684 static bool on_cmd_atcmdinfo_stored_profile0(struct net_buf **buf, uint16_t len)
2685 {
2686 	return profile_handler(buf, len, false);
2687 }
2688 
on_cmd_atcmdinfo_stored_profile1(struct net_buf ** buf,uint16_t len)2689 static bool on_cmd_atcmdinfo_stored_profile1(struct net_buf **buf, uint16_t len)
2690 {
2691 	return profile_handler(buf, len, false);
2692 }
2693 
2694 /* +WPPP: 1,1,"username","password" */
on_cmd_atcmdinfo_pdp_authentication_cfg(struct net_buf ** buf,uint16_t len)2695 static bool on_cmd_atcmdinfo_pdp_authentication_cfg(struct net_buf **buf,
2696 						    uint16_t len)
2697 {
2698 	struct net_buf *frag = NULL;
2699 	uint16_t line_length;
2700 	char line[MDM_HL7800_APN_CMD_MAX_SIZE];
2701 	size_t output_length;
2702 	size_t i;
2703 	char *p;
2704 
2705 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
2706 					MDM_HL7800_APN_CMD_MAX_SIZE);
2707 
2708 	line_length = net_buf_findcrlf(*buf, &frag);
2709 	if (line_length) {
2710 		memset(line, 0, sizeof(line));
2711 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2712 						  *buf, 0, line_length);
2713 		LOG_DBG("length: %u: %s", line_length, line);
2714 		if (output_length > 0) {
2715 			memset(iface_ctx.mdm_apn.username, 0,
2716 			       sizeof(iface_ctx.mdm_apn.username));
2717 			memset(iface_ctx.mdm_apn.password, 0,
2718 			       sizeof(iface_ctx.mdm_apn.password));
2719 
2720 			i = 0;
2721 			p = strchr(line, '"');
2722 			if (p != NULL) {
2723 				p += 1;
2724 				i = 0;
2725 				while ((p != NULL) && (*p != '"') &&
2726 				       (i <
2727 					MDM_HL7800_APN_USERNAME_MAX_STRLEN)) {
2728 					iface_ctx.mdm_apn.username[i++] = *p++;
2729 				}
2730 			} else {
2731 				LOG_WRN("Issue parsing APN username");
2732 				goto done;
2733 			}
2734 			LOG_INF("APN Username: %s",
2735 				iface_ctx.mdm_apn.username);
2736 
2737 			p = strchr(p + 1, '"');
2738 			if (p != NULL) {
2739 				p += 1;
2740 				i = 0;
2741 				while ((p != NULL) && (*p != '"') &&
2742 				       (i <
2743 					MDM_HL7800_APN_PASSWORD_MAX_STRLEN)) {
2744 					iface_ctx.mdm_apn.password[i++] = *p++;
2745 				}
2746 			}
2747 			LOG_INF("APN Password: %s",
2748 				iface_ctx.mdm_apn.password);
2749 		}
2750 	}
2751 done:
2752 	net_buf_remove(buf, line_length);
2753 	net_buf_skipcrlf(buf);
2754 
2755 	return false;
2756 }
2757 
2758 /* Only context 1 is used. Other contexts are unhandled.
2759  *
2760  * +CGDCONT: 1,"IP","access point name",,0,0,0,0,0,,0,,,,,
2761  */
on_cmd_atcmdinfo_pdp_context(struct net_buf ** buf,uint16_t len)2762 static bool on_cmd_atcmdinfo_pdp_context(struct net_buf **buf, uint16_t len)
2763 {
2764 	struct net_buf *frag = NULL;
2765 	uint16_t line_length;
2766 	char line[MDM_HL7800_APN_CMD_MAX_SIZE];
2767 	size_t output_length;
2768 	char *p;
2769 	size_t i;
2770 
2771 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
2772 					MDM_HL7800_APN_CMD_MAX_SIZE);
2773 
2774 	line_length = net_buf_findcrlf(*buf, &frag);
2775 	if (line_length) {
2776 		memset(line, 0, sizeof(line));
2777 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2778 						  *buf, 0, line_length);
2779 		LOG_DBG("length: %u: %s", line_length, line);
2780 		if (output_length > 0) {
2781 			memset(iface_ctx.mdm_apn.value, 0, sizeof(iface_ctx.mdm_apn.value));
2782 			memset(iface_ctx.mdm_pdp_addr_fam, 0, MDM_ADDR_FAM_MAX_LEN);
2783 
2784 			/* Address family after first , */
2785 			p = strchr(line, ',');
2786 			if (p == NULL) {
2787 				LOG_WRN("Issue parsing APN response");
2788 				goto done;
2789 			}
2790 			p += 2;
2791 			i = 0;
2792 			while ((p != NULL) && (*p != '"') && (i < MDM_ADDR_FAM_MAX_LEN)) {
2793 				iface_ctx.mdm_pdp_addr_fam[i++] = *p++;
2794 			}
2795 
2796 			if (strcmp(iface_ctx.mdm_pdp_addr_fam, ADDRESS_FAMILY_IP) == 0) {
2797 				snprintk(iface_ctx.mdm_pdp_addr_fam,
2798 					 sizeof(iface_ctx.mdm_pdp_addr_fam), "%s",
2799 					 ADDRESS_FAMILY_IPV4);
2800 			}
2801 
2802 			LOG_DBG("PDP address family: %s", iface_ctx.mdm_pdp_addr_fam);
2803 
2804 			/* APN after second , " */
2805 			p = strchr(p, ',');
2806 			if (p == NULL) {
2807 				LOG_WRN("Issue parsing APN response");
2808 				goto done;
2809 			}
2810 			p++;
2811 			if (*p == ',') {
2812 				/* APN is blank */
2813 				goto done;
2814 			}
2815 			if (*p == '"') {
2816 				p++;
2817 				i = 0;
2818 				while ((p != NULL) && (*p != '"') &&
2819 				       (i < MDM_HL7800_APN_MAX_STRLEN)) {
2820 					iface_ctx.mdm_apn.value[i++] = *p++;
2821 				}
2822 			}
2823 
2824 			LOG_INF("APN: %s", iface_ctx.mdm_apn.value);
2825 		}
2826 	}
2827 done:
2828 	net_buf_remove(buf, line_length);
2829 	net_buf_skipcrlf(buf);
2830 
2831 	return false;
2832 }
2833 
hl7800_query_rssi(void)2834 static int hl7800_query_rssi(void)
2835 {
2836 	int ret;
2837 
2838 	ret = send_at_cmd(NULL, "AT+KCELLMEAS=0", MDM_CMD_SEND_TIMEOUT, 1,
2839 			  false);
2840 	if (ret < 0) {
2841 		LOG_ERR("AT+KCELLMEAS ret:%d", ret);
2842 	}
2843 	return ret;
2844 }
2845 
hl7800_start_rssi_work(void)2846 static void hl7800_start_rssi_work(void)
2847 {
2848 	/* Rate is not checked here to allow one reading
2849 	 * when going from network down->up
2850 	 */
2851 	k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.rssi_query_work,
2852 				    K_NO_WAIT);
2853 }
2854 
hl7800_stop_rssi_work(void)2855 static void hl7800_stop_rssi_work(void)
2856 {
2857 	int rc;
2858 
2859 	rc = k_work_cancel_delayable(&iface_ctx.rssi_query_work);
2860 	if (rc != 0) {
2861 		LOG_ERR("Could not cancel RSSI work [%d]", rc);
2862 	}
2863 }
2864 
rssi_query(void)2865 static void rssi_query(void)
2866 {
2867 	hl7800_lock();
2868 	wakeup_hl7800();
2869 	hl7800_query_rssi();
2870 	set_busy(false);
2871 	allow_sleep(true);
2872 	hl7800_unlock();
2873 }
2874 
hl7800_rssi_query_work(struct k_work * work)2875 static void hl7800_rssi_query_work(struct k_work *work)
2876 {
2877 	rssi_query();
2878 
2879 	/* re-start RSSI query work */
2880 	if (CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS > 0) {
2881 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.rssi_query_work,
2882 					    K_SECONDS(CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS));
2883 	}
2884 }
2885 
2886 #ifdef CONFIG_MODEM_HL7800_GPS
2887 /* Unsolicited notification
2888  * Handler: +GNSSEV: <eventType>,<eventStatus>
2889  */
on_cmd_gps_event(struct net_buf ** buf,uint16_t len)2890 static bool on_cmd_gps_event(struct net_buf **buf, uint16_t len)
2891 {
2892 	size_t out_len;
2893 	char value[MDM_MAX_RESP_SIZE];
2894 	char *start = NULL;
2895 	char *end = NULL;
2896 	int8_t event = -1;
2897 	int8_t status = -1;
2898 
2899 	memset(value, 0, sizeof(value));
2900 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2901 	if (out_len > 0) {
2902 		start = value;
2903 		event = strtol(start, &end, 10);
2904 		if (end == strchr(value, ',')) {
2905 			start = end + 1;
2906 			status = strtol(start, &end, 10);
2907 		}
2908 	}
2909 
2910 	LOG_INF("GPS event: %d status: %d", event, status);
2911 
2912 	if (event == HL7800_GNSS_EVENT_POSITION) {
2913 		event_handler(HL7800_EVENT_GPS_POSITION_STATUS, &status);
2914 	}
2915 
2916 	return true;
2917 }
2918 
gps_work_callback(struct k_work * work)2919 static void gps_work_callback(struct k_work *work)
2920 {
2921 	ARG_UNUSED(work);
2922 	int r;
2923 
2924 	hl7800_lock();
2925 	wakeup_hl7800();
2926 	r = send_at_cmd(NULL, "AT+GNSSLOC?", MDM_CMD_SEND_TIMEOUT, 1, false);
2927 	set_busy(false);
2928 	allow_sleep(true);
2929 	hl7800_unlock();
2930 
2931 	LOG_DBG("GPS location request status: %d", r);
2932 
2933 	if (iface_ctx.gps_query_location_rate_seconds) {
2934 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.gps_work,
2935 					    K_SECONDS(iface_ctx.gps_query_location_rate_seconds));
2936 	}
2937 }
2938 
2939 /* The AT+GNSSLOC? command returns 1 of 2 things:
2940  *
2941  * +GNSSLOC:
2942  * Latitude: "49 Deg 10 Min 21.49 Sec N"
2943  * Longitude:  "123 Deg 4 Min 14.76 Sec W"
2944  * GpsTime: "yyyy mm dd hh:mm:ss"
2945  * FixType: "2D" or "3D"
2946  * HEPE: "8.485 m" (Horizontal Estimated Position Error)
2947  * Altitude: "-1 m"
2948  * AltUnc: "3.0 m"
2949  * Direction: "0.0 deg"
2950  * HorSpeed: "0.0 m/s"
2951  * VerSpeed: "0.0 m/s"
2952  * OK
2953  *
2954  * OR
2955  *
2956  * +GNSSLOC:
2957  * FIX NOT AVAILABLE
2958  * OK
2959  *
2960  * Since each response is on its own line, the command handler is used
2961  * to handle each one as an individual response.
2962  */
gps_handler(struct net_buf ** buf,uint16_t len,enum mdm_hl7800_gps_string_types str_type)2963 static bool gps_handler(struct net_buf **buf, uint16_t len,
2964 			enum mdm_hl7800_gps_string_types str_type)
2965 {
2966 	struct mdm_hl7800_compound_event event;
2967 	char gps_str[MDM_HL7800_MAX_GPS_STR_SIZE];
2968 	size_t gps_len = sizeof(gps_str) - 1;
2969 	struct net_buf *frag = NULL;
2970 	size_t out_len;
2971 
2972 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(gps_str));
2973 
2974 	frag = NULL;
2975 	len = net_buf_findcrlf(*buf, &frag);
2976 	if (!frag) {
2977 		LOG_ERR("Unable to find end");
2978 		goto done;
2979 	}
2980 
2981 	if (len > gps_len) {
2982 		LOG_WRN("GPS string too long (len:%d)", len);
2983 		len = gps_len;
2984 	}
2985 
2986 	out_len = net_buf_linearize(gps_str, gps_len, *buf, 0, len);
2987 	gps_str[out_len] = 0;
2988 
2989 	event.code = str_type;
2990 	event.string = gps_str;
2991 	event_handler(HL7800_EVENT_GPS, &event);
2992 done:
2993 	return true;
2994 }
2995 
on_cmd_latitude(struct net_buf ** buf,uint16_t len)2996 static bool on_cmd_latitude(struct net_buf **buf, uint16_t len)
2997 {
2998 	return gps_handler(buf, len, HL7800_GPS_STR_LATITUDE);
2999 }
3000 
on_cmd_longitude(struct net_buf ** buf,uint16_t len)3001 static bool on_cmd_longitude(struct net_buf **buf, uint16_t len)
3002 {
3003 	return gps_handler(buf, len, HL7800_GPS_STR_LONGITUDE);
3004 }
3005 
on_cmd_gps_time(struct net_buf ** buf,uint16_t len)3006 static bool on_cmd_gps_time(struct net_buf **buf, uint16_t len)
3007 {
3008 	return gps_handler(buf, len, HL7800_GPS_STR_GPS_TIME);
3009 }
3010 
on_cmd_fix_type(struct net_buf ** buf,uint16_t len)3011 static bool on_cmd_fix_type(struct net_buf **buf, uint16_t len)
3012 {
3013 	return gps_handler(buf, len, HL7800_GPS_STR_FIX_TYPE);
3014 }
3015 
on_cmd_hepe(struct net_buf ** buf,uint16_t len)3016 static bool on_cmd_hepe(struct net_buf **buf, uint16_t len)
3017 {
3018 	return gps_handler(buf, len, HL7800_GPS_STR_HEPE);
3019 }
3020 
on_cmd_altitude(struct net_buf ** buf,uint16_t len)3021 static bool on_cmd_altitude(struct net_buf **buf, uint16_t len)
3022 {
3023 	return gps_handler(buf, len, HL7800_GPS_STR_ALTITUDE);
3024 }
3025 
on_cmd_alt_unc(struct net_buf ** buf,uint16_t len)3026 static bool on_cmd_alt_unc(struct net_buf **buf, uint16_t len)
3027 {
3028 	return gps_handler(buf, len, HL7800_GPS_STR_ALT_UNC);
3029 }
3030 
on_cmd_direction(struct net_buf ** buf,uint16_t len)3031 static bool on_cmd_direction(struct net_buf **buf, uint16_t len)
3032 {
3033 	return gps_handler(buf, len, HL7800_GPS_STR_DIRECTION);
3034 }
3035 
on_cmd_hor_speed(struct net_buf ** buf,uint16_t len)3036 static bool on_cmd_hor_speed(struct net_buf **buf, uint16_t len)
3037 {
3038 	return gps_handler(buf, len, HL7800_GPS_STR_HOR_SPEED);
3039 }
3040 
on_cmd_ver_speed(struct net_buf ** buf,uint16_t len)3041 static bool on_cmd_ver_speed(struct net_buf **buf, uint16_t len)
3042 {
3043 	return gps_handler(buf, len, HL7800_GPS_STR_VER_SPEED);
3044 }
3045 #endif /* CONFIG_MODEM_HL7800_GPS */
3046 
3047 #ifdef CONFIG_MODEM_HL7800_POLTE
3048 /* Handler: %POLTEEVU: "REGISTER",0, <mqttAuthUser>, <mqttAuthPassword> */
on_cmd_polte_registration(struct net_buf ** buf,uint16_t len)3049 static bool on_cmd_polte_registration(struct net_buf **buf, uint16_t len)
3050 {
3051 	char rsp[MDM_MAX_RESP_SIZE] = { 0 };
3052 	size_t rsp_len = sizeof(rsp) - 1;
3053 	char *rsp_end = rsp + rsp_len;
3054 	struct mdm_hl7800_polte_registration_event_data data;
3055 	struct net_buf *frag = NULL;
3056 	size_t out_len;
3057 	char *location;
3058 	bool parsed;
3059 
3060 	memset(&data, 0, sizeof(data));
3061 
3062 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
3063 
3064 	location = rsp;
3065 	parsed = false;
3066 	frag = NULL;
3067 	len = net_buf_findcrlf(*buf, &frag);
3068 	do {
3069 		if (!frag) {
3070 			LOG_ERR("Unable to find end");
3071 			break;
3072 		}
3073 
3074 		if (len > rsp_len) {
3075 			LOG_WRN("string too long (len:%d)", len);
3076 			len = rsp_len;
3077 		}
3078 
3079 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
3080 		rsp[out_len] = 0;
3081 
3082 		/* Command handler looks for string up to the user field */
3083 		location = strstr(location, "\"");
3084 		if (location != NULL && location < rsp_end) {
3085 			location += 1;
3086 			if (location >= rsp_end) {
3087 				break;
3088 			}
3089 			data.user = location;
3090 		} else {
3091 			break;
3092 		}
3093 
3094 		/* Find end of user field and null terminate string */
3095 		location = strstr(location, "\"");
3096 		if (location != NULL && location < rsp_end) {
3097 			*location = 0;
3098 			location += 1;
3099 			if (location >= rsp_end) {
3100 				break;
3101 			}
3102 		} else {
3103 			break;
3104 		}
3105 
3106 		location = strstr(location, ",\"");
3107 		if (location != NULL && location < rsp_end) {
3108 			location += 2;
3109 			if (location >= rsp_end) {
3110 				break;
3111 			}
3112 			data.password = location;
3113 
3114 		} else {
3115 			break;
3116 		}
3117 
3118 		location = strstr(location, "\"");
3119 		if (location != NULL && location < rsp_end) {
3120 			*location = 0;
3121 		} else {
3122 			break;
3123 		}
3124 		parsed = true;
3125 	} while (false);
3126 
3127 	if (parsed && data.user && data.password) {
3128 		data.status = 0;
3129 	} else {
3130 		data.status = -1;
3131 		LOG_ERR("Unable to parse PoLTE registration");
3132 	}
3133 
3134 	event_handler(HL7800_EVENT_POLTE_REGISTRATION, &data);
3135 
3136 	return true;
3137 }
3138 
3139 /* Handler: %POLTECMD: "LOCATE",<res> */
on_cmd_polte_locate_cmd_rsp(struct net_buf ** buf,uint16_t len)3140 static bool on_cmd_polte_locate_cmd_rsp(struct net_buf **buf, uint16_t len)
3141 {
3142 	char rsp[sizeof("99")] = { 0 };
3143 	size_t rsp_len = sizeof(rsp) - 1;
3144 	size_t out_len;
3145 	struct net_buf *frag = NULL;
3146 	struct mdm_hl7800_polte_location_data data;
3147 
3148 	memset(&data, 0, sizeof(data));
3149 
3150 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
3151 
3152 	data.status = -1;
3153 	frag = NULL;
3154 	len = net_buf_findcrlf(*buf, &frag);
3155 	do {
3156 		if (!frag) {
3157 			LOG_ERR("Unable to find end");
3158 			break;
3159 		}
3160 
3161 		if (len > rsp_len) {
3162 			LOG_WRN("string too long (len:%d)", len);
3163 			len = rsp_len;
3164 		}
3165 
3166 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
3167 		rsp[out_len] = 0;
3168 
3169 		data.status = (uint32_t)strtoul(rsp, NULL, 10);
3170 	} while (false);
3171 
3172 	event_handler(HL7800_EVENT_POLTE_LOCATE_STATUS, &data);
3173 
3174 	return true;
3175 }
3176 
3177 /* Handler:
3178  * %POLTEEVU: "LOCATION",<stat>[,<latitude>,<longitude>,<time>,<confidence>]
3179  */
on_cmd_polte_location(struct net_buf ** buf,uint16_t len)3180 static bool on_cmd_polte_location(struct net_buf **buf, uint16_t len)
3181 {
3182 	char rsp[MDM_MAX_RESP_SIZE] = { 0 };
3183 	size_t rsp_len = sizeof(rsp) - 1;
3184 	char *rsp_end = rsp + rsp_len;
3185 	struct net_buf *frag = NULL;
3186 	size_t out_len = 0;
3187 	char *start;
3188 	char *end;
3189 	bool parsed;
3190 	struct mdm_hl7800_polte_location_data data;
3191 	static const char POLTE_LOC_DELIMITER[] = "\",\"";
3192 
3193 	memset(&data, 0, sizeof(data));
3194 
3195 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
3196 
3197 	parsed = false;
3198 	frag = NULL;
3199 	len = net_buf_findcrlf(*buf, &frag);
3200 	do {
3201 		if (!frag) {
3202 			LOG_ERR("Unable to find end");
3203 			break;
3204 		}
3205 
3206 		if (len > rsp_len) {
3207 			LOG_WRN("string too long (len:%d)", len);
3208 			len = rsp_len;
3209 		}
3210 
3211 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
3212 		rsp[out_len] = 0;
3213 
3214 		data.status = -1;
3215 		start = rsp;
3216 		end = "";
3217 		/* Comma isn't present when there is an error. */
3218 		start = strstr(start, ",");
3219 		if (start != NULL && start < rsp_end) {
3220 			*start = ' ';
3221 			start += 1;
3222 		}
3223 		data.status = (uint32_t)strtoul(rsp, &end, 10);
3224 		if (data.status != 0) {
3225 			LOG_WRN("Response not received from PoLTE server: %d", data.status);
3226 			data.status = MDM_HL7800_POLTE_SERVER_ERROR;
3227 			parsed = true;
3228 			break;
3229 		} else if (start >= rsp_end) {
3230 			break;
3231 		}
3232 
3233 		start = strstr(start, "\"") + 1;
3234 		end = strstr(start, POLTE_LOC_DELIMITER);
3235 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3236 			memcpy(data.latitude, start, MIN(end - start, sizeof(data.latitude) - 1));
3237 		} else {
3238 			break;
3239 		}
3240 
3241 		start = end + strlen(POLTE_LOC_DELIMITER);
3242 		end = strstr(start, POLTE_LOC_DELIMITER);
3243 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3244 			memcpy(data.longitude, start, MIN(end - start, sizeof(data.longitude) - 1));
3245 		} else {
3246 			break;
3247 		}
3248 
3249 		start = end + strlen(POLTE_LOC_DELIMITER);
3250 		end = strstr(start, POLTE_LOC_DELIMITER);
3251 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3252 			data.timestamp = (uint32_t)strtoul(start, NULL, 10);
3253 		} else {
3254 			break;
3255 		}
3256 
3257 		start = end + strlen(POLTE_LOC_DELIMITER);
3258 		end = strstr(start, "\"");
3259 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3260 			memcpy(data.confidence_in_meters, start,
3261 			       MIN(end - start, sizeof(data.confidence_in_meters) - 1));
3262 		} else {
3263 			break;
3264 		}
3265 
3266 		parsed = true;
3267 	} while (false);
3268 
3269 	if (!parsed) {
3270 		LOG_HEXDUMP_ERR(rsp, out_len, "Unable to parse PoLTE location");
3271 	} else {
3272 		LOG_HEXDUMP_DBG(rsp, out_len, "PoLTE Location");
3273 	}
3274 
3275 	event_handler(HL7800_EVENT_POLTE, &data);
3276 
3277 	return true;
3278 }
3279 #endif /* CONFIG_MODEM_HL7800_POLTE */
3280 
notify_all_tcp_sockets_closed(void)3281 static void notify_all_tcp_sockets_closed(void)
3282 {
3283 	int i;
3284 	struct hl7800_socket *sock = NULL;
3285 
3286 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
3287 		sock = &iface_ctx.sockets[i];
3288 		if ((sock->context != NULL) && (sock->type == SOCK_STREAM)) {
3289 			LOG_DBG("Sock %d closed", sock->socket_id);
3290 			/* signal RX callback with null packet */
3291 			if (sock->recv_cb) {
3292 				sock->recv_cb(sock->context, sock->recv_pkt,
3293 					      NULL, NULL, 0,
3294 					      sock->recv_user_data);
3295 			}
3296 		}
3297 	}
3298 }
3299 
iface_status_work_cb(struct k_work * work)3300 static void iface_status_work_cb(struct k_work *work)
3301 {
3302 	int ret;
3303 	hl7800_lock();
3304 	enum mdm_hl7800_network_state state;
3305 
3306 	if (iface_ctx.off) {
3307 		goto done;
3308 	} else if (!iface_ctx.initialized && iface_ctx.restarting) {
3309 		LOG_DBG("Wait for driver init, process network state later");
3310 		/* we are not ready to process this yet, try again later */
3311 		k_work_reschedule_for_queue(&hl7800_workq,
3312 					    &iface_ctx.iface_status_work,
3313 					    IFACE_WORK_DELAY);
3314 		goto done;
3315 	} else if (iface_ctx.wait_for_KSUP &&
3316 		   iface_ctx.wait_for_KSUP_tries < WAIT_FOR_KSUP_RETRIES) {
3317 		LOG_DBG("Wait for +KSUP before updating network state");
3318 		iface_ctx.wait_for_KSUP_tries++;
3319 		/* we have not received +KSUP yet, lets wait more time to receive +KSUP */
3320 		k_work_reschedule_for_queue(&hl7800_workq,
3321 					    &iface_ctx.iface_status_work,
3322 					    IFACE_WORK_DELAY);
3323 		goto done;
3324 	} else if (iface_ctx.wait_for_KSUP &&
3325 		   iface_ctx.wait_for_KSUP_tries >= WAIT_FOR_KSUP_RETRIES) {
3326 		/* give up waiting for KSUP */
3327 		LOG_DBG("Give up waiting for");
3328 		iface_ctx.wait_for_KSUP = false;
3329 		check_hl7800_awake();
3330 	}
3331 
3332 	wakeup_hl7800();
3333 
3334 	LOG_DBG("Updating network state...");
3335 
3336 	state = iface_ctx.network_state;
3337 	/* Ensure we bring the network interface down and then re-check the current state */
3338 	if (iface_ctx.network_dropped) {
3339 		iface_ctx.network_dropped = false;
3340 		state = HL7800_OUT_OF_COVERAGE;
3341 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.iface_status_work,
3342 					    IFACE_WORK_DELAY);
3343 	}
3344 
3345 	/* Query operator selection */
3346 	ret = send_at_cmd(NULL, "AT+COPS?", MDM_CMD_SEND_TIMEOUT, 0, false);
3347 	if (ret < 0) {
3348 		LOG_ERR("AT+COPS ret:%d", ret);
3349 	}
3350 
3351 	/* bring iface up/down */
3352 	switch (state) {
3353 	case HL7800_HOME_NETWORK:
3354 	case HL7800_ROAMING:
3355 		if (iface_ctx.iface) {
3356 			LOG_DBG("HL7800 iface UP");
3357 			net_if_carrier_on(iface_ctx.iface);
3358 		}
3359 		break;
3360 	case HL7800_OUT_OF_COVERAGE:
3361 	default:
3362 		if (iface_ctx.iface && (iface_ctx.low_power_mode != HL7800_LPM_PSM)) {
3363 			LOG_DBG("HL7800 iface DOWN");
3364 			iface_ctx.dns_ready = false;
3365 			net_if_carrier_off(iface_ctx.iface);
3366 		}
3367 		break;
3368 	}
3369 
3370 	if ((iface_ctx.iface && !net_if_is_up(iface_ctx.iface)) ||
3371 	    (iface_ctx.low_power_mode == HL7800_LPM_PSM && state == HL7800_OUT_OF_COVERAGE)) {
3372 		hl7800_stop_rssi_work();
3373 		notify_all_tcp_sockets_closed();
3374 	} else if (iface_ctx.iface && net_if_is_up(iface_ctx.iface)) {
3375 		hl7800_start_rssi_work();
3376 		/* get IP address info */
3377 		(void)send_at_cmd(NULL, "AT+CGCONTRDP=1", MDM_CMD_SEND_TIMEOUT,
3378 				  CONFIG_MODEM_HL7800_GET_IP_ADDR_INFO_ATTEMPTS, false);
3379 		/* get active bands */
3380 		SEND_AT_CMD_IGNORE_ERROR("AT+KBND?");
3381 	}
3382 	LOG_DBG("Network state updated");
3383 	set_busy(false);
3384 	allow_sleep(true);
3385 done:
3386 	hl7800_unlock();
3387 }
3388 
get_network_state_string(enum mdm_hl7800_network_state state)3389 static char *get_network_state_string(enum mdm_hl7800_network_state state)
3390 {
3391 	switch (state) {
3392 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, NOT_REGISTERED);
3393 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, HOME_NETWORK);
3394 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, SEARCHING);
3395 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, REGISTRATION_DENIED);
3396 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, OUT_OF_COVERAGE);
3397 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, ROAMING);
3398 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, EMERGENCY);
3399 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, UNABLE_TO_CONFIGURE);
3400 	default:
3401 		return "UNKNOWN";
3402 	}
3403 }
3404 
set_network_state(enum mdm_hl7800_network_state state)3405 static void set_network_state(enum mdm_hl7800_network_state state)
3406 {
3407 	iface_ctx.network_state = state;
3408 	generate_network_state_event();
3409 }
3410 
generate_network_state_event(void)3411 static void generate_network_state_event(void)
3412 {
3413 	struct mdm_hl7800_compound_event event;
3414 
3415 	event.code = iface_ctx.network_state;
3416 	event.string = get_network_state_string(iface_ctx.network_state);
3417 	LOG_INF("Network State: %d %s", iface_ctx.network_state, event.string);
3418 	event_handler(HL7800_EVENT_NETWORK_STATE_CHANGE, &event);
3419 }
3420 
3421 /* Handler: +CEREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>]
3422  *  [,[<cause_type>],[<reject_cause>] [,[<Active-Time>],[<Periodic-TAU>]]]]
3423  */
on_cmd_network_report_query(struct net_buf ** buf,uint16_t len)3424 static bool on_cmd_network_report_query(struct net_buf **buf, uint16_t len)
3425 {
3426 	size_t out_len;
3427 	char value[MDM_MAX_RESP_SIZE];
3428 	char *pos;
3429 	int l;
3430 	char val[MDM_MAX_RESP_SIZE];
3431 
3432 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3433 	pos = strchr(value, ',');
3434 	if (pos) {
3435 		l = (value + out_len) - pos;
3436 		strncpy(val, pos + 1, l);
3437 		val[l] = 0;
3438 		set_network_state(strtol(val, NULL, 0));
3439 
3440 		/* start work to adjust iface */
3441 		k_work_reschedule_for_queue(&hl7800_workq,
3442 					    &iface_ctx.iface_status_work,
3443 					    IFACE_WORK_DELAY);
3444 	}
3445 
3446 	return true;
3447 }
3448 
on_cmd_operator_index_query(struct net_buf ** buf,uint16_t len)3449 static bool on_cmd_operator_index_query(struct net_buf **buf, uint16_t len)
3450 {
3451 	struct net_buf *frag = NULL;
3452 	char carrier[MDM_HL7800_OPERATOR_INDEX_SIZE];
3453 	size_t out_len;
3454 
3455 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3456 					MDM_HL7800_OPERATOR_INDEX_SIZE);
3457 
3458 	frag = NULL;
3459 	len = net_buf_findcrlf(*buf, &frag);
3460 	if (!frag) {
3461 		LOG_ERR("Unable to find end of operator index response");
3462 		goto done;
3463 	}
3464 
3465 	out_len = net_buf_linearize(carrier, MDM_HL7800_OPERATOR_INDEX_STRLEN,
3466 				    *buf, 0, len);
3467 	carrier[out_len] = 0;
3468 	iface_ctx.operator_index = (uint8_t)strtol(carrier, NULL, 10);
3469 
3470 	LOG_INF("Operator Index: %u", iface_ctx.operator_index);
3471 done:
3472 	return true;
3473 }
3474 
on_cmd_modem_functionality(struct net_buf ** buf,uint16_t len)3475 static bool on_cmd_modem_functionality(struct net_buf **buf, uint16_t len)
3476 {
3477 	struct net_buf *frag;
3478 	size_t out_len;
3479 	char rsp[MDM_HL7800_MODEM_FUNCTIONALITY_SIZE];
3480 
3481 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3482 					MDM_HL7800_MODEM_FUNCTIONALITY_SIZE);
3483 
3484 	frag = NULL;
3485 	len = net_buf_findcrlf(*buf, &frag);
3486 	if (!frag) {
3487 		LOG_ERR("Unable to find end of response");
3488 		goto done;
3489 	}
3490 
3491 	out_len = net_buf_linearize(rsp, MDM_HL7800_MODEM_FUNCTIONALITY_STRLEN,
3492 				    *buf, 0, len);
3493 	rsp[out_len] = 0;
3494 	iface_ctx.functionality = strtol(rsp, NULL, 10);
3495 
3496 	LOG_INF("Modem Functionality: %u", iface_ctx.functionality);
3497 done:
3498 	return true;
3499 }
3500 
3501 /* There can be multiple responses from a single command.
3502  * %MEAS: EARFCN=5826, CellID=420, RSRP=-99, RSRQ=-15
3503  * %MEAS: EARFCN=6400, CellID=201, RSRP=-93, RSRQ=-21
3504  */
on_cmd_survey_status(struct net_buf ** buf,uint16_t len)3505 static bool on_cmd_survey_status(struct net_buf **buf, uint16_t len)
3506 {
3507 	struct net_buf *frag = NULL;
3508 	char response[sizeof("EARFCN=XXXXXXXXXXX, CellID=XXXXXXXXXXX, RSRP=-XXX, RSRQ=-XXX")];
3509 	char *key;
3510 	size_t out_len;
3511 	char *value;
3512 	struct mdm_hl7800_site_survey site_survey;
3513 
3514 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3515 					sizeof(response));
3516 
3517 	frag = NULL;
3518 	len = net_buf_findcrlf(*buf, &frag);
3519 	if (!frag) {
3520 		LOG_ERR("Unable to find end");
3521 		goto done;
3522 	}
3523 
3524 	out_len = net_buf_linearize(response, sizeof(response), *buf, 0, len);
3525 	LOG_HEXDUMP_DBG(response, out_len, "Site Survey");
3526 
3527 	key = "EARFCN=";
3528 	value = strstr(response, key);
3529 	if (value == NULL) {
3530 		goto done;
3531 	} else {
3532 		value += strlen(key);
3533 		site_survey.earfcn = strtoul(value, NULL, 10);
3534 	}
3535 
3536 	key = "CellID=";
3537 	value = strstr(response, key);
3538 	if (value == NULL) {
3539 		goto done;
3540 	} else {
3541 		value += strlen(key);
3542 		site_survey.cell_id = strtoul(value, NULL, 10);
3543 	}
3544 
3545 	key = "RSRP=";
3546 	value = strstr(response, key);
3547 	if (value == NULL) {
3548 		goto done;
3549 	} else {
3550 		value += strlen(key);
3551 		site_survey.rsrp = strtol(value, NULL, 10);
3552 	}
3553 
3554 	key = "RSRQ=";
3555 	value = strstr(response, key);
3556 	if (value == NULL) {
3557 		goto done;
3558 	} else {
3559 		value += strlen(key);
3560 		site_survey.rsrq = strtol(value, NULL, 10);
3561 	}
3562 
3563 	event_handler(HL7800_EVENT_SITE_SURVEY, &site_survey);
3564 
3565 done:
3566 	return true;
3567 }
3568 
3569 /* Handler: +CCLK: "yy/MM/dd,hh:mm:ss±zz" */
on_cmd_rtc_query(struct net_buf ** buf,uint16_t len)3570 static bool on_cmd_rtc_query(struct net_buf **buf, uint16_t len)
3571 {
3572 	struct net_buf *frag = NULL;
3573 	size_t str_len = sizeof(TIME_STRING_FORMAT) - 1;
3574 	char rtc_string[sizeof(TIME_STRING_FORMAT)];
3575 
3576 	memset(rtc_string, 0, sizeof(rtc_string));
3577 	iface_ctx.local_time_valid = false;
3578 
3579 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3580 					sizeof(TIME_STRING_FORMAT));
3581 
3582 	frag = NULL;
3583 	len = net_buf_findcrlf(*buf, &frag);
3584 	if (!frag) {
3585 		goto done;
3586 	}
3587 	if (len != str_len) {
3588 		LOG_WRN("Unexpected length for RTC string %d (expected:%zu)",
3589 			len, str_len);
3590 	} else {
3591 		net_buf_linearize(rtc_string, str_len, *buf, 0, str_len);
3592 		LOG_INF("RTC string: '%s'", rtc_string);
3593 		iface_ctx.local_time_valid = convert_time_string_to_struct(
3594 			&iface_ctx.local_time, &iface_ctx.local_time_offset, rtc_string);
3595 	}
3596 done:
3597 	return true;
3598 }
3599 
valid_time_string(const char * time_string)3600 static bool valid_time_string(const char *time_string)
3601 {
3602 	size_t offset, i;
3603 
3604 	/* Ensure the all the expected delimiters are present */
3605 	offset = TIME_STRING_DIGIT_STRLEN + TIME_STRING_SEPARATOR_STRLEN;
3606 	i = TIME_STRING_FIRST_SEPARATOR_INDEX;
3607 
3608 	for (; i < TIME_STRING_PLUS_MINUS_INDEX; i += offset) {
3609 		if (time_string[i] != TIME_STRING_FORMAT[i]) {
3610 			return false;
3611 		}
3612 	}
3613 	/* The last character is the offset from UTC and can be either
3614 	 * positive or negative.  The last " is also handled here.
3615 	 */
3616 	if ((time_string[i] == '+' || time_string[i] == '-') &&
3617 	    (time_string[i + offset] == '"')) {
3618 		return true;
3619 	}
3620 	return false;
3621 }
3622 
get_next_time_string_digit(int * failure_cnt,char ** pp,int min,int max)3623 int get_next_time_string_digit(int *failure_cnt, char **pp, int min, int max)
3624 {
3625 	char digits[TIME_STRING_DIGIT_STRLEN + SIZE_OF_NUL];
3626 	int result;
3627 
3628 	memset(digits, 0, sizeof(digits));
3629 	memcpy(digits, *pp, TIME_STRING_DIGIT_STRLEN);
3630 	*pp += TIME_STRING_DIGIT_STRLEN + TIME_STRING_SEPARATOR_STRLEN;
3631 	result = strtol(digits, NULL, 10);
3632 	if (result > max) {
3633 		*failure_cnt += 1;
3634 		return max;
3635 	} else if (result < min) {
3636 		*failure_cnt += 1;
3637 		return min;
3638 	} else {
3639 		return result;
3640 	}
3641 }
3642 
convert_time_string_to_struct(struct tm * tm,int32_t * offset,char * time_string)3643 static bool convert_time_string_to_struct(struct tm *tm, int32_t *offset,
3644 					  char *time_string)
3645 {
3646 	int fc = 0;
3647 	char *ptr = time_string;
3648 
3649 	if (!valid_time_string(ptr)) {
3650 		return false;
3651 	}
3652 	ptr = &ptr[TIME_STRING_FIRST_DIGIT_INDEX];
3653 	tm->tm_year = TIME_STRING_TO_TM_STRUCT_YEAR_OFFSET +
3654 		      get_next_time_string_digit(&fc, &ptr, TM_YEAR_RANGE);
3655 	tm->tm_mon =
3656 		get_next_time_string_digit(&fc, &ptr, TM_MONTH_RANGE_PLUS_1) -
3657 		1;
3658 	tm->tm_mday = get_next_time_string_digit(&fc, &ptr, TM_DAY_RANGE);
3659 	tm->tm_hour = get_next_time_string_digit(&fc, &ptr, TM_HOUR_RANGE);
3660 	tm->tm_min = get_next_time_string_digit(&fc, &ptr, TM_MIN_RANGE);
3661 	tm->tm_sec = get_next_time_string_digit(&fc, &ptr, TM_SEC_RANGE);
3662 	tm->tm_isdst = 0;
3663 	*offset = (int32_t)get_next_time_string_digit(&fc, &ptr,
3664 						      QUARTER_HOUR_RANGE) *
3665 		  SECONDS_PER_QUARTER_HOUR;
3666 	if (time_string[TIME_STRING_PLUS_MINUS_INDEX] == '-') {
3667 		*offset *= -1;
3668 	}
3669 	return (fc == 0);
3670 }
3671 
3672 /* Handler: +CEREG: <stat>[,[<lac>],[<ci>],[<AcT>]
3673  *  [,[<cause_type>],[<reject_cause>] [,[<Active-Time>],[<Periodic-TAU>]]]]
3674  */
on_cmd_network_report(struct net_buf ** buf,uint16_t len)3675 static bool on_cmd_network_report(struct net_buf **buf, uint16_t len)
3676 {
3677 	size_t out_len;
3678 	char *pos;
3679 	int l;
3680 	char val[MDM_MAX_RESP_SIZE];
3681 
3682 	out_len = net_buf_linearize(iface_ctx.mdm_network_status,
3683 				    sizeof(iface_ctx.mdm_network_status) - 1, *buf,
3684 				    0, len);
3685 	iface_ctx.mdm_network_status[out_len] = 0;
3686 	LOG_DBG("Network status: %s", iface_ctx.mdm_network_status);
3687 	pos = strchr(iface_ctx.mdm_network_status, ',');
3688 	if (pos) {
3689 		l = pos - iface_ctx.mdm_network_status;
3690 		strncpy(val, iface_ctx.mdm_network_status, l);
3691 		val[l] = 0;
3692 		set_network_state(strtol(val, NULL, 0));
3693 	} else {
3694 		set_network_state(strtol(iface_ctx.mdm_network_status, NULL, 0));
3695 	}
3696 
3697 	/* keep HL7800 awake because we want to process the network state soon */
3698 	set_busy(true);
3699 	allow_sleep(false);
3700 	/* start work to adjust iface */
3701 	k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.iface_status_work,
3702 				    IFACE_WORK_DELAY);
3703 
3704 	return true;
3705 }
3706 
3707 /* Handler: +KCELLMEAS: <RSRP>,<Downlink Path Loss>,<PUSCH Tx Power>,
3708  *                       <PUCCH Tx Power>,<SiNR>
3709  */
on_cmd_atcmdinfo_rssi(struct net_buf ** buf,uint16_t len)3710 static bool on_cmd_atcmdinfo_rssi(struct net_buf **buf, uint16_t len)
3711 {
3712 	/* number of ',' delimiters in this response */
3713 	int num_delims = KCELLMEAS_RESPONSE_NUM_DELIMS;
3714 	char *delims[KCELLMEAS_RESPONSE_NUM_DELIMS];
3715 	size_t out_len;
3716 	char value[MDM_MAX_RESP_SIZE];
3717 	char *search_start;
3718 	int i;
3719 
3720 	out_len = net_buf_linearize(value, len, *buf, 0, len);
3721 	value[out_len] = 0;
3722 	search_start = value;
3723 
3724 	/* find all delimiters */
3725 	for (i = 0; i < num_delims; i++) {
3726 		delims[i] = strchr(search_start, ',');
3727 		if (!delims[i]) {
3728 			LOG_ERR("Could not find delim %d, val: %s", i,
3729 				value);
3730 			goto done;
3731 		}
3732 		/* Start next search after current delim location */
3733 		search_start = delims[i] + 1;
3734 	}
3735 	/* the first value in the message is the RSRP */
3736 	iface_ctx.mdm_rssi = strtol(value, NULL, 10);
3737 	/* the 4th ',' (last in the msg) is the start of the SINR */
3738 	iface_ctx.mdm_sinr = strtol(delims[3] + 1, NULL, 10);
3739 	if ((delims[1] - delims[0]) == 1) {
3740 		/* there is no value between the first and second
3741 		 *  delimiter, signal is unknown
3742 		 */
3743 		LOG_INF("RSSI (RSRP): UNKNOWN");
3744 	} else {
3745 		LOG_INF("RSSI (RSRP): %d SINR: %d", iface_ctx.mdm_rssi,
3746 			iface_ctx.mdm_sinr);
3747 		event_handler(HL7800_EVENT_RSSI, &iface_ctx.mdm_rssi);
3748 		event_handler(HL7800_EVENT_SINR, &iface_ctx.mdm_sinr);
3749 	}
3750 done:
3751 	return true;
3752 }
3753 
3754 /* Handle the "OK" response from an AT command or a socket call */
on_cmd_sockok(struct net_buf ** buf,uint16_t len)3755 static bool on_cmd_sockok(struct net_buf **buf, uint16_t len)
3756 {
3757 	struct hl7800_socket *sock = NULL;
3758 
3759 	sock = socket_from_id(iface_ctx.last_socket_id);
3760 	if (!sock || !iface_ctx.socket_cmd) {
3761 		iface_ctx.last_error = 0;
3762 		k_sem_give(&iface_ctx.response_sem);
3763 	} else {
3764 		sock->error = 0;
3765 		k_sem_give(&sock->sock_send_sem);
3766 	}
3767 	return true;
3768 }
3769 
3770 /* Handler: +KTCP_IND/+KUDP_IND */
on_cmd_sock_ind(struct net_buf ** buf,uint16_t len,const char * const type)3771 static bool on_cmd_sock_ind(struct net_buf **buf, uint16_t len, const char *const type)
3772 {
3773 	struct hl7800_socket *sock = NULL;
3774 	char *delim;
3775 	char value[MDM_MAX_RESP_SIZE];
3776 	size_t out_len;
3777 	int id;
3778 
3779 	iface_ctx.last_error = 0;
3780 
3781 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3782 	value[out_len] = 0;
3783 
3784 	/* find ',' because this is the format we expect */
3785 	delim = strchr(value, ',');
3786 	if (!delim) {
3787 		LOG_ERR("%s could not find ','", type);
3788 		goto done;
3789 	}
3790 
3791 	id = strtol(value, NULL, 10);
3792 	LOG_DBG("%s ID: %d", type, id);
3793 	sock = socket_from_id(id);
3794 	if (sock) {
3795 		sock->error = 0;
3796 		k_sem_give(&sock->sock_send_sem);
3797 	}
3798 
3799 done:
3800 	return true;
3801 }
3802 
on_cmd_ktcp_ind(struct net_buf ** buf,uint16_t len)3803 static bool on_cmd_ktcp_ind(struct net_buf **buf, uint16_t len)
3804 {
3805 	return on_cmd_sock_ind(buf, len, "+KTCP_IND");
3806 }
3807 
on_cmd_kudp_ind(struct net_buf ** buf,uint16_t len)3808 static bool on_cmd_kudp_ind(struct net_buf **buf, uint16_t len)
3809 {
3810 	return on_cmd_sock_ind(buf, len, "+KUDP_IND");
3811 }
3812 
3813 
3814 /* Handler: ERROR */
on_cmd_sockerror(struct net_buf ** buf,uint16_t len)3815 static bool on_cmd_sockerror(struct net_buf **buf, uint16_t len)
3816 {
3817 	struct hl7800_socket *sock = NULL;
3818 	char string[MDM_MAX_RESP_SIZE];
3819 
3820 	if (len > 0) {
3821 		memset(string, 0, sizeof(string));
3822 		net_buf_linearize(string, sizeof(string), *buf, 0, len);
3823 		LOG_ERR("'%s'", string);
3824 	}
3825 
3826 	sock = socket_from_id(iface_ctx.last_socket_id);
3827 	if (!sock) {
3828 		iface_ctx.last_error = -EIO;
3829 		k_sem_give(&iface_ctx.response_sem);
3830 	} else {
3831 		sock->error = -EIO;
3832 		k_sem_give(&sock->sock_send_sem);
3833 	}
3834 
3835 	return true;
3836 }
3837 
3838 /* Handler: CME/CMS Error */
on_cmd_sock_error_code(struct net_buf ** buf,uint16_t len)3839 static bool on_cmd_sock_error_code(struct net_buf **buf, uint16_t len)
3840 {
3841 	struct hl7800_socket *sock = NULL;
3842 	char value[MDM_MAX_RESP_SIZE];
3843 	size_t out_len;
3844 
3845 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3846 	value[out_len] = 0;
3847 
3848 	LOG_ERR("Error code: %s", value);
3849 
3850 	sock = socket_from_id(iface_ctx.last_socket_id);
3851 	if (!sock) {
3852 		iface_ctx.last_error = -EIO;
3853 		k_sem_give(&iface_ctx.response_sem);
3854 	} else {
3855 		sock->error = -EIO;
3856 		k_sem_give(&sock->sock_send_sem);
3857 	}
3858 
3859 	return true;
3860 }
3861 
sock_notif_cb_work(struct k_work * work)3862 static void sock_notif_cb_work(struct k_work *work)
3863 {
3864 	struct hl7800_socket *sock = NULL;
3865 	struct k_work_delayable *dwork;
3866 
3867 	dwork = k_work_delayable_from_work(work);
3868 	sock = CONTAINER_OF(dwork, struct hl7800_socket, notif_work);
3869 
3870 	hl7800_lock();
3871 	/* send null packet */
3872 	if (sock->recv_pkt != NULL) {
3873 		/* we are in the middle of RX,
3874 		 * requeue this and try again
3875 		 */
3876 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work,
3877 					    MDM_SOCK_NOTIF_DELAY);
3878 	} else {
3879 		if (sock->type == SOCK_STREAM) {
3880 			LOG_DBG("Sock %d trigger NULL packet", sock->socket_id);
3881 			k_work_submit_to_queue(&hl7800_workq, &sock->recv_cb_work);
3882 		}
3883 	}
3884 	hl7800_unlock();
3885 }
3886 
3887 /* Handler: +KTCP_NOTIF/+KUDP_NOTIF */
on_cmd_sock_notif(struct net_buf ** buf,uint16_t len)3888 static bool on_cmd_sock_notif(struct net_buf **buf, uint16_t len)
3889 {
3890 	struct hl7800_socket *sock = NULL;
3891 	char *delim;
3892 	char value[MDM_MAX_RESP_SIZE];
3893 	size_t out_len;
3894 	uint8_t notif_val;
3895 	bool err = false;
3896 	bool trigger_sem = true;
3897 	int id;
3898 
3899 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3900 	value[out_len] = 0;
3901 
3902 	/* find ',' because this is the format we expect */
3903 	delim = strchr(value, ',');
3904 	if (!delim) {
3905 		LOG_ERR("+K**P_NOTIF could not find ','");
3906 		goto done;
3907 	}
3908 
3909 	id = strtol(value, NULL, 10);
3910 	notif_val = strtol(delim + 1, NULL, 10);
3911 	if (notif_val == HL7800_TCP_DISCON) {
3912 		LOG_DBG("+K**P_NOTIF: %d,%d", id, notif_val);
3913 	} else {
3914 		LOG_WRN("+K**P_NOTIF: %d,%d", id, notif_val);
3915 	}
3916 	sock = socket_from_id(id);
3917 	if (!sock) {
3918 		goto done;
3919 	}
3920 
3921 	switch (notif_val) {
3922 	case HL7800_TCP_DATA_SND:
3923 		err = false;
3924 		sock->error = 0;
3925 		break;
3926 	case HL7800_TCP_DISCON:
3927 		trigger_sem = false;
3928 		err = true;
3929 		sock->error = -ENOTCONN;
3930 		break;
3931 	default:
3932 		iface_ctx.network_dropped = true;
3933 		err = true;
3934 		sock->error = -EIO;
3935 		break;
3936 	}
3937 
3938 	if (err) {
3939 		/* Send NULL packet to callback to notify upper stack layers
3940 		 * that the peer closed the connection or there was an error.
3941 		 * This is so an app will not get stuck in recv() forever.
3942 		 * Let's do the callback processing in a different work queue
3943 		 * so RX is not delayed.
3944 		 */
3945 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work, MDM_SOCK_NOTIF_DELAY);
3946 		if (trigger_sem) {
3947 			k_sem_give(&sock->sock_send_sem);
3948 		}
3949 
3950 		if (iface_ctx.network_dropped) {
3951 			k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.iface_status_work,
3952 						    IFACE_WORK_DELAY);
3953 		}
3954 	}
3955 done:
3956 	return true;
3957 }
3958 
delete_socket(struct hl7800_socket * sock,enum net_sock_type type,uint8_t id)3959 static int delete_socket(struct hl7800_socket *sock, enum net_sock_type type, uint8_t id)
3960 {
3961 	char cmd[sizeof("AT+KUDPCLOSE=###")];
3962 
3963 	if (type == SOCK_STREAM) {
3964 		snprintk(cmd, sizeof(cmd), "AT+KTCPDEL=%d", id);
3965 	} else if (type == SOCK_DGRAM) {
3966 		snprintk(cmd, sizeof(cmd), "AT+KUDPCLOSE=%d", id);
3967 	}
3968 
3969 	return send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
3970 }
3971 
delete_untracked_socket_work_cb(struct k_work * item)3972 static void delete_untracked_socket_work_cb(struct k_work *item)
3973 {
3974 	struct stale_socket *sock = NULL;
3975 
3976 	hl7800_lock();
3977 	wakeup_hl7800();
3978 	do {
3979 		sock = dequeue_stale_socket();
3980 		if (sock != NULL) {
3981 			LOG_DBG("Delete untracked socket [%d]", sock->id);
3982 			delete_socket(NULL, sock->type, sock->id);
3983 			free_stale_socket(sock);
3984 		}
3985 	} while (sock != NULL);
3986 
3987 	set_busy(false);
3988 	allow_sleep(true);
3989 	hl7800_unlock();
3990 }
3991 
on_cmd_sockcreate(enum net_sock_type type,struct net_buf ** buf,uint16_t len)3992 static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uint16_t len)
3993 {
3994 	size_t out_len;
3995 	char value[MDM_MAX_RESP_SIZE];
3996 	struct hl7800_socket *sock = NULL;
3997 
3998 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3999 	value[out_len] = 0;
4000 	iface_ctx.last_socket_id = strtol(value, NULL, 10);
4001 	if (type == SOCK_STREAM) {
4002 		LOG_DBG("+KTCPCFG: %d", iface_ctx.last_socket_id);
4003 	} else if (type == SOCK_DGRAM) {
4004 		LOG_DBG("+KUDPCFG: %d", iface_ctx.last_socket_id);
4005 	}
4006 
4007 	/* check if the socket has been created already */
4008 	sock = socket_from_id(iface_ctx.last_socket_id);
4009 	if (!sock) {
4010 		LOG_DBG("look up new socket by creation id");
4011 		sock = socket_from_id(MDM_CREATE_SOCKET_ID);
4012 		if (!sock || sock->type != type) {
4013 			if (queue_stale_socket(type, iface_ctx.last_socket_id) == 0) {
4014 				/* delay some time before socket cleanup in case there
4015 				 * are multiple sockets to cleanup
4016 				 */
4017 				k_work_reschedule_for_queue(&hl7800_workq,
4018 							    &iface_ctx.delete_untracked_socket_work,
4019 							    SOCKET_CLEANUP_WORK_DELAY);
4020 			}
4021 			goto done;
4022 		}
4023 	}
4024 
4025 	sock->socket_id = iface_ctx.last_socket_id;
4026 	sock->created = true;
4027 	sock->reconfig = false;
4028 	/* don't give back semaphore -- OK to follow */
4029 done:
4030 	return true;
4031 }
4032 
4033 /* Handler: +KTCPCFG: <session_id> */
on_cmd_sock_tcp_create(struct net_buf ** buf,uint16_t len)4034 static bool on_cmd_sock_tcp_create(struct net_buf **buf, uint16_t len)
4035 {
4036 	return on_cmd_sockcreate(SOCK_STREAM, buf, len);
4037 }
4038 
4039 /* Handler: +KUDPCFG: <session_id> */
on_cmd_sock_udp_create(struct net_buf ** buf,uint16_t len)4040 static bool on_cmd_sock_udp_create(struct net_buf **buf, uint16_t len)
4041 {
4042 	return on_cmd_sockcreate(SOCK_DGRAM, buf, len);
4043 }
4044 
sockreadrecv_cb_work(struct k_work * work)4045 static void sockreadrecv_cb_work(struct k_work *work)
4046 {
4047 	struct hl7800_socket *sock = NULL;
4048 	struct net_pkt *pkt;
4049 
4050 	sock = CONTAINER_OF(work, struct hl7800_socket, recv_cb_work);
4051 
4052 	LOG_DBG("Sock %d RX CB (size: %zd)", sock->socket_id,
4053 		(sock->recv_pkt != NULL) ? net_pkt_get_len(sock->recv_pkt) : 0);
4054 	/* return data */
4055 	pkt = sock->recv_pkt;
4056 	sock->recv_pkt = NULL;
4057 	if (sock->recv_cb) {
4058 		sock->recv_cb(sock->context, pkt, NULL, NULL, 0,
4059 			      sock->recv_user_data);
4060 	} else {
4061 		net_pkt_unref(pkt);
4062 	}
4063 }
4064 
sock_read(struct net_buf ** buf)4065 static void sock_read(struct net_buf **buf)
4066 {
4067 	struct hl7800_socket *sock = NULL;
4068 	struct net_buf *frag;
4069 	uint8_t c = 0U;
4070 	int i, hdr_len;
4071 	char ok_resp[sizeof(OK_STRING)];
4072 	char eof[sizeof(EOF_PATTERN)];
4073 	size_t out_len;
4074 
4075 	sock = socket_from_id(iface_ctx.last_socket_id);
4076 	if (!sock) {
4077 		LOG_ERR("Socket not found! (%d)", iface_ctx.last_socket_id);
4078 		goto exit;
4079 	}
4080 
4081 	if (sock->error != 0) {
4082 		/* cancel notif work and restart */
4083 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work,
4084 					    MDM_SOCK_NOTIF_DELAY);
4085 	}
4086 
4087 	LOG_DBG("Socket %d RX %u bytes", sock->socket_id, sock->rx_size);
4088 
4089 	/* remove ending \r\n from last CONNECT */
4090 	if (net_buf_frags_len(*buf) < 2) {
4091 		/* wait for \n to be RXd.  \r was already RXd. */
4092 		wait_for_modem_data(buf, 0, 1);
4093 	}
4094 	/* remove \r\n */
4095 	net_buf_remove(buf, 2);
4096 	if (!*buf) {
4097 		wait_for_modem_data(buf, 0, sock->rx_size);
4098 	}
4099 
4100 	LOG_DBG("Processing RX, buf len: %zd", net_buf_frags_len(*buf));
4101 
4102 	/* allocate an RX pkt */
4103 	sock->recv_pkt = net_pkt_rx_alloc_with_buffer(
4104 		net_context_get_iface(sock->context), sock->rx_size,
4105 		sock->family, sock->ip_proto, BUF_ALLOC_TIMEOUT);
4106 	if (!sock->recv_pkt) {
4107 		LOG_ERR("Failed net_pkt_get_reserve_rx!");
4108 		goto done;
4109 	}
4110 
4111 	/* set pkt data */
4112 	net_pkt_set_context(sock->recv_pkt, sock->context);
4113 
4114 	/* add IP / protocol headers */
4115 	hdr_len = pkt_setup_ip_data(sock->recv_pkt, sock);
4116 
4117 	/* receive data */
4118 	for (i = 0; i < sock->rx_size; i++) {
4119 		/* pull data from buf and advance to the next frag if needed */
4120 		c = net_buf_get_u8(buf);
4121 		/* write data to packet */
4122 		if (net_pkt_write_u8(sock->recv_pkt, c)) {
4123 			LOG_ERR("Unable to add data! Aborting! Bytes RXd:%d",
4124 				i);
4125 			goto rx_err;
4126 		}
4127 
4128 		if (!*buf && i < sock->rx_size) {
4129 			LOG_DBG("RX more data, bytes RXd:%d", i + 1);
4130 			/* wait for at least one more byte */
4131 			wait_for_modem_data(buf, 0, 1);
4132 			if (!*buf) {
4133 				LOG_ERR("No data in buf!");
4134 				break;
4135 			}
4136 		}
4137 	}
4138 
4139 	LOG_DBG("Got all data, get EOF and OK (buf len:%zd)",
4140 		net_buf_frags_len(*buf));
4141 
4142 	if (!*buf || (net_buf_frags_len(*buf) < strlen(EOF_PATTERN))) {
4143 		wait_for_modem_data(buf, net_buf_frags_len(*buf),
4144 				    strlen(EOF_PATTERN));
4145 		if (!*buf) {
4146 			LOG_WRN("No EOF present");
4147 			goto all_rx_data;
4148 		}
4149 	}
4150 
4151 	out_len = net_buf_linearize(eof, sizeof(eof), *buf, 0,
4152 				    strlen(EOF_PATTERN));
4153 	eof[out_len] = 0;
4154 	/* remove EOF pattern from buffer */
4155 	net_buf_remove(buf, strlen(EOF_PATTERN));
4156 	if (strcmp(eof, EOF_PATTERN)) {
4157 		LOG_WRN("Could not find EOF [%s]", eof);
4158 	}
4159 
4160 	/* Make sure we have \r\nOK\r\n length in the buffer */
4161 	if (!*buf || (net_buf_frags_len(*buf) < strlen(OK_STRING) + 4)) {
4162 		wait_for_modem_data(buf, net_buf_frags_len(*buf),
4163 				    strlen(OK_STRING) + 4);
4164 		if (!*buf) {
4165 			LOG_WRN("No OK present");
4166 			goto all_rx_data;
4167 		}
4168 	}
4169 
4170 	frag = NULL;
4171 	(void)net_buf_findcrlf(*buf, &frag);
4172 	if (!frag) {
4173 		LOG_WRN("Unable to find OK start");
4174 		goto all_rx_data;
4175 	}
4176 	/* remove \r\n before OK */
4177 	net_buf_skipcrlf(buf);
4178 
4179 	out_len = net_buf_linearize(ok_resp, sizeof(ok_resp), *buf, 0,
4180 				    strlen(OK_STRING));
4181 	ok_resp[out_len] = 0;
4182 	/* remove the message from the buffer */
4183 	net_buf_remove(buf, strlen(OK_STRING));
4184 	if (strcmp(ok_resp, OK_STRING)) {
4185 		LOG_WRN("Could not find OK [%s]", ok_resp);
4186 	}
4187 
4188 	/* remove \r\n after OK */
4189 	net_buf_skipcrlf(buf);
4190 
4191 all_rx_data:
4192 	net_pkt_cursor_init(sock->recv_pkt);
4193 	net_pkt_set_overwrite(sock->recv_pkt, true);
4194 
4195 	if (hdr_len > 0) {
4196 		net_pkt_skip(sock->recv_pkt, hdr_len);
4197 	}
4198 
4199 	/* Let's do the callback processing in a different work queue in
4200 	 * case the app takes a long time.
4201 	 */
4202 	k_work_submit_to_queue(&hl7800_workq, &sock->recv_cb_work);
4203 	LOG_DBG("Sock %d RX done", sock->socket_id);
4204 	goto done;
4205 rx_err:
4206 	net_pkt_unref(sock->recv_pkt);
4207 	sock->recv_pkt = NULL;
4208 done:
4209 	if (sock->type == SOCK_STREAM) {
4210 		if (sock->error == 0) {
4211 			sock->state = SOCK_CONNECTED;
4212 		}
4213 	} else {
4214 		sock->state = SOCK_IDLE;
4215 	}
4216 exit:
4217 	set_busy(false);
4218 	allow_sleep(true);
4219 	hl7800_TX_unlock();
4220 }
4221 
on_cmd_connect(struct net_buf ** buf,uint16_t len)4222 static bool on_cmd_connect(struct net_buf **buf, uint16_t len)
4223 {
4224 	bool remove_data_from_buffer = true;
4225 	struct hl7800_socket *sock = NULL;
4226 
4227 	sock = socket_from_id(iface_ctx.last_socket_id);
4228 	if (!sock) {
4229 		LOG_ERR("Sock (%d) not found", iface_ctx.last_socket_id);
4230 		goto done;
4231 	}
4232 
4233 	if (sock->state == SOCK_RX) {
4234 		remove_data_from_buffer = false;
4235 		sock_read(buf);
4236 	} else {
4237 		k_sem_give(&sock->sock_send_sem);
4238 	}
4239 
4240 done:
4241 	return remove_data_from_buffer;
4242 }
4243 
start_socket_rx(struct hl7800_socket * sock,uint16_t rx_size)4244 static int start_socket_rx(struct hl7800_socket *sock, uint16_t rx_size)
4245 {
4246 	char sendbuf[sizeof("AT+KTCPRCV=+#########,#####")];
4247 
4248 	if ((sock->socket_id <= 0) || (sock->rx_size <= 0)) {
4249 		LOG_WRN("Cannot start socket RX, ID: %d rx size: %d",
4250 			sock->socket_id, sock->rx_size);
4251 		return -1;
4252 	}
4253 
4254 	LOG_DBG("Start socket RX ID:%d size:%d", sock->socket_id, rx_size);
4255 	sock->state = SOCK_RX;
4256 	if (sock->type == SOCK_DGRAM) {
4257 #if defined(CONFIG_NET_IPV4)
4258 		if (rx_size > (net_if_get_mtu(iface_ctx.iface) - NET_IPV4UDPH_LEN)) {
4259 			sock->rx_size =
4260 				net_if_get_mtu(iface_ctx.iface) - NET_IPV4UDPH_LEN;
4261 		}
4262 #endif
4263 #if defined(CONFIG_NET_IPV6)
4264 		if (rx_size > (net_if_get_mtu(iface_ctx.iface) - NET_IPV6UDPH_LEN)) {
4265 			sock->rx_size =
4266 				net_if_get_mtu(iface_ctx.iface) - NET_IPV6UDPH_LEN;
4267 		}
4268 #endif
4269 		snprintk(sendbuf, sizeof(sendbuf), "AT+KUDPRCV=%d,%u",
4270 			 sock->socket_id, rx_size);
4271 	} else {
4272 #if defined(CONFIG_NET_IPV4)
4273 		if (rx_size > (net_if_get_mtu(iface_ctx.iface) - NET_IPV4TCPH_LEN)) {
4274 			sock->rx_size =
4275 				net_if_get_mtu(iface_ctx.iface) - NET_IPV4TCPH_LEN;
4276 		}
4277 #endif
4278 #if defined(CONFIG_NET_IPV6)
4279 		if (rx_size > (net_if_get_mtu(iface_ctx.iface) - NET_IPV6TCPH_LEN)) {
4280 			sock->rx_size =
4281 				net_if_get_mtu(iface_ctx.iface) - NET_IPV6TCPH_LEN;
4282 		}
4283 #endif
4284 		snprintk(sendbuf, sizeof(sendbuf), "AT+KTCPRCV=%d,%u",
4285 			 sock->socket_id, sock->rx_size);
4286 	}
4287 
4288 	/* Send AT+K**PRCV, The modem
4289 	 * will respond with "CONNECT" and the data requested
4290 	 * and then "OK" or "ERROR".
4291 	 * The rest of the data processing will be handled
4292 	 * once CONNECT is RXd.
4293 	 */
4294 	send_at_cmd(sock, sendbuf, K_NO_WAIT, 0, false);
4295 	return 0;
4296 }
4297 
sock_rx_data_cb_work(struct k_work * work)4298 static void sock_rx_data_cb_work(struct k_work *work)
4299 {
4300 	struct hl7800_socket *sock = NULL;
4301 	int rc;
4302 
4303 	sock = CONTAINER_OF(work, struct hl7800_socket, rx_data_work);
4304 
4305 	hl7800_lock();
4306 	wakeup_hl7800();
4307 
4308 	/* start RX */
4309 	rc = start_socket_rx(sock, sock->rx_size);
4310 
4311 	/* Only unlock the RX because we just locked it above.
4312 	 *  At the end of socket RX, the TX will be unlocked.
4313 	 */
4314 	hl7800_RX_unlock();
4315 	if (rc < 0) {
4316 		/* we didn't start socket RX so unlock TX now. */
4317 		hl7800_TX_unlock();
4318 	}
4319 }
4320 
4321 /* Handler: +KTCP_DATA/+KUDP_DATA: <socket_id>,<left_bytes> */
on_cmd_sockdataind(struct net_buf ** buf,uint16_t len)4322 static bool on_cmd_sockdataind(struct net_buf **buf, uint16_t len)
4323 {
4324 	int socket_id, left_bytes, rc;
4325 	size_t out_len;
4326 	char *delim;
4327 	char value[sizeof("##,####")];
4328 	struct hl7800_socket *sock = NULL;
4329 	bool unlock = false;
4330 	bool defer_rx = false;
4331 
4332 	if (!hl7800_TX_locked()) {
4333 		hl7800_TX_lock();
4334 		unlock = true;
4335 	} else {
4336 		defer_rx = true;
4337 	}
4338 
4339 	out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
4340 	value[out_len] = 0;
4341 
4342 	/* First comma separator marks the end of socket_id */
4343 	delim = strchr(value, ',');
4344 	if (!delim) {
4345 		LOG_ERR("Missing comma");
4346 		goto error;
4347 	}
4348 
4349 	/* replace comma with null */
4350 	*delim++ = '\0';
4351 	socket_id = strtol(value, NULL, 0);
4352 
4353 	/* second param is for left_bytes */
4354 	left_bytes = strtol(delim, NULL, 0);
4355 
4356 	sock = socket_from_id(socket_id);
4357 	if (!sock) {
4358 		LOG_ERR("Unable to find socket_id:%d", socket_id);
4359 		goto error;
4360 	}
4361 
4362 	sock->rx_size = left_bytes;
4363 	if (defer_rx) {
4364 		LOG_DBG("Defer socket RX -> ID: %d bytes: %u", socket_id,
4365 			left_bytes);
4366 		k_work_submit_to_queue(&hl7800_workq, &sock->rx_data_work);
4367 	} else {
4368 		if (left_bytes > 0) {
4369 			wakeup_hl7800();
4370 			rc = start_socket_rx(sock, left_bytes);
4371 			if (rc < 0) {
4372 				goto error;
4373 			}
4374 			goto done;
4375 		}
4376 	}
4377 error:
4378 	if (unlock) {
4379 		hl7800_TX_unlock();
4380 	}
4381 done:
4382 	return true;
4383 }
4384 
4385 /* Handler: +WDSI: ## */
on_cmd_device_service_ind(struct net_buf ** buf,uint16_t len)4386 static bool on_cmd_device_service_ind(struct net_buf **buf, uint16_t len)
4387 {
4388 	char value[MDM_MAX_RESP_SIZE];
4389 	size_t out_len;
4390 
4391 	memset(value, 0, sizeof(value));
4392 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
4393 	if (out_len > 0) {
4394 		iface_ctx.device_services_ind = strtol(value, NULL, 10);
4395 	}
4396 	LOG_INF("+WDSI: %d", iface_ctx.device_services_ind);
4397 
4398 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
4399 	if (iface_ctx.device_services_ind == WDSI_PKG_DOWNLOADED) {
4400 		k_work_submit_to_queue(&hl7800_workq,
4401 				       &iface_ctx.finish_fw_update_work);
4402 	}
4403 #endif
4404 
4405 	return true;
4406 }
4407 
read_rx_allocator(k_timeout_t timeout,void * user_data)4408 static inline struct net_buf *read_rx_allocator(k_timeout_t timeout,
4409 						void *user_data)
4410 {
4411 	return net_buf_alloc((struct net_buf_pool *)user_data, timeout);
4412 }
4413 
hl7800_read_rx(struct net_buf ** buf)4414 static size_t hl7800_read_rx(struct net_buf **buf)
4415 {
4416 	uint8_t uart_buffer[CONFIG_MODEM_HL7800_RECV_BUF_SIZE];
4417 	size_t bytes_read, total_read;
4418 	int ret;
4419 	uint16_t rx_len;
4420 
4421 	bytes_read = 0, total_read = 0;
4422 
4423 	/* read all of the data from mdm_receiver */
4424 	while (true) {
4425 		ret = mdm_receiver_recv(&iface_ctx.mdm_ctx, uart_buffer,
4426 					sizeof(uart_buffer), &bytes_read);
4427 		if (ret < 0 || bytes_read == 0) {
4428 			/* mdm_receiver buffer is empty */
4429 			break;
4430 		}
4431 
4432 		if (IS_ENABLED(HL7800_ENABLE_VERBOSE_MODEM_RECV_HEXDUMP)) {
4433 			LOG_HEXDUMP_DBG((const uint8_t *)&uart_buffer,
4434 					bytes_read, "HL7800 RX");
4435 		}
4436 		/* make sure we have storage */
4437 		if (!*buf) {
4438 			*buf = net_buf_alloc(&mdm_recv_pool, BUF_ALLOC_TIMEOUT);
4439 			if (!*buf) {
4440 				LOG_ERR("Can't allocate RX data! "
4441 					"Skipping data!");
4442 				break;
4443 			}
4444 		}
4445 
4446 		rx_len =
4447 			net_buf_append_bytes(*buf, bytes_read, uart_buffer,
4448 					     BUF_ALLOC_TIMEOUT,
4449 					     read_rx_allocator, &mdm_recv_pool);
4450 		if (rx_len < bytes_read) {
4451 			LOG_ERR("Data was lost! read %u of %zu!", rx_len,
4452 				bytes_read);
4453 		}
4454 		total_read += bytes_read;
4455 	}
4456 
4457 	return total_read;
4458 }
4459 
4460 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
finish_fw_update_work_callback(struct k_work * item)4461 static void finish_fw_update_work_callback(struct k_work *item)
4462 {
4463 	ARG_UNUSED(item);
4464 
4465 	send_at_cmd(NULL, "AT+WDSR=4", MDM_CMD_SEND_TIMEOUT, 0, false);
4466 	iface_ctx.fw_updated = true;
4467 	set_fota_state(HL7800_FOTA_INSTALL);
4468 	hl7800_unlock();
4469 }
4470 
calc_fw_update_crc(uint8_t * ptr,int count)4471 static uint8_t calc_fw_update_crc(uint8_t *ptr, int count)
4472 {
4473 	uint8_t crc = 0;
4474 	unsigned char l;
4475 	uint16_t i = 0;
4476 
4477 	while (i < count) {
4478 		l = *ptr;
4479 		crc += l;
4480 		++ptr;
4481 		++i;
4482 	}
4483 
4484 	return crc;
4485 }
4486 
send_fw_update_packet(struct xmodem_packet * pkt)4487 static int send_fw_update_packet(struct xmodem_packet *pkt)
4488 {
4489 	generate_fota_count_event();
4490 	LOG_DBG("Send FW update packet %d,%d", pkt->id, iface_ctx.fw_packet_count);
4491 	return mdm_receiver_send(&iface_ctx.mdm_ctx, (const uint8_t *)pkt,
4492 				 XMODEM_PACKET_SIZE);
4493 }
4494 
prepare_and_send_fw_packet(void)4495 static int prepare_and_send_fw_packet(void)
4496 {
4497 	int ret = 0;
4498 	int read_res;
4499 
4500 	iface_ctx.fw_packet.id_complement = 0xFF - iface_ctx.fw_packet.id;
4501 
4502 	ret = fs_seek(&iface_ctx.fw_update_file, iface_ctx.file_pos, FS_SEEK_SET);
4503 	if (ret < 0) {
4504 		set_fota_state(HL7800_FOTA_FILE_ERROR);
4505 		LOG_ERR("Could not seek to offset %d of file", iface_ctx.file_pos);
4506 		return ret;
4507 	}
4508 
4509 	read_res = fs_read(&iface_ctx.fw_update_file, iface_ctx.fw_packet.data,
4510 			   XMODEM_DATA_SIZE);
4511 	if (read_res < 0) {
4512 		set_fota_state(HL7800_FOTA_FILE_ERROR);
4513 		LOG_ERR("Failed to read fw update file [%d]", read_res);
4514 		return ret;
4515 	} else if (read_res < XMODEM_DATA_SIZE) {
4516 		set_fota_state(HL7800_FOTA_PAD);
4517 		fs_close(&iface_ctx.fw_update_file);
4518 		/* pad rest of data */
4519 		for (int i = read_res; i < XMODEM_DATA_SIZE; i++) {
4520 			iface_ctx.fw_packet.data[i] = XMODEM_PAD_VALUE;
4521 		}
4522 	}
4523 
4524 	iface_ctx.fw_packet.crc =
4525 		calc_fw_update_crc(iface_ctx.fw_packet.data, XMODEM_DATA_SIZE);
4526 
4527 	send_fw_update_packet(&iface_ctx.fw_packet);
4528 
4529 	iface_ctx.file_pos += read_res;
4530 	iface_ctx.fw_packet_count++;
4531 	iface_ctx.fw_packet.id++;
4532 
4533 	return ret;
4534 }
4535 
process_fw_update_rx(struct net_buf ** rx_buf)4536 static void process_fw_update_rx(struct net_buf **rx_buf)
4537 {
4538 	static uint8_t xm_msg;
4539 	uint8_t eot = XM_EOT;
4540 
4541 	xm_msg = net_buf_get_u8(rx_buf);
4542 
4543 	if (xm_msg == XM_NACK) {
4544 		if (iface_ctx.fw_update_state == HL7800_FOTA_START) {
4545 			/* send first FW update packet */
4546 			set_fota_state(HL7800_FOTA_WIP);
4547 			iface_ctx.file_pos = 0;
4548 			iface_ctx.fw_packet_count = 1;
4549 			iface_ctx.fw_packet.id = 1;
4550 			iface_ctx.fw_packet.preamble = XM_SOH_1K;
4551 
4552 			prepare_and_send_fw_packet();
4553 		} else if (iface_ctx.fw_update_state == HL7800_FOTA_WIP) {
4554 			LOG_DBG("RX FW update NACK");
4555 			/* resend last packet */
4556 			send_fw_update_packet(&iface_ctx.fw_packet);
4557 		}
4558 	} else if (xm_msg == XM_ACK) {
4559 		LOG_DBG("RX FW update ACK");
4560 		if (iface_ctx.fw_update_state == HL7800_FOTA_WIP) {
4561 			/* send next FW update packet */
4562 			prepare_and_send_fw_packet();
4563 		} else if (iface_ctx.fw_update_state == HL7800_FOTA_PAD) {
4564 			set_fota_state(HL7800_FOTA_SEND_EOT);
4565 			mdm_receiver_send(&iface_ctx.mdm_ctx, &eot, sizeof(eot));
4566 		}
4567 	} else {
4568 		LOG_WRN("RX unhandled FW update value: %02x", xm_msg);
4569 	}
4570 }
4571 
4572 #endif /* CONFIG_MODEM_HL7800_FW_UPDATE */
4573 
4574 /* RX thread */
hl7800_rx(void * p1,void * p2,void * p3)4575 static void hl7800_rx(void *p1, void *p2, void *p3)
4576 {
4577 	ARG_UNUSED(p1);
4578 	ARG_UNUSED(p2);
4579 	ARG_UNUSED(p3);
4580 
4581 	struct net_buf *rx_buf = NULL;
4582 	struct net_buf *frag = NULL;
4583 	int i, cmp_res;
4584 	uint16_t len;
4585 	size_t out_len;
4586 	bool cmd_handled = false;
4587 	static char rx_msg[MDM_HANDLER_MATCH_MAX_LEN];
4588 	bool unlock = false;
4589 	bool remove_line_from_buf = true;
4590 #ifdef HL7800_LOG_UNHANDLED_RX_MSGS
4591 	char msg[MDM_MAX_RESP_SIZE];
4592 #endif
4593 
4594 	static const struct cmd_handler handlers[] = {
4595 		/* MODEM Information */
4596 		CMD_HANDLER("AT+CGMI", atcmdinfo_manufacturer),
4597 		CMD_HANDLER("AT+CGMM", atcmdinfo_model),
4598 		CMD_HANDLER("AT+CGMR", atcmdinfo_revision),
4599 		CMD_HANDLER("AT+CGSN", atcmdinfo_imei),
4600 		CMD_HANDLER("AT+KGSN=3", atcmdinfo_serial_number),
4601 		CMD_HANDLER("+KCELLMEAS: ", atcmdinfo_rssi),
4602 		CMD_HANDLER("+CGCONTRDP: ", atcmdinfo_ipaddr),
4603 		CMD_HANDLER("+COPS: ", atcmdinfo_operator_status),
4604 		CMD_HANDLER("+KSRAT: ", radio_tech_status),
4605 		CMD_HANDLER("+KBNDCFG: ", radio_band_configuration),
4606 		CMD_HANDLER("+KBND: ", radio_active_bands),
4607 		CMD_HANDLER("+CCID: ", atcmdinfo_iccid),
4608 		CMD_HANDLER("ACTIVE PROFILE:", atcmdinfo_active_profile),
4609 		CMD_HANDLER("STORED PROFILE 0:", atcmdinfo_stored_profile0),
4610 		CMD_HANDLER("STORED PROFILE 1:", atcmdinfo_stored_profile1),
4611 		CMD_HANDLER("+WPPP: 1,1,", atcmdinfo_pdp_authentication_cfg),
4612 		CMD_HANDLER("+CGDCONT: 1", atcmdinfo_pdp_context),
4613 		CMD_HANDLER("AT+CEREG?", network_report_query),
4614 		CMD_HANDLER("+KCARRIERCFG: ", operator_index_query),
4615 		CMD_HANDLER("AT+CIMI", atcmdinfo_imsi),
4616 		CMD_HANDLER("+CFUN: ", modem_functionality),
4617 		CMD_HANDLER("%MEAS: ", survey_status),
4618 		CMD_HANDLER("+CCLK: ", rtc_query),
4619 
4620 		/* UNSOLICITED modem information */
4621 		/* mobile startup report */
4622 		CMD_HANDLER("+KSUP: ", startup_report),
4623 		/* network status */
4624 		CMD_HANDLER("+CEREG: ", network_report),
4625 
4626 		/* SOLICITED CMD AND SOCKET RESPONSES */
4627 		CMD_HANDLER("OK", sockok),
4628 		CMD_HANDLER("ERROR", sockerror),
4629 
4630 		/* SOLICITED SOCKET RESPONSES */
4631 		CMD_HANDLER("+CME ERROR: ", sock_error_code),
4632 		CMD_HANDLER("+CMS ERROR: ", sock_error_code),
4633 		CMD_HANDLER("+CEER: ", sockerror),
4634 		CMD_HANDLER("+KTCPCFG: ", sock_tcp_create),
4635 		CMD_HANDLER("+KUDPCFG: ", sock_udp_create),
4636 		CMD_HANDLER(CONNECT_STRING, connect),
4637 		CMD_HANDLER("NO CARRIER", sockerror),
4638 
4639 		/* UNSOLICITED SOCKET RESPONSES */
4640 		CMD_HANDLER("+KTCP_IND: ", ktcp_ind),
4641 		CMD_HANDLER("+KUDP_IND: ", kudp_ind),
4642 		CMD_HANDLER("+KTCP_NOTIF: ", sock_notif),
4643 		CMD_HANDLER("+KUDP_NOTIF: ", sock_notif),
4644 		CMD_HANDLER("+KTCP_DATA: ", sockdataind),
4645 		CMD_HANDLER("+KUDP_DATA: ", sockdataind),
4646 
4647 		/* FIRMWARE UPDATE RESPONSES */
4648 		CMD_HANDLER("+WDSI: ", device_service_ind),
4649 
4650 #ifdef CONFIG_MODEM_HL7800_GPS
4651 		CMD_HANDLER("+GNSSEV: ", gps_event),
4652 		CMD_HANDLER("Latitude: ", latitude),
4653 		CMD_HANDLER("Longitude: ", longitude),
4654 		CMD_HANDLER("GpsTime: ", gps_time),
4655 		CMD_HANDLER("FixType: ", fix_type),
4656 		CMD_HANDLER("HEPE: ", hepe),
4657 		CMD_HANDLER("Altitude: ", altitude),
4658 		CMD_HANDLER("AltUnc: ", alt_unc),
4659 		CMD_HANDLER("Direction: ", direction),
4660 		CMD_HANDLER("HorSpeed: ", hor_speed),
4661 		CMD_HANDLER("VerSpeed: ", ver_speed),
4662 #endif
4663 
4664 #ifdef CONFIG_MODEM_HL7800_POLTE
4665 		CMD_HANDLER("%POLTEEVU: \"REGISTER\",0,", polte_registration),
4666 		CMD_HANDLER("%POLTECMD: \"LOCATE\",", polte_locate_cmd_rsp),
4667 		CMD_HANDLER("%POLTEEVU: \"LOCATION\",", polte_location),
4668 #endif
4669 	};
4670 
4671 	while (true) {
4672 		/* wait for incoming data */
4673 		(void)k_sem_take(&iface_ctx.mdm_ctx.rx_sem, K_FOREVER);
4674 
4675 		hl7800_read_rx(&rx_buf);
4676 		/* If an external module hasn't locked the command processor,
4677 		 * then do so now.
4678 		 */
4679 		if (!hl7800_RX_locked()) {
4680 			hl7800_RX_lock();
4681 			unlock = true;
4682 		} else {
4683 			unlock = false;
4684 		}
4685 
4686 		while (rx_buf) {
4687 			remove_line_from_buf = true;
4688 			cmd_handled = false;
4689 
4690 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
4691 			if ((iface_ctx.fw_update_state == HL7800_FOTA_START) ||
4692 			    (iface_ctx.fw_update_state == HL7800_FOTA_WIP) ||
4693 			    (iface_ctx.fw_update_state == HL7800_FOTA_PAD)) {
4694 				process_fw_update_rx(&rx_buf);
4695 				if (!rx_buf) {
4696 					break;
4697 				}
4698 			}
4699 #endif
4700 
4701 			net_buf_skipcrlf(&rx_buf);
4702 			if (!rx_buf) {
4703 				break;
4704 			}
4705 
4706 			frag = NULL;
4707 			len = net_buf_findcrlf(rx_buf, &frag);
4708 			if (!frag) {
4709 				break;
4710 			}
4711 
4712 			out_len = net_buf_linearize(rx_msg, sizeof(rx_msg),
4713 						    rx_buf, 0, len);
4714 
4715 			/* look for matching data handlers */
4716 			i = -1;
4717 			for (i = 0; i < ARRAY_SIZE(handlers); i++) {
4718 				if (iface_ctx.search_no_id_resp) {
4719 					cmp_res = strncmp(iface_ctx.no_id_resp_cmd,
4720 							  handlers[i].cmd,
4721 							  handlers[i].cmd_len);
4722 				} else {
4723 					cmp_res =
4724 						strncmp(rx_msg, handlers[i].cmd,
4725 							handlers[i].cmd_len);
4726 				}
4727 
4728 				if (cmp_res == 0) {
4729 					/* found a matching handler */
4730 
4731 					/* skip cmd_len */
4732 					if (!iface_ctx.search_no_id_resp) {
4733 						rx_buf = net_buf_skip(
4734 							rx_buf,
4735 							handlers[i].cmd_len);
4736 					}
4737 
4738 					/* locate next cr/lf */
4739 					frag = NULL;
4740 					len = net_buf_findcrlf(rx_buf, &frag);
4741 					if (!frag) {
4742 						break;
4743 					}
4744 
4745 					LOG_DBG("HANDLE %s (len:%u)",
4746 						handlers[i].cmd, len);
4747 					/* call handler */
4748 					if (handlers[i].func) {
4749 						remove_line_from_buf =
4750 							handlers[i].func(
4751 								&rx_buf, len);
4752 					}
4753 					cmd_handled = true;
4754 					iface_ctx.search_no_id_resp = false;
4755 					frag = NULL;
4756 					/* make sure buf still has data */
4757 					if (!rx_buf) {
4758 						break;
4759 					}
4760 
4761 					/* We've handled the current line
4762 					 * and need to exit the "search for
4763 					 * handler loop".  Let's skip any
4764 					 * "extra" data and look for the next
4765 					 * CR/LF, leaving us ready for the
4766 					 * next handler search.
4767 					 */
4768 					len = net_buf_findcrlf(rx_buf, &frag);
4769 					break;
4770 				}
4771 			}
4772 
4773 			/* Handle unhandled commands */
4774 			if (IS_ENABLED(HL7800_LOG_UNHANDLED_RX_MSGS) &&
4775 			    !cmd_handled && frag && len > 1) {
4776 				out_len = net_buf_linearize(msg, sizeof(msg),
4777 							    rx_buf, 0, len);
4778 				msg[out_len] = 0;
4779 				LOG_HEXDUMP_DBG((const uint8_t *)&msg, len,
4780 						"UNHANDLED RX");
4781 			}
4782 			if (remove_line_from_buf && frag && rx_buf) {
4783 				/* clear out processed line (buffers) */
4784 				net_buf_remove(&rx_buf, len);
4785 			}
4786 		}
4787 
4788 		if (unlock) {
4789 			hl7800_RX_unlock();
4790 		}
4791 
4792 		/* give up time if we have a solid stream of data */
4793 		k_yield();
4794 	}
4795 }
4796 
shutdown_uart(void)4797 static void shutdown_uart(void)
4798 {
4799 #ifdef CONFIG_PM_DEVICE
4800 	int rc;
4801 	enum pm_device_state state;
4802 
4803 	rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state);
4804 	if (rc) {
4805 		LOG_ERR("Error getting UART power state (%d)", rc);
4806 	}
4807 	if (state != PM_DEVICE_STATE_SUSPENDED) {
4808 		HL7800_IO_DBG_LOG("Power OFF the UART");
4809 		uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev);
4810 		rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_SUSPEND);
4811 		if (rc) {
4812 			LOG_ERR("Error disabling UART peripheral (%d)", rc);
4813 			uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev);
4814 		}
4815 	}
4816 #endif
4817 }
4818 
power_on_uart(void)4819 static void power_on_uart(void)
4820 {
4821 #ifdef CONFIG_PM_DEVICE
4822 	int rc;
4823 	enum pm_device_state state;
4824 
4825 	rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state);
4826 	if (rc) {
4827 		LOG_ERR("Error getting UART power state (%d)", rc);
4828 	}
4829 	if (state != PM_DEVICE_STATE_ACTIVE) {
4830 		HL7800_IO_DBG_LOG("Power ON the UART");
4831 		rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_RESUME);
4832 		if (rc) {
4833 			LOG_ERR("Error enabling UART peripheral (%d)", rc);
4834 			uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev);
4835 		} else {
4836 			uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev);
4837 		}
4838 	}
4839 #endif
4840 }
4841 
4842 /* Make sure all IO voltages are removed for proper reset. */
prepare_io_for_reset(void)4843 static void prepare_io_for_reset(void)
4844 {
4845 	HL7800_IO_DBG_LOG("Preparing IO for reset/sleep");
4846 	shutdown_uart();
4847 	modem_assert_wake(false);
4848 	modem_assert_pwr_on(false);
4849 	modem_assert_fast_shutd(false);
4850 	iface_ctx.wait_for_KSUP = true;
4851 	iface_ctx.wait_for_KSUP_tries = 0;
4852 }
4853 
mdm_vgpio_work_cb(struct k_work * item)4854 static void mdm_vgpio_work_cb(struct k_work *item)
4855 {
4856 	ARG_UNUSED(item);
4857 
4858 	hl7800_lock();
4859 	if (!iface_ctx.vgpio_state) {
4860 		if (iface_ctx.desired_sleep_level == HL7800_SLEEP_HIBERNATE ||
4861 		    iface_ctx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE) {
4862 			if (iface_ctx.sleep_state != iface_ctx.desired_sleep_level) {
4863 				set_sleep_state(iface_ctx.desired_sleep_level);
4864 			}
4865 		}
4866 		if (iface_ctx.iface && iface_ctx.initialized &&
4867 		    iface_ctx.low_power_mode != HL7800_LPM_PSM) {
4868 			net_if_carrier_off(iface_ctx.iface);
4869 		}
4870 	}
4871 	hl7800_unlock();
4872 }
4873 
mdm_vgpio_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4874 void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins)
4875 {
4876 	ARG_UNUSED(port);
4877 	ARG_UNUSED(cb);
4878 	ARG_UNUSED(pins);
4879 
4880 	iface_ctx.vgpio_state = read_pin(1, &hl7800_cfg.gpio[MDM_VGPIO]);
4881 	HL7800_IO_DBG_LOG("VGPIO:%d", iface_ctx.vgpio_state);
4882 	if (!iface_ctx.vgpio_state) {
4883 		prepare_io_for_reset();
4884 		if (!iface_ctx.restarting && iface_ctx.initialized) {
4885 			iface_ctx.reconfig_IP_connection = true;
4886 		}
4887 	} else {
4888 		if (iface_ctx.off) {
4889 			return;
4890 		}
4891 		/* The peripheral must be enabled in ISR context
4892 		 * because the driver may be
4893 		 * waiting for +KSUP or waiting to send commands.
4894 		 * This can occur, for example, during a modem reset.
4895 		 */
4896 		power_on_uart();
4897 		/* Keep the modem awake to see if it has anything to send to us. */
4898 		allow_sleep(false);
4899 		/* Allow the modem to go back to sleep if it was the one who
4900 		 * sourced the transition.
4901 		 */
4902 		allow_sleep(true);
4903 	}
4904 	check_hl7800_awake();
4905 
4906 	/* When the network state changes a semaphore must be taken.
4907 	 * This can't be done in interrupt context because the wait time != 0.
4908 	 */
4909 	k_work_submit_to_queue(&hl7800_workq, &iface_ctx.mdm_vgpio_work);
4910 }
4911 
mdm_uart_dsr_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4912 void mdm_uart_dsr_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins)
4913 {
4914 	ARG_UNUSED(port);
4915 	ARG_UNUSED(cb);
4916 	ARG_UNUSED(pins);
4917 
4918 	iface_ctx.dsr_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_DSR]);
4919 	HL7800_IO_DBG_LOG("MDM_UART_DSR:%d", iface_ctx.dsr_state);
4920 }
4921 
4922 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
mark_sockets_for_reconfig(void)4923 static void mark_sockets_for_reconfig(void)
4924 {
4925 	int i;
4926 	struct hl7800_socket *sock = NULL;
4927 
4928 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
4929 		sock = &iface_ctx.sockets[i];
4930 		if ((sock->context != NULL) && (sock->created)) {
4931 			/* mark socket as possibly needing re-configuration */
4932 			sock->reconfig = true;
4933 		}
4934 	}
4935 }
4936 #endif
4937 
mdm_gpio6_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4938 void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins)
4939 {
4940 	ARG_UNUSED(port);
4941 	ARG_UNUSED(cb);
4942 	ARG_UNUSED(pins);
4943 
4944 	iface_ctx.gpio6_state = read_pin(1, &hl7800_cfg.gpio[MDM_GPIO6]);
4945 	HL7800_IO_DBG_LOG("MDM_GPIO6:%d", iface_ctx.gpio6_state);
4946 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
4947 	if (!iface_ctx.gpio6_state) {
4948 		/* HL7800 is not awake, shut down UART to save power */
4949 		shutdown_uart();
4950 		iface_ctx.wait_for_KSUP = true;
4951 		iface_ctx.wait_for_KSUP_tries = 0;
4952 		iface_ctx.reconfig_IP_connection = true;
4953 		mark_sockets_for_reconfig();
4954 	} else {
4955 		if (iface_ctx.off) {
4956 			return;
4957 		} else if (iface_ctx.vgpio_state) {
4958 			power_on_uart();
4959 			/* Keep the modem awake to see if it has anything to send to us. */
4960 			allow_sleep(false);
4961 			/* Allow the modem to go back to sleep if it was the one who
4962 			 * sourced the transition.
4963 			 */
4964 			allow_sleep(true);
4965 		}
4966 	}
4967 	check_hl7800_awake();
4968 
4969 	if ((iface_ctx.gpio6_callback != NULL) &&
4970 	    ((iface_ctx.desired_sleep_level == HL7800_SLEEP_HIBERNATE) ||
4971 	     (iface_ctx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE))) {
4972 		iface_ctx.gpio6_callback(iface_ctx.gpio6_state);
4973 	}
4974 #endif
4975 }
4976 
mdm_uart_cts_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4977 void mdm_uart_cts_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins)
4978 {
4979 	ARG_UNUSED(port);
4980 	ARG_UNUSED(cb);
4981 	ARG_UNUSED(pins);
4982 	uint64_t now;
4983 	uint64_t elapsed;
4984 	int resample_state;
4985 
4986 	iface_ctx.cts_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]);
4987 
4988 	/* Debounce the CTS signal */
4989 	now = k_ticks_to_us_floor64(k_uptime_ticks());
4990 	elapsed = now - iface_ctx.last_cts_time;
4991 	if (iface_ctx.last_cts_time <= 0) {
4992 		/* This is the first transition we have seen, continue */
4993 	} else if (elapsed <= CONFIG_MODEM_HL7800_CTS_FILTER_US) {
4994 		/* CTS changed too quickly, ignore this transition */
4995 		iface_ctx.last_cts_time = now;
4996 		return;
4997 	}
4998 	iface_ctx.last_cts_time = now;
4999 	k_busy_wait(CONFIG_MODEM_HL7800_CTS_FILTER_US);
5000 	resample_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]);
5001 	if (iface_ctx.cts_state != resample_state) {
5002 		/* CTS changed while we were debouncing, ignore it */
5003 		iface_ctx.cts_state = resample_state;
5004 		return;
5005 	}
5006 	iface_ctx.cts_state = resample_state;
5007 	if (iface_ctx.cts_state != iface_ctx.last_cts_state) {
5008 		iface_ctx.last_cts_state = iface_ctx.cts_state;
5009 	} else {
5010 		return;
5011 	}
5012 
5013 	HL7800_IO_DBG_LOG("MDM_UART_CTS:%d(%llu)", iface_ctx.cts_state, elapsed);
5014 
5015 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5016 	if (iface_ctx.cts_state && iface_ctx.allow_sleep) {
5017 		/* HL7800 cannot receive UART data, shut down UART to save power.
5018 		 * This is critical for proper low power operation. If the UART is disabled
5019 		 * after VGPIO is low, the UART will not suspend properly.
5020 		 */
5021 		shutdown_uart();
5022 	} else {
5023 		if (iface_ctx.off) {
5024 			return;
5025 		}
5026 		if (iface_ctx.vgpio_state && iface_ctx.gpio6_state) {
5027 			power_on_uart();
5028 			/* Wake up the modem to see if it has anything to send to us. */
5029 			allow_sleep(false);
5030 			/* Allow the modem to go back to sleep if it was the one who
5031 			 * sourced the CTS transition.
5032 			 */
5033 			allow_sleep(true);
5034 		}
5035 	}
5036 #endif
5037 
5038 	if ((iface_ctx.cts_callback != NULL) &&
5039 	    (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP)) {
5040 		iface_ctx.cts_callback(iface_ctx.cts_state);
5041 	}
5042 
5043 	check_hl7800_awake();
5044 }
5045 
modem_reset(void)5046 static void modem_reset(void)
5047 {
5048 	prepare_io_for_reset();
5049 
5050 	LOG_INF("Modem Reset");
5051 	/* Hard reset the modem */
5052 	modem_assert_reset(true);
5053 	/* >20 milliseconds required for reset low */
5054 	k_sleep(MDM_RESET_LOW_TIME);
5055 
5056 	iface_ctx.mdm_startup_reporting_on = false;
5057 	set_sleep_state(HL7800_SLEEP_UNINITIALIZED);
5058 	check_hl7800_awake();
5059 	set_network_state(HL7800_NOT_REGISTERED);
5060 	set_startup_state(HL7800_STARTUP_STATE_UNKNOWN);
5061 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
5062 	if (iface_ctx.fw_update_state == HL7800_FOTA_REBOOT_AND_RECONFIGURE) {
5063 		set_fota_state(HL7800_FOTA_COMPLETE);
5064 	} else {
5065 		set_fota_state(HL7800_FOTA_IDLE);
5066 	}
5067 #endif
5068 	k_sem_reset(&iface_ctx.mdm_awake);
5069 	iface_ctx.off = true;
5070 }
5071 
modem_run(void)5072 static void modem_run(void)
5073 {
5074 	LOG_INF("Modem Run");
5075 	iface_ctx.off = false;
5076 	modem_assert_reset(false);
5077 	allow_sleep(false);
5078 	k_sleep(MDM_RESET_HIGH_TIME);
5079 }
5080 
modem_boot_handler(char * reason)5081 static int modem_boot_handler(char *reason)
5082 {
5083 	int ret;
5084 
5085 	LOG_DBG("%s", reason);
5086 	ret = k_sem_take(&iface_ctx.mdm_awake, MDM_BOOT_TIME);
5087 	if (ret) {
5088 		LOG_WRN("Err waiting for boot: %d, DSR: %u", ret, iface_ctx.dsr_state);
5089 	} else {
5090 		LOG_INF("Modem booted!");
5091 	}
5092 
5093 	/* Turn OFF EPS network registration status reporting because
5094 	 * it isn't needed until after initialization is complete.
5095 	 */
5096 	SEND_AT_CMD_EXPECT_OK("AT+CEREG=0");
5097 
5098 	/* Determine if echo is on/off by reading the profile
5099 	 * note: It wasn't clear how to read the
5100 	 * active profile so all 3 are read.
5101 	 */
5102 	iface_ctx.mdm_echo_is_on = true;
5103 	SEND_AT_CMD_EXPECT_OK("AT&V");
5104 
5105 	if (iface_ctx.mdm_echo_is_on) {
5106 		/* Turn OFF echo (after boot/reset) because a profile
5107 		 * hasn't been saved yet
5108 		 */
5109 		SEND_AT_CMD_EXPECT_OK("ATE0");
5110 
5111 		/* Save profile 0 */
5112 		SEND_AT_CMD_EXPECT_OK("AT&W");
5113 
5114 		/* Reread profiles so echo state can be checked again. */
5115 		SEND_AT_CMD_EXPECT_OK("AT&V");
5116 	}
5117 
5118 	__ASSERT(!iface_ctx.mdm_echo_is_on, "Echo should be off");
5119 
5120 	return 0;
5121 
5122 error:
5123 	return ret;
5124 }
5125 
5126 /**
5127  * @brief  compares two version strings with any delimiter
5128  *
5129  * @param  v1: version string 1
5130  * @param  v2: version string 2
5131  *
5132  * @retval 0 if equal, < 0 if v1 < v2, > 0 if v1 > v2.
5133  */
compare_versions(char * v1,const char * v2)5134 static int compare_versions(char *v1, const char *v2)
5135 {
5136 	int result = 0;
5137 	char *tail1;
5138 	char *tail2;
5139 	unsigned long ver1, ver2;
5140 
5141 	/* loop through each level of the version string */
5142 	while (result == 0) {
5143 		/* extract leading version numbers */
5144 		ver1 = strtoul(v1, &tail1, 10);
5145 		ver2 = strtoul(v2, &tail2, 10);
5146 
5147 		/* if numbers differ, then set the result */
5148 		if (ver1 < ver2) {
5149 			result = -1;
5150 		} else if (ver1 > ver2) {
5151 			result = 1;
5152 		} else {
5153 			/* if numbers are the same, go to next level */
5154 			v1 = tail1;
5155 			v2 = tail2;
5156 			/* if we reach the end of both, then they are identical */
5157 			if (*v1 == '\0' && *v2 == '\0') {
5158 				break;
5159 			/* if we reach the end of one only, it is the smaller */
5160 			} else if (*v1 == '\0') {
5161 				result = -1;
5162 			} else if (*v2 == '\0') {
5163 				result = 1;
5164 			/*  not at end ... so far they match so keep going */
5165 			} else {
5166 				v1++;
5167 				v2++;
5168 			}
5169 		}
5170 	}
5171 	return result;
5172 }
5173 
setup_gprs_connection(char * access_point_name)5174 static int setup_gprs_connection(char *access_point_name)
5175 {
5176 	char cmd_string[sizeof("AT+KCNXCFG=1,\"GPRS\",\"\",,,"
5177 			       "\"IPV4V6\"") +
5178 			MDM_HL7800_APN_MAX_SIZE];
5179 	int cmd_max_len = sizeof(cmd_string) - 1;
5180 
5181 	memset(cmd_string, 0, cmd_max_len);
5182 	strncat(cmd_string, "AT+KCNXCFG=1,\"GPRS\",\"", cmd_max_len);
5183 	strncat(cmd_string, access_point_name, cmd_max_len);
5184 	strncat(cmd_string, "\",,,\"", cmd_max_len);
5185 	strncat(cmd_string, MODEM_HL7800_ADDRESS_FAMILY "\"", cmd_max_len);
5186 	return send_at_cmd(NULL, cmd_string, MDM_CMD_SEND_TIMEOUT, 0, false);
5187 }
5188 
set_bands(const char * bands,bool full_reboot)5189 static int set_bands(const char *bands, bool full_reboot)
5190 {
5191 	int ret;
5192 	char cmd[sizeof("AT+KBNDCFG=#,####################")];
5193 
5194 	snprintk(cmd, sizeof(cmd), "AT+KBNDCFG=%d,%s", iface_ctx.mdm_rat, bands);
5195 	ret = send_at_cmd(NULL, cmd, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false);
5196 	if (ret < 0) {
5197 		return ret;
5198 	}
5199 
5200 	if (!full_reboot) {
5201 		ret = send_at_cmd(NULL, "AT+CFUN=1,1", MDM_CMD_SEND_TIMEOUT,
5202 				  MDM_DEFAULT_AT_CMD_RETRIES, false);
5203 		if (ret < 0) {
5204 			return ret;
5205 		}
5206 
5207 		ret = modem_boot_handler("LTE bands were just set");
5208 	} else {
5209 		k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.mdm_reset_work, K_NO_WAIT);
5210 	}
5211 	return ret;
5212 }
5213 
mdm_hl7800_set_bands(const char * bands)5214 int32_t mdm_hl7800_set_bands(const char *bands)
5215 {
5216 	int ret, i;
5217 	char temp_bands[MDM_BAND_BITMAP_STR_LENGTH_MAX + 1];
5218 	int num_leading_zeros;
5219 
5220 	if ((bands == NULL) || (strlen(bands) > MDM_BAND_BITMAP_STR_LENGTH_MAX) ||
5221 	    (strlen(bands) < MDM_BAND_BITMAP_STR_LENGTH_MIN)) {
5222 		return -EINVAL;
5223 	}
5224 
5225 	if (strlen(bands) < MDM_BAND_BITMAP_STR_LENGTH_MAX) {
5226 		num_leading_zeros = MDM_BAND_BITMAP_STR_LENGTH_MAX - strlen(bands);
5227 		for (i = 0; i < num_leading_zeros; i++) {
5228 			temp_bands[i] = '0';
5229 			if (i == (num_leading_zeros - 1)) {
5230 				strncpy(temp_bands + (i + 1), bands, sizeof(temp_bands) - (i + 1));
5231 			}
5232 		}
5233 	} else {
5234 		memcpy(temp_bands, bands, sizeof(temp_bands));
5235 	}
5236 
5237 	/* no need to set bands if settings match */
5238 	if (strncmp(temp_bands, iface_ctx.mdm_bands_string, sizeof(temp_bands)) == 0) {
5239 		return 0;
5240 	}
5241 
5242 	hl7800_lock();
5243 
5244 	ret = set_bands(temp_bands, true);
5245 
5246 	hl7800_unlock();
5247 
5248 	return ret;
5249 }
5250 
modem_reset_and_configure(void)5251 static int modem_reset_and_configure(void)
5252 {
5253 	int ret = 0;
5254 	bool sleep = false;
5255 	bool config_apn = false;
5256 	char *apn;
5257 #ifdef CONFIG_MODEM_HL7800_EDRX
5258 	int edrx_act_type;
5259 	char set_edrx_msg[sizeof("AT+CEDRXS=2,4,\"0000\"")];
5260 #endif
5261 #if CONFIG_MODEM_HL7800_CONFIGURE_BANDS
5262 	uint16_t bands_top = 0;
5263 	uint32_t bands_middle = 0, bands_bottom = 0;
5264 	char new_bands[MDM_BAND_BITMAP_STR_LENGTH_MAX + 1];
5265 #endif
5266 #if CONFIG_MODEM_HL7800_PSM
5267 	const char TURN_ON_PSM[] =
5268 		"AT+CPSMS=1,,,\"" CONFIG_MODEM_HL7800_PSM_PERIODIC_TAU
5269 		"\",\"" CONFIG_MODEM_HL7800_PSM_ACTIVE_TIME "\"";
5270 #endif
5271 
5272 	set_busy(true);
5273 	iface_ctx.restarting = true;
5274 	iface_ctx.dns_ready = false;
5275 	if (iface_ctx.iface) {
5276 		net_if_carrier_off(iface_ctx.iface);
5277 	}
5278 
5279 	hl7800_stop_rssi_work();
5280 	initialize_sleep_level();
5281 
5282 reboot:
5283 	modem_reset();
5284 	modem_run();
5285 	ret = modem_boot_handler("Initialization");
5286 	if (!iface_ctx.mdm_startup_reporting_on) {
5287 		/* Turn on mobile start-up reporting for next reset.
5288 		 * It will indicate if SIM is present.
5289 		 * Its value is saved in non-volatile memory on the HL7800.
5290 		 */
5291 		SEND_AT_CMD_EXPECT_OK("AT+KSREP=1");
5292 		goto reboot;
5293 	} else if (ret < 0) {
5294 		goto error;
5295 	}
5296 
5297 	/* turn on numeric error codes */
5298 	SEND_AT_CMD_EXPECT_OK("AT+CMEE=1");
5299 
5300 	/* modem revision */
5301 	SEND_COMPLEX_AT_CMD("AT+CGMR");
5302 
5303 	/* determine RAT command support */
5304 	ret = compare_versions(iface_ctx.mdm_revision, NEW_RAT_CMD_MIN_VERSION);
5305 	if (ret < 0) {
5306 		iface_ctx.new_rat_cmd_support = false;
5307 	} else {
5308 		iface_ctx.new_rat_cmd_support = true;
5309 	}
5310 
5311 	/* Query current Radio Access Technology (RAT) */
5312 	SEND_AT_CMD_EXPECT_OK("AT+KSRAT?");
5313 
5314 	/* If CONFIG_MODEM_HL7800_RAT_M1 or CONFIG_MODEM_HL7800_RAT_NB1, then
5315 	 * set the radio mode. This is only done here if the driver has not been
5316 	 * initialized (!iface_ctx.configured) yet because the public API also
5317 	 * allows the RAT to be changed (and will reset the modem).
5318 	 */
5319 #ifndef CONFIG_MODEM_HL7800_RAT_NO_CHANGE
5320 	if (!iface_ctx.configured) {
5321 #if CONFIG_MODEM_HL7800_RAT_M1
5322 		if (iface_ctx.mdm_rat != MDM_RAT_CAT_M1) {
5323 			if (iface_ctx.new_rat_cmd_support) {
5324 				SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD);
5325 			} else {
5326 				SEND_AT_CMD_ONCE_EXPECT_OK(
5327 					SET_RAT_M1_CMD_LEGACY);
5328 			}
5329 			if (ret >= 0) {
5330 				goto reboot;
5331 			}
5332 		}
5333 #elif CONFIG_MODEM_HL7800_RAT_NB1
5334 		if (iface_ctx.mdm_rat != MDM_RAT_CAT_NB1) {
5335 			if (iface_ctx.new_rat_cmd_support) {
5336 				SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD);
5337 			} else {
5338 				SEND_AT_CMD_ONCE_EXPECT_OK(
5339 					SET_RAT_NB1_CMD_LEGACY);
5340 			}
5341 
5342 			if (ret >= 0) {
5343 				goto reboot;
5344 			}
5345 		}
5346 #endif
5347 	}
5348 #endif
5349 
5350 	SEND_AT_CMD_EXPECT_OK("AT+KBNDCFG?");
5351 	/* Configure LTE bands */
5352 #if CONFIG_MODEM_HL7800_CONFIGURE_BANDS
5353 #if CONFIG_MODEM_HL7800_BAND_1
5354 	bands_bottom |= 1 << 0;
5355 #endif
5356 #if CONFIG_MODEM_HL7800_BAND_2
5357 	bands_bottom |= 1 << 1;
5358 #endif
5359 #if CONFIG_MODEM_HL7800_BAND_3
5360 	bands_bottom |= 1 << 2;
5361 #endif
5362 #if CONFIG_MODEM_HL7800_BAND_4
5363 	bands_bottom |= 1 << 3;
5364 #endif
5365 #if CONFIG_MODEM_HL7800_BAND_5
5366 	bands_bottom |= 1 << 4;
5367 #endif
5368 #if CONFIG_MODEM_HL7800_BAND_8
5369 	bands_bottom |= 1 << 7;
5370 #endif
5371 #if CONFIG_MODEM_HL7800_BAND_9
5372 	bands_bottom |= 1 << 8;
5373 #endif
5374 #if CONFIG_MODEM_HL7800_BAND_10
5375 	bands_bottom |= 1 << 9;
5376 #endif
5377 #if CONFIG_MODEM_HL7800_BAND_12
5378 	bands_bottom |= 1 << 11;
5379 #endif
5380 #if CONFIG_MODEM_HL7800_BAND_13
5381 	bands_bottom |= 1 << 12;
5382 #endif
5383 #if CONFIG_MODEM_HL7800_BAND_14
5384 	bands_bottom |= 1 << 13;
5385 #endif
5386 #if CONFIG_MODEM_HL7800_BAND_17
5387 	bands_bottom |= 1 << 16;
5388 #endif
5389 #if CONFIG_MODEM_HL7800_BAND_18
5390 	bands_bottom |= 1 << 17;
5391 #endif
5392 #if CONFIG_MODEM_HL7800_BAND_19
5393 	bands_bottom |= 1 << 18;
5394 #endif
5395 #if CONFIG_MODEM_HL7800_BAND_20
5396 	bands_bottom |= 1 << 19;
5397 #endif
5398 #if CONFIG_MODEM_HL7800_BAND_25
5399 	bands_bottom |= 1 << 24;
5400 #endif
5401 #if CONFIG_MODEM_HL7800_BAND_26
5402 	bands_bottom |= 1 << 25;
5403 #endif
5404 #if CONFIG_MODEM_HL7800_BAND_27
5405 	bands_bottom |= 1 << 26;
5406 #endif
5407 #if CONFIG_MODEM_HL7800_BAND_28
5408 	bands_bottom |= 1 << 27;
5409 #endif
5410 #if CONFIG_MODEM_HL7800_BAND_66
5411 	bands_top |= 1 << 1;
5412 #endif
5413 
5414 	/* Check if bands are configured correctly */
5415 	if (iface_ctx.mdm_bands_top != bands_top ||
5416 	    iface_ctx.mdm_bands_middle != bands_middle ||
5417 	    iface_ctx.mdm_bands_bottom != bands_bottom) {
5418 		if (iface_ctx.mdm_bands_top != bands_top) {
5419 			LOG_INF("Top band mismatch, want %04x got %04x",
5420 				bands_top, iface_ctx.mdm_bands_top);
5421 		}
5422 		if (iface_ctx.mdm_bands_middle != bands_middle) {
5423 			LOG_INF("Middle band mismatch, want %08x got %08x",
5424 				bands_middle, iface_ctx.mdm_bands_middle);
5425 		}
5426 		if (iface_ctx.mdm_bands_bottom != bands_bottom) {
5427 			LOG_INF("Bottom band mismatch, want %08x got %08x",
5428 				bands_bottom, iface_ctx.mdm_bands_bottom);
5429 		}
5430 
5431 		snprintk(new_bands, sizeof(new_bands),
5432 			 "%0" STRINGIFY(MDM_TOP_BAND_SIZE) "x%0" STRINGIFY(
5433 				 MDM_MIDDLE_BAND_SIZE) "x%0" STRINGIFY(MDM_BOTTOM_BAND_SIZE) "x",
5434 			 bands_top, bands_middle, bands_bottom);
5435 
5436 		ret = set_bands(new_bands, false);
5437 		if (ret < 0) {
5438 			goto error;
5439 		}
5440 	}
5441 #endif
5442 
5443 	/**
5444 	 * Disable the radio until all config is done.
5445 	 * This ensures all settings are applied during this session instead of on the next reboot.
5446 	 */
5447 	SEND_AT_CMD_EXPECT_OK("AT+CFUN=4,0");
5448 
5449 	iface_ctx.low_power_mode = HL7800_LPM_NONE;
5450 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5451 	/* enable GPIO6 low power monitoring */
5452 	SEND_AT_CMD_EXPECT_OK("AT+KHWIOCFG=3,1,6");
5453 
5454 	ret = set_sleep_level();
5455 	if (ret < 0) {
5456 		goto error;
5457 	}
5458 
5459 #if CONFIG_MODEM_HL7800_PSM
5460 	iface_ctx.low_power_mode = HL7800_LPM_PSM;
5461 	/* Turn off eDRX */
5462 	SEND_AT_CMD_EXPECT_OK("AT+CEDRXS=0");
5463 
5464 	SEND_AT_CMD_EXPECT_OK(TURN_ON_PSM);
5465 #elif CONFIG_MODEM_HL7800_EDRX
5466 	iface_ctx.low_power_mode = HL7800_LPM_EDRX;
5467 	/* Turn off PSM */
5468 	SEND_AT_CMD_EXPECT_OK("AT+CPSMS=0");
5469 
5470 	/* turn on eDRX */
5471 	if (iface_ctx.mdm_rat == MDM_RAT_CAT_NB1) {
5472 		edrx_act_type = 5;
5473 	} else {
5474 		edrx_act_type = 4;
5475 	}
5476 	snprintk(set_edrx_msg, sizeof(set_edrx_msg), "AT+CEDRXS=1,%d,\"%s\"",
5477 		 edrx_act_type, CONFIG_MODEM_HL7800_EDRX_VALUE);
5478 	SEND_AT_CMD_EXPECT_OK(set_edrx_msg);
5479 #endif
5480 	sleep = true;
5481 #else
5482 	/* Turn off sleep mode */
5483 	SEND_AT_CMD_EXPECT_OK("AT+KSLEEP=2");
5484 
5485 	/* Turn off PSM */
5486 	SEND_AT_CMD_EXPECT_OK("AT+CPSMS=0");
5487 
5488 	/* Turn off eDRX */
5489 	SEND_AT_CMD_EXPECT_OK("AT+CEDRXS=0");
5490 #endif
5491 
5492 	/* modem manufacturer */
5493 	SEND_COMPLEX_AT_CMD("AT+CGMI");
5494 
5495 	/* modem model */
5496 	SEND_COMPLEX_AT_CMD("AT+CGMM");
5497 
5498 	/* query modem IMEI */
5499 	SEND_COMPLEX_AT_CMD("AT+CGSN");
5500 
5501 	/* query modem serial number */
5502 	SEND_COMPLEX_AT_CMD("AT+KGSN=3");
5503 
5504 	if (iface_ctx.mdm_startup_state != HL7800_STARTUP_STATE_SIM_NOT_PRESENT) {
5505 		/* query SIM ICCID */
5506 		SEND_AT_CMD_IGNORE_ERROR("AT+CCID?");
5507 
5508 		/* query SIM IMSI */
5509 		(void)send_at_cmd(NULL, "AT+CIMI", MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES,
5510 				  true);
5511 	}
5512 
5513 	/* Query PDP context to get APN */
5514 	SEND_AT_CMD_EXPECT_OK("AT+CGDCONT?");
5515 	apn = iface_ctx.mdm_apn.value;
5516 	if (strcmp(iface_ctx.mdm_pdp_addr_fam, MODEM_HL7800_ADDRESS_FAMILY)) {
5517 		config_apn = true;
5518 	}
5519 
5520 	/* Query PDP authentication context to get APN username/password.
5521 	 * Temporary Workaround - Ignore error
5522 	 * On some modules this is returning an error and the response data.
5523 	 */
5524 	SEND_AT_CMD_IGNORE_ERROR("AT+WPPP?");
5525 
5526 #if CONFIG_MODEM_HL7800_SET_APN_NAME_ON_STARTUP
5527 	if (!iface_ctx.configured) {
5528 		if (strncmp(iface_ctx.mdm_apn.value, CONFIG_MODEM_HL7800_APN_NAME,
5529 			    MDM_HL7800_APN_MAX_STRLEN) != 0) {
5530 			apn = CONFIG_MODEM_HL7800_APN_NAME;
5531 			config_apn = true;
5532 		}
5533 	}
5534 #endif
5535 
5536 	if (config_apn) {
5537 		/* set PDP context address family along with current APN */
5538 		ret = write_apn(apn);
5539 		if (ret < 0) {
5540 			goto error;
5541 		}
5542 		SEND_AT_CMD_EXPECT_OK("AT+CGDCONT?");
5543 	}
5544 
5545 	ret = setup_gprs_connection(iface_ctx.mdm_apn.value);
5546 	if (ret < 0) {
5547 		goto error;
5548 	}
5549 
5550 	/* query the network status in case we already registered */
5551 	SEND_COMPLEX_AT_CMD("AT+CEREG?");
5552 
5553 	/* Turn on EPS network registration status reporting */
5554 	SEND_AT_CMD_EXPECT_OK("AT+CEREG=5");
5555 
5556 	/* query all socket configs to cleanup any sockets that are not
5557 	 * tracked by the driver
5558 	 */
5559 	SEND_AT_CMD_EXPECT_OK("AT+KTCPCFG?");
5560 	SEND_AT_CMD_EXPECT_OK("AT+KUDPCFG?");
5561 
5562 	/* Enabled the LTE radio */
5563 #if !defined(CONFIG_MODEM_HL7800_BOOT_IN_AIRPLANE_MODE)
5564 	SEND_AT_CMD_EXPECT_OK("AT+CFUN=1,0");
5565 #endif
5566 
5567 	/* The modem has been initialized and now the network interface can be
5568 	 * started in the CEREG message handler.
5569 	 */
5570 	LOG_INF("Modem ready!");
5571 	iface_ctx.restarting = false;
5572 	iface_ctx.configured = true;
5573 	set_busy(false);
5574 	allow_sleep(sleep);
5575 	/* trigger APN update event */
5576 	event_handler(HL7800_EVENT_APN_UPDATE, &iface_ctx.mdm_apn);
5577 
5578 #ifdef CONFIG_MODEM_HL7800_BOOT_DELAY
5579 	if (!iface_ctx.initialized) {
5580 		if (iface_ctx.iface != NULL) {
5581 			hl7800_build_mac(&iface_ctx);
5582 			net_if_set_link_addr(iface_ctx.iface, iface_ctx.mac_addr,
5583 					     sizeof(iface_ctx.mac_addr),
5584 					     NET_LINK_ETHERNET);
5585 			iface_ctx.initialized = true;
5586 		}
5587 	}
5588 #endif
5589 
5590 	return 0;
5591 
5592 error:
5593 	LOG_ERR("Unable to configure modem");
5594 	iface_ctx.configured = false;
5595 	set_network_state(HL7800_UNABLE_TO_CONFIGURE);
5596 	/* Kernel will fault with non-zero return value.
5597 	 * Allow other parts of application to run when modem cannot be configured.
5598 	 */
5599 	return 0;
5600 }
5601 
write_apn(char * access_point_name)5602 static int write_apn(char *access_point_name)
5603 {
5604 	char cmd_string[MDM_HL7800_APN_CMD_MAX_SIZE];
5605 
5606 	/* PDP Context */
5607 	memset(cmd_string, 0, MDM_HL7800_APN_CMD_MAX_SIZE);
5608 	if (strcmp(MODEM_HL7800_ADDRESS_FAMILY, ADDRESS_FAMILY_IPV4)) {
5609 		strncat(cmd_string, "AT+CGDCONT=1,\"" MODEM_HL7800_ADDRESS_FAMILY "\",\"",
5610 			MDM_HL7800_APN_CMD_MAX_STRLEN);
5611 	} else {
5612 		strncat(cmd_string, "AT+CGDCONT=1,\"" ADDRESS_FAMILY_IP "\",\"",
5613 			MDM_HL7800_APN_CMD_MAX_STRLEN);
5614 	}
5615 	strncat(cmd_string, access_point_name, MDM_HL7800_APN_CMD_MAX_STRLEN);
5616 	strncat(cmd_string, "\"", MDM_HL7800_APN_CMD_MAX_STRLEN);
5617 	return send_at_cmd(NULL, cmd_string, MDM_CMD_SEND_TIMEOUT, 0, false);
5618 }
5619 
mdm_reset_work_callback(struct k_work * item)5620 static void mdm_reset_work_callback(struct k_work *item)
5621 {
5622 	ARG_UNUSED(item);
5623 
5624 	mdm_hl7800_reset();
5625 }
5626 
mdm_hl7800_reset(void)5627 int32_t mdm_hl7800_reset(void)
5628 {
5629 	int ret;
5630 
5631 	hl7800_lock();
5632 
5633 	ret = modem_reset_and_configure();
5634 
5635 	hl7800_unlock();
5636 
5637 	return ret;
5638 }
5639 
mdm_power_off_work_callback(struct k_work * item)5640 static void mdm_power_off_work_callback(struct k_work *item)
5641 {
5642 	ARG_UNUSED(item);
5643 	int ret;
5644 #if defined(CONFIG_DNS_RESOLVER)
5645 	struct dns_resolve_context *dns_ctx;
5646 
5647 	LOG_DBG("Shutdown DNS resolver");
5648 	dns_ctx = dns_resolve_get_default();
5649 	(void)dns_resolve_close(dns_ctx);
5650 #endif
5651 
5652 	hl7800_lock();
5653 
5654 	notify_all_tcp_sockets_closed();
5655 
5656 	ret = send_at_cmd(NULL, "AT+CPOF", MDM_CMD_SEND_TIMEOUT, 1, false);
5657 	if (ret) {
5658 		LOG_ERR("AT+CPOF ret:%d", ret);
5659 		return;
5660 	}
5661 	prepare_io_for_reset();
5662 	iface_ctx.dns_ready = false;
5663 	iface_ctx.configured = false;
5664 	iface_ctx.off = true;
5665 	set_busy(false);
5666 	/* bring the iface down */
5667 	if (iface_ctx.iface) {
5668 		net_if_carrier_off(iface_ctx.iface);
5669 	}
5670 	LOG_INF("Modem powered off");
5671 
5672 	hl7800_unlock();
5673 }
5674 
hl7800_power_off(void)5675 static int hl7800_power_off(void)
5676 {
5677 	LOG_INF("Powering off modem");
5678 	wakeup_hl7800();
5679 	hl7800_stop_rssi_work();
5680 	k_work_cancel_delayable(&iface_ctx.iface_status_work);
5681 	k_work_cancel_delayable(&iface_ctx.dns_work);
5682 	k_work_cancel_delayable(&iface_ctx.mdm_reset_work);
5683 	k_work_cancel_delayable(&iface_ctx.allow_sleep_work);
5684 	k_work_cancel_delayable(&iface_ctx.delete_untracked_socket_work);
5685 	(void)k_work_submit_to_queue(&hl7800_workq, &iface_ctx.mdm_pwr_off_work);
5686 
5687 	return 0;
5688 }
5689 
mdm_hl7800_power_off(void)5690 int32_t mdm_hl7800_power_off(void)
5691 {
5692 	int rc;
5693 
5694 	hl7800_lock();
5695 	rc = hl7800_power_off();
5696 	hl7800_unlock();
5697 
5698 	return rc;
5699 }
5700 
mdm_hl7800_register_event_callback(struct mdm_hl7800_callback_agent * agent)5701 int mdm_hl7800_register_event_callback(struct mdm_hl7800_callback_agent *agent)
5702 {
5703 	int ret;
5704 
5705 	ret = k_sem_take(&cb_lock, K_NO_WAIT);
5706 	if (ret < 0) {
5707 		return ret;
5708 	}
5709 	if (!agent->event_callback) {
5710 		LOG_WRN("event_callback is NULL");
5711 	}
5712 	sys_slist_append(&hl7800_event_callback_list, &agent->node);
5713 	k_sem_give(&cb_lock);
5714 
5715 	return ret;
5716 }
5717 
mdm_hl7800_unregister_event_callback(struct mdm_hl7800_callback_agent * agent)5718 int mdm_hl7800_unregister_event_callback(struct mdm_hl7800_callback_agent *agent)
5719 {
5720 	int ret;
5721 
5722 	ret = k_sem_take(&cb_lock, K_NO_WAIT);
5723 	if (ret < 0) {
5724 		return ret;
5725 	}
5726 	ret = (int)sys_slist_find_and_remove(&hl7800_event_callback_list, &agent->node);
5727 	if (ret) {
5728 		ret = 0;
5729 	} else {
5730 		ret = -ENOENT;
5731 	}
5732 	k_sem_give(&cb_lock);
5733 
5734 	return ret;
5735 }
5736 
5737 /*** OFFLOAD FUNCTIONS ***/
5738 
connect_TCP_socket(struct hl7800_socket * sock)5739 static int connect_TCP_socket(struct hl7800_socket *sock)
5740 {
5741 	int ret;
5742 	char cmd_con[sizeof("AT+KTCPCNX=##")];
5743 
5744 	snprintk(cmd_con, sizeof(cmd_con), "AT+KTCPCNX=%d", sock->socket_id);
5745 	ret = send_at_cmd(sock, cmd_con, MDM_CMD_SEND_TIMEOUT, 0, false);
5746 	if (ret < 0) {
5747 		LOG_ERR("AT+KTCPCNX ret:%d", ret);
5748 		ret = -EIO;
5749 		goto done;
5750 	}
5751 	/* Now wait for +KTCP_IND or +KTCP_NOTIF to ensure
5752 	 * the connection succeeded or failed.
5753 	 */
5754 	ret = k_sem_take(&sock->sock_send_sem, MDM_CMD_CONN_TIMEOUT);
5755 	if (ret == 0) {
5756 		ret = sock->error;
5757 	} else if (ret == -EAGAIN) {
5758 		ret = -ETIMEDOUT;
5759 	}
5760 	if (ret < 0) {
5761 		LOG_ERR("+KTCP_IND/NOTIF ret:%d", ret);
5762 		goto done;
5763 	} else {
5764 		sock->state = SOCK_CONNECTED;
5765 		net_context_set_state(sock->context, NET_CONTEXT_CONNECTED);
5766 	}
5767 done:
5768 	return ret;
5769 }
5770 
configure_TCP_socket(struct hl7800_socket * sock)5771 static int configure_TCP_socket(struct hl7800_socket *sock)
5772 {
5773 	int ret;
5774 	char cmd_cfg[sizeof("AT+KTCPCFG=#,#,\"" IPV6_ADDR_FORMAT "\",#####,,,,#,,#")];
5775 	int dst_port = -1;
5776 	int af;
5777 	bool restore_on_boot = false;
5778 
5779 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5780 	restore_on_boot = true;
5781 #endif
5782 
5783 	if (sock->dst.sa_family == AF_INET6) {
5784 		af = MDM_HL7800_SOCKET_AF_IPV6;
5785 		dst_port = net_sin6(&sock->dst)->sin6_port;
5786 	} else if (sock->dst.sa_family == AF_INET) {
5787 		af = MDM_HL7800_SOCKET_AF_IPV4;
5788 		dst_port = net_sin(&sock->dst)->sin_port;
5789 	} else {
5790 		return -EINVAL;
5791 	}
5792 
5793 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5794 
5795 	snprintk(cmd_cfg, sizeof(cmd_cfg), "AT+KTCPCFG=%d,%d,\"%s\",%u,,,,%d,,%d", 1, 0,
5796 		 hl7800_sprint_ip_addr(&sock->dst), dst_port, af, restore_on_boot);
5797 	ret = send_at_cmd(sock, cmd_cfg, MDM_CMD_SEND_TIMEOUT, 0, false);
5798 	if (ret < 0) {
5799 		LOG_ERR("AT+KTCPCFG ret:%d", ret);
5800 		ret = -EIO;
5801 		goto done;
5802 	}
5803 
5804 done:
5805 	return ret;
5806 }
5807 
configure_UDP_socket(struct hl7800_socket * sock)5808 static int configure_UDP_socket(struct hl7800_socket *sock)
5809 {
5810 	int ret = 0;
5811 	char cmd[sizeof("AT+KUDPCFG=1,0,,,,,0,#")];
5812 	int af;
5813 	bool restore_on_boot = false;
5814 
5815 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5816 	restore_on_boot = true;
5817 #endif
5818 
5819 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5820 
5821 	if (sock->family == AF_INET) {
5822 		af = MDM_HL7800_SOCKET_AF_IPV4;
5823 	} else if (sock->family == AF_INET6) {
5824 		af = MDM_HL7800_SOCKET_AF_IPV6;
5825 	} else {
5826 		return -EINVAL;
5827 	}
5828 
5829 	snprintk(cmd, sizeof(cmd), "AT+KUDPCFG=1,0,,,,,%d,%d", af, restore_on_boot);
5830 	ret = send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
5831 	if (ret < 0) {
5832 		LOG_ERR("AT+KUDPCFG ret:%d", ret);
5833 		goto done;
5834 	}
5835 
5836 	/* Now wait for +KUDP_IND or +KUDP_NOTIF to ensure
5837 	 * the socket was created.
5838 	 */
5839 	ret = k_sem_take(&sock->sock_send_sem, MDM_CMD_CONN_TIMEOUT);
5840 	if (ret == 0) {
5841 		ret = sock->error;
5842 	} else if (ret == -EAGAIN) {
5843 		ret = -ETIMEDOUT;
5844 	}
5845 	if (ret < 0) {
5846 		LOG_ERR("+KUDP_IND/NOTIF ret:%d", ret);
5847 		goto done;
5848 	}
5849 done:
5850 	return ret;
5851 }
5852 
reconfigure_IP_connection(void)5853 static int reconfigure_IP_connection(void)
5854 {
5855 	int ret = 0;
5856 
5857 	if (iface_ctx.reconfig_IP_connection) {
5858 		iface_ctx.reconfig_IP_connection = false;
5859 
5860 		/* reconfigure GPRS connection so sockets can be used */
5861 		ret = setup_gprs_connection(iface_ctx.mdm_apn.value);
5862 		if (ret < 0) {
5863 			LOG_ERR("AT+KCNXCFG= ret:%d", ret);
5864 			goto done;
5865 		}
5866 
5867 		/* query all TCP socket configs */
5868 		ret = send_at_cmd(NULL, "AT+KTCPCFG?", MDM_CMD_SEND_TIMEOUT, 0,
5869 				  false);
5870 
5871 		/* query all UDP socket configs */
5872 		ret = send_at_cmd(NULL, "AT+KUDPCFG?", MDM_CMD_SEND_TIMEOUT, 0,
5873 				  false);
5874 
5875 		/* TODO: to make this better, wait for +KUDP_IND or timeout */
5876 		k_sleep(K_SECONDS(1));
5877 	}
5878 
5879 done:
5880 	return ret;
5881 }
5882 
offload_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)5883 static int offload_get(sa_family_t family, enum net_sock_type type,
5884 		       enum net_ip_protocol ip_proto,
5885 		       struct net_context **context)
5886 {
5887 	int ret = 0;
5888 	struct hl7800_socket *sock = NULL;
5889 
5890 	hl7800_lock();
5891 	/* new socket */
5892 	sock = socket_get();
5893 	if (!sock) {
5894 		ret = -ENOMEM;
5895 		goto done;
5896 	}
5897 
5898 	(*context)->offload_context = sock;
5899 	/* set the context iface index to our iface */
5900 	(*context)->iface = net_if_get_by_iface(iface_ctx.iface);
5901 	sock->family = family;
5902 	sock->type = type;
5903 	sock->ip_proto = ip_proto;
5904 	sock->context = *context;
5905 	sock->reconfig = false;
5906 	sock->created = false;
5907 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5908 
5909 	/* If UDP, create UDP socket now.
5910 	 * TCP socket needs to be created later once the
5911 	 * connection IP address is known.
5912 	 */
5913 	if (type == SOCK_DGRAM) {
5914 		wakeup_hl7800();
5915 
5916 		/* reconfig IP connection if necessary */
5917 		(void)reconfigure_IP_connection();
5918 
5919 		if (!sock->created) {
5920 			ret = configure_UDP_socket(sock);
5921 			if (ret < 0) {
5922 				socket_put(sock);
5923 				goto done;
5924 			}
5925 		}
5926 	}
5927 done:
5928 	set_busy(false);
5929 	allow_sleep(true);
5930 	hl7800_unlock();
5931 	return ret;
5932 }
5933 
offload_bind(struct net_context * context,const struct sockaddr * addr,socklen_t addr_len)5934 static int offload_bind(struct net_context *context,
5935 			const struct sockaddr *addr, socklen_t addr_len)
5936 {
5937 	struct hl7800_socket *sock = NULL;
5938 
5939 	if (!context) {
5940 		return -EINVAL;
5941 	}
5942 
5943 	sock = (struct hl7800_socket *)context->offload_context;
5944 	if (!sock) {
5945 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
5946 		return -EINVAL;
5947 	}
5948 
5949 	/* save bind address information */
5950 	sock->src.sa_family = addr->sa_family;
5951 #if defined(CONFIG_NET_IPV6)
5952 	if (addr->sa_family == AF_INET6) {
5953 		net_ipaddr_copy(&net_sin6(&sock->src)->sin6_addr,
5954 				&net_sin6(addr)->sin6_addr);
5955 		net_sin6(&sock->src)->sin6_port = net_sin6(addr)->sin6_port;
5956 	} else
5957 #endif
5958 #if defined(CONFIG_NET_IPV4)
5959 		if (addr->sa_family == AF_INET) {
5960 		net_ipaddr_copy(&net_sin(&sock->src)->sin_addr,
5961 				&net_sin(addr)->sin_addr);
5962 		net_sin(&sock->src)->sin_port = net_sin(addr)->sin_port;
5963 	} else
5964 #endif
5965 	{
5966 		return -EPFNOSUPPORT;
5967 	}
5968 
5969 	return 0;
5970 }
5971 
offload_listen(struct net_context * context,int backlog)5972 static int offload_listen(struct net_context *context, int backlog)
5973 {
5974 	/* NOT IMPLEMENTED */
5975 	return -ENOTSUP;
5976 }
5977 
offload_connect(struct net_context * context,const struct sockaddr * addr,socklen_t addr_len,net_context_connect_cb_t cb,int32_t timeout,void * user_data)5978 static int offload_connect(struct net_context *context,
5979 			   const struct sockaddr *addr, socklen_t addr_len,
5980 			   net_context_connect_cb_t cb, int32_t timeout,
5981 			   void *user_data)
5982 {
5983 	int ret = 0;
5984 	int dst_port = -1;
5985 	struct hl7800_socket *sock;
5986 
5987 	if (!context || !addr) {
5988 		return -EINVAL;
5989 	}
5990 
5991 	sock = (struct hl7800_socket *)context->offload_context;
5992 	if (!sock) {
5993 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
5994 		return -EINVAL;
5995 	}
5996 
5997 	if (sock->socket_id < 1) {
5998 		LOG_ERR("Invalid socket_id(%d) for net_ctx:%p!",
5999 			sock->socket_id, context);
6000 		return -EINVAL;
6001 	}
6002 
6003 	sock->dst.sa_family = addr->sa_family;
6004 
6005 #if defined(CONFIG_NET_IPV6)
6006 	if (addr->sa_family == AF_INET6) {
6007 		net_ipaddr_copy(&net_sin6(&sock->dst)->sin6_addr,
6008 				&net_sin6(addr)->sin6_addr);
6009 		dst_port = ntohs(net_sin6(addr)->sin6_port);
6010 		net_sin6(&sock->dst)->sin6_port = dst_port;
6011 	} else
6012 #endif
6013 #if defined(CONFIG_NET_IPV4)
6014 		if (addr->sa_family == AF_INET) {
6015 		net_ipaddr_copy(&net_sin(&sock->dst)->sin_addr,
6016 				&net_sin(addr)->sin_addr);
6017 		dst_port = ntohs(net_sin(addr)->sin_port);
6018 		net_sin(&sock->dst)->sin_port = dst_port;
6019 	} else
6020 #endif
6021 	{
6022 		return -EINVAL;
6023 	}
6024 
6025 	if (dst_port < 0) {
6026 		LOG_ERR("Invalid port: %d", dst_port);
6027 		return -EINVAL;
6028 	}
6029 
6030 	hl7800_lock();
6031 
6032 	if (sock->type == SOCK_STREAM) {
6033 		wakeup_hl7800();
6034 
6035 		reconfigure_IP_connection();
6036 
6037 		/* Configure/create TCP connection */
6038 		if (!sock->created) {
6039 			ret = configure_TCP_socket(sock);
6040 			if (ret < 0) {
6041 				goto done;
6042 			}
6043 		}
6044 
6045 		/* Connect to TCP */
6046 		ret = connect_TCP_socket(sock);
6047 		if (ret < 0) {
6048 			goto done;
6049 		}
6050 	}
6051 
6052 done:
6053 	set_busy(false);
6054 	allow_sleep(true);
6055 	hl7800_unlock();
6056 
6057 	if (cb) {
6058 		cb(context, ret, user_data);
6059 	}
6060 
6061 	return ret;
6062 }
6063 
offload_accept(struct net_context * context,net_tcp_accept_cb_t cb,int32_t timeout,void * user_data)6064 static int offload_accept(struct net_context *context, net_tcp_accept_cb_t cb,
6065 			  int32_t timeout, void *user_data)
6066 {
6067 	/* NOT IMPLEMENTED */
6068 	return -ENOTSUP;
6069 }
6070 
offload_sendto(struct net_pkt * pkt,const struct sockaddr * dst_addr,socklen_t addr_len,net_context_send_cb_t cb,int32_t timeout,void * user_data)6071 static int offload_sendto(struct net_pkt *pkt, const struct sockaddr *dst_addr,
6072 			  socklen_t addr_len, net_context_send_cb_t cb,
6073 			  int32_t timeout, void *user_data)
6074 {
6075 	struct net_context *context = net_pkt_context(pkt);
6076 	struct hl7800_socket *sock;
6077 	int ret, dst_port = 0;
6078 
6079 	if (!context) {
6080 		return -EINVAL;
6081 	}
6082 
6083 	sock = (struct hl7800_socket *)context->offload_context;
6084 	if (!sock) {
6085 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
6086 		return -EINVAL;
6087 	}
6088 
6089 #if defined(CONFIG_NET_IPV6)
6090 	if (dst_addr->sa_family == AF_INET6) {
6091 		net_ipaddr_copy(&net_sin6(&sock->dst)->sin6_addr,
6092 				&net_sin6(dst_addr)->sin6_addr);
6093 		dst_port = ntohs(net_sin6(dst_addr)->sin6_port);
6094 		net_sin6(&sock->dst)->sin6_port = dst_port;
6095 	} else
6096 #endif
6097 #if defined(CONFIG_NET_IPV4)
6098 		if (dst_addr->sa_family == AF_INET) {
6099 		net_ipaddr_copy(&net_sin(&sock->dst)->sin_addr,
6100 				&net_sin(dst_addr)->sin_addr);
6101 		dst_port = ntohs(net_sin(dst_addr)->sin_port);
6102 		net_sin(&sock->dst)->sin_port = dst_port;
6103 	} else
6104 #endif
6105 	{
6106 		return -EINVAL;
6107 	}
6108 
6109 	hl7800_lock();
6110 
6111 	wakeup_hl7800();
6112 
6113 	reconfigure_IP_connection();
6114 
6115 	ret = send_data(sock, pkt);
6116 
6117 	set_busy(false);
6118 	allow_sleep(true);
6119 	hl7800_unlock();
6120 
6121 	if (ret >= 0) {
6122 		net_pkt_unref(pkt);
6123 	}
6124 
6125 	if (cb) {
6126 		cb(context, ret, user_data);
6127 	}
6128 
6129 	return ret;
6130 }
6131 
offload_send(struct net_pkt * pkt,net_context_send_cb_t cb,int32_t timeout,void * user_data)6132 static int offload_send(struct net_pkt *pkt, net_context_send_cb_t cb,
6133 			int32_t timeout, void *user_data)
6134 {
6135 	struct net_context *context = net_pkt_context(pkt);
6136 	socklen_t addr_len;
6137 
6138 	addr_len = 0;
6139 #if defined(CONFIG_NET_IPV6)
6140 	if (net_pkt_family(pkt) == AF_INET6) {
6141 		addr_len = sizeof(struct sockaddr_in6);
6142 	} else
6143 #endif /* CONFIG_NET_IPV6 */
6144 #if defined(CONFIG_NET_IPV4)
6145 		if (net_pkt_family(pkt) == AF_INET) {
6146 		addr_len = sizeof(struct sockaddr_in);
6147 	} else
6148 #endif /* CONFIG_NET_IPV4 */
6149 	{
6150 		return -EPFNOSUPPORT;
6151 	}
6152 
6153 	return offload_sendto(pkt, &context->remote, addr_len, cb, timeout,
6154 			      user_data);
6155 }
6156 
offload_recv(struct net_context * context,net_context_recv_cb_t cb,int32_t timeout,void * user_data)6157 static int offload_recv(struct net_context *context, net_context_recv_cb_t cb,
6158 			int32_t timeout, void *user_data)
6159 {
6160 	struct hl7800_socket *sock;
6161 
6162 	if (!context) {
6163 		return -EINVAL;
6164 	}
6165 
6166 	sock = (struct hl7800_socket *)context->offload_context;
6167 	if (!sock) {
6168 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
6169 		return -EINVAL;
6170 	}
6171 
6172 	sock->recv_cb = cb;
6173 	sock->recv_user_data = user_data;
6174 
6175 	return 0;
6176 }
6177 
offload_put(struct net_context * context)6178 static int offload_put(struct net_context *context)
6179 {
6180 	struct hl7800_socket *sock;
6181 	char cmd[sizeof("AT+KTCPCLOSE=##")];
6182 
6183 	if (!context) {
6184 		return -EINVAL;
6185 	}
6186 
6187 	sock = (struct hl7800_socket *)context->offload_context;
6188 	if (!sock) {
6189 		/* socket was already closed?  Exit quietly here. */
6190 		return 0;
6191 	}
6192 
6193 	/* cancel notif work if queued */
6194 	k_work_cancel_delayable(&sock->notif_work);
6195 
6196 	hl7800_lock();
6197 
6198 	/* close connection */
6199 	if (sock->type == SOCK_STREAM) {
6200 		snprintk(cmd, sizeof(cmd), "AT+KTCPCLOSE=%d",
6201 			 sock->socket_id);
6202 	} else {
6203 		snprintk(cmd, sizeof(cmd), "AT+KUDPCLOSE=%d",
6204 			 sock->socket_id);
6205 	}
6206 
6207 	wakeup_hl7800();
6208 
6209 	if ((sock->type == SOCK_DGRAM) || (sock->error != -ENOTCONN)) {
6210 		send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
6211 	}
6212 
6213 	if (sock->type == SOCK_STREAM) {
6214 		/* delete session */
6215 		delete_socket(sock, sock->type, sock->socket_id);
6216 	}
6217 	set_busy(false);
6218 	allow_sleep(true);
6219 
6220 	socket_put(sock);
6221 	net_context_unref(context);
6222 	if (sock->type == SOCK_STREAM) {
6223 		/* TCP contexts are referenced twice,
6224 		 * once for the app and once for the stack.
6225 		 * Since TCP stack is not used for offload,
6226 		 * unref a second time.
6227 		 */
6228 		net_context_unref(context);
6229 	}
6230 
6231 	hl7800_unlock();
6232 
6233 	return 0;
6234 }
6235 
6236 static struct net_offload offload_funcs = {
6237 	.get = offload_get,
6238 	.bind = offload_bind,
6239 	.listen = offload_listen,
6240 	.connect = offload_connect,
6241 	.accept = offload_accept,
6242 	.send = offload_send,
6243 	.sendto = offload_sendto,
6244 	.recv = offload_recv,
6245 	.put = offload_put,
6246 };
6247 
6248 /* Use the last 6 digits of the IMEI as the mac address */
hl7800_build_mac(struct hl7800_iface_ctx * ictx)6249 static void hl7800_build_mac(struct hl7800_iface_ctx *ictx)
6250 {
6251 	ictx->mac_addr[0] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 6];
6252 	ictx->mac_addr[1] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 5];
6253 	ictx->mac_addr[2] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 4];
6254 	ictx->mac_addr[3] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 3];
6255 	ictx->mac_addr[4] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 2];
6256 	ictx->mac_addr[5] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 1];
6257 }
6258 
6259 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
mdm_hl7800_update_fw(char * file_path)6260 int32_t mdm_hl7800_update_fw(char *file_path)
6261 {
6262 	int ret = 0;
6263 	struct fs_dirent file_info;
6264 	char cmd1[sizeof("AT+WDSD=24643584")];
6265 
6266 	/* get file info */
6267 	ret = fs_stat(file_path, &file_info);
6268 	if (ret >= 0) {
6269 		LOG_DBG("file '%s' size %zu", file_info.name, file_info.size);
6270 	} else {
6271 		LOG_ERR("Failed to get file [%s] info: %d", file_path, ret);
6272 		goto err;
6273 	}
6274 
6275 	ret = fs_open(&iface_ctx.fw_update_file, file_path, FS_O_READ);
6276 	if (ret < 0) {
6277 		LOG_ERR("%s open err: %d", file_path, ret);
6278 		goto err;
6279 	}
6280 
6281 	/* turn on device service indications */
6282 	ret = send_at_cmd(NULL, "AT+WDSI=2", MDM_CMD_SEND_TIMEOUT, 0, false);
6283 	if (ret < 0) {
6284 		goto err;
6285 	}
6286 
6287 	notify_all_tcp_sockets_closed();
6288 	hl7800_stop_rssi_work();
6289 	k_work_cancel_delayable(&iface_ctx.iface_status_work);
6290 	k_work_cancel_delayable(&iface_ctx.dns_work);
6291 	k_work_cancel_delayable(&iface_ctx.mdm_reset_work);
6292 	k_work_cancel_delayable(&iface_ctx.allow_sleep_work);
6293 	k_work_cancel_delayable(&iface_ctx.delete_untracked_socket_work);
6294 	iface_ctx.dns_ready = false;
6295 	if (iface_ctx.iface) {
6296 		LOG_DBG("HL7800 iface DOWN");
6297 		net_if_carrier_off(iface_ctx.iface);
6298 	}
6299 
6300 	/* HL7800 will stay locked for the duration of the FW update */
6301 	hl7800_lock();
6302 
6303 	/* start firmware update process */
6304 	LOG_INF("Initiate FW update, total packets: %zd",
6305 		((file_info.size / XMODEM_DATA_SIZE) + 1));
6306 	set_fota_state(HL7800_FOTA_START);
6307 	(void)snprintk(cmd1, sizeof(cmd1), "AT+WDSD=%zd", file_info.size);
6308 	(void)send_at_cmd(NULL, cmd1, K_NO_WAIT, 0, false);
6309 
6310 err:
6311 	return ret;
6312 }
6313 #endif
6314 
hl7800_init(const struct device * dev)6315 static int hl7800_init(const struct device *dev)
6316 {
6317 	int i, ret = 0;
6318 	struct k_work_queue_config cfg = {
6319 		.name = "hl7800_workq",
6320 	};
6321 	ARG_UNUSED(dev);
6322 
6323 	LOG_DBG("HL7800 Init");
6324 
6325 	/* The UART starts in the on state and CTS is set low by the HL7800 */
6326 	iface_ctx.cts_state = iface_ctx.last_cts_state = 0;
6327 
6328 	/* Prevent the network interface from starting until
6329 	 * the modem has been initialized
6330 	 * because the modem may not have a valid SIM card.
6331 	 */
6332 	iface_ctx.iface = net_if_get_default();
6333 	if (iface_ctx.iface == NULL) {
6334 		return -EIO;
6335 	}
6336 
6337 	net_if_carrier_off(iface_ctx.iface);
6338 
6339 	/* init sockets */
6340 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
6341 		iface_ctx.sockets[i].socket_id = MDM_INVALID_SOCKET_ID;
6342 		k_work_init(&iface_ctx.sockets[i].recv_cb_work,
6343 			    sockreadrecv_cb_work);
6344 		k_work_init(&iface_ctx.sockets[i].rx_data_work,
6345 			    sock_rx_data_cb_work);
6346 		k_work_init_delayable(&iface_ctx.sockets[i].notif_work,
6347 				      sock_notif_cb_work);
6348 		k_sem_init(&iface_ctx.sockets[i].sock_send_sem, 0, 1);
6349 	}
6350 	iface_ctx.last_socket_id = 0;
6351 	k_sem_init(&iface_ctx.response_sem, 0, 1);
6352 	k_sem_init(&iface_ctx.mdm_awake, 0, 1);
6353 
6354 	/* initialize the work queue */
6355 	k_work_queue_start(&hl7800_workq, hl7800_workq_stack,
6356 			   K_THREAD_STACK_SIZEOF(hl7800_workq_stack),
6357 			   WORKQ_PRIORITY, &cfg);
6358 
6359 	/* init work tasks */
6360 	k_work_init_delayable(&iface_ctx.rssi_query_work, hl7800_rssi_query_work);
6361 	k_work_init_delayable(&iface_ctx.iface_status_work, iface_status_work_cb);
6362 	k_work_init_delayable(&iface_ctx.dns_work, dns_work_cb);
6363 	k_work_init(&iface_ctx.mdm_vgpio_work, mdm_vgpio_work_cb);
6364 	k_work_init_delayable(&iface_ctx.mdm_reset_work, mdm_reset_work_callback);
6365 	k_work_init_delayable(&iface_ctx.allow_sleep_work,
6366 			      allow_sleep_work_callback);
6367 	k_work_init_delayable(&iface_ctx.delete_untracked_socket_work,
6368 			      delete_untracked_socket_work_cb);
6369 	k_work_init(&iface_ctx.mdm_pwr_off_work, mdm_power_off_work_callback);
6370 
6371 #ifdef CONFIG_MODEM_HL7800_GPS
6372 	k_work_init_delayable(&iface_ctx.gps_work, gps_work_callback);
6373 #endif
6374 
6375 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
6376 	k_work_init(&iface_ctx.finish_fw_update_work,
6377 		    finish_fw_update_work_callback);
6378 	iface_ctx.fw_updated = false;
6379 #endif
6380 
6381 	/* setup port devices and pin directions */
6382 	for (i = 0; i < MAX_MDM_CONTROL_PINS; i++) {
6383 		if (!gpio_is_ready_dt(&hl7800_cfg.gpio[i])) {
6384 			LOG_ERR("gpio port (%s) not ready!",
6385 				hl7800_cfg.gpio[i].port->name);
6386 			return -ENODEV;
6387 		}
6388 	}
6389 
6390 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_RESET], GPIO_OUTPUT);
6391 	if (ret) {
6392 		LOG_ERR("Error configuring IO MDM_RESET %d err: %d!",
6393 			hl7800_cfg.gpio[MDM_RESET].pin, ret);
6394 		return ret;
6395 	}
6396 
6397 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_WAKE], GPIO_OUTPUT);
6398 	if (ret) {
6399 		LOG_ERR("Error configuring IO MDM_WAKE %d err: %d!",
6400 			hl7800_cfg.gpio[MDM_WAKE].pin, ret);
6401 		return ret;
6402 	}
6403 
6404 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_PWR_ON], GPIO_OUTPUT);
6405 	if (ret) {
6406 		LOG_ERR("Error configuring IO MDM_PWR_ON %d err: %d!",
6407 			hl7800_cfg.gpio[MDM_PWR_ON].pin, ret);
6408 		return ret;
6409 	}
6410 
6411 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], GPIO_OUTPUT);
6412 	if (ret) {
6413 		LOG_ERR("Error configuring IO MDM_FAST_SHUTD %d err: %d!",
6414 			hl7800_cfg.gpio[MDM_FAST_SHUTD].pin, ret);
6415 		return ret;
6416 	}
6417 
6418 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_VGPIO], GPIO_INPUT);
6419 	if (ret) {
6420 		LOG_ERR("Error configuring IO MDM_VGPIO %d err: %d!",
6421 			hl7800_cfg.gpio[MDM_VGPIO].pin, ret);
6422 		return ret;
6423 	}
6424 
6425 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_UART_DSR], GPIO_INPUT);
6426 	if (ret) {
6427 		LOG_ERR("Error configuring IO MDM_UART_DSR %d err: %d!",
6428 			hl7800_cfg.gpio[MDM_UART_DSR].pin, ret);
6429 		return ret;
6430 	}
6431 
6432 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_UART_CTS], GPIO_INPUT);
6433 	if (ret) {
6434 		LOG_ERR("Error configuring IO MDM_UART_CTS %d err: %d!",
6435 			hl7800_cfg.gpio[MDM_UART_CTS].pin, ret);
6436 		return ret;
6437 	}
6438 
6439 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_GPIO6], GPIO_INPUT);
6440 	if (ret) {
6441 		LOG_ERR("Error configuring IO MDM_GPIO6 %d err: %d!",
6442 			hl7800_cfg.gpio[MDM_GPIO6].pin, ret);
6443 		return ret;
6444 	}
6445 
6446 	modem_assert_wake(false);
6447 	modem_assert_pwr_on(false);
6448 	modem_assert_fast_shutd(false);
6449 
6450 	/* Allow modem to run so we are in a known state.
6451 	 * This allows HL7800 VGPIO to be high, which is good because the UART
6452 	 * IO are already configured.
6453 	 */
6454 	modem_run();
6455 
6456 	/* setup input pin callbacks */
6457 	/* VGPIO */
6458 	gpio_init_callback(&iface_ctx.mdm_vgpio_cb, mdm_vgpio_callback_isr,
6459 			   BIT(hl7800_cfg.gpio[MDM_VGPIO].pin));
6460 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_VGPIO].port,
6461 				&iface_ctx.mdm_vgpio_cb);
6462 	if (ret) {
6463 		LOG_ERR("Cannot setup vgpio callback! (%d)", ret);
6464 		return ret;
6465 	}
6466 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_VGPIO], GPIO_INT_EDGE_BOTH);
6467 	if (ret) {
6468 		LOG_ERR("Error config vgpio interrupt! (%d)", ret);
6469 		return ret;
6470 	}
6471 
6472 	/* UART DSR */
6473 	gpio_init_callback(&iface_ctx.mdm_uart_dsr_cb, mdm_uart_dsr_callback_isr,
6474 			   BIT(hl7800_cfg.gpio[MDM_UART_DSR].pin));
6475 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_DSR].port,
6476 				&iface_ctx.mdm_uart_dsr_cb);
6477 	if (ret) {
6478 		LOG_ERR("Cannot setup uart dsr callback! (%d)", ret);
6479 		return ret;
6480 	}
6481 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_UART_DSR], GPIO_INT_EDGE_BOTH);
6482 	if (ret) {
6483 		LOG_ERR("Error config uart dsr interrupt! (%d)", ret);
6484 		return ret;
6485 	}
6486 
6487 	/* GPIO6 */
6488 	gpio_init_callback(&iface_ctx.mdm_gpio6_cb, mdm_gpio6_callback_isr,
6489 			   BIT(hl7800_cfg.gpio[MDM_GPIO6].pin));
6490 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_GPIO6].port,
6491 				&iface_ctx.mdm_gpio6_cb);
6492 	if (ret) {
6493 		LOG_ERR("Cannot setup gpio6 callback! (%d)", ret);
6494 		return ret;
6495 	}
6496 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_GPIO6], GPIO_INT_EDGE_BOTH);
6497 	if (ret) {
6498 		LOG_ERR("Error config gpio6 interrupt! (%d)", ret);
6499 		return ret;
6500 	}
6501 
6502 	/* UART CTS */
6503 	gpio_init_callback(&iface_ctx.mdm_uart_cts_cb, mdm_uart_cts_callback_isr,
6504 			   BIT(hl7800_cfg.gpio[MDM_UART_CTS].pin));
6505 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_CTS].port,
6506 				&iface_ctx.mdm_uart_cts_cb);
6507 	if (ret) {
6508 		LOG_ERR("Cannot setup uart cts callback! (%d)", ret);
6509 		return ret;
6510 	}
6511 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_UART_CTS], GPIO_INT_EDGE_BOTH);
6512 	if (ret) {
6513 		LOG_ERR("Error config uart cts interrupt! (%d)", ret);
6514 		return ret;
6515 	}
6516 
6517 	/* Set modem data storage */
6518 	iface_ctx.mdm_ctx.data_manufacturer = iface_ctx.mdm_manufacturer;
6519 	iface_ctx.mdm_ctx.data_model = iface_ctx.mdm_model;
6520 	iface_ctx.mdm_ctx.data_revision = iface_ctx.mdm_revision;
6521 #ifdef CONFIG_MODEM_SIM_NUMBERS
6522 	iface_ctx.mdm_ctx.data_imei = iface_ctx.mdm_imei;
6523 #endif
6524 	iface_ctx.mdm_ctx.data_rssi = &iface_ctx.mdm_rssi;
6525 
6526 	ret = mdm_receiver_register(&iface_ctx.mdm_ctx, MDM_UART_DEV,
6527 				    mdm_recv_buf, sizeof(mdm_recv_buf));
6528 	if (ret < 0) {
6529 		LOG_ERR("Error registering modem receiver (%d)!", ret);
6530 		return ret;
6531 	}
6532 
6533 	k_queue_init(&iface_ctx.stale_socket_queue);
6534 
6535 	/* start RX thread */
6536 	k_thread_name_set(
6537 		k_thread_create(&hl7800_rx_thread, hl7800_rx_stack,
6538 				K_THREAD_STACK_SIZEOF(hl7800_rx_stack),
6539 				hl7800_rx, NULL, NULL, NULL,
6540 				RX_THREAD_PRIORITY, 0, K_NO_WAIT),
6541 		"hl7800 rx");
6542 
6543 #ifdef CONFIG_MODEM_HL7800_BOOT_DELAY
6544 	modem_reset();
6545 #else
6546 	ret = modem_reset_and_configure();
6547 #endif
6548 
6549 	return ret;
6550 }
6551 
offload_iface_init(struct net_if * iface)6552 static void offload_iface_init(struct net_if *iface)
6553 {
6554 	const struct device *dev = net_if_get_device(iface);
6555 	struct hl7800_iface_ctx *ctx = dev->data;
6556 
6557 	iface->if_dev->offload = &offload_funcs;
6558 	ctx->iface = iface;
6559 
6560 	if (!IS_ENABLED(CONFIG_MODEM_HL7800_BOOT_DELAY)) {
6561 		hl7800_build_mac(&iface_ctx);
6562 		net_if_set_link_addr(iface, iface_ctx.mac_addr, sizeof(iface_ctx.mac_addr),
6563 				     NET_LINK_ETHERNET);
6564 		iface_ctx.initialized = true;
6565 	}
6566 }
6567 
6568 static struct offloaded_if_api api_funcs = {
6569 	.iface_api.init = offload_iface_init,
6570 };
6571 
6572 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, hl7800_init, NULL, &iface_ctx,
6573 				  &hl7800_cfg, CONFIG_MODEM_HL7800_INIT_PRIORITY,
6574 				  &api_funcs, MDM_MTU);
6575