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