1 /*
2  * Copyright (c) 2019 Foundries.io
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define LOG_MODULE_NAME net_lwm2m_obj_conn_mon
8 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
9 
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
12 
13 #include <string.h>
14 #include <zephyr/init.h>
15 #include <zephyr/net/net_if.h>
16 #include <zephyr/net/net_ip.h>
17 
18 #include "lwm2m_object.h"
19 #include "lwm2m_engine.h"
20 
21 #define CONNMON_VERSION_MAJOR 1
22 #if defined(CONFIG_LWM2M_CONNMON_OBJECT_VERSION_1_3)
23 #define CONNMON_VERSION_MINOR 3
24 #define CONNMON_MAX_ID 14
25 #elif defined(CONFIG_LWM2M_CONNMON_OBJECT_VERSION_1_2)
26 #define CONNMON_VERSION_MINOR 2
27 #define CONNMON_MAX_ID 13
28 #else
29 #define CONNMON_VERSION_MINOR 0
30 #define CONNMON_MAX_ID 11
31 #endif
32 
33 /* Connectivity Monitoring resource IDs */
34 #define CONNMON_NETWORK_BEARER_ID		0
35 #define CONNMON_AVAIL_NETWORK_BEARER_ID		1
36 #define CONNMON_RADIO_SIGNAL_STRENGTH		2
37 #define CONNMON_LINK_QUALITY			3
38 #define CONNMON_IP_ADDRESSES			4
39 #define CONNMON_ROUTER_IP_ADDRESSES		5
40 #define CONNMON_LINK_UTILIZATION		6
41 #define CONNMON_APN				7
42 #define CONNMON_CELLID				8
43 #define CONNMON_SMNC				9
44 #define CONNMON_SMCC				10
45 #if CONNMON_VERSION_MINOR > 0
46 #define CONNMON_SIGNAL_SNR			11
47 #endif
48 #if CONNMON_VERSION_MINOR > 1
49 #define CONNMON_LAC				12
50 #endif
51 #if CONNMON_VERSION_MINOR > 2
52 #define CONNMON_COVERAGE_ENHANCEMENT_LEVEL	13
53 #endif
54 
55 #define CONNMON_STRING_SHORT			8
56 
57 #define CONNMON_AVAIL_BEARER_MAX	CONFIG_LWM2M_CONN_MON_BEARER_MAX
58 #define CONNMON_APN_MAX			CONFIG_LWM2M_CONN_MON_APN_MAX
59 
60 #if defined(CONFIG_NET_IF_MAX_IPV6_COUNT) \
61 	&& defined(CONFIG_NET_IF_MAX_IPV4_COUNT)
62 #define CONNMON_IP_ADDRESS_MAX		(CONFIG_NET_IF_MAX_IPV6_COUNT + \
63 					CONFIG_NET_IF_MAX_IPV4_COUNT)
64 #elif defined(CONFIG_NET_IF_MAX_IPV6_COUNT)
65 #define CONNMON_IP_ADDRESS_MAX		CONFIG_NET_IF_MAX_IPV6_COUNT
66 #elif defined(CONFIG_NET_IF_MAX_IPV4_COUNT)
67 #define CONNMON_IP_ADDRESS_MAX		CONFIG_NET_IF_MAX_IPV4_COUNT
68 #else
69 #define CONNMON_IP_ADDRESS_MAX		1
70 #endif
71 
72 #if defined(CONFIG_NET_MAX_ROUTERS)
73 #define CONNMON_ROUTER_IP_ADDRESS_MAX	CONFIG_NET_MAX_ROUTERS
74 #else
75 #define CONNMON_ROUTER_IP_ADDRESS_MAX	1
76 #endif
77 
78 /*
79  * Calculate resource instances as follows:
80  * start with CONNMON_MAX_ID
81  * subtract MULTI resources because their counts include 0 resource (4)
82  * add CONNMON_AVAIL_BEARER_MAX resource instances
83  * add CONNMON_APN_MAX resource instances
84  * add CONNMON_IP_ADDRESS_MAX resource instances
85  * add CONNMON_ROUTER_IP_ADDRESS_MAX resource instances
86  */
87 #define RESOURCE_INSTANCE_COUNT        (CONNMON_MAX_ID - 4 + \
88 					CONNMON_AVAIL_BEARER_MAX + \
89 					CONNMON_APN_MAX + \
90 					CONNMON_IP_ADDRESS_MAX + \
91 					CONNMON_ROUTER_IP_ADDRESS_MAX)
92 
93 /* resource state variables */
94 static int8_t net_bearer;
95 static int16_t rss;
96 static int16_t link_quality;
97 static uint32_t cellid;
98 static uint16_t mnc;
99 static uint16_t mcc;
100 #if CONNMON_VERSION_MINOR > 0
101 static int32_t snr;
102 #endif
103 #if CONNMON_VERSION_MINOR > 1
104 static uint16_t lac;
105 #endif
106 #if CONNMON_VERSION_MINOR > 2
107 static uint8_t cel;
108 #endif
109 
110 /* only 1 instance of Connection Monitoring object exists */
111 static struct lwm2m_engine_obj connmon;
112 static struct lwm2m_engine_obj_field fields[] = {
113 	OBJ_FIELD_DATA(CONNMON_NETWORK_BEARER_ID, R, U8),
114 	OBJ_FIELD_DATA(CONNMON_AVAIL_NETWORK_BEARER_ID, R, U8),
115 	OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S16),
116 	OBJ_FIELD_DATA(CONNMON_LINK_QUALITY, R, S16),
117 	OBJ_FIELD_DATA(CONNMON_IP_ADDRESSES, R, STRING),
118 	OBJ_FIELD_DATA(CONNMON_ROUTER_IP_ADDRESSES, R_OPT, STRING),
119 	OBJ_FIELD_DATA(CONNMON_LINK_UTILIZATION, R_OPT, U8),
120 	OBJ_FIELD_DATA(CONNMON_APN, R_OPT, STRING),
121 	OBJ_FIELD_DATA(CONNMON_CELLID, R_OPT, U32),
122 	OBJ_FIELD_DATA(CONNMON_SMNC, R_OPT, U16),
123 	OBJ_FIELD_DATA(CONNMON_SMCC, R_OPT, U16),
124 #if CONNMON_VERSION_MINOR > 0
125 	OBJ_FIELD_DATA(CONNMON_SIGNAL_SNR, R_OPT, S32),
126 #endif
127 #if CONNMON_VERSION_MINOR > 1
128 	OBJ_FIELD_DATA(CONNMON_LAC, R_OPT, U16),
129 #endif
130 #if CONNMON_VERSION_MINOR > 2
131 	OBJ_FIELD_DATA(CONNMON_COVERAGE_ENHANCEMENT_LEVEL, R_OPT, U8),
132 #endif
133 };
134 
135 static struct lwm2m_engine_obj_inst inst;
136 static struct lwm2m_engine_res res[CONNMON_MAX_ID];
137 static struct lwm2m_engine_res_inst res_inst[RESOURCE_INSTANCE_COUNT];
138 
connmon_create(uint16_t obj_inst_id)139 static struct lwm2m_engine_obj_inst *connmon_create(uint16_t obj_inst_id)
140 {
141 	int i = 0, j = 0;
142 
143 	/* Set default values */
144 	net_bearer = 42U; /* Ethernet */
145 	rss = 0;
146 	link_quality = 0U;
147 	mnc = 0U;
148 	mcc = 0U;
149 #if CONNMON_VERSION_MINOR > 0
150 	snr = 0U;
151 #endif
152 #if CONNMON_VERSION_MINOR > 1
153 	lac = 0U;
154 #endif
155 #if CONNMON_VERSION_MINOR > 2
156 	cel = 0U;
157 #endif
158 
159 	init_res_instance(res_inst, ARRAY_SIZE(res_inst));
160 
161 	/* initialize instance resource data */
162 	INIT_OBJ_RES_DATA(CONNMON_NETWORK_BEARER_ID, res, i, res_inst, j,
163 			  &net_bearer, sizeof(net_bearer));
164 	INIT_OBJ_RES_MULTI_OPTDATA(CONNMON_AVAIL_NETWORK_BEARER_ID, res, i,
165 				   res_inst, j, CONNMON_AVAIL_BEARER_MAX,
166 				   false);
167 	INIT_OBJ_RES_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, res, i, res_inst, j,
168 			  &rss, sizeof(rss));
169 	INIT_OBJ_RES_DATA(CONNMON_LINK_QUALITY, res, i, res_inst, j,
170 			  &link_quality, sizeof(link_quality));
171 	INIT_OBJ_RES_MULTI_OPTDATA(CONNMON_IP_ADDRESSES, res, i,
172 				   res_inst, j, CONNMON_IP_ADDRESS_MAX, false);
173 	INIT_OBJ_RES_MULTI_OPTDATA(CONNMON_ROUTER_IP_ADDRESSES, res, i,
174 				   res_inst, j, CONNMON_ROUTER_IP_ADDRESS_MAX,
175 				   false);
176 	INIT_OBJ_RES_MULTI_OPTDATA(CONNMON_APN, res, i, res_inst, j,
177 				   CONNMON_APN_MAX, false);
178 	INIT_OBJ_RES_DATA(CONNMON_CELLID, res, i, res_inst, j, &cellid,
179 			  sizeof(cellid));
180 	INIT_OBJ_RES_DATA(CONNMON_SMNC, res, i, res_inst, j, &mnc, sizeof(mnc));
181 	INIT_OBJ_RES_DATA(CONNMON_SMCC, res, i, res_inst, j, &mcc, sizeof(mcc));
182 #if CONNMON_VERSION_MINOR > 0
183 	INIT_OBJ_RES_DATA(CONNMON_SIGNAL_SNR, res, i, res_inst, j, &snr, sizeof(snr));
184 #endif
185 #if CONNMON_VERSION_MINOR > 1
186 	INIT_OBJ_RES_DATA(CONNMON_LAC, res, i, res_inst, j, &lac, sizeof(lac));
187 #endif
188 #if CONNMON_VERSION_MINOR > 2
189 	INIT_OBJ_RES_DATA(CONNMON_COVERAGE_ENHANCEMENT_LEVEL, res, i, res_inst, j, &cel,
190 			  sizeof(cel));
191 #endif
192 	inst.resources = res;
193 	inst.resource_count = i;
194 	LOG_DBG("Create LWM2M connectivity monitoring instance: %d",
195 		obj_inst_id);
196 	return &inst;
197 }
198 
lwm2m_connmon_init(void)199 static int lwm2m_connmon_init(void)
200 {
201 	struct lwm2m_engine_obj_inst *obj_inst = NULL;
202 	int ret = 0;
203 
204 	/* initialize the Connection Monitoring field data */
205 	connmon.obj_id = LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID;
206 	connmon.version_major = CONNMON_VERSION_MAJOR;
207 	connmon.version_minor = CONNMON_VERSION_MINOR;
208 	connmon.is_core = true;
209 	connmon.fields = fields;
210 	connmon.field_count = ARRAY_SIZE(fields);
211 	connmon.max_instance_count = 1U;
212 	connmon.create_cb = connmon_create;
213 	lwm2m_register_obj(&connmon);
214 
215 	/* auto create the only instance */
216 	ret = lwm2m_create_obj_inst(LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID,
217 				    0, &obj_inst);
218 	if (ret < 0) {
219 		LOG_DBG("Create LWM2M instance 0 error: %d", ret);
220 	}
221 
222 	return ret;
223 }
224 
225 LWM2M_CORE_INIT(lwm2m_connmon_init);
226