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 <stdio.h> 23 #include <string.h> 24 #include <strings.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 28 #include <libubox/blobmsg.h> 29 #include <libubox/blobmsg_json.h> 30 31 #include "uqmi.h" 32 #include "utils.h" 33 #include "commands.h" 34 35 struct blob_buf status; 36 bool single_line = false; 37 38 static void no_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 39 { 40 } 41 42 static void cmd_version_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 43 { 44 struct qmi_ctl_get_version_info_response res; 45 void *c; 46 char name_buf[16]; 47 int i; 48 49 qmi_parse_ctl_get_version_info_response(msg, &res); 50 51 c = blobmsg_open_table(&status, NULL); 52 for (i = 0; i < res.data.service_list_n; i++) { 53 sprintf(name_buf, "service_%d", res.data.service_list[i].service); 54 blobmsg_printf(&status, name_buf, "%d,%d", 55 res.data.service_list[i].major_version, 56 res.data.service_list[i].minor_version); 57 } 58 blobmsg_close_table(&status, c); 59 } 60 61 static enum qmi_cmd_result 62 cmd_version_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 63 { 64 qmi_set_ctl_get_version_info_request(msg); 65 return QMI_CMD_REQUEST; 66 } 67 68 #define cmd_sync_cb no_cb 69 static enum qmi_cmd_result 70 cmd_sync_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 71 { 72 qmi_set_ctl_sync_request(msg); 73 return QMI_CMD_REQUEST; 74 } 75 76 #define cmd_get_client_id_cb no_cb 77 static enum qmi_cmd_result 78 cmd_get_client_id_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 79 { 80 QmiService svc = qmi_service_get_by_name(arg); 81 82 if (svc < 0) { 83 fprintf(stderr, "Invalid service name '%s'\n", arg); 84 return QMI_CMD_EXIT; 85 } 86 87 if (qmi_service_connect(qmi, svc, -1)) { 88 fprintf(stderr, "Failed to connect to service\n"); 89 return QMI_CMD_EXIT; 90 } 91 92 printf("%d\n", qmi_service_get_client_id(qmi, svc)); 93 return QMI_CMD_DONE; 94 } 95 96 #define cmd_set_client_id_cb no_cb 97 static enum qmi_cmd_result 98 cmd_set_client_id_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 99 { 100 QmiService svc; 101 int id; 102 char *s; 103 104 s = strchr(arg, ','); 105 if (!s) { 106 fprintf(stderr, "Invalid argument\n"); 107 return QMI_CMD_EXIT; 108 } 109 *s = 0; 110 s++; 111 112 id = strtoul(s, &s, 0); 113 if (s && *s) { 114 fprintf(stderr, "Invalid argument\n"); 115 return QMI_CMD_EXIT; 116 } 117 118 svc = qmi_service_get_by_name(arg); 119 if (svc < 0) { 120 fprintf(stderr, "Invalid service name '%s'\n", arg); 121 return QMI_CMD_EXIT; 122 } 123 124 if (qmi_service_connect(qmi, svc, id)) { 125 fprintf(stderr, "Failed to connect to service\n"); 126 return QMI_CMD_EXIT; 127 } 128 129 return QMI_CMD_DONE; 130 } 131 132 static int 133 qmi_get_array_idx(const char **array, int size, const char *str) 134 { 135 int i; 136 137 for (i = 0; i < size; i++) { 138 if (!array[i]) 139 continue; 140 141 if (!strcmp(array[i], str)) 142 return i; 143 } 144 145 return -1; 146 } 147 148 #define cmd_ctl_set_data_format_cb no_cb 149 static enum qmi_cmd_result 150 cmd_ctl_set_data_format_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 151 { 152 struct qmi_ctl_set_data_format_request sreq = {}; 153 const char *modes[] = { 154 [QMI_CTL_DATA_LINK_PROTOCOL_802_3] = "802.3", 155 [QMI_CTL_DATA_LINK_PROTOCOL_RAW_IP] = "raw-ip", 156 }; 157 int mode = qmi_get_array_idx(modes, ARRAY_SIZE(modes), arg); 158 159 if (mode < 0) { 160 uqmi_add_error("Invalid mode (modes: 802.3, raw-ip)"); 161 return QMI_CMD_EXIT; 162 } 163 164 qmi_set_ctl_set_data_format_request(msg, &sreq); 165 return QMI_CMD_DONE; 166 } 167 168 #include "commands-wds.c" 169 #include "commands-dms.c" 170 #include "commands-nas.c" 171 #include "commands-wms.c" 172 #include "commands-wda.c" 173 #include "commands-uim.c" 174 175 #define __uqmi_command(_name, _optname, _arg, _type) \ 176 [__UQMI_COMMAND_##_name] = { \ 177 .name = #_optname, \ 178 .type = _type, \ 179 .prepare = cmd_##_name##_prepare, \ 180 .cb = cmd_##_name##_cb, \ 181 } 182 183 const struct uqmi_cmd_handler uqmi_cmd_handler[__UQMI_COMMAND_LAST] = { 184 __uqmi_commands 185 }; 186 #undef __uqmi_command 187 188 static struct uqmi_cmd *cmds; 189 static int n_cmds; 190 191 void uqmi_add_command(char *arg, int cmd) 192 { 193 int idx = n_cmds++; 194 195 cmds = realloc(cmds, n_cmds * sizeof(*cmds)); 196 cmds[idx].handler = &uqmi_cmd_handler[cmd]; 197 cmds[idx].arg = arg; 198 } 199 200 static void uqmi_print_result(struct blob_attr *data) 201 { 202 char *str; 203 204 if (!blob_len(data)) 205 return; 206 207 str = blobmsg_format_json_indent(blob_data(data), false, single_line ? -1 : 0); 208 if (!str) 209 return; 210 211 printf("%s\n", str); 212 free(str); 213 } 214 215 static bool __uqmi_run_commands(struct qmi_dev *qmi, bool option) 216 { 217 static struct qmi_request req; 218 char *buf = qmi->buf; 219 int i; 220 221 for (i = 0; i < n_cmds; i++) { 222 enum qmi_cmd_result res; 223 bool cmd_option = cmds[i].handler->type == CMD_TYPE_OPTION; 224 bool do_break = false; 225 226 if (cmd_option != option) 227 continue; 228 229 blob_buf_init(&status, 0); 230 if (cmds[i].handler->type > QMI_SERVICE_CTL && 231 qmi_service_connect(qmi, cmds[i].handler->type, -1)) { 232 uqmi_add_error("Failed to connect to service"); 233 res = QMI_CMD_EXIT; 234 } else { 235 res = cmds[i].handler->prepare(qmi, &req, (void *) buf, cmds[i].arg); 236 } 237 238 if (res == QMI_CMD_REQUEST) { 239 qmi_request_start(qmi, &req, cmds[i].handler->cb); 240 req.no_error_cb = true; 241 if (qmi_request_wait(qmi, &req)) { 242 uqmi_add_error(qmi_get_error_str(req.ret)); 243 do_break = true; 244 } 245 } else if (res == QMI_CMD_EXIT) { 246 do_break = true; 247 } 248 249 uqmi_print_result(status.head); 250 if (do_break) 251 return false; 252 } 253 return true; 254 } 255 256 int uqmi_add_error(const char *msg) 257 { 258 blobmsg_add_string(&status, NULL, msg); 259 return QMI_CMD_EXIT; 260 } 261 262 bool uqmi_run_commands(struct qmi_dev *qmi) 263 { 264 bool ret; 265 266 ret = __uqmi_run_commands(qmi, true) && 267 __uqmi_run_commands(qmi, false); 268 269 free(cmds); 270 cmds = NULL; 271 n_cmds = 0; 272 273 return ret; 274 } 275
This page was automatically generated by LXR 0.3.1. • OpenWrt