• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uqmi/uqmi/commands-nas.c

  1 /*
  2  * uqmi -- tiny QMI support implementation
  3  *
  4  * Copyright (C) 2014-2015 Felix Fietkau <nbd@openwrt.org>
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the
 18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 19  * Boston, MA 02110-1301 USA.
 20  */
 21 
 22 #include "uqmi.h"
 23 #include "qmi-message.h"
 24 #include "commands.h"
 25 
 26 #include <libubox/blobmsg.h>
 27 
 28 /* According to libqmi, a value of -32768 in 5G
 29  * indicates that the modem is not connected. */
 30 #define _5GNR_NOT_CONNECTED_VALUE       -32768
 31 
 32 static struct qmi_nas_get_tx_rx_info_request tx_rx_req;
 33 static struct qmi_nas_set_system_selection_preference_request sel_req;
 34 static struct   {
 35         bool mcc_is_set;
 36         bool mnc_is_set;
 37 } plmn_code_flag;
 38 
 39 static void
 40 print_earfcn_info(uint32_t earfcn)
 41 {
 42         /* https://www.sqimway.com/lte_band.php */
 43         static const struct {
 44                 uint32_t    min;
 45                 uint32_t    max;
 46                 uint16_t    band;
 47                 uint16_t    freq;
 48                 const char *duplex;
 49         } earfcn_ranges[] = {
 50                 {     0,   599, 1,  2100, "FDD" },
 51                 {   600,  1199, 2,  1800, "FDD" },
 52                 {  1200,  1949, 3,  1800, "FDD" },
 53                 {  1950,  2399, 4,  1700, "FDD" },
 54                 {  2400,  2649, 5,  850,  "FDD" },
 55                 {  2650,  2749, 6,  800,  "FDD" },
 56                 {  2750,  3449, 7,  2600, "FDD" },
 57                 {  3450,  3799, 8,  900,  "FDD" },
 58                 {  3800,  4149, 9,  1800, "FDD" },
 59                 {  4150,  4749, 10, 1700, "FDD" },
 60                 {  4750,  4999, 11, 1500, "FDD" },
 61                 {  5000,  5179, 12, 700,  "FDD" },
 62                 {  5180,  5279, 13, 700,  "FDD" },
 63                 {  5280,  5379, 14, 700,  "FDD" },
 64                 {  5730,  5849, 17, 700,  "FDD" },
 65                 {  5850,  5999, 18, 850,  "FDD" },
 66                 {  6000,  6149, 19, 850,  "FDD" },
 67                 {  6150,  6449, 20, 800,  "FDD" },
 68                 {  6450,  6599, 21, 1500, "FDD" },
 69                 {  6600,  7399, 22, 3500, "FDD" },
 70                 {  7500,  7699, 23, 2000, "FDD" },
 71                 {  7700,  8039, 24, 1600, "FDD" },
 72                 {  8040,  8689, 25, 1900, "FDD" },
 73                 {  8690,  9039, 26, 850,  "FDD" },
 74                 {  9040,  9209, 27, 800,  "FDD" },
 75                 {  9210,  9659, 28, 700,  "FDD" },
 76                 {  9660,  9769, 29, 700,  "SDL" },
 77                 {  9770,  9869, 30, 2300, "FDD" },
 78                 {  9870,  9919, 31, 450,  "FDD" },
 79                 {  9920, 10359, 32, 1500, "SDL" },
 80                 { 36000, 36199, 33, 1900, "TDD" },
 81                 { 36200, 36349, 34, 2000, "TDD" },
 82                 { 36350, 36949, 35, 1900, "TDD" },
 83                 { 36950, 37549, 36, 1900, "TDD" },
 84                 { 37550, 37749, 37, 1900, "TDD" },
 85                 { 37750, 38249, 38, 2600, "TDD" },
 86                 { 38250, 38649, 39, 1900, "TDD" },
 87                 { 38650, 39649, 40, 2300, "TDD" },
 88                 { 39650, 41589, 41, 2500, "TDD" },
 89                 { 41590, 43589, 42, 3500, "TDD" },
 90                 { 43590, 45589, 43, 3700, "TDD" },
 91                 { 45590, 46589, 44, 700,  "TDD" },
 92         };
 93 
 94         for (int i = 0; i < (sizeof(earfcn_ranges) / sizeof(*earfcn_ranges)); i++) {
 95                 if (earfcn <= earfcn_ranges[i].max && earfcn >= earfcn_ranges[i].min) {
 96                         blobmsg_add_u32(&status, "band", earfcn_ranges[i].band);
 97                         blobmsg_add_u32(&status, "frequency", earfcn_ranges[i].freq);
 98                         blobmsg_add_string(&status, "duplex", earfcn_ranges[i].duplex);
 99                         return;
100                 }
101         }
102 }
103 
104 static char *
105 print_radio_interface(int8_t radio_interface)
106 {
107         switch (radio_interface) {
108                 case QMI_NAS_RADIO_INTERFACE_NONE:
109                         return "none";
110                 case QMI_NAS_RADIO_INTERFACE_CDMA_1X:
111                         return "cdma-1x";
112                 case QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO:
113                         return "cdma-1x_evdo";
114                 case QMI_NAS_RADIO_INTERFACE_AMPS:
115                         return "amps";
116                 case QMI_NAS_RADIO_INTERFACE_GSM:
117                         return "gsm";
118                 case QMI_NAS_RADIO_INTERFACE_UMTS:
119                         return "umts";
120                 case QMI_NAS_RADIO_INTERFACE_LTE:
121                         return "lte";
122                 case QMI_NAS_RADIO_INTERFACE_TD_SCDMA:
123                         return "td-scdma";
124                 case QMI_NAS_RADIO_INTERFACE_5GNR:
125                         return "5gnr";
126                 default:
127                         return "unknown";
128         }
129 }
130 
131 #define cmd_nas_do_set_system_selection_cb no_cb
132 static enum qmi_cmd_result
133 cmd_nas_do_set_system_selection_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
134 {
135         qmi_set_nas_set_system_selection_preference_request(msg, &sel_req);
136         return QMI_CMD_REQUEST;
137 }
138 
139 static enum qmi_cmd_result
140 do_sel_network(void)
141 {
142         static bool use_sel_req = false;
143 
144         if (!use_sel_req) {
145                 use_sel_req = true;
146                 uqmi_add_command(NULL, __UQMI_COMMAND_nas_do_set_system_selection);
147         }
148 
149         return QMI_CMD_DONE;
150 }
151 
152 #define cmd_nas_set_network_modes_cb no_cb
153 static enum qmi_cmd_result
154 cmd_nas_set_network_modes_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
155 {
156         static const struct {
157                 const char *name;
158                 QmiNasRatModePreference val;
159         } modes[] = {
160                 { "cdma", QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X | QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO },
161                 { "td-scdma", QMI_NAS_RAT_MODE_PREFERENCE_TD_SCDMA },
162                 { "gsm", QMI_NAS_RAT_MODE_PREFERENCE_GSM },
163                 { "umts", QMI_NAS_RAT_MODE_PREFERENCE_UMTS },
164                 { "lte", QMI_NAS_RAT_MODE_PREFERENCE_LTE },
165                 { "5gnr", QMI_NAS_RAT_MODE_PREFERENCE_5GNR },
166         };
167         QmiNasRatModePreference val = 0;
168         char *word;
169         int i;
170 
171         for (word = strtok(arg, ",");
172              word;
173              word = strtok(NULL, ",")) {
174                 bool found = false;
175 
176                 for (i = 0; i < ARRAY_SIZE(modes); i++) {
177                         if (strcmp(word, modes[i].name) != 0 &&
178                                 strcmp(word, "all") != 0)
179                                 continue;
180 
181                         val |= modes[i].val;
182                         found = true;
183                 }
184 
185                 if (!found) {
186                         uqmi_add_error("Invalid network mode");
187                         return QMI_CMD_EXIT;
188                 }
189         }
190 
191         qmi_set(&sel_req, mode_preference, val);
192         return do_sel_network();
193 }
194 
195 #define cmd_nas_set_network_preference_cb no_cb
196 static enum qmi_cmd_result
197 cmd_nas_set_network_preference_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
198 {
199         QmiNasGsmWcdmaAcquisitionOrderPreference pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC;
200 
201         if (!strcmp(arg, "gsm"))
202                 pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM;
203         else if (!strcmp(arg, "wcdma"))
204                 pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA;
205 
206         qmi_set(&sel_req, gsm_wcdma_acquisition_order_preference, pref);
207         return do_sel_network();
208 }
209 
210 #define cmd_nas_set_roaming_cb no_cb
211 static enum qmi_cmd_result
212 cmd_nas_set_roaming_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
213 {
214         QmiNasRoamingPreference pref;
215 
216         if (!strcmp(arg, "any"))
217                 pref = QMI_NAS_ROAMING_PREFERENCE_ANY;
218         else if (!strcmp(arg, "only"))
219                 pref = QMI_NAS_ROAMING_PREFERENCE_NOT_OFF;
220         else if (!strcmp(arg, "off"))
221                 pref = QMI_NAS_ROAMING_PREFERENCE_OFF;
222         else
223                 return uqmi_add_error("Invalid argument");
224 
225         qmi_set(&sel_req, roaming_preference, pref);
226         return do_sel_network();
227 }
228 
229 #define cmd_nas_set_mcc_cb no_cb
230 static enum qmi_cmd_result
231 cmd_nas_set_mcc_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
232 {
233         char *err;
234         int value = strtoul(arg, &err, 10);
235         if (err && *err) {
236                 uqmi_add_error("Invalid MCC value");
237                 return QMI_CMD_EXIT;
238         }
239 
240         sel_req.data.network_selection_preference.mcc = value;
241         plmn_code_flag.mcc_is_set = true;
242         return QMI_CMD_DONE;
243 }
244 
245 #define cmd_nas_set_mnc_cb no_cb
246 static enum qmi_cmd_result
247 cmd_nas_set_mnc_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
248 {
249         char *err;
250         int value = strtoul(arg, &err, 10);
251         if (err && *err) {
252                 uqmi_add_error("Invalid MNC value");
253                 return QMI_CMD_EXIT;
254         }
255 
256         sel_req.data.network_selection_preference.mnc = value;
257         plmn_code_flag.mnc_is_set = true;
258         return QMI_CMD_DONE;
259 }
260 
261 #define cmd_nas_set_plmn_cb no_cb
262 static enum qmi_cmd_result
263 cmd_nas_set_plmn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
264 {
265         sel_req.set.network_selection_preference = 1;
266         sel_req.data.network_selection_preference.mode = QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC;
267 
268         if (!plmn_code_flag.mcc_is_set && plmn_code_flag.mnc_is_set) {
269                 uqmi_add_error("No MCC value");
270                 return QMI_CMD_EXIT;
271         }
272 
273         if (plmn_code_flag.mcc_is_set && sel_req.data.network_selection_preference.mcc) {
274                 if (!plmn_code_flag.mnc_is_set) {
275                         uqmi_add_error("No MNC value");
276                         return QMI_CMD_EXIT;
277                 } else {
278                         sel_req.data.network_selection_preference.mode = QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL;
279                 }
280         }
281 
282         return do_sel_network();
283 }
284 
285 #define cmd_nas_initiate_network_register_cb no_cb
286 static enum qmi_cmd_result
287 cmd_nas_initiate_network_register_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
288 {
289         static struct qmi_nas_initiate_network_register_request register_req = {
290                 QMI_INIT(action, QMI_NAS_NETWORK_REGISTER_TYPE_AUTOMATIC)
291         };
292 
293         qmi_set_nas_initiate_network_register_request(msg, &register_req);
294         return QMI_CMD_REQUEST;
295 }
296 
297 static void
298 cmd_nas_get_signal_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
299 {
300         struct qmi_nas_get_signal_info_response res;
301         void *c, *a;
302         bool is_5gnr_connected = false;
303         bool is_5gnr_endc = false;
304 
305         qmi_parse_nas_get_signal_info_response(msg, &res);
306 
307         /* If 5G NR EN-DC (dual connectivity) is enabled, the mobile device has two connections,
308          * one with the LTE base station, and one with the NR base station.
309          * Therefore an array of signals has to be reported in this case. */
310         is_5gnr_connected = ((res.set._5g_signal_strength &&
311                 ((res.data._5g_signal_strength.rsrp != _5GNR_NOT_CONNECTED_VALUE) ||
312                  (res.data._5g_signal_strength.snr != _5GNR_NOT_CONNECTED_VALUE))) ||
313                 (res.set._5g_signal_strength_extended &&
314                 (res.data._5g_signal_strength_extended != _5GNR_NOT_CONNECTED_VALUE)));
315         is_5gnr_endc = (res.set.lte_signal_strength && is_5gnr_connected);
316 
317         if (is_5gnr_endc) {
318                 a = blobmsg_open_array(&status, NULL);
319         }
320 
321         c = blobmsg_open_table(&status, NULL);
322         if (res.set.cdma_signal_strength) {
323                 blobmsg_add_string(&status, "type", "cdma");
324                 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.cdma_signal_strength.rssi);
325                 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.cdma_signal_strength.ecio);
326         }
327 
328         if (res.set.hdr_signal_strength) {
329                 blobmsg_add_string(&status, "type", "hdr");
330                 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.hdr_signal_strength.rssi);
331                 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.hdr_signal_strength.ecio);
332                 blobmsg_add_u32(&status, "io", res.data.hdr_signal_strength.io);
333         }
334 
335         if (res.set.gsm_signal_strength) {
336                 blobmsg_add_string(&status, "type", "gsm");
337                 blobmsg_add_u32(&status, "signal", (int32_t) res.data.gsm_signal_strength);
338         }
339 
340         if (res.set.wcdma_signal_strength) {
341                 blobmsg_add_string(&status, "type", "wcdma");
342                 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.wcdma_signal_strength.rssi);
343                 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.wcdma_signal_strength.ecio);
344         }
345 
346         if (res.set.lte_signal_strength) {
347                 blobmsg_add_string(&status, "type", "lte");
348                 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.lte_signal_strength.rssi);
349                 blobmsg_add_u32(&status, "rsrq", (int32_t) res.data.lte_signal_strength.rsrq);
350                 blobmsg_add_u32(&status, "rsrp", (int32_t) res.data.lte_signal_strength.rsrp);
351                 blobmsg_add_double(&status, "snr", (double) res.data.lte_signal_strength.snr*0.1);
352         }
353 
354         if (res.set.tdma_signal_strength) {
355                 blobmsg_add_string(&status, "type", "tdma");
356                 blobmsg_add_u32(&status, "signal", (int32_t) res.data.tdma_signal_strength);
357         }
358 
359         if (is_5gnr_connected) {
360                 if (is_5gnr_endc) {
361                         blobmsg_close_table(&status, c);
362                         c = blobmsg_open_table(&status, NULL);
363                 }
364                 blobmsg_add_string(&status, "type", "5gnr");
365                 if (res.set._5g_signal_strength) {
366                         if (res.data._5g_signal_strength.rsrp != _5GNR_NOT_CONNECTED_VALUE)
367                                 blobmsg_add_u32(&status, "rsrp", (int32_t) res.data._5g_signal_strength.rsrp);
368                         if (res.data._5g_signal_strength.snr != _5GNR_NOT_CONNECTED_VALUE)
369                                 blobmsg_add_double(&status, "snr", (double) res.data._5g_signal_strength.snr*0.1);
370                 }
371 
372                 if (res.set._5g_signal_strength_extended &&
373                         (res.data._5g_signal_strength_extended != _5GNR_NOT_CONNECTED_VALUE)) {
374                         blobmsg_add_u32(&status, "rsrq", (int32_t) res.data._5g_signal_strength_extended);
375                 }
376         }
377 
378         blobmsg_close_table(&status, c);
379 
380         if (is_5gnr_endc) {
381                 blobmsg_close_array(&status, a);
382         }
383 }
384 
385 static void
386 print_system_info(uint8_t svc_status, uint8_t tsvc_status, bool preferred, bool system_info,
387                   bool domain_valid, uint8_t domain,
388                   bool service_cap_valid, uint8_t service_cap,
389                   bool roaming_status_valid, uint8_t roaming_status,
390                   bool forbidden_valid, bool forbidden,
391                   bool network_id_valid, char *mcc, char *mnc,
392                   bool lac_valid, uint16_t lac)
393 {
394         static const char *map_service[] = {
395                 [QMI_NAS_SERVICE_STATUS_NONE] = "none",
396                 [QMI_NAS_SERVICE_STATUS_LIMITED] = "limited",
397                 [QMI_NAS_SERVICE_STATUS_AVAILABLE] = "available",
398                 [QMI_NAS_SERVICE_STATUS_LIMITED_REGIONAL] = "limited regional",
399                 [QMI_NAS_SERVICE_STATUS_POWER_SAVE] = "power save",
400         };
401 
402         static const char *map_roaming[] = {
403                 [QMI_NAS_ROAMING_STATUS_OFF] = "off",
404                 [QMI_NAS_ROAMING_STATUS_ON] = "on",
405                 [QMI_NAS_ROAMING_STATUS_BLINK] = "blink",
406                 [QMI_NAS_ROAMING_STATUS_OUT_OF_NEIGHBORHOOD] = "out of neighborhood",
407                 [QMI_NAS_ROAMING_STATUS_OUT_OF_BUILDING] = "out of building",
408                 [QMI_NAS_ROAMING_STATUS_PREFERRED_SYSTEM] = "preferred system",
409                 [QMI_NAS_ROAMING_STATUS_AVAILABLE_SYSTEM] = "available system",
410                 [QMI_NAS_ROAMING_STATUS_ALLIANCE_PARTNER] = "alliance partner",
411                 [QMI_NAS_ROAMING_STATUS_PREMIUM_PARTNER] = "premium partner",
412                 [QMI_NAS_ROAMING_STATUS_FULL_SERVICE] = "full service",
413                 [QMI_NAS_ROAMING_STATUS_PARTIAL_SERVICE] = "partial service",
414                 [QMI_NAS_ROAMING_STATUS_BANNER_ON] = "banner on",
415                 [QMI_NAS_ROAMING_STATUS_BANNER_OFF] = "banner off",
416         };
417 
418         static const char *map_network[] = {
419                 [QMI_NAS_NETWORK_SERVICE_DOMAIN_NONE] = "none",
420                 [QMI_NAS_NETWORK_SERVICE_DOMAIN_CS] = "cs",
421                 [QMI_NAS_NETWORK_SERVICE_DOMAIN_PS] = "ps",
422                 [QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS] = "cs-ps",
423                 [QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN] = "unknown",
424                 };
425 
426         blobmsg_add_string(&status, "service_status", map_service[svc_status]);
427         blobmsg_add_string(&status, "true_service_status", map_service[tsvc_status]);
428         blobmsg_add_u8(&status, "preferred_data_path", preferred);
429 
430         if (system_info) {
431                 if (domain_valid)
432                         blobmsg_add_string(&status, "domain", map_network[domain]);
433                 if (service_cap_valid)
434                         blobmsg_add_string(&status, "service", map_network[service_cap]);
435                 if (roaming_status_valid)
436                         blobmsg_add_string(&status, "roaming_status", map_roaming[roaming_status]);
437                 if (forbidden_valid)
438                         blobmsg_add_u8(&status, "forbidden", forbidden);
439                 if (network_id_valid) {
440                         blobmsg_add_string(&status, "mcc", mcc);
441                         if ((uint8_t)mnc[2] == 255)
442                                 mnc[2] = 0;
443                         blobmsg_add_string(&status, "mnc", mnc);
444                 }
445                 if (lac_valid)
446                         blobmsg_add_u32(&status, "location_area_code", (int32_t) lac);
447         }
448 }
449 
450 static void
451 cmd_nas_get_system_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
452 {
453         static const char *cell_status[] = {
454                 [QMI_NAS_CELL_ACCESS_STATUS_NORMAL_ONLY] = "normal",
455                 [QMI_NAS_CELL_ACCESS_STATUS_EMERGENCY_ONLY] = "emergency",
456                 [QMI_NAS_CELL_ACCESS_STATUS_NO_CALLS] = "no calls",
457                 [QMI_NAS_CELL_ACCESS_STATUS_ALL_CALLS] = "all calls",
458                 [QMI_NAS_CELL_ACCESS_STATUS_UNKNOWN] = "unknown",
459         };
460 
461         struct qmi_nas_get_system_info_response res;
462         void *c, *t;
463 
464         qmi_parse_nas_get_system_info_response(msg, &res);
465         t = blobmsg_open_table(&status, NULL);
466         if (res.set.gsm_service_status) {
467                 c = blobmsg_open_table(&status, "gsm");
468                 print_system_info(res.data.gsm_service_status.service_status,
469                                   res.data.gsm_service_status.true_service_status,
470                                   res.data.gsm_service_status.preferred_data_path,
471                                   res.set.gsm_system_info_v2,
472                                   res.data.gsm_system_info_v2.domain_valid,
473                                   res.data.gsm_system_info_v2.domain,
474                                   res.data.gsm_system_info_v2.service_capability_valid,
475                                   res.data.gsm_system_info_v2.service_capability,
476                                   res.data.gsm_system_info_v2.roaming_status_valid,
477                                   res.data.gsm_system_info_v2.roaming_status,
478                                   res.data.gsm_system_info_v2.forbidden_valid,
479                                   res.data.gsm_system_info_v2.forbidden,
480                                   res.data.gsm_system_info_v2.network_id_valid,
481                                   res.data.gsm_system_info_v2.mcc,
482                                   res.data.gsm_system_info_v2.mnc,
483                                   res.data.gsm_system_info_v2.lac_valid,
484                                   res.data.gsm_system_info_v2.lac);
485                 if (res.set.gsm_system_info_v2 && res.data.gsm_system_info_v2.cid_valid)
486                         blobmsg_add_u32(&status, "cell_id",
487                                         res.data.gsm_system_info_v2.cid);
488                 if (res.set.additional_gsm_system_info &&
489                     res.data.additional_gsm_system_info.geo_system_index != 0xFFFF)
490                         blobmsg_add_u32(&status, "geo_system_index",
491                                         res.data.additional_gsm_system_info.geo_system_index);
492                 blobmsg_close_table(&status, c);
493         }
494 
495         if (res.set.wcdma_service_status) {
496                 c = blobmsg_open_table(&status, "wcdma");
497                 print_system_info(res.data.wcdma_service_status.service_status,
498                                   res.data.wcdma_service_status.true_service_status,
499                                   res.data.wcdma_service_status.preferred_data_path,
500                                   res.set.wcdma_system_info_v2,
501                                   res.data.wcdma_system_info_v2.domain_valid,
502                                   res.data.wcdma_system_info_v2.domain,
503                                   res.data.wcdma_system_info_v2.service_capability_valid,
504                                   res.data.wcdma_system_info_v2.service_capability,
505                                   res.data.wcdma_system_info_v2.roaming_status_valid,
506                                   res.data.wcdma_system_info_v2.roaming_status,
507                                   res.data.wcdma_system_info_v2.forbidden_valid,
508                                   res.data.wcdma_system_info_v2.forbidden,
509                                   res.data.wcdma_system_info_v2.network_id_valid,
510                                   res.data.wcdma_system_info_v2.mcc,
511                                   res.data.wcdma_system_info_v2.mnc,
512                                   res.data.wcdma_system_info_v2.lac_valid,
513                                   res.data.wcdma_system_info_v2.lac);
514                 if (res.set.wcdma_system_info_v2 && res.data.wcdma_system_info_v2.cid_valid) {
515                         blobmsg_add_u32(&status, "rnc_id",res.data.wcdma_system_info_v2.cid/65536);
516                         blobmsg_add_u32(&status, "cell_id",res.data.wcdma_system_info_v2.cid%65536);
517                 }
518                 if (res.set.additional_wcdma_system_info &&
519                     res.data.additional_wcdma_system_info.geo_system_index != 0xFFFF)
520                         blobmsg_add_u32(&status, "geo_system_index",
521                                         res.data.additional_wcdma_system_info.geo_system_index);
522                 blobmsg_close_table(&status, c);
523         }
524 
525         if (res.set.lte_service_status) {
526                 c = blobmsg_open_table(&status, "lte");
527                 print_system_info(res.data.lte_service_status.service_status,
528                                   res.data.lte_service_status.true_service_status,
529                                   res.data.lte_service_status.preferred_data_path,
530                                   res.set.lte_system_info_v2,
531                                   res.data.lte_system_info_v2.domain_valid,
532                                   res.data.lte_system_info_v2.domain,
533                                   res.data.lte_system_info_v2.service_capability_valid,
534                                   res.data.lte_system_info_v2.service_capability,
535                                   res.data.lte_system_info_v2.roaming_status_valid,
536                                   res.data.lte_system_info_v2.roaming_status,
537                                   res.data.lte_system_info_v2.forbidden_valid,
538                                   res.data.lte_system_info_v2.forbidden,
539                                   res.data.lte_system_info_v2.network_id_valid,
540                                   res.data.lte_system_info_v2.mcc,
541                                   res.data.lte_system_info_v2.mnc,
542                                   res.data.lte_system_info_v2.lac_valid,
543                                   res.data.lte_system_info_v2.lac);
544                 if (res.set.lte_system_info_v2 && res.data.lte_system_info_v2.tac_valid)
545                         blobmsg_add_u32(&status, "tracking_area_code",
546                                         res.data.lte_system_info_v2.tac);
547                 if (res.set.lte_system_info_v2 && res.data.lte_system_info_v2.cid_valid) {
548                         blobmsg_add_u32(&status, "enodeb_id",res.data.lte_system_info_v2.cid/256);
549                         blobmsg_add_u32(&status, "cell_id",res.data.lte_system_info_v2.cid%256);
550                 }
551                 if (res.set.additional_lte_system_info &&
552                     res.data.additional_lte_system_info.geo_system_index != 0xFFFF)
553                         blobmsg_add_u32(&status, "geo_system_index",
554                                         res.data.additional_lte_system_info.geo_system_index);
555                 if (res.set.lte_voice_support)
556                         blobmsg_add_u8(&status, "voice_support", res.data.lte_voice_support);
557                 if (res.set.ims_voice_support)
558                         blobmsg_add_u8(&status, "ims_voice_support", res.data.ims_voice_support);
559                 if (res.set.lte_cell_access_status)
560                         blobmsg_add_string(&status, "cell_access_status",
561                                            cell_status[res.data.lte_cell_access_status]);
562                 if (res.set.network_selection_registration_restriction)
563                         blobmsg_add_u32(&status, "registration_restriction",
564                                         res.data.network_selection_registration_restriction);
565                 if (res.set.lte_registration_domain)
566                         blobmsg_add_u32(&status, "registration_domain",
567                                         res.data.lte_registration_domain);
568                 if (res.set.eutra_with_nr5g_availability)
569                         blobmsg_add_u8(&status, "5g_nsa_available",
570                                        res.data.eutra_with_nr5g_availability);
571                 if (res.set.dcnr_restriction_info)
572                         blobmsg_add_u8(&status, "dcnr_restriction", res.data.dcnr_restriction_info);
573 
574                 blobmsg_close_table(&status, c);
575         }
576 
577         if (res.set.nr5g_service_status_info) {
578                 c = blobmsg_open_table(&status, "5gnr");
579                 print_system_info(res.data.nr5g_service_status_info.service_status,
580                                   res.data.nr5g_service_status_info.true_service_status,
581                                   res.data.nr5g_service_status_info.preferred_data_path,
582                                   res.set.nr5g_system_info,
583                                   res.data.nr5g_system_info.domain_valid,
584                                   res.data.nr5g_system_info.domain,
585                                   res.data.nr5g_system_info.service_capability_valid,
586                                   res.data.nr5g_system_info.service_capability,
587                                   res.data.nr5g_system_info.roaming_status_valid,
588                                   res.data.nr5g_system_info.roaming_status,
589                                   res.data.nr5g_system_info.forbidden_valid,
590                                   res.data.nr5g_system_info.forbidden,
591                                   res.data.nr5g_system_info.network_id_valid,
592                                   res.data.nr5g_system_info.mcc,
593                                   res.data.nr5g_system_info.mnc,
594                                   res.data.nr5g_system_info.lac_valid,
595                                   res.data.nr5g_system_info.lac);
596                 if (res.set.nr5g_system_info && res.data.nr5g_system_info.tac_valid)
597                         blobmsg_add_u32(&status, "tracking_area_code",
598                                         res.data.nr5g_system_info.tac);
599                 if (res.set.nr5g_system_info && res.data.nr5g_system_info.cid_valid) {
600                         blobmsg_add_u32(&status, "enodeb_id",res.data.nr5g_system_info.cid/256);
601                         blobmsg_add_u32(&status, "cell_id",res.data.nr5g_system_info.cid%256);
602                 }
603 
604                 blobmsg_close_table(&status, c);
605         }
606 
607         blobmsg_close_table(&status, t);
608 }
609 
610 static enum qmi_cmd_result
611 cmd_nas_get_system_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
612 {
613         qmi_set_nas_get_system_info_request(msg);
614         return QMI_CMD_REQUEST;
615 }
616 
617 static void
618 print_channel_info(int32_t cell_id, int32_t channel, uint32_t bw)
619 {
620         static const char *map_bandwidth[] = {
621                 [QMI_NAS_DL_BANDWIDTH_1_4] = "1.4",
622                 [QMI_NAS_DL_BANDWIDTH_3] = "3",
623                 [QMI_NAS_DL_BANDWIDTH_5] = "5",
624                 [QMI_NAS_DL_BANDWIDTH_10] = "10",
625                 [QMI_NAS_DL_BANDWIDTH_15] = "15",
626                 [QMI_NAS_DL_BANDWIDTH_20] = "20",
627                 [QMI_NAS_DL_BANDWIDTH_INVALID] = "invalid",
628                 [QMI_NAS_DL_BANDWIDTH_UNKNOWN] = "unknown",
629         };
630 
631         blobmsg_add_u32(&status, "cell_id", cell_id);
632         blobmsg_add_u32(&status, "channel", channel);
633         print_earfcn_info(channel);
634         blobmsg_add_string(&status, "bandwidth", map_bandwidth[bw]);
635 }
636 
637 static void
638 cmd_nas_get_lte_cphy_ca_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
639 {
640         struct qmi_nas_get_lte_cphy_ca_info_response res;
641         static const char *scell_state[] = {
642                 [QMI_NAS_SCELL_STATE_DECONFIGURED] = "deconfigured",
643                 [QMI_NAS_SCELL_STATE_DEACTIVATED] = "deactivated",
644                 [QMI_NAS_SCELL_STATE_ACTIVATED] = "activated",
645         };
646         char idx_buf[16];
647         void *t, *c;
648         int i;
649 
650         qmi_parse_nas_get_lte_cphy_ca_info_response(msg, &res);
651         t = blobmsg_open_table(&status, NULL);
652         if (res.set.phy_ca_agg_pcell_info) {
653                 c = blobmsg_open_table(&status, "primary");
654                 print_channel_info(res.data.phy_ca_agg_pcell_info.physical_cell_id,
655                                    res.data.phy_ca_agg_pcell_info.rx_channel,
656                                    res.data.phy_ca_agg_pcell_info.dl_bandwidth);
657                 blobmsg_close_table(&status, c);
658         }
659         if (res.set.phy_ca_agg_scell_info && res.data.phy_ca_agg_secondary_cells_n) {
660                 for (i = 0; i < res.data.phy_ca_agg_secondary_cells_n; i++) {
661                         if (res.data.phy_ca_agg_secondary_cells[i].rx_channel == 0)
662                                 break;
663                         sprintf(idx_buf, "secondary_%d",
664                                 res.data.phy_ca_agg_secondary_cells[i].cell_index);
665                         c = blobmsg_open_table(&status, idx_buf);
666                         print_channel_info(res.data.phy_ca_agg_secondary_cells[i].physical_cell_id,
667                                            res.data.phy_ca_agg_secondary_cells[i].rx_channel,
668                                            res.data.phy_ca_agg_secondary_cells[i].dl_bandwidth);
669                         blobmsg_add_string(&status, "state",
670                                            scell_state[res.data.phy_ca_agg_secondary_cells[i].state]);
671                         blobmsg_close_table(&status, c);
672                 }
673         } else {
674                 if (res.set.scell_index)
675                         sprintf(idx_buf, "secondary_%d", res.data.scell_index);
676                 else
677                         sprintf(idx_buf, "secondary");
678                 if (res.set.phy_ca_agg_scell_info && res.data.phy_ca_agg_scell_info.rx_channel != 0) {
679                         c = blobmsg_open_table(&status, idx_buf);
680                         print_channel_info(res.data.phy_ca_agg_scell_info.physical_cell_id,
681                                            res.data.phy_ca_agg_scell_info.rx_channel,
682                                            res.data.phy_ca_agg_scell_info.dl_bandwidth);
683                         blobmsg_add_string(&status, "state",
684                                            scell_state[res.data.phy_ca_agg_scell_info.state]);
685                         blobmsg_close_table(&status, c);
686                 }
687         }
688         blobmsg_close_table(&status, t);
689 }
690 
691 static enum qmi_cmd_result
692 cmd_nas_get_lte_cphy_ca_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
693 {
694         qmi_set_nas_get_lte_cphy_ca_info_request(msg);
695         return QMI_CMD_REQUEST;
696 }
697 
698 static void
699 print_chain_info(int8_t radio, bool tuned, int32_t rssi, int32_t ecio, int32_t rsrp, int32_t rscp, uint32_t phase)
700 {
701         blobmsg_add_u8(&status, "tuned", tuned);
702         blobmsg_add_double(&status, "rssi", (double) rssi*0.1);
703         if (radio == QMI_NAS_RADIO_INTERFACE_5GNR) {
704                 blobmsg_add_double(&status, "rsrp", (double) rsrp*-0.1);
705         }
706         else if (radio == QMI_NAS_RADIO_INTERFACE_LTE) {
707                 blobmsg_add_double(&status, "rsrq", (double) ecio*-0.1);
708                 blobmsg_add_double(&status, "rsrp", (double) rsrp*-0.1);
709         }
710         else if (radio == QMI_NAS_RADIO_INTERFACE_UMTS) {
711                 blobmsg_add_double(&status, "ecio", (double) ecio*-0.1);
712                 blobmsg_add_double(&status, "rscp", (double) rscp*-0.1);
713         }
714         if (phase != 0xFFFFFFFF)
715                 blobmsg_add_double(&status, "phase", (double) phase*0.01);
716 }
717 
718 static void
719 cmd_nas_get_tx_rx_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
720 {
721         struct qmi_nas_get_tx_rx_info_response res;
722         void *c, *t;
723 
724         qmi_parse_nas_get_tx_rx_info_response(msg, &res);
725         t = blobmsg_open_table(&status, NULL);
726         if (res.set.rx_chain_0_info) {
727                 c = blobmsg_open_table(&status, "rx_chain_0");
728                 print_chain_info(tx_rx_req.data.radio_interface,
729                                  res.data.rx_chain_0_info.is_radio_tuned,
730                                  res.data.rx_chain_0_info.rx_power,
731                                  res.data.rx_chain_0_info.ecio,
732                                  res.data.rx_chain_0_info.rsrp,
733                                  res.data.rx_chain_0_info.rscp,
734                                  res.data.rx_chain_0_info.phase);
735                 blobmsg_close_table(&status, c);
736         }
737         if (res.set.rx_chain_1_info) {
738                 c = blobmsg_open_table(&status, "rx_chain_1");
739                 print_chain_info(tx_rx_req.data.radio_interface,
740                                  res.data.rx_chain_1_info.is_radio_tuned,
741                                  res.data.rx_chain_1_info.rx_power,
742                                  res.data.rx_chain_1_info.ecio,
743                                  res.data.rx_chain_1_info.rsrp,
744                                  res.data.rx_chain_1_info.rscp,
745                                  res.data.rx_chain_1_info.phase);
746                 blobmsg_close_table(&status, c);
747         }
748         if (res.set.rx_chain_2_info) {
749                 c = blobmsg_open_table(&status, "rx_chain_2");
750                 print_chain_info(tx_rx_req.data.radio_interface,
751                                  res.data.rx_chain_2_info.is_radio_tuned,
752                                  res.data.rx_chain_2_info.rx_power,
753                                  res.data.rx_chain_2_info.ecio,
754                                  res.data.rx_chain_2_info.rsrp,
755                                  res.data.rx_chain_2_info.rscp,
756                                  res.data.rx_chain_2_info.phase);
757                 blobmsg_close_table(&status, c);
758         }
759         if (res.set.rx_chain_3_info) {
760                 c = blobmsg_open_table(&status, "rx_chain_3");
761                 print_chain_info(tx_rx_req.data.radio_interface,
762                                  res.data.rx_chain_3_info.is_radio_tuned,
763                                  res.data.rx_chain_3_info.rx_power,
764                                  res.data.rx_chain_3_info.ecio,
765                                  res.data.rx_chain_3_info.rsrp,
766                                  res.data.rx_chain_3_info.rscp,
767                                  res.data.rx_chain_3_info.phase);
768                 blobmsg_close_table(&status, c);
769         }
770         if (res.set.tx_info) {
771                 c = blobmsg_open_table(&status, "tx");
772                 blobmsg_add_u8(&status, "traffic", res.data.tx_info.is_in_traffic);
773                 if (res.data.tx_info.is_in_traffic)
774                         blobmsg_add_double(&status, "tx_power",
775                                            (double) res.data.tx_info.tx_power*0.1);
776                 blobmsg_close_table(&status, c);
777         }
778         blobmsg_close_table(&status, t);
779 }
780 
781 
782 static enum qmi_cmd_result
783 cmd_nas_get_tx_rx_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
784 {
785         int radio = 0;
786 
787         if (!strcmp(arg, "5gnr"))
788                 radio = QMI_NAS_RADIO_INTERFACE_5GNR;
789         else if (!strcmp(arg, "lte"))
790                 radio = QMI_NAS_RADIO_INTERFACE_LTE;
791         else if (!strcmp(arg, "umts"))
792                 radio = QMI_NAS_RADIO_INTERFACE_UMTS;
793         else if (!strcmp(arg, "gsm"))
794                 radio = QMI_NAS_RADIO_INTERFACE_GSM;
795         else
796                 return uqmi_add_error("Invalid argument");
797 
798         qmi_set(&tx_rx_req, radio_interface, radio);
799         qmi_set_nas_get_tx_rx_info_request(msg, &tx_rx_req);
800         return QMI_CMD_REQUEST;
801 }
802 
803 static void
804 print_lte_info(int32_t cell_id, int16_t rsrp, int16_t rsrq, int16_t rssi)
805 {
806         blobmsg_add_u32(&status, "physical_cell_id", cell_id);
807         blobmsg_add_double(&status, "rsrq", ((double)rsrq)/10);
808         blobmsg_add_double(&status, "rsrp", ((double)rsrp)/10);
809         blobmsg_add_double(&status, "rssi", ((double)rssi)/10);
810 }
811 
812 static void
813 print_sel_info(int32_t priority, int32_t high, int32_t low)
814 {
815         blobmsg_add_u32(&status, "cell_reselection_priority", priority);
816         blobmsg_add_u32(&status, "cell_reselection_low", low);
817         blobmsg_add_u32(&status, "cell_reselection_high", high);
818 }
819 
820 static void
821 cmd_nas_get_cell_location_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
822 {
823         struct qmi_nas_get_cell_location_info_response res;
824         void *c = NULL, *t, *cell, *freq;
825         int i, j;
826 
827         qmi_parse_nas_get_cell_location_info_response(msg, &res);
828         t = blobmsg_open_table(&status, NULL);
829 
830         if (res.set.umts_info_v2) {
831                 c = blobmsg_open_table(&status, "umts_info");
832                 blobmsg_add_u32(&status, "location_area_code", res.data.umts_info_v2.lac);
833                 blobmsg_add_u32(&status, "cell_id", res.data.umts_info_v2.cell_id);
834                 blobmsg_add_u32(&status, "channel",
835                                 res.data.umts_info_v2.utra_absolute_rf_channel_number);
836                 blobmsg_add_u32(&status, "primary_scrambling_code",
837                                 res.data.umts_info_v2.primary_scrambling_code);
838                 blobmsg_add_u32(&status, "rscp", res.data.umts_info_v2.rscp);
839                 blobmsg_add_u32(&status, "ecio", res.data.umts_info_v2.ecio);
840                 for (j = 0; j < res.data.umts_info_v2.cell_n; j++) {
841                         cell = blobmsg_open_table(&status, NULL);
842                         blobmsg_add_u32(&status, "channel",
843                                         res.data.umts_info_v2.cell[j].utra_absolute_rf_channel_number);
844                         blobmsg_add_u32(&status, "primary_scrambling_code",
845                                         res.data.umts_info_v2.cell[j].primary_scrambling_code);
846                         blobmsg_add_u32(&status, "rscp", res.data.umts_info_v2.cell[j].rscp);
847                         blobmsg_add_u32(&status, "ecio", res.data.umts_info_v2.cell[j].ecio);
848                         blobmsg_close_table(&status, cell);
849                 }
850                 for (j = 0; j < res.data.umts_info_v2.neighboring_geran_n; j++) {
851                         cell = blobmsg_open_table(&status, "neighboring_geran");
852                         blobmsg_add_u32(&status, "channel",
853                                         res.data.umts_info_v2.neighboring_geran[j].geran_absolute_rf_channel_number);
854                         blobmsg_add_u8(&status, "network_color_code",
855                                        res.data.umts_info_v2.neighboring_geran[j].network_color_code);
856                         blobmsg_add_u8(&status, "base_station_color_code",
857                                        res.data.umts_info_v2.neighboring_geran[j].base_station_color_code);
858                         blobmsg_add_u32(&status, "rssi",
859                                         res.data.umts_info_v2.neighboring_geran[j].rssi);
860                         blobmsg_close_table(&status, cell);
861                 }
862                 blobmsg_close_table(&status, c);
863         }
864         if (res.set.intrafrequency_lte_info_v2) {
865                 c = blobmsg_open_table(&status, "intrafrequency_lte_info");
866                 blobmsg_add_u32(&status, "tracking_area_code",
867                                 res.data.intrafrequency_lte_info_v2.tracking_area_code);
868                 blobmsg_add_u32(&status, "enodeb_id",
869                                 res.data.intrafrequency_lte_info_v2.global_cell_id/256);
870                 blobmsg_add_u32(&status, "cell_id",
871                                 res.data.intrafrequency_lte_info_v2.global_cell_id%256);
872                 blobmsg_add_u32(&status, "channel",
873                                 res.data.intrafrequency_lte_info_v2.eutra_absolute_rf_channel_number);
874                 print_earfcn_info(res.data.intrafrequency_lte_info_v2.eutra_absolute_rf_channel_number);
875                 blobmsg_add_u32(&status, "serving_cell_id",
876                                 res.data.intrafrequency_lte_info_v2.serving_cell_id);
877                 if (res.data.intrafrequency_lte_info_v2.ue_in_idle) {
878                         blobmsg_add_u32(&status, "cell_reselection_priority",
879                                         res.data.intrafrequency_lte_info_v2.cell_reselection_priority);
880                         blobmsg_add_u32(&status, "s_non_intra_search_threshold",
881                                         res.data.intrafrequency_lte_info_v2.s_non_intra_search_threshold);
882                         blobmsg_add_u32(&status, "serving_cell_low_threshold",
883                                         res.data.intrafrequency_lte_info_v2.serving_cell_low_threshold);
884                         blobmsg_add_u32(&status, "s_intra_search_threshold",
885                                         res.data.intrafrequency_lte_info_v2.s_intra_search_threshold);
886                 }
887                 for (i = 0; i < res.data.intrafrequency_lte_info_v2.cell_n; i++) {
888                         cell = blobmsg_open_table(&status, NULL);
889                         print_lte_info(res.data.intrafrequency_lte_info_v2.cell[i].physical_cell_id,
890                                        res.data.intrafrequency_lte_info_v2.cell[i].rsrq,
891                                        res.data.intrafrequency_lte_info_v2.cell[i].rsrp,
892                                        res.data.intrafrequency_lte_info_v2.cell[i].rssi);
893                         if (res.data.intrafrequency_lte_info_v2.ue_in_idle)
894                                 blobmsg_add_u32(&status, "cell_selection_rx_level",
895                                                 res.data.intrafrequency_lte_info_v2.cell[i].cell_selection_rx_level);
896                         blobmsg_close_table(&status, cell);
897                 }
898                 blobmsg_close_table(&status, c);
899         }
900         if (res.set.interfrequency_lte_info) {
901                 if (res.data.interfrequency_lte_info.frequency_n > 0)
902                         c = blobmsg_open_table(&status, "interfrequency_lte_info");
903                 for (i = 0; i < res.data.interfrequency_lte_info.frequency_n; i++) {
904                         freq = blobmsg_open_table(&status, NULL);
905                         blobmsg_add_u32(&status, "channel",
906                                         res.data.interfrequency_lte_info.frequency[i].eutra_absolute_rf_channel_number);
907                         print_earfcn_info(res.data.interfrequency_lte_info.frequency[i].eutra_absolute_rf_channel_number);
908                         if (res.data.interfrequency_lte_info.ue_in_idle) {
909                                 print_sel_info(res.data.interfrequency_lte_info.frequency[i].cell_reselection_priority,
910                                                res.data.interfrequency_lte_info.frequency[i].cell_selection_rx_level_high_threshold,
911                                                res.data.interfrequency_lte_info.frequency[i].cell_selection_rx_level_low_threshold);
912                         }
913                         for (j = 0; j < res.data.interfrequency_lte_info.frequency[i].cell_n; j++) {
914                                 cell = blobmsg_open_table(&status, NULL);
915                                 print_lte_info(res.data.interfrequency_lte_info.frequency[i].cell[j].physical_cell_id,
916                                                res.data.interfrequency_lte_info.frequency[i].cell[j].rsrq,
917                                                res.data.interfrequency_lte_info.frequency[i].cell[j].rsrp,
918                                                res.data.interfrequency_lte_info.frequency[i].cell[j].rssi);
919                                 if (res.data.interfrequency_lte_info.ue_in_idle)
920                                         blobmsg_add_u32(&status, "cell_selection_rx_level",
921                                                         res.data.interfrequency_lte_info.frequency[i].cell[j].cell_selection_rx_level);
922                                 blobmsg_close_table(&status, cell);
923                         }
924                         blobmsg_close_table(&status, freq);
925                 }
926                 if (res.data.interfrequency_lte_info.frequency_n > 0)
927                         blobmsg_close_table(&status, c);
928         }
929         if (res.set.lte_info_neighboring_gsm) {
930                 if (res.data.lte_info_neighboring_gsm.frequency_n > 0)
931                         c = blobmsg_open_table(&status, "lte_info_neighboring_gsm");
932                 for (i = 0; i < res.data.lte_info_neighboring_gsm.frequency_n; i++) {
933                         freq = blobmsg_open_table(&status, NULL);
934                         blobmsg_add_u32(&status, "ncc_permitted",
935                                         res.data.lte_info_neighboring_gsm.frequency[i].ncc_permitted);
936                         if (res.data.lte_info_neighboring_gsm.ue_in_idle) {
937                                 print_sel_info(res.data.lte_info_neighboring_gsm.frequency[i].cell_reselection_priority,
938                                                res.data.lte_info_neighboring_gsm.frequency[i].cell_reselection_high_threshold,
939                                                res.data.lte_info_neighboring_gsm.frequency[i].cell_reselection_low_threshold);
940                         }
941                         for (j = 0; j < res.data.lte_info_neighboring_gsm.frequency[i].cell_n; j++) {
942                                 cell = blobmsg_open_table(&status, NULL);
943                                 blobmsg_add_u32(&status, "channel",
944                                                 res.data.lte_info_neighboring_gsm.frequency[i].cell[j].geran_absolute_rf_channel_number);
945                                 blobmsg_add_u32(&status, "base_station_identity_code",
946                                                 res.data.lte_info_neighboring_gsm.frequency[i].cell[j].base_station_identity_code);
947                                 blobmsg_add_double(&status, "rssi",
948                                                    ((double)res.data.lte_info_neighboring_gsm.frequency[i].cell[j].rssi)/10);
949                                 if (res.data.lte_info_neighboring_gsm.ue_in_idle)
950                                         blobmsg_add_u32(&status, "cell_selection_rx_level",
951                                                         res.data.lte_info_neighboring_gsm.frequency[i].cell[j].cell_selection_rx_level);
952                                 blobmsg_close_table(&status, cell);
953                         }
954                         blobmsg_close_table(&status, freq);
955                 }
956                 if (res.data.lte_info_neighboring_gsm.frequency_n > 0)
957                         blobmsg_close_table(&status, c);
958         }
959         if (res.set.lte_info_neighboring_wcdma) {
960                 if (res.data.lte_info_neighboring_wcdma.frequency_n > 0)
961                         c = blobmsg_open_table(&status, "lte_info_neighboring_wcdma");
962                 for (i = 0; i < res.data.lte_info_neighboring_wcdma.frequency_n; i++) {
963                         freq = blobmsg_open_table(&status, NULL);
964                         blobmsg_add_u32(&status, "channel",
965                                         res.data.lte_info_neighboring_wcdma.frequency[i].utra_absolute_rf_channel_number);
966                         if (res.data.lte_info_neighboring_wcdma.ue_in_idle) {
967                                 print_sel_info(res.data.lte_info_neighboring_wcdma.frequency[i].cell_reselection_priority,
968                                                res.data.lte_info_neighboring_wcdma.frequency[i].cell_reselection_high_threshold,
969                                                res.data.lte_info_neighboring_wcdma.frequency[i].cell_reselection_low_threshold);
970                         }
971                         for (j = 0; j < res.data.lte_info_neighboring_wcdma.frequency[i].cell_n; j++) {
972                                 cell = blobmsg_open_table(&status, NULL);
973                                 blobmsg_add_u32(&status, "primary_scrambling_code",
974                                                 res.data.lte_info_neighboring_wcdma.frequency[i].cell[j].primary_scrambling_code);
975                                 blobmsg_add_double(&status, "rscp",
976                                                    ((double)res.data.lte_info_neighboring_wcdma.frequency[i].cell[j].cpich_rscp)/10);
977                                 blobmsg_add_double(&status, "ecno",
978                                                    ((double)res.data.lte_info_neighboring_wcdma.frequency[i].cell[j].cpich_ecno)/10);
979                                 if (res.data.lte_info_neighboring_wcdma.ue_in_idle)
980                                         blobmsg_add_u32(&status, "cell_selection_rx_level",
981                                                         res.data.lte_info_neighboring_wcdma.frequency[i].cell[j].cell_selection_rx_level);
982                                 blobmsg_close_table(&status, cell);
983                         }
984                         blobmsg_close_table(&status, freq);
985                 }
986                 if (res.data.lte_info_neighboring_wcdma.frequency_n > 0)
987                         blobmsg_close_table(&status, c);
988         }
989         if (res.set.umts_info_neighboring_lte) {
990                 if (res.data.umts_info_neighboring_lte.frequency_n > 0)
991                         c = blobmsg_open_table(&status, "umts_info_neighboring_lte");
992                 for (i = 0; i < res.data.umts_info_neighboring_lte.frequency_n; i++) {
993                         freq = blobmsg_open_table(&status, NULL);
994                         blobmsg_add_u32(&status, "channel",
995                                         res.data.umts_info_neighboring_lte.frequency[i].eutra_absolute_rf_channel_number);
996                         print_earfcn_info(res.data.umts_info_neighboring_lte.frequency[i].eutra_absolute_rf_channel_number);
997                         blobmsg_add_u32(&status, "physical_cell_id",
998                                         res.data.umts_info_neighboring_lte.frequency[i].physical_cell_id);
999                         blobmsg_add_double(&status, "rsrp",
1000                                            (double) res.data.umts_info_neighboring_lte.frequency[i].rsrp);
1001                         blobmsg_add_double(&status, "rsrq",
1002                                            (double) res.data.umts_info_neighboring_lte.frequency[i].rsrq);
1003                         blobmsg_add_u32(&status, "cell_selection_rx_level",
1004                                         res.data.umts_info_neighboring_lte.frequency[i].cell_selection_rx_level);
1005                         blobmsg_close_table(&status, freq);
1006                 }
1007                 if (res.data.umts_info_neighboring_lte.frequency_n > 0)
1008                         blobmsg_close_table(&status, c);
1009         }
1010         if (res.set.nr5g_cell_information) {
1011                 c = blobmsg_open_table(&status, "nr5g_cell_information");
1012                 blobmsg_add_u32(&status, "enodeb_id",
1013                                 res.data.nr5g_cell_information.global_cell_id/256);
1014                 blobmsg_add_u32(&status, "cell_id",
1015                                 res.data.nr5g_cell_information.global_cell_id%256);
1016                 blobmsg_add_u32(&status, "physical_cell_id",
1017                                 res.data.nr5g_cell_information.physical_cell_id);
1018                 blobmsg_add_double(&status, "rsrq", ((double)res.data.nr5g_cell_information.rsrq)/10);
1019                 blobmsg_add_double(&status, "rsrp", ((double)res.data.nr5g_cell_information.rsrp)/10);
1020                 blobmsg_add_double(&status, "snr", ((double)res.data.nr5g_cell_information.snr)/10);
1021                 blobmsg_close_table(&status, c);
1022         }
1023         if (res.set.nr5g_arfcn) {
1024                 c = blobmsg_open_table(&status, "nr5g_arfcn");
1025                 blobmsg_add_u32(&status, "arfcn",
1026                                 res.data.nr5g_arfcn);
1027                 blobmsg_close_table(&status, c);
1028         }
1029         blobmsg_close_table(&status, t);
1030 }
1031 
1032 static enum qmi_cmd_result
1033 cmd_nas_get_cell_location_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
1034 {
1035         qmi_set_nas_get_cell_location_info_request(msg);
1036         return QMI_CMD_REQUEST;
1037 }
1038 
1039 static enum qmi_cmd_result
1040 cmd_nas_get_signal_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
1041 {
1042         qmi_set_nas_get_signal_info_request(msg);
1043         return QMI_CMD_REQUEST;
1044 }
1045 
1046 static void
1047 cmd_nas_get_serving_system_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
1048 {
1049         struct qmi_nas_get_serving_system_response res;
1050         static const char *reg_states[] = {
1051                 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED] = "not_registered",
1052                 [QMI_NAS_REGISTRATION_STATE_REGISTERED] = "registered",
1053                 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING] = "searching",
1054                 [QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED] = "registering_denied",
1055                 [QMI_NAS_REGISTRATION_STATE_UNKNOWN] = "unknown",
1056         };
1057         void *c, *a;
1058 
1059         qmi_parse_nas_get_serving_system_response(msg, &res);
1060 
1061         c = blobmsg_open_table(&status, NULL);
1062         if (res.set.serving_system) {
1063                 int state = res.data.serving_system.registration_state;
1064 
1065                 if (state > QMI_NAS_REGISTRATION_STATE_UNKNOWN)
1066                         state = QMI_NAS_REGISTRATION_STATE_UNKNOWN;
1067 
1068                 blobmsg_add_string(&status, "registration", reg_states[state]);
1069 
1070                 a = blobmsg_open_array(&status, "radio_interface");
1071                 for (int i = 0; i < res.data.serving_system.radio_interfaces_n; i++) {
1072                         int8_t r_i = res.data.serving_system.radio_interfaces[i];
1073 
1074                         blobmsg_add_string(&status, "radio", print_radio_interface(r_i));
1075                 }
1076                 blobmsg_close_array(&status, a);
1077         }
1078         if (res.set.current_plmn) {
1079                 blobmsg_add_u32(&status, "plmn_mcc", res.data.current_plmn.mcc);
1080                 blobmsg_add_u32(&status, "plmn_mnc", res.data.current_plmn.mnc);
1081                 if (res.data.current_plmn.description)
1082                         blobmsg_add_string(&status, "plmn_description", res.data.current_plmn.description);
1083         }
1084 
1085         if (res.set.roaming_indicator)
1086                 blobmsg_add_u8(&status, "roaming", !res.data.roaming_indicator);
1087 
1088         blobmsg_close_table(&status, c);
1089 }
1090 
1091 static enum qmi_cmd_result
1092 cmd_nas_get_serving_system_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
1093 {
1094         qmi_set_nas_get_serving_system_request(msg);
1095         return QMI_CMD_REQUEST;
1096 }
1097 
1098 static void
1099 cmd_nas_get_plmn_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
1100 {
1101         struct qmi_nas_get_system_selection_preference_response res;
1102         static const char *modes[] = {
1103                 [QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC] = "automatic",
1104                 [QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL] = "manual",
1105         };
1106         void *c;
1107 
1108         qmi_parse_nas_get_system_selection_preference_response(msg, &res);
1109 
1110         c = blobmsg_open_table(&status, NULL);
1111         if (res.set.network_selection_preference) {
1112                 blobmsg_add_string(&status, "mode", modes[res.data.network_selection_preference]);
1113         }
1114         if (res.set.manual_network_selection) {
1115                 blobmsg_add_u32(&status, "mcc", res.data.manual_network_selection.mcc);
1116                 blobmsg_add_u32(&status, "mnc", res.data.manual_network_selection.mnc);
1117         }
1118 
1119         blobmsg_close_table(&status, c);
1120 }
1121 
1122 static enum qmi_cmd_result
1123 cmd_nas_get_plmn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
1124 {
1125         qmi_set_nas_get_system_selection_preference_request(msg);
1126         return QMI_CMD_REQUEST;
1127 }
1128 
1129 static void
1130 cmd_nas_network_scan_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
1131 {
1132         static struct qmi_nas_network_scan_response res;
1133         const char *network_status[] = {
1134                 "current_serving",
1135                 "available",
1136                 "home",
1137                 "roaming",
1138                 "forbidden",
1139                 "not_forbidden",
1140                 "preferred",
1141                 "not_preferred",
1142         };
1143         void *t, *c, *info, *stat;
1144         int i, j;
1145 
1146         qmi_parse_nas_network_scan_response(msg, &res);
1147 
1148         t = blobmsg_open_table(&status, NULL);
1149 
1150         c = blobmsg_open_array(&status, "network_info");
1151         for (i = 0; i < res.data.network_information_n; i++) {
1152                 info = blobmsg_open_table(&status, NULL);
1153                 blobmsg_add_u32(&status, "mcc", res.data.network_information[i].mcc);
1154                 blobmsg_add_u32(&status, "mnc", res.data.network_information[i].mnc);
1155                 if (res.data.network_information[i].description)
1156                         blobmsg_add_string(&status, "description", res.data.network_information[i].description);
1157                 stat = blobmsg_open_array(&status, "status");
1158                 for (j = 0; j < ARRAY_SIZE(network_status); j++) {
1159                         if (!(res.data.network_information[i].network_status & (1 << j)))
1160                                 continue;
1161 
1162                         blobmsg_add_string(&status, NULL, network_status[j]);
1163                 }
1164                 blobmsg_close_array(&status, stat);
1165                 blobmsg_close_table(&status, info);
1166         }
1167         blobmsg_close_array(&status, c);
1168 
1169         c = blobmsg_open_array(&status, "radio_access_technology");
1170         for (i = 0; i < res.data.radio_access_technology_n; i++) {
1171                 int8_t r_i = res.data.radio_access_technology[i].radio_interface;
1172 
1173                 info = blobmsg_open_table(&status, NULL);
1174                 blobmsg_add_u32(&status, "mcc", res.data.radio_access_technology[i].mcc);
1175                 blobmsg_add_u32(&status, "mnc", res.data.radio_access_technology[i].mnc);
1176                 blobmsg_add_string(&status, "radio", print_radio_interface(r_i));
1177                 blobmsg_close_table(&status, info);
1178         }
1179         blobmsg_close_array(&status, c);
1180 
1181         blobmsg_close_table(&status, t);
1182 }
1183 
1184 static enum qmi_cmd_result
1185 cmd_nas_network_scan_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
1186 {
1187         struct qmi_nas_network_scan_request sreq = {
1188                 QMI_INIT(network_type,
1189                      QMI_NAS_NETWORK_SCAN_TYPE_GSM |
1190                      QMI_NAS_NETWORK_SCAN_TYPE_UMTS |
1191                      QMI_NAS_NETWORK_SCAN_TYPE_LTE |
1192                      QMI_NAS_NETWORK_SCAN_TYPE_TD_SCDMA),
1193         };
1194 
1195         qmi_set_nas_network_scan_request(msg, &sreq);
1196         return QMI_CMD_REQUEST;
1197 }
1198 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt