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