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