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, ®ister_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