umbim: fix invalid mbim message string encoding
[project/umbim.git] / cli.c
1 /*
2 * umbim
3 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #define __STDC_FORMAT_MACROS
16 #include <inttypes.h>
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20
21 #include <alloca.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <ctype.h>
28
29 #include <libubox/utils.h>
30 #include <libubox/uloop.h>
31
32 #include "mbim.h"
33
34 #include "data/mbim-service-basic-connect.h"
35
36 int return_code = -1;
37 int verbose;
38
39 struct mbim_handler *current_handler;
40 static uint8_t uuid_context_type_internet[16] = { 0x7E, 0x5E, 0x2A, 0x7E, 0x4E, 0x6F, 0x72, 0x72, 0x73, 0x6B, 0x65, 0x6E, 0x7E, 0x5E, 0x2A, 0x7E };
41 static int _argc;
42 static char **_argv;
43
44 static int
45 mbim_device_caps_response(void *buffer, size_t len)
46 {
47 struct mbim_basic_connect_device_caps_r *caps = (struct mbim_basic_connect_device_caps_r *) buffer;
48 char *deviceid, *firmwareinfo, *hardwareinfo;
49
50 if (len < sizeof(struct mbim_basic_connect_device_caps_r)) {
51 fprintf(stderr, "message not long enough\n");
52 return -1;
53 }
54
55 deviceid = mbim_get_string(&caps->deviceid, buffer);
56 firmwareinfo = mbim_get_string(&caps->firmwareinfo, buffer);
57 hardwareinfo = mbim_get_string(&caps->hardwareinfo, buffer);
58
59 printf(" devicetype: %04X - %s\n", le32toh(caps->devicetype),
60 mbim_enum_string(mbim_device_type_values, le32toh(caps->devicetype)));
61 printf(" cellularclass: %04X\n", le32toh(caps->cellularclass));
62 printf(" voiceclass: %04X - %s\n", le32toh(caps->voiceclass),
63 mbim_enum_string(mbim_voice_class_values, le32toh(caps->voiceclass)));
64 printf(" simclass: %04X\n", le32toh(caps->simclass));
65 printf(" dataclass: %04X\n", le32toh(caps->dataclass));
66 printf(" smscaps: %04X\n", le32toh(caps->smscaps));
67 printf(" controlcaps: %04X\n", le32toh(caps->controlcaps));
68 printf(" maxsessions: %04X\n", le32toh(caps->maxsessions));
69 printf(" deviceid: %s\n", deviceid);
70 printf(" firmwareinfo: %s\n", firmwareinfo);
71 printf(" hardwareinfo: %s\n", hardwareinfo);
72
73 return 0;
74 }
75
76 static int
77 mbim_pin_state_response(void *buffer, size_t len)
78 {
79 struct mbim_basic_connect_pin_r *pin = (struct mbim_basic_connect_pin_r *) buffer;
80
81 if (len < sizeof(struct mbim_basic_connect_pin_r)) {
82 fprintf(stderr, "message not long enough\n");
83 return -1;
84 }
85
86 if (le32toh(pin->pinstate) != MBIM_PIN_STATE_UNLOCKED) {
87 fprintf(stderr, "required pin: %d - %s\n",
88 le32toh(pin->pintype), mbim_enum_string(mbim_pin_type_values, le32toh(pin->pintype)));
89 fprintf(stderr, "remaining attempts: %d\n", le32toh(pin->remainingattempts));
90 return le32toh(pin->pintype);
91 }
92
93 fprintf(stderr, "Pin Unlocked\n");
94
95 return 0;
96 }
97
98 static int
99 mbim_home_provider_response(void *buffer, size_t len)
100 {
101 struct mbim_basic_connect_home_provider_r *state = (struct mbim_basic_connect_home_provider_r *) buffer;
102 struct mbimprovider *provider;
103 char *provider_id, *provider_name;
104
105 if (len < sizeof(struct mbim_basic_connect_home_provider_r)) {
106 fprintf(stderr, "message not long enough\n");
107 return -1;
108 }
109
110 provider = &state->provider;
111 provider_id = mbim_get_string(&provider->providerid, buffer);
112 provider_name = mbim_get_string(&provider->providername, buffer);
113
114 printf(" provider_id: %s\n", provider_id);
115 printf(" provider_name: %s\n", provider_name);
116 printf(" cellularclass: %04X - %s\n", le32toh(provider->cellularclass),
117 mbim_enum_string(mbim_cellular_class_values, le32toh(provider->cellularclass)));
118 printf(" rssi: %04X\n", le32toh(provider->rssi));
119 printf(" errorrate: %04X\n", le32toh(provider->errorrate));
120
121 return 0;
122 }
123
124 static int
125 mbim_registration_response(void *buffer, size_t len)
126 {
127 struct mbim_basic_connect_register_state_r *state = (struct mbim_basic_connect_register_state_r *) buffer;
128 char *provider_id, *provider_name, *roamingtext;
129
130 if (len < sizeof(struct mbim_basic_connect_register_state_r)) {
131 fprintf(stderr, "message not long enough\n");
132 return -1;
133 }
134
135 provider_id = mbim_get_string(&state->providerid, buffer);
136 provider_name = mbim_get_string(&state->providername, buffer);
137 roamingtext = mbim_get_string(&state->roamingtext, buffer);
138
139 printf(" nwerror: %04X - %s\n", le32toh(state->nwerror),
140 mbim_enum_string(mbim_nw_error_values, le32toh(state->nwerror)));
141 printf(" registerstate: %04X - %s\n", le32toh(state->registerstate),
142 mbim_enum_string(mbim_register_state_values, le32toh(state->registerstate)));
143 printf(" registermode: %04X - %s\n", le32toh(state->registermode),
144 mbim_enum_string(mbim_register_mode_values, le32toh(state->registermode)));
145 printf(" availabledataclasses: %04X - %s\n", le32toh(state->availabledataclasses),
146 mbim_enum_string(mbim_data_class_values, le32toh(state->availabledataclasses)));
147 printf(" currentcellularclass: %04X - %s\n", le32toh(state->currentcellularclass),
148 mbim_enum_string(mbim_cellular_class_values, le32toh(state->currentcellularclass)));
149 printf(" provider_id: %s\n", provider_id);
150 printf(" provider_name: %s\n", provider_name);
151 printf(" roamingtext: %s\n", roamingtext);
152
153 if (le32toh(state->registerstate) == MBIM_REGISTER_STATE_HOME)
154 return 0;
155
156 return le32toh(state->registerstate);
157 }
158
159 static int
160 mbim_subscriber_response(void *buffer, size_t len)
161 {
162 struct mbim_basic_connect_subscriber_ready_status_r *state = (struct mbim_basic_connect_subscriber_ready_status_r *) buffer;
163 char *subscriberid, *simiccid;
164 unsigned int nr;
165
166 if (len < sizeof(struct mbim_basic_connect_subscriber_ready_status_r)) {
167 fprintf(stderr, "message not long enough\n");
168 return -1;
169 }
170
171 subscriberid = mbim_get_string(&state->subscriberid, buffer);
172 simiccid = mbim_get_string(&state->simiccid, buffer);
173
174 printf(" readystate: %04X - %s\n", le32toh(state->readystate),
175 mbim_enum_string(mbim_subscriber_ready_state_values, le32toh(state->readystate)));
176 printf(" simiccid: %s\n", simiccid);
177 printf(" subscriberid: %s\n", subscriberid);
178 if (le32toh(state->readyinfo) & MBIM_READY_INFO_FLAG_PROTECT_UNIQUE_ID)
179 printf(" dont display subscriberID: 1\n");
180 for (nr = 0; nr < le32toh(state->telephonenumberscount); nr++) {
181 struct mbim_string *str = (void *)&state->telephonenumbers + (nr * sizeof(struct mbim_string));
182 char *number = mbim_get_string(str, buffer);
183 printf(" number: %s\n", number);
184 }
185
186 if (MBIM_SUBSCRIBER_READY_STATE_INITIALIZED == le32toh(state->readystate))
187 return 0;
188
189 return le32toh(state->readystate);
190 }
191
192 static int
193 mbim_attach_response(void *buffer, size_t len)
194 {
195 struct mbim_basic_connect_packet_service_r *ps = (struct mbim_basic_connect_packet_service_r *) buffer;
196
197 if (len < sizeof(struct mbim_basic_connect_packet_service_r)) {
198 fprintf(stderr, "message not long enough\n");
199 return -1;
200 }
201
202 printf(" nwerror: %04X - %s\n", le32toh(ps->nwerror),
203 mbim_enum_string(mbim_nw_error_values, le32toh(ps->nwerror)));
204 printf(" packetservicestate: %04X - %s\n", le32toh(ps->packetservicestate),
205 mbim_enum_string(mbim_packet_service_state_values, le32toh(ps->packetservicestate)));
206 printf(" uplinkspeed: %"PRIu64"\n", (uint64_t) le64toh(ps->uplinkspeed));
207 printf(" downlinkspeed: %"PRIu64"\n", (uint64_t) le64toh(ps->downlinkspeed));
208
209 if (MBIM_PACKET_SERVICE_STATE_ATTACHED == le32toh(ps->packetservicestate))
210 return 0;
211
212 return le32toh(ps->packetservicestate);
213 }
214
215 static int
216 mbim_connect_response(void *buffer, size_t len)
217 {
218 struct mbim_basic_connect_connect_r *c = (struct mbim_basic_connect_connect_r *) buffer;
219
220 if (len < sizeof(struct mbim_basic_connect_connect_r)) {
221 fprintf(stderr, "message not long enough\n");
222 return -1;
223 }
224
225 printf(" sessionid: %d\n", le32toh(c->sessionid));
226 printf(" activationstate: %04X - %s\n", le32toh(c->activationstate),
227 mbim_enum_string(mbim_activation_state_values, le32toh(c->activationstate)));
228 printf(" voicecallstate: %04X - %s\n", le32toh(c->voicecallstate),
229 mbim_enum_string(mbim_voice_call_state_values, le32toh(c->voicecallstate)));
230 printf(" nwerror: %04X - %s\n", le32toh(c->nwerror),
231 mbim_enum_string(mbim_nw_error_values, le32toh(c->nwerror)));
232 printf(" iptype: %04X - %s\n", le32toh(c->iptype),
233 mbim_enum_string(mbim_context_ip_type_values, le32toh(c->iptype)));
234
235 if (MBIM_ACTIVATION_STATE_ACTIVATED == le32toh(c->activationstate))
236 return 0;
237
238 return le32toh(c->activationstate);
239 }
240
241 static int
242 mbim_config_response(void *buffer, size_t len)
243 {
244 struct mbim_basic_connect_ip_configuration_r *ip = (struct mbim_basic_connect_ip_configuration_r *) buffer;
245 char out[40];
246 unsigned int i;
247 uint32_t offset;
248
249 if (len < sizeof(struct mbim_basic_connect_ip_configuration_r)) {
250 fprintf(stderr, "message not long enough\n");
251 return -1;
252 }
253
254 if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS)
255 for (i = 0; i < le32toh(ip->ipv4addresscount); i++) {
256 offset = le32toh(ip->ipv4address) + (i * 4);
257 mbim_get_ipv4(buffer, out, 4 + offset);
258 printf(" ipv4address: %s/%d\n", out, mbim_get_int(buffer, offset));
259 }
260 if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS) {
261 mbim_get_ipv4(buffer, out, le32toh(ip->ipv4gateway));
262 printf(" ipv4gateway: %s\n", out);
263 }
264 if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU)
265 printf(" ipv4mtu: %d\n", le32toh(ip->ipv4mtu));
266 if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS)
267 for (i = 0; i < le32toh(ip->ipv4dnsservercount); i++) {
268 mbim_get_ipv4(buffer, out, le32toh(ip->ipv4dnsserver) + (i * 4));
269 printf(" ipv4dnsserver: %s\n", out);
270 }
271
272 if (le32toh(ip->ipv6configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS)
273 for (i = 0; i < le32toh(ip->ipv6addresscount); i++) {
274 offset = le32toh(ip->ipv6address) + (i * 16);
275 mbim_get_ipv6(buffer, out, 4 + offset);
276 printf(" ipv6address: %s/%d\n", out, mbim_get_int(buffer, offset));
277 }
278 if (le32toh(ip->ipv6configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS) {
279 mbim_get_ipv6(buffer, out, le32toh(ip->ipv6gateway));
280 printf(" ipv6gateway: %s\n", out);
281 }
282 if (le32toh(ip->ipv6configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU)
283 printf(" ipv6mtu: %d\n", le32toh(ip->ipv6mtu));
284 if (le32toh(ip->ipv6configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS)
285 for (i = 0; i < le32toh(ip->ipv6dnsservercount); i++) {
286 mbim_get_ipv6(buffer, out, le32toh(ip->ipv6dnsserver) + (i * 16));
287 printf(" ipv6dnsserver: %s\n", out);
288 }
289
290 return 0;
291 }
292
293 static int
294 mbim_radio_response(void *buffer, size_t len)
295 {
296 struct mbim_basic_connect_radio_state_r *r = (struct mbim_basic_connect_radio_state_r *) buffer;
297
298 if (len < sizeof(struct mbim_basic_connect_radio_state_r)) {
299 fprintf(stderr, "message not long enough\n");
300 return -1;
301 }
302 printf(" hwradiostate: %s\n", r->hwradiostate ? "on" : "off");
303 printf(" swradiostate: %s\n", r->swradiostate ? "on" : "off");
304 return 0;
305 }
306
307 static int
308 mbim_device_caps_request(void)
309 {
310 mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_DEVICE_CAPS, 0);
311
312 return mbim_send_command_msg();
313 }
314
315 static int
316 mbim_pin_state_request(void)
317 {
318 mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_PIN, 0);
319
320 return mbim_send_command_msg();
321 }
322
323 static int
324 mbim_home_provider_request(void)
325 {
326 mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CID_BASIC_CONNECT_HOME_PROVIDER, 0);
327
328 return mbim_send_command_msg();
329 }
330
331 static int
332 mbim_registration_request(void)
333 {
334 if (_argc > 0) {
335 struct mbim_basic_connect_register_state_s *rs =
336 (struct mbim_basic_connect_register_state_s *) mbim_setup_command_msg(basic_connect,
337 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_REGISTER_STATE,
338 sizeof(struct mbim_basic_connect_register_state_s));
339
340 rs->registeraction = htole32(MBIM_REGISTER_ACTION_AUTOMATIC);
341 } else {
342 mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_REGISTER_STATE, 0);
343 }
344
345 return mbim_send_command_msg();
346 }
347
348 static int
349 mbim_subscriber_request(void)
350 {
351 mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_SUBSCRIBER_READY_STATUS, 0);
352
353 return mbim_send_command_msg();
354 }
355
356 static int
357 _mbim_attach_request(int action)
358 {
359 struct mbim_basic_connect_packet_service_s *ps =
360 (struct mbim_basic_connect_packet_service_s *) mbim_setup_command_msg(basic_connect,
361 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_PACKET_SERVICE,
362 sizeof(struct mbim_basic_connect_packet_service_s));
363
364 ps->packetserviceaction = htole32(action);
365
366 return mbim_send_command_msg();
367 }
368
369 static int
370 mbim_attach_request(void)
371 {
372 return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_ATTACH);
373 }
374
375 static int
376 mbim_detach_request(void)
377 {
378 return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_DETACH);
379 }
380
381 static int
382 mbim_connect_request(void)
383 {
384 char *apn;
385 struct mbim_basic_connect_connect_s *c =
386 (struct mbim_basic_connect_connect_s *) mbim_setup_command_msg(basic_connect,
387 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_CONNECT,
388 sizeof(struct mbim_basic_connect_connect_s));
389
390 c->activationcommand = htole32(MBIM_ACTIVATION_COMMAND_ACTIVATE);
391 c->iptype = htole32(MBIM_CONTEXT_IP_TYPE_DEFAULT);
392 memcpy(c->contexttype, uuid_context_type_internet, 16);
393 if (_argc > 0) {
394 apn = index(*_argv, ':');
395 if (!apn) {
396 apn = *_argv;
397 } else {
398 apn[0] = 0;
399 apn++;
400 if (!strcmp(*_argv, "ipv4"))
401 c->iptype = htole32(MBIM_CONTEXT_IP_TYPE_IPV4);
402 else if (!strcmp(*_argv, "ipv6"))
403 c->iptype = htole32(MBIM_CONTEXT_IP_TYPE_IPV6);
404 else if (!strcmp(*_argv, "ipv4v6"))
405 c->iptype = htole32(MBIM_CONTEXT_IP_TYPE_IPV4V6);
406 }
407 mbim_encode_string(&c->accessstring, apn);
408 }
409 if (_argc > 3) {
410 if (!strcmp(_argv[1], "pap"))
411 c->authprotocol = htole32(MBIM_AUTH_PROTOCOL_PAP);
412 else if (!strcmp(_argv[1], "chap"))
413 c->authprotocol = htole32(MBIM_AUTH_PROTOCOL_CHAP);
414 else if (!strcmp(_argv[1], "mschapv2"))
415 c->authprotocol = htole32(MBIM_AUTH_PROTOCOL_MSCHAPV2);
416
417 if (c->authprotocol) {
418 mbim_encode_string(&c->username, _argv[2]);
419 mbim_encode_string(&c->password, _argv[3]);
420 }
421 }
422 return mbim_send_command_msg();
423 }
424
425 static int
426 mbim_disconnect_request(void)
427 {
428 struct mbim_basic_connect_connect_s *c =
429 (struct mbim_basic_connect_connect_s *) mbim_setup_command_msg(basic_connect,
430 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_CONNECT,
431 sizeof(struct mbim_basic_connect_connect_s));
432
433 c->activationcommand = htole32(MBIM_ACTIVATION_COMMAND_DEACTIVATE);
434 memcpy(c->contexttype, uuid_context_type_internet, 16);
435
436 no_close = 0;
437
438 return mbim_send_command_msg();
439 }
440
441 static char*
442 mbim_pin_sanitize(char *pin)
443 {
444 char *p;
445
446 while (*pin && !isdigit(*pin))
447 pin++;
448 p = pin;
449 if (!*p)
450 return NULL;
451 while (*pin && isdigit(*pin))
452 pin++;
453 if (*pin)
454 *pin = '\0';
455
456 return p;
457 }
458
459 static int
460 mbim_pin_unlock_request(void)
461 {
462 struct mbim_basic_connect_pin_s *p =
463 (struct mbim_basic_connect_pin_s *) mbim_setup_command_msg(basic_connect,
464 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_PIN,
465 sizeof(struct mbim_basic_connect_pin_s));
466 char *pin = mbim_pin_sanitize(_argv[0]);
467
468 if (!pin || !strlen(pin)) {
469 fprintf(stderr, "failed to sanitize the pincode\n");
470 return -1;
471 }
472
473 p->pintype = htole32(MBIM_PIN_TYPE_PIN1);
474 p->pinoperation = htole32(MBIM_PIN_OPERATION_ENTER);
475 mbim_encode_string(&p->pin, _argv[0]);
476
477 return mbim_send_command_msg();
478 }
479
480 static int
481 mbim_config_request(void)
482 {
483 mbim_setup_command_msg(basic_connect,
484 MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_IP_CONFIGURATION,
485 sizeof(struct mbim_basic_connect_ip_configuration_q));
486
487 return mbim_send_command_msg();
488 }
489
490 static int
491 mbim_radio_request(void)
492 {
493 if (_argc > 0) {
494 struct mbim_basic_connect_radio_state_s *rs =
495 (struct mbim_basic_connect_radio_state_s *) mbim_setup_command_msg(basic_connect,
496 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_RADIO_STATE,
497 sizeof(struct mbim_basic_connect_radio_state_r));
498
499 if (!strcmp(_argv[0], "off"))
500 rs->radiostate = htole32(MBIM_RADIO_SWITCH_STATE_OFF);
501 else
502 rs->radiostate = htole32(MBIM_RADIO_SWITCH_STATE_ON);
503 } else {
504 mbim_setup_command_msg(basic_connect,
505 MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_RADIO_STATE,
506 sizeof(struct mbim_basic_connect_radio_state_r));
507 }
508 return mbim_send_command_msg();
509 }
510
511 static struct mbim_handler handlers[] = {
512 { "caps", 0, mbim_device_caps_request, mbim_device_caps_response },
513 { "pinstate", 0, mbim_pin_state_request, mbim_pin_state_response },
514 { "unlock", 1, mbim_pin_unlock_request, mbim_pin_state_response },
515 { "home", 0, mbim_home_provider_request, mbim_home_provider_response },
516 { "registration", 0, mbim_registration_request, mbim_registration_response },
517 { "subscriber", 0, mbim_subscriber_request, mbim_subscriber_response },
518 { "attach", 0, mbim_attach_request, mbim_attach_response },
519 { "detach", 0, mbim_detach_request, mbim_attach_response },
520 { "connect", 0, mbim_connect_request, mbim_connect_response },
521 { "disconnect", 0, mbim_disconnect_request, mbim_connect_response },
522 { "config", 0, mbim_config_request, mbim_config_response },
523 { "radio", 0, mbim_radio_request, mbim_radio_response },
524 };
525
526 static int
527 usage(void)
528 {
529 fprintf(stderr, "Usage: umbim <caps|pinstate|unlock|home|registration|subscriber|attach|detach|connect|disconnect|config|radio> [options]\n"
530 "Options:\n"
531 #ifdef LIBQMI_MBIM_PROXY
532 " -p use mbim-proxy\n"
533 #endif
534 " -d <device> the device (/dev/cdc-wdmX)\n"
535 " -t <transaction> the transaction id\n"
536 " -n no close\n\n"
537 " -v verbose\n\n");
538 return 1;
539 }
540
541 int
542 main(int argc, char **argv)
543 {
544 char *cmd, *device = NULL;
545 int no_open = 0, ch;
546 unsigned int i;
547 #ifdef LIBQMI_MBIM_PROXY
548 int proxy = 0;
549 #endif
550
551 while ((ch = getopt(argc, argv, "pnvd:t:")) != -1) {
552 switch (ch) {
553 case 'v':
554 verbose = 1;
555 break;
556 case 'n':
557 no_close = 1;
558 break;
559 case 'd':
560 device = optarg;
561 break;
562 case 't':
563 no_open = 1;
564 transaction_id = atoi(optarg);
565 break;
566 #ifdef LIBQMI_MBIM_PROXY
567 case 'p':
568 proxy = 1;
569 break;
570 #endif
571 default:
572 return usage();
573 }
574 }
575
576 if (!device || optind == argc)
577 return usage();
578
579 cmd = argv[optind];
580 optind++;
581
582 _argc = argc - optind;
583 _argv = &argv[optind];
584
585 for (i = 0; i < ARRAY_SIZE(handlers); i++)
586 if (!strcmp(cmd, handlers[i].name))
587 current_handler = &handlers[i];
588
589 if (!current_handler || (optind + current_handler->argc > argc))
590 return usage();
591
592 uloop_init();
593
594 #ifdef LIBQMI_MBIM_PROXY
595 if (proxy)
596 mbim_proxy_open(device);
597 else
598 #endif
599 mbim_open(device);
600 if (!no_open)
601 mbim_send_open_msg();
602 else if (current_handler->request() < 0)
603 return -1;
604
605 uloop_run();
606 uloop_done();
607
608 return return_code;
609 }