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 <stdlib.h> 23 #include <arpa/inet.h> 24 25 #include "qmi-message.h" 26 27 static const struct { 28 const char *auth_name; 29 QmiWdsAuthentication auth; 30 } auth_modes[] = { 31 { "none", QMI_WDS_AUTHENTICATION_NONE }, 32 { "pap", QMI_WDS_AUTHENTICATION_PAP }, 33 { "chap", QMI_WDS_AUTHENTICATION_CHAP }, 34 { "both", QMI_WDS_AUTHENTICATION_PAP | QMI_WDS_AUTHENTICATION_CHAP }, 35 }; 36 37 static const struct { 38 const char *ipfam_name; 39 const QmiWdsIpFamily mode; 40 } ipfam_modes[] = { 41 { "ipv4", QMI_WDS_IP_FAMILY_IPV4 }, 42 { "ipv6", QMI_WDS_IP_FAMILY_IPV6 }, 43 { "unspecified", QMI_WDS_IP_FAMILY_UNSPECIFIED }, 44 }; 45 46 static const struct { 47 const char *pdp_name; 48 const QmiWdsPdpType type; 49 } pdp_types[] = { 50 { "ipv4", QMI_WDS_PDP_TYPE_IPV4 }, 51 { "ppp", QMI_WDS_PDP_TYPE_PPP }, 52 { "ipv6", QMI_WDS_PDP_TYPE_IPV6 }, 53 { "ipv4v6", QMI_WDS_PDP_TYPE_IPV4_OR_IPV6 }, 54 }; 55 56 static const struct { 57 const char *profile_name; 58 const QmiWdsProfileType profile; 59 } profile_types[] = { 60 { "3gpp", QMI_WDS_PROFILE_TYPE_3GPP }, 61 { "3gpp2", QMI_WDS_PROFILE_TYPE_3GPP2 }, 62 }; 63 64 struct uqmi_wds_profile_identifier { 65 QmiWdsProfileType type; 66 uint32_t index; 67 }; 68 69 static struct qmi_wds_start_network_request wds_sn_req = { 70 QMI_INIT(authentication_preference, 71 QMI_WDS_AUTHENTICATION_PAP | QMI_WDS_AUTHENTICATION_CHAP), 72 }; 73 74 static struct qmi_wds_stop_network_request wds_stn_req; 75 76 static struct qmi_wds_modify_profile_request wds_mp_req = { 77 QMI_INIT_SEQUENCE(profile_identifier, 78 .profile_type = QMI_WDS_PROFILE_TYPE_3GPP, 79 .profile_index = 1, 80 ), 81 QMI_INIT(apn_disabled_flag, false), 82 }; 83 84 static struct qmi_wds_create_profile_request wds_cp_req = { 85 QMI_INIT(profile_type,QMI_WDS_PROFILE_TYPE_3GPP), 86 QMI_INIT(apn_disabled_flag, false), 87 }; 88 89 static int 90 uqmi_wds_profile_type_parse(const char *type_string, QmiWdsProfileType *type) 91 { 92 int i; 93 94 for (i = 0; i < ARRAY_SIZE(profile_types); i++) { 95 if (strcasecmp(profile_types[i].profile_name, type_string) != 0) 96 continue; 97 98 *type = profile_types[i].profile; 99 return 0; 100 } 101 102 return -1; 103 } 104 105 static int 106 uqmi_wds_profile_identifier_parse(char *arg, struct uqmi_wds_profile_identifier *profile) 107 { 108 char *s; 109 char *p_type; 110 int id; 111 112 s = strchr(arg, ','); 113 if (!s) 114 return -1; 115 *s = 0; 116 s++; 117 118 id = strtoul(s, &s, 0); 119 if (s && *s) 120 return -1; 121 122 p_type = strtok(arg, ","); 123 124 if (uqmi_wds_profile_type_parse(p_type, &profile->type)) 125 return -1; 126 127 profile->index = id; 128 129 return 0; 130 } 131 132 #define cmd_wds_set_apn_cb no_cb 133 static enum qmi_cmd_result 134 cmd_wds_set_apn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 135 { 136 qmi_set_ptr(&wds_sn_req, apn, arg); 137 qmi_set_ptr(&wds_mp_req, apn_name, arg); 138 qmi_set_ptr(&wds_cp_req, apn_name, arg); 139 return QMI_CMD_DONE; 140 } 141 142 #define cmd_wds_set_auth_cb no_cb 143 static enum qmi_cmd_result 144 cmd_wds_set_auth_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 145 { 146 int i; 147 for (i = 0; i < ARRAY_SIZE(auth_modes); i++) { 148 if (strcasecmp(auth_modes[i].auth_name, arg) != 0) 149 continue; 150 151 qmi_set(&wds_sn_req, authentication_preference, auth_modes[i].auth); 152 qmi_set(&wds_mp_req, authentication, auth_modes[i].auth); 153 qmi_set(&wds_cp_req, authentication, auth_modes[i].auth); 154 return QMI_CMD_DONE; 155 } 156 157 uqmi_add_error("Invalid auth mode (valid: pap, chap, both, none)"); 158 return QMI_CMD_EXIT; 159 } 160 161 #define cmd_wds_set_username_cb no_cb 162 static enum qmi_cmd_result 163 cmd_wds_set_username_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 164 { 165 qmi_set_ptr(&wds_sn_req, username, arg); 166 qmi_set_ptr(&wds_mp_req, username, arg); 167 qmi_set_ptr(&wds_cp_req, username, arg); 168 return QMI_CMD_DONE; 169 } 170 171 #define cmd_wds_set_password_cb no_cb 172 static enum qmi_cmd_result 173 cmd_wds_set_password_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 174 { 175 qmi_set_ptr(&wds_sn_req, password, arg); 176 qmi_set_ptr(&wds_mp_req, password, arg); 177 qmi_set_ptr(&wds_cp_req, password, arg); 178 return QMI_CMD_DONE; 179 } 180 181 #define cmd_wds_set_autoconnect_cb no_cb 182 static enum qmi_cmd_result 183 cmd_wds_set_autoconnect_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 184 { 185 qmi_set(&wds_sn_req, enable_autoconnect, true); 186 qmi_set(&wds_stn_req, disable_autoconnect, true); 187 return QMI_CMD_DONE; 188 } 189 190 #define cmd_wds_set_ip_family_pref_cb no_cb 191 static enum qmi_cmd_result 192 cmd_wds_set_ip_family_pref_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 193 { 194 int i; 195 for (i = 0; i < ARRAY_SIZE(ipfam_modes); i++) { 196 if (strcasecmp(ipfam_modes[i].ipfam_name, arg) != 0) 197 continue; 198 199 qmi_set(&wds_sn_req, ip_family_preference, ipfam_modes[i].mode); 200 return QMI_CMD_DONE; 201 } 202 203 uqmi_add_error("Invalid value (valid: ipv4, ipv6, unspecified)"); 204 return QMI_CMD_EXIT; 205 } 206 207 #define cmd_wds_set_pdp_type_cb no_cb 208 static enum qmi_cmd_result 209 cmd_wds_set_pdp_type_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 210 { 211 int i; 212 213 for (i = 0; i < ARRAY_SIZE(pdp_types); i++) { 214 if (strcasecmp(pdp_types[i].pdp_name, arg) != 0) 215 continue; 216 217 qmi_set(&wds_mp_req, pdp_type, pdp_types[i].type); 218 qmi_set(&wds_cp_req, pdp_type, pdp_types[i].type); 219 return QMI_CMD_DONE; 220 } 221 222 uqmi_add_error("Invalid value (valid: ipv4, ipv6, ipv4v6)"); 223 return QMI_CMD_EXIT; 224 } 225 226 #define cmd_wds_no_roaming_cb no_cb 227 static enum qmi_cmd_result 228 cmd_wds_no_roaming_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 229 { 230 if (strcmp(arg, "true") == 0) { 231 qmi_set(&wds_mp_req, roaming_disallowed_flag, true); 232 qmi_set(&wds_cp_req, roaming_disallowed_flag, true); 233 } else if (strcmp(arg, "false") == 0) { 234 qmi_set(&wds_mp_req, roaming_disallowed_flag, false); 235 qmi_set(&wds_cp_req, roaming_disallowed_flag, false); 236 } else { 237 uqmi_add_error("Invalid value (true or false)"); 238 return QMI_CMD_EXIT; 239 } 240 return QMI_CMD_DONE; 241 } 242 243 #define cmd_wds_set_profile_cb no_cb 244 static enum qmi_cmd_result 245 cmd_wds_set_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 246 { 247 uint32_t idx = strtoul(arg, NULL, 10); 248 249 qmi_set(&wds_sn_req, profile_index_3gpp, idx); 250 return QMI_CMD_DONE; 251 } 252 253 static void 254 cmd_wds_start_network_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 255 { 256 struct qmi_wds_start_network_response res; 257 258 qmi_parse_wds_start_network_response(msg, &res); 259 if (res.set.packet_data_handle) 260 blobmsg_add_u32(&status, NULL, res.data.packet_data_handle); 261 } 262 263 static enum qmi_cmd_result 264 cmd_wds_start_network_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 265 { 266 qmi_set_wds_start_network_request(msg, &wds_sn_req); 267 return QMI_CMD_REQUEST; 268 } 269 270 #define cmd_wds_stop_network_cb no_cb 271 static enum qmi_cmd_result 272 cmd_wds_stop_network_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 273 { 274 uint32_t pdh = strtoul(arg, NULL, 0); 275 276 qmi_set(&wds_stn_req, packet_data_handle, pdh); 277 qmi_set_wds_stop_network_request(msg, &wds_stn_req); 278 return QMI_CMD_REQUEST; 279 } 280 281 static void 282 cmd_wds_modify_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 283 { 284 struct qmi_wds_modify_profile_response res; 285 qmi_parse_wds_modify_profile_response(msg, &res); 286 } 287 288 static enum qmi_cmd_result 289 cmd_wds_modify_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 290 { 291 struct uqmi_wds_profile_identifier profile; 292 293 if (uqmi_wds_profile_identifier_parse(arg, &profile) < 0) { 294 fprintf(stderr, "Invalid argument\n"); 295 return QMI_CMD_EXIT; 296 } 297 298 qmi_set_ptr(&wds_mp_req, profile_identifier.profile_type, profile.type); 299 qmi_set_ptr(&wds_mp_req, profile_identifier.profile_index, profile.index); 300 qmi_set_wds_modify_profile_request(msg, &wds_mp_req); 301 302 return QMI_CMD_REQUEST; 303 } 304 305 static void 306 cmd_wds_get_profile_list_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 307 { 308 struct qmi_wds_get_profile_list_response res; 309 void *p, *t, *root; 310 int i; 311 312 qmi_parse_wds_get_profile_list_response(msg, &res); 313 314 root = blobmsg_open_table(&status, NULL); 315 p = blobmsg_open_array(&status, "profiles"); 316 for (i = 0; i < res.data.profile_list_n; i++) { 317 t = blobmsg_open_table(&status, NULL); 318 blobmsg_add_u32(&status, "index", res.data.profile_list[i].profile_index); 319 blobmsg_add_string(&status, "name", res.data.profile_list[i].profile_name); 320 blobmsg_close_table(&status, t); 321 } 322 blobmsg_close_array(&status, p); 323 blobmsg_close_table(&status, root); 324 } 325 326 static enum qmi_cmd_result 327 cmd_wds_get_profile_list_prepare(struct qmi_dev *qmi, struct qmi_request *req, 328 struct qmi_msg *msg, char *arg) 329 { 330 struct qmi_wds_get_profile_list_request pl_req = {}; 331 QmiWdsProfileType profile_type; 332 333 if (uqmi_wds_profile_type_parse(arg, &profile_type) < 0) { 334 uqmi_add_error("Invalid type (valid: 3gpp or 3gpp2)"); 335 return QMI_CMD_EXIT; 336 } 337 338 qmi_set(&pl_req, profile_type, profile_type); 339 340 qmi_set_wds_get_profile_list_request(msg, &pl_req); 341 return QMI_CMD_REQUEST; 342 } 343 344 static void 345 cmd_wds_create_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 346 { 347 struct qmi_wds_create_profile_response res; 348 void *p; 349 350 qmi_parse_wds_create_profile_response(msg, &res); 351 352 if (res.set.profile_identifier) { 353 p = blobmsg_open_table(&status, NULL); 354 blobmsg_add_u32(&status, "created-profile", res.data.profile_identifier.profile_index); 355 blobmsg_close_table(&status, p); 356 } 357 } 358 359 static enum qmi_cmd_result 360 cmd_wds_create_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 361 { 362 int i; 363 for (i = 0; i < ARRAY_SIZE(profile_types); i++) { 364 if (strcasecmp(profile_types[i].profile_name, arg) != 0) 365 continue; 366 367 qmi_set_ptr(&wds_cp_req, profile_type, profile_types[i].profile); 368 369 qmi_set_wds_create_profile_request(msg, &wds_cp_req); 370 return QMI_CMD_REQUEST; 371 } 372 373 uqmi_add_error("Invalid value (valid: 3gpp or 3gpp2)"); 374 return QMI_CMD_EXIT; 375 } 376 377 static void 378 cmd_wds_get_packet_service_status_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 379 { 380 struct qmi_wds_get_packet_service_status_response res; 381 const char *data_status[] = { 382 [QMI_WDS_CONNECTION_STATUS_UNKNOWN] = "unknown", 383 [QMI_WDS_CONNECTION_STATUS_DISCONNECTED] = "disconnected", 384 [QMI_WDS_CONNECTION_STATUS_CONNECTED] = "connected", 385 [QMI_WDS_CONNECTION_STATUS_SUSPENDED] = "suspended", 386 [QMI_WDS_CONNECTION_STATUS_AUTHENTICATING] = "authenticating", 387 }; 388 int s = 0; 389 390 qmi_parse_wds_get_packet_service_status_response(msg, &res); 391 if (res.set.connection_status && 392 res.data.connection_status < ARRAY_SIZE(data_status)) 393 s = res.data.connection_status; 394 395 blobmsg_add_string(&status, NULL, data_status[s]); 396 } 397 398 static enum qmi_cmd_result 399 cmd_wds_get_packet_service_status_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 400 { 401 qmi_set_wds_get_packet_service_status_request(msg); 402 return QMI_CMD_REQUEST; 403 } 404 405 #define cmd_wds_set_autoconnect_settings_cb no_cb 406 static enum qmi_cmd_result 407 cmd_wds_set_autoconnect_settings_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 408 { 409 struct qmi_wds_set_autoconnect_settings_request ac_req; 410 const char *modes[] = { 411 [QMI_WDS_AUTOCONNECT_SETTING_DISABLED] = "disabled", 412 [QMI_WDS_AUTOCONNECT_SETTING_ENABLED] = "enabled", 413 [QMI_WDS_AUTOCONNECT_SETTING_PAUSED] = "paused", 414 }; 415 int i; 416 417 for (i = 0; i < ARRAY_SIZE(modes); i++) { 418 if (strcasecmp(modes[i], arg) != 0) 419 continue; 420 421 qmi_set(&ac_req, status, i); 422 qmi_set_wds_set_autoconnect_settings_request(msg, &ac_req); 423 return QMI_CMD_DONE; 424 } 425 426 uqmi_add_error("Invalid value (valid: disabled, enabled, paused)"); 427 return QMI_CMD_EXIT; 428 } 429 430 #define cmd_wds_reset_cb no_cb 431 static enum qmi_cmd_result 432 cmd_wds_reset_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 433 { 434 qmi_set_wds_reset_request(msg); 435 return QMI_CMD_REQUEST; 436 } 437 438 #define cmd_wds_set_ip_family_cb no_cb 439 static enum qmi_cmd_result 440 cmd_wds_set_ip_family_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 441 { 442 struct qmi_wds_set_ip_family_request ipf_req; 443 444 int i; 445 for (i = 0; i < ARRAY_SIZE(ipfam_modes); i++) { 446 if (strcasecmp(ipfam_modes[i].ipfam_name, arg) != 0) 447 continue; 448 449 qmi_set(&ipf_req, preference, ipfam_modes[i].mode); 450 qmi_set_wds_set_ip_family_request(msg, &ipf_req); 451 return QMI_CMD_REQUEST; 452 } 453 454 uqmi_add_error("Invalid value (valid: ipv4, ipv6, unspecified)"); 455 return QMI_CMD_EXIT; 456 } 457 458 static struct { 459 uint32_t type; 460 uint32_t iface; 461 } wds_endpoint_info; 462 463 #define cmd_wds_bind_mux_cb no_cb 464 465 static enum qmi_cmd_result 466 cmd_wds_bind_mux_prepare(struct qmi_dev *qmi, struct qmi_request *req, 467 struct qmi_msg *msg, char *arg) 468 { 469 uint32_t mux_num = strtoul(arg, NULL, 10); 470 struct qmi_wds_bind_mux_data_port_request wds_mux_req = { 471 QMI_INIT_SEQUENCE( 472 endpoint_info, 473 .endpoint_type = wds_endpoint_info.type, 474 .interface_number = wds_endpoint_info.iface, 475 ), 476 QMI_INIT(mux_id, mux_num), 477 QMI_INIT(client_type, QMI_WDS_CLIENT_TYPE_TETHERED), 478 }; 479 480 qmi_set_wds_bind_mux_data_port_request(msg, &wds_mux_req); 481 return QMI_CMD_REQUEST; 482 } 483 484 #define cmd_wds_ep_iface_cb no_cb 485 486 static enum qmi_cmd_result 487 cmd_wds_ep_iface_prepare(struct qmi_dev *qmi, struct qmi_request *req, 488 struct qmi_msg *msg, char *arg) 489 { 490 uint32_t iface_num = strtoul(arg, NULL, 10); 491 492 wds_endpoint_info.iface = iface_num; 493 return QMI_CMD_DONE; 494 } 495 496 #define cmd_wds_ep_type_cb no_cb 497 498 static enum qmi_cmd_result 499 cmd_wds_ep_type_prepare(struct qmi_dev *qmi, struct qmi_request *req, 500 struct qmi_msg *msg, char *arg) 501 { 502 if (strcmp(arg, "hsusb") == 0) { 503 wds_endpoint_info.type = QMI_DATA_ENDPOINT_TYPE_HSUSB; 504 } else if (strcmp(arg, "pcie") == 0) { 505 wds_endpoint_info.type = QMI_DATA_ENDPOINT_TYPE_PCIE; 506 } else { 507 uqmi_add_error("Invalid value (valid: hsusb, pcie)"); 508 return QMI_CMD_EXIT; 509 } 510 511 return QMI_CMD_DONE; 512 } 513 514 static void wds_to_ipv4(const char *name, const uint32_t addr) 515 { 516 struct in_addr ip_addr; 517 char buf[INET_ADDRSTRLEN]; 518 519 ip_addr.s_addr = htonl(addr); 520 blobmsg_add_string(&status, name, inet_ntop(AF_INET, &ip_addr, buf, sizeof(buf))); 521 } 522 523 static void wds_to_ipv6(const char *name, const uint16_t *addr) 524 { 525 char buf[INET6_ADDRSTRLEN]; 526 uint16_t ip_addr[8]; 527 int i; 528 529 for (i = 0; i < ARRAY_SIZE(ip_addr); i++) 530 ip_addr[i] = htons(addr[i]); 531 532 blobmsg_add_string(&status, name, inet_ntop(AF_INET6, &ip_addr, buf, sizeof(buf))); 533 } 534 535 static enum qmi_cmd_result 536 cmd_wds_get_profile_settings_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 537 { 538 struct uqmi_wds_profile_identifier profile; 539 540 if (uqmi_wds_profile_identifier_parse(arg, &profile) < 0) { 541 fprintf(stderr, "Invalid argument\n"); 542 return QMI_CMD_EXIT; 543 } 544 545 struct qmi_wds_get_profile_settings_request p_num = { 546 QMI_INIT_SEQUENCE(profile_id, 547 .profile_type = profile.type, 548 .profile_index = profile.index, 549 ) 550 }; 551 552 qmi_set_wds_get_profile_settings_request(msg, &p_num); 553 return QMI_CMD_REQUEST; 554 } 555 556 static void 557 cmd_wds_get_profile_settings_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 558 { 559 struct qmi_wds_get_profile_settings_response res; 560 561 void *p; 562 563 qmi_parse_wds_get_profile_settings_response(msg, &res); 564 565 p = blobmsg_open_table(&status, NULL); 566 567 blobmsg_add_string(&status, "apn", res.data.apn_name); 568 if (res.set.pdp_type && (int) res.data.pdp_type < ARRAY_SIZE(pdp_types)) 569 blobmsg_add_string(&status, "pdp-type", pdp_types[res.data.pdp_type].pdp_name); 570 blobmsg_add_string(&status, "username", res.data.username); 571 blobmsg_add_string(&status, "password", res.data.password); 572 if (res.set.authentication && (int) res.data.authentication < ARRAY_SIZE(auth_modes)) 573 blobmsg_add_string(&status, "auth", auth_modes[res.data.authentication].auth_name); 574 blobmsg_add_u8(&status, "no-roaming", res.data.roaming_disallowed_flag); 575 blobmsg_add_u8(&status, "apn-disabled", res.data.apn_disabled_flag); 576 blobmsg_close_table(&status, p); 577 } 578 579 static void 580 cmd_wds_get_current_settings_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 581 { 582 void *v4, *v6, *d, *t; 583 struct qmi_wds_get_current_settings_response res; 584 int i; 585 586 qmi_parse_wds_get_current_settings_response(msg, &res); 587 588 t = blobmsg_open_table(&status, NULL); 589 590 if (res.set.pdp_type && (int) res.data.pdp_type < ARRAY_SIZE(pdp_types)) 591 blobmsg_add_string(&status, "pdp-type", pdp_types[res.data.pdp_type].pdp_name); 592 593 if (res.set.ip_family) { 594 for (i = 0; i < ARRAY_SIZE(ipfam_modes); i++) { 595 if (ipfam_modes[i].mode != res.data.ip_family) 596 continue; 597 blobmsg_add_string(&status, "ip-family", ipfam_modes[i].ipfam_name); 598 break; 599 } 600 } 601 602 if (res.set.mtu) 603 blobmsg_add_u32(&status, "mtu", res.data.mtu); 604 605 /* IPV4 */ 606 v4 = blobmsg_open_table(&status, "ipv4"); 607 608 if (res.set.ipv4_address) 609 wds_to_ipv4("ip", res.data.ipv4_address); 610 if (res.set.primary_ipv4_dns_address) 611 wds_to_ipv4("dns1", res.data.primary_ipv4_dns_address); 612 if (res.set.secondary_ipv4_dns_address) 613 wds_to_ipv4("dns2", res.data.secondary_ipv4_dns_address); 614 if (res.set.ipv4_gateway_address) 615 wds_to_ipv4("gateway", res.data.ipv4_gateway_address); 616 if (res.set.ipv4_gateway_subnet_mask) 617 wds_to_ipv4("subnet", res.data.ipv4_gateway_subnet_mask); 618 blobmsg_close_table(&status, v4); 619 620 /* IPV6 */ 621 v6 = blobmsg_open_table(&status, "ipv6"); 622 623 if (res.set.ipv6_address) { 624 wds_to_ipv6("ip", res.data.ipv6_address.address); 625 blobmsg_add_u32(&status, "ip-prefix-length", res.data.ipv6_address.prefix_length); 626 } 627 if (res.set.ipv6_gateway_address) { 628 wds_to_ipv6("gateway", res.data.ipv6_gateway_address.address); 629 blobmsg_add_u32(&status, "gw-prefix-length", res.data.ipv6_gateway_address.prefix_length); 630 } 631 if (res.set.ipv6_primary_dns_address) 632 wds_to_ipv6("dns1", res.data.ipv6_primary_dns_address); 633 if (res.set.ipv6_secondary_dns_address) 634 wds_to_ipv6("dns2", res.data.ipv6_secondary_dns_address); 635 636 blobmsg_close_table(&status, v6); 637 638 d = blobmsg_open_table(&status, "domain-names"); 639 for (i = 0; i < res.data.domain_name_list_n; i++) { 640 blobmsg_add_string(&status, NULL, res.data.domain_name_list[i]); 641 } 642 blobmsg_close_table(&status, d); 643 644 blobmsg_close_table(&status, t); 645 } 646 647 static enum qmi_cmd_result 648 cmd_wds_get_current_settings_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 649 { 650 struct qmi_wds_get_current_settings_request gcs_req; 651 memset(&gcs_req, '\0', sizeof(struct qmi_wds_get_current_settings_request)); 652 qmi_set(&gcs_req, requested_settings, 653 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_PDP_TYPE | 654 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_DNS_ADDRESS | 655 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_GRANTED_QOS | 656 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_IP_ADDRESS | 657 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_GATEWAY_INFO | 658 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_MTU | 659 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_DOMAIN_NAME_LIST | 660 QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_IP_FAMILY); 661 qmi_set_wds_get_current_settings_request(msg, &gcs_req); 662 return QMI_CMD_REQUEST; 663 } 664 665 static enum qmi_cmd_result 666 cmd_wds_get_default_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 667 { 668 int i; 669 for (i = 0; i < ARRAY_SIZE(profile_types); i++) { 670 if (strcasecmp(profile_types[i].profile_name, arg) != 0) 671 continue; 672 673 struct qmi_wds_get_default_profile_number_request type_family = { 674 QMI_INIT_SEQUENCE(profile_type, 675 .type = profile_types[i].profile, 676 .family = QMI_WDS_PROFILE_FAMILY_TETHERED, 677 ) 678 }; 679 680 qmi_set_wds_get_default_profile_number_request(msg, &type_family); 681 return QMI_CMD_REQUEST; 682 } 683 684 uqmi_add_error("Invalid value (valid: 3gpp or 3gpp2)"); 685 return QMI_CMD_EXIT; 686 } 687 688 static void 689 cmd_wds_get_default_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 690 { 691 struct qmi_wds_get_default_profile_number_response res; 692 void *p; 693 qmi_parse_wds_get_default_profile_number_response(msg, &res); 694 695 p = blobmsg_open_table(&status, NULL); 696 697 blobmsg_add_u32(&status, "default-profile", res.data.index); 698 699 blobmsg_close_table(&status, p); 700 } 701 702 #define cmd_wds_set_default_profile_cb no_cb 703 704 static enum qmi_cmd_result 705 cmd_wds_set_default_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, 706 struct qmi_msg *msg, char *arg) 707 { 708 struct uqmi_wds_profile_identifier profile; 709 710 if (uqmi_wds_profile_identifier_parse(arg, &profile) < 0) { 711 fprintf(stderr, "Invalid argument\n"); 712 return QMI_CMD_EXIT; 713 } 714 715 struct qmi_wds_set_default_profile_number_request set_default_profile = { 716 QMI_INIT_SEQUENCE(profile_identifier, 717 .family = QMI_WDS_PROFILE_FAMILY_TETHERED, 718 .type = profile.type, 719 .index = profile.index, 720 ) 721 }; 722 723 qmi_set_wds_set_default_profile_number_request(msg, &set_default_profile); 724 return QMI_CMD_REQUEST; 725 } 726 727 #define cmd_wds_delete_profile_cb no_cb 728 729 static enum qmi_cmd_result 730 cmd_wds_delete_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, 731 struct qmi_msg *msg, char *arg) 732 { 733 struct qmi_wds_delete_profile_request delete_req = { 734 QMI_INIT_SEQUENCE(profile_identifier, 735 .profile_type = QMI_WDS_PROFILE_TYPE_3GPP, 736 .profile_index = 1, 737 ) 738 }; 739 struct uqmi_wds_profile_identifier profile; 740 741 if (uqmi_wds_profile_identifier_parse(arg, &profile) < 0) { 742 fprintf(stderr, "Invalid argument\n"); 743 return QMI_CMD_EXIT; 744 } 745 746 qmi_set_ptr(&delete_req, profile_identifier.profile_type, profile.type); 747 qmi_set_ptr(&delete_req, profile_identifier.profile_index, profile.index); 748 749 qmi_set_wds_delete_profile_request(msg, &delete_req); 750 751 return QMI_CMD_REQUEST; 752 } 753 754 #define cmd_wds_set_lte_attach_pdn_cb no_cb 755 756 static enum qmi_cmd_result 757 cmd_wds_set_lte_attach_pdn_prepare(struct qmi_dev *qmi, struct qmi_request *req, 758 struct qmi_msg *msg, char *arg) 759 { 760 uint16_t list[8] = {0}; 761 762 char *s = arg; 763 int i = 0; 764 765 while (s) { 766 if (i >= 8) { 767 fprintf(stderr, "Only 8 attach PDN supported\n"); 768 return QMI_CMD_EXIT; 769 } 770 771 list[i] = strtoul(s, &s, 10); 772 i++; 773 if (*s == ',') { 774 s++; 775 } else { 776 fprintf(stderr, "Invalid argument\n"); 777 return QMI_CMD_EXIT; 778 } 779 } 780 781 782 struct qmi_wds_set_lte_attach_pdn_list_request lte_attach_pdn = { 783 QMI_INIT_ARRAY(list, list, i), 784 QMI_INIT(action, QMI_WDS_ATTACH_PDN_LIST_ACTION_DETACH_OR_PDN_DISCONNECT) 785 }; 786 787 qmi_set_wds_set_lte_attach_pdn_list_request(msg, <e_attach_pdn); 788 return QMI_CMD_REQUEST; 789 } 790
This page was automatically generated by LXR 0.3.1. • OpenWrt