QMI: add uqmi tool with all depends
[tomato.git] / release / src / router / uqmi / commands-nas.c
blobfd51a132c1c052852a1c6a2b78191040f6a6650c
1 /*
2 * uqmi -- tiny QMI support implementation
4 * Copyright (C) 2014-2015 Felix Fietkau <nbd@openwrt.org>
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.
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.
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.
22 #include "qmi-message.h"
24 static struct qmi_nas_set_system_selection_preference_request sel_req;
25 static struct {
26 bool mcc_is_set;
27 bool mnc_is_set;
28 } plmn_code_flag;
30 #define cmd_nas_do_set_system_selection_cb no_cb
31 static enum qmi_cmd_result
32 cmd_nas_do_set_system_selection_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
34 qmi_set_nas_set_system_selection_preference_request(msg, &sel_req);
35 return QMI_CMD_REQUEST;
38 static enum qmi_cmd_result
39 do_sel_network(void)
41 static bool use_sel_req = false;
43 if (!use_sel_req) {
44 use_sel_req = true;
45 uqmi_add_command(NULL, __UQMI_COMMAND_nas_do_set_system_selection);
48 return QMI_CMD_DONE;
51 #define cmd_nas_set_network_modes_cb no_cb
52 static enum qmi_cmd_result
53 cmd_nas_set_network_modes_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
55 static const struct {
56 const char *name;
57 QmiNasRatModePreference val;
58 } modes[] = {
59 { "cdma", QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X | QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO },
60 { "td-scdma", QMI_NAS_RAT_MODE_PREFERENCE_TD_SCDMA },
61 { "gsm", QMI_NAS_RAT_MODE_PREFERENCE_GSM },
62 { "umts", QMI_NAS_RAT_MODE_PREFERENCE_UMTS },
63 { "lte", QMI_NAS_RAT_MODE_PREFERENCE_LTE },
65 QmiNasRatModePreference val = 0;
66 char *word;
67 int i;
69 for (word = strtok(arg, ",");
70 word;
71 word = strtok(NULL, ",")) {
72 bool found = false;
74 for (i = 0; i < ARRAY_SIZE(modes); i++) {
75 if (strcmp(word, modes[i].name) != 0 &&
76 strcmp(word, "all") != 0)
77 continue;
79 val |= modes[i].val;
80 found = true;
83 if (!found) {
84 uqmi_add_error("Invalid network mode");
85 return QMI_CMD_EXIT;
89 qmi_set(&sel_req, mode_preference, val);
90 return do_sel_network();
93 #define cmd_nas_set_network_preference_cb no_cb
94 static enum qmi_cmd_result
95 cmd_nas_set_network_preference_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
97 QmiNasGsmWcdmaAcquisitionOrderPreference pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC;
99 if (!strcmp(arg, "gsm"))
100 pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM;
101 else if (!strcmp(arg, "wcdma"))
102 pref = QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA;
104 qmi_set(&sel_req, gsm_wcdma_acquisition_order_preference, pref);
105 return do_sel_network();
108 #define cmd_nas_set_roaming_cb no_cb
109 static enum qmi_cmd_result
110 cmd_nas_set_roaming_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
112 QmiNasRoamingPreference pref;
114 if (!strcmp(arg, "any"))
115 pref = QMI_NAS_ROAMING_PREFERENCE_ANY;
116 else if (!strcmp(arg, "only"))
117 pref = QMI_NAS_ROAMING_PREFERENCE_NOT_OFF;
118 else if (!strcmp(arg, "off"))
119 pref = QMI_NAS_ROAMING_PREFERENCE_OFF;
120 else
121 return uqmi_add_error("Invalid argument");
123 qmi_set(&sel_req, roaming_preference, pref);
124 return do_sel_network();
127 #define cmd_nas_set_mcc_cb no_cb
128 static enum qmi_cmd_result
129 cmd_nas_set_mcc_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
131 char *err;
132 int value = strtoul(arg, &err, 10);
133 if (err && *err) {
134 uqmi_add_error("Invalid MCC value");
135 return QMI_CMD_EXIT;
138 sel_req.data.network_selection_preference.mcc = value;
139 plmn_code_flag.mcc_is_set = true;
140 return QMI_CMD_DONE;
143 #define cmd_nas_set_mnc_cb no_cb
144 static enum qmi_cmd_result
145 cmd_nas_set_mnc_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
147 char *err;
148 int value = strtoul(arg, &err, 10);
149 if (err && *err) {
150 uqmi_add_error("Invalid MNC value");
151 return QMI_CMD_EXIT;
154 sel_req.data.network_selection_preference.mnc = value;
155 plmn_code_flag.mnc_is_set = true;
156 return QMI_CMD_DONE;
159 #define cmd_nas_set_plmn_cb no_cb
160 static enum qmi_cmd_result
161 cmd_nas_set_plmn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
163 sel_req.set.network_selection_preference = 1;
164 sel_req.data.network_selection_preference.mode = QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC;
166 if (!plmn_code_flag.mcc_is_set && plmn_code_flag.mnc_is_set) {
167 uqmi_add_error("No MCC value");
168 return QMI_CMD_EXIT;
171 if (plmn_code_flag.mcc_is_set && sel_req.data.network_selection_preference.mcc) {
172 if (!plmn_code_flag.mnc_is_set) {
173 uqmi_add_error("No MNC value");
174 return QMI_CMD_EXIT;
175 } else {
176 sel_req.data.network_selection_preference.mode = QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL;
180 return do_sel_network();
183 #define cmd_nas_initiate_network_register_cb no_cb
184 static enum qmi_cmd_result
185 cmd_nas_initiate_network_register_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
187 static struct qmi_nas_initiate_network_register_request register_req = {
188 QMI_INIT(action, QMI_NAS_NETWORK_REGISTER_TYPE_AUTOMATIC)
191 qmi_set_nas_initiate_network_register_request(msg, &register_req);
192 return QMI_CMD_REQUEST;
195 static void
196 cmd_nas_get_signal_info_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
198 struct qmi_nas_get_signal_info_response res;
199 void *c;
201 qmi_parse_nas_get_signal_info_response(msg, &res);
203 c = blobmsg_open_table(&status, NULL);
204 if (res.set.cdma_signal_strength) {
205 blobmsg_add_string(&status, "type", "cdma");
206 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.cdma_signal_strength.rssi);
207 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.cdma_signal_strength.ecio);
210 if (res.set.hdr_signal_strength) {
211 blobmsg_add_string(&status, "type", "hdr");
212 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.hdr_signal_strength.rssi);
213 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.hdr_signal_strength.ecio);
214 blobmsg_add_u32(&status, "io", res.data.hdr_signal_strength.io);
217 if (res.set.gsm_signal_strength) {
218 blobmsg_add_string(&status, "type", "gsm");
219 blobmsg_add_u32(&status, "signal", (int32_t) res.data.gsm_signal_strength);
222 if (res.set.wcdma_signal_strength) {
223 blobmsg_add_string(&status, "type", "wcdma");
224 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.wcdma_signal_strength.rssi);
225 blobmsg_add_u32(&status, "ecio", (int32_t) res.data.wcdma_signal_strength.ecio);
228 if (res.set.lte_signal_strength) {
229 blobmsg_add_string(&status, "type", "lte");
230 blobmsg_add_u32(&status, "rssi", (int32_t) res.data.lte_signal_strength.rssi);
231 blobmsg_add_u32(&status, "rsrq", (int32_t) res.data.lte_signal_strength.rsrq);
232 blobmsg_add_u32(&status, "rsrp", (int32_t) res.data.lte_signal_strength.rsrp);
233 blobmsg_add_u32(&status, "snr", (int32_t) res.data.lte_signal_strength.snr);
236 if (res.set.tdma_signal_strength) {
237 blobmsg_add_string(&status, "type", "tdma");
238 blobmsg_add_u32(&status, "signal", (int32_t) res.data.tdma_signal_strength);
241 blobmsg_close_table(&status, c);
244 static enum qmi_cmd_result
245 cmd_nas_get_signal_info_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
247 qmi_set_nas_get_signal_info_request(msg);
248 return QMI_CMD_REQUEST;
251 static void
252 cmd_nas_get_serving_system_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
254 struct qmi_nas_get_serving_system_response res;
255 static const char *reg_states[] = {
256 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED] = "not_registered",
257 [QMI_NAS_REGISTRATION_STATE_REGISTERED] = "registered",
258 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING] = "searching",
259 [QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED] = "registering_denied",
260 [QMI_NAS_REGISTRATION_STATE_UNKNOWN] = "unknown",
262 void *c;
264 qmi_parse_nas_get_serving_system_response(msg, &res);
266 c = blobmsg_open_table(&status, NULL);
267 if (res.set.serving_system) {
268 int state = res.data.serving_system.registration_state;
270 if (state > QMI_NAS_REGISTRATION_STATE_UNKNOWN)
271 state = QMI_NAS_REGISTRATION_STATE_UNKNOWN;
273 blobmsg_add_string(&status, "registration", reg_states[state]);
275 if (res.set.current_plmn) {
276 blobmsg_add_u32(&status, "plmn_mcc", res.data.current_plmn.mcc);
277 blobmsg_add_u32(&status, "plmn_mnc", res.data.current_plmn.mnc);
278 if (res.data.current_plmn.description)
279 blobmsg_add_string(&status, "plmn_description", res.data.current_plmn.description);
282 if (res.set.roaming_indicator)
283 blobmsg_add_u8(&status, "roaming", !res.data.roaming_indicator);
285 blobmsg_close_table(&status, c);
288 static enum qmi_cmd_result
289 cmd_nas_get_serving_system_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
291 qmi_set_nas_get_serving_system_request(msg);
292 return QMI_CMD_REQUEST;
295 static void
296 cmd_nas_network_scan_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
298 static struct qmi_nas_network_scan_response res;
299 const char *network_status[] = {
300 "current_serving",
301 "available",
302 "home",
303 "roaming",
304 "forbidden",
305 "not_forbidden",
306 "preferred",
307 "not_preferred",
309 const char *radio[] = {
310 [QMI_NAS_RADIO_INTERFACE_NONE] = "none",
311 [QMI_NAS_RADIO_INTERFACE_CDMA_1X] = "cdma-1x",
312 [QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO] = "cdma-1x_evdo",
313 [QMI_NAS_RADIO_INTERFACE_AMPS] = "amps",
314 [QMI_NAS_RADIO_INTERFACE_GSM] = "gsm",
315 [QMI_NAS_RADIO_INTERFACE_UMTS] = "umts",
316 [QMI_NAS_RADIO_INTERFACE_LTE] = "lte",
317 [QMI_NAS_RADIO_INTERFACE_TD_SCDMA] = "td-scdma",
319 void *t, *c, *info, *stat;
320 int i, j;
322 qmi_parse_nas_network_scan_response(msg, &res);
324 t = blobmsg_open_table(&status, NULL);
326 c = blobmsg_open_array(&status, "network_info");
327 for (i = 0; i < res.data.network_information_n; i++) {
328 info = blobmsg_open_table(&status, NULL);
329 blobmsg_add_u32(&status, "mcc", res.data.network_information[i].mcc);
330 blobmsg_add_u32(&status, "mnc", res.data.network_information[i].mnc);
331 if (res.data.network_information[i].description)
332 blobmsg_add_string(&status, "description", res.data.network_information[i].description);
333 stat = blobmsg_open_array(&status, "status");
334 for (j = 0; j < ARRAY_SIZE(network_status); j++) {
335 if (!(res.data.network_information[i].network_status & (1 << j)))
336 continue;
338 blobmsg_add_string(&status, NULL, network_status[j]);
340 blobmsg_close_array(&status, stat);
341 blobmsg_close_table(&status, info);
343 blobmsg_close_array(&status, c);
345 c = blobmsg_open_array(&status, "radio_access_technology");
346 for (i = 0; i < res.data.radio_access_technology_n; i++) {
347 const char *r = "unknown";
348 int r_i = res.data.radio_access_technology[i].radio_interface;
350 info = blobmsg_open_table(&status, NULL);
351 blobmsg_add_u32(&status, "mcc", res.data.radio_access_technology[i].mcc);
352 blobmsg_add_u32(&status, "mnc", res.data.radio_access_technology[i].mnc);
353 if (r_i >= 0 && r_i < ARRAY_SIZE(radio))
354 r = radio[r_i];
356 blobmsg_add_string(&status, "radio", r);
357 blobmsg_close_table(&status, info);
359 blobmsg_close_array(&status, c);
361 blobmsg_close_table(&status, t);
364 static enum qmi_cmd_result
365 cmd_nas_network_scan_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
367 struct qmi_nas_network_scan_request sreq = {};
369 qmi_set_nas_network_scan_request(msg, &sreq);
370 return QMI_CMD_REQUEST;