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

Sources/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 "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, &register_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