3 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
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
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.
15 #define __STDC_FORMAT_MACROS
18 #include <sys/types.h>
29 #include <libubox/utils.h>
30 #include <libubox/uloop.h>
34 #include "data/mbim-service-basic-connect.h"
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 };
45 mbim_device_caps_response(void *buffer
, size_t len
)
47 struct mbim_basic_connect_device_caps_r
*caps
= (struct mbim_basic_connect_device_caps_r
*) buffer
;
48 char *deviceid
, *firmwareinfo
, *hardwareinfo
;
50 if (len
< sizeof(struct mbim_basic_connect_device_caps_r
)) {
51 fprintf(stderr
, "message not long enough\n");
55 deviceid
= mbim_get_string(&caps
->deviceid
, buffer
);
56 firmwareinfo
= mbim_get_string(&caps
->firmwareinfo
, buffer
);
57 hardwareinfo
= mbim_get_string(&caps
->hardwareinfo
, buffer
);
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
);
77 mbim_pin_state_response(void *buffer
, size_t len
)
79 struct mbim_basic_connect_pin_r
*pin
= (struct mbim_basic_connect_pin_r
*) buffer
;
81 if (len
< sizeof(struct mbim_basic_connect_pin_r
)) {
82 fprintf(stderr
, "message not long enough\n");
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
);
93 fprintf(stderr
, "Pin Unlocked\n");
99 mbim_registration_response(void *buffer
, size_t len
)
101 struct mbim_basic_connect_register_state_r
*state
= (struct mbim_basic_connect_register_state_r
*) buffer
;
102 char *provider_id
, *provider_name
, *roamingtext
;
104 if (len
< sizeof(struct mbim_basic_connect_register_state_r
)) {
105 fprintf(stderr
, "message not long enough\n");
109 provider_id
= mbim_get_string(&state
->providerid
, buffer
);
110 provider_name
= mbim_get_string(&state
->providername
, buffer
);
111 roamingtext
= mbim_get_string(&state
->roamingtext
, buffer
);
113 printf(" nwerror: %04X - %s\n", le32toh(state
->nwerror
),
114 mbim_enum_string(mbim_nw_error_values
, le32toh(state
->nwerror
)));
115 printf(" registerstate: %04X - %s\n", le32toh(state
->registerstate
),
116 mbim_enum_string(mbim_register_state_values
, le32toh(state
->registerstate
)));
117 printf(" registermode: %04X - %s\n", le32toh(state
->registermode
),
118 mbim_enum_string(mbim_register_mode_values
, le32toh(state
->registermode
)));
119 printf(" availabledataclasses: %04X - %s\n", le32toh(state
->availabledataclasses
),
120 mbim_enum_string(mbim_data_class_values
, le32toh(state
->availabledataclasses
)));
121 printf(" currentcellularclass: %04X - %s\n", le32toh(state
->currentcellularclass
),
122 mbim_enum_string(mbim_cellular_class_values
, le32toh(state
->currentcellularclass
)));
123 printf(" provider_id: %s\n", provider_id
);
124 printf(" provider_name: %s\n", provider_name
);
125 printf(" roamingtext: %s\n", roamingtext
);
127 if (le32toh(state
->registerstate
) == MBIM_REGISTER_STATE_HOME
)
130 return le32toh(state
->registerstate
);
134 mbim_subscriber_response(void *buffer
, size_t len
)
136 struct mbim_basic_connect_subscriber_ready_status_r
*state
= (struct mbim_basic_connect_subscriber_ready_status_r
*) buffer
;
137 char *subscriberid
, *simiccid
;
140 if (len
< sizeof(struct mbim_basic_connect_subscriber_ready_status_r
)) {
141 fprintf(stderr
, "message not long enough\n");
145 subscriberid
= mbim_get_string(&state
->subscriberid
, buffer
);
146 simiccid
= mbim_get_string(&state
->simiccid
, buffer
);
148 printf(" readystate: %04X - %s\n", le32toh(state
->readystate
),
149 mbim_enum_string(mbim_subscriber_ready_state_values
, le32toh(state
->readystate
)));
150 printf(" simiccid: %s\n", simiccid
);
151 printf(" subscriberid: %s\n", subscriberid
);
152 if (le32toh(state
->readyinfo
) & MBIM_READY_INFO_FLAG_PROTECT_UNIQUE_ID
)
153 printf(" dont display subscriberID: 1\n");
154 for (nr
= 0; nr
< le32toh(state
->telephonenumberscount
); nr
++) {
155 struct mbim_string
*str
= (void *)&state
->telephonenumbers
+ (nr
* sizeof(struct mbim_string
));
156 char *number
= mbim_get_string(str
, buffer
);
157 printf(" number: %s\n", number
);
160 if (MBIM_SUBSCRIBER_READY_STATE_INITIALIZED
== le32toh(state
->readystate
))
163 return le32toh(state
->readystate
);
167 mbim_attach_response(void *buffer
, size_t len
)
169 struct mbim_basic_connect_packet_service_r
*ps
= (struct mbim_basic_connect_packet_service_r
*) buffer
;
171 if (len
< sizeof(struct mbim_basic_connect_packet_service_r
)) {
172 fprintf(stderr
, "message not long enough\n");
176 printf(" nwerror: %04X - %s\n", le32toh(ps
->nwerror
),
177 mbim_enum_string(mbim_nw_error_values
, le32toh(ps
->nwerror
)));
178 printf(" packetservicestate: %04X - %s\n", le32toh(ps
->packetservicestate
),
179 mbim_enum_string(mbim_packet_service_state_values
, le32toh(ps
->packetservicestate
)));
180 printf(" uplinkspeed: %"PRIu64
"\n", (uint64_t) le64toh(ps
->uplinkspeed
));
181 printf(" downlinkspeed: %"PRIu64
"\n", (uint64_t) le64toh(ps
->downlinkspeed
));
183 if (MBIM_PACKET_SERVICE_STATE_ATTACHED
== le32toh(ps
->packetservicestate
))
186 return le32toh(ps
->packetservicestate
);
190 mbim_connect_response(void *buffer
, size_t len
)
192 struct mbim_basic_connect_connect_r
*c
= (struct mbim_basic_connect_connect_r
*) buffer
;
194 if (len
< sizeof(struct mbim_basic_connect_connect_r
)) {
195 fprintf(stderr
, "message not long enough\n");
199 printf(" sessionid: %d\n", le32toh(c
->sessionid
));
200 printf(" activationstate: %04X - %s\n", le32toh(c
->activationstate
),
201 mbim_enum_string(mbim_activation_state_values
, le32toh(c
->activationstate
)));
202 printf(" voicecallstate: %04X - %s\n", le32toh(c
->voicecallstate
),
203 mbim_enum_string(mbim_voice_call_state_values
, le32toh(c
->voicecallstate
)));
204 printf(" nwerror: %04X - %s\n", le32toh(c
->nwerror
),
205 mbim_enum_string(mbim_nw_error_values
, le32toh(c
->nwerror
)));
206 printf(" iptype: %04X - %s\n", le32toh(c
->iptype
),
207 mbim_enum_string(mbim_context_ip_type_values
, le32toh(c
->iptype
)));
209 if (MBIM_ACTIVATION_STATE_ACTIVATED
== le32toh(c
->activationstate
))
212 return le32toh(c
->activationstate
);
216 mbim_config_response(void *buffer
, size_t len
)
218 struct mbim_basic_connect_ip_configuration_r
*ip
= (struct mbim_basic_connect_ip_configuration_r
*) buffer
;
223 if (len
< sizeof(struct mbim_basic_connect_ip_configuration_r
)) {
224 fprintf(stderr
, "message not long enough\n");
228 if (le32toh(ip
->ipv4configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS
)
229 for (i
= 0; i
< le32toh(ip
->ipv4addresscount
); i
++) {
230 offset
= le32toh(ip
->ipv4address
) + (i
* 4);
231 mbim_get_ipv4(buffer
, out
, 4 + offset
);
232 printf(" ipv4address: %s/%d\n", out
, mbim_get_int(buffer
, offset
));
234 if (le32toh(ip
->ipv4configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS
) {
235 mbim_get_ipv4(buffer
, out
, le32toh(ip
->ipv4gateway
));
236 printf(" ipv4gateway: %s\n", out
);
238 if (le32toh(ip
->ipv4configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU
)
239 printf(" ipv4mtu: %d\n", le32toh(ip
->ipv4mtu
));
240 if (le32toh(ip
->ipv4configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS
)
241 for (i
= 0; i
< le32toh(ip
->ipv4dnsservercount
); i
++) {
242 mbim_get_ipv4(buffer
, out
, le32toh(ip
->ipv4dnsserver
) + (i
* 4));
243 printf(" ipv4dnsserver: %s\n", out
);
246 if (le32toh(ip
->ipv6configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS
)
247 for (i
= 0; i
< le32toh(ip
->ipv6addresscount
); i
++) {
248 offset
= le32toh(ip
->ipv6address
) + (i
* 16);
249 mbim_get_ipv6(buffer
, out
, 4 + offset
);
250 printf(" ipv6address: %s/%d\n", out
, mbim_get_int(buffer
, offset
));
252 if (le32toh(ip
->ipv6configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS
) {
253 mbim_get_ipv6(buffer
, out
, le32toh(ip
->ipv6gateway
));
254 printf(" ipv6gateway: %s\n", out
);
256 if (le32toh(ip
->ipv6configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU
)
257 printf(" ipv6mtu: %d\n", le32toh(ip
->ipv6mtu
));
258 if (le32toh(ip
->ipv6configurationavailable
) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS
)
259 for (i
= 0; i
< le32toh(ip
->ipv6dnsservercount
); i
++) {
260 mbim_get_ipv6(buffer
, out
, le32toh(ip
->ipv6dnsserver
) + (i
* 16));
261 printf(" ipv6dnsserver: %s\n", out
);
268 mbim_radio_response(void *buffer
, size_t len
)
270 struct mbim_basic_connect_radio_state_r
*r
= (struct mbim_basic_connect_radio_state_r
*) buffer
;
272 if (len
< sizeof(struct mbim_basic_connect_radio_state_r
)) {
273 fprintf(stderr
, "message not long enough\n");
276 printf(" hwradiostate: %s\n", r
->hwradiostate
? "on" : "off");
277 printf(" swradiostate: %s\n", r
->swradiostate
? "on" : "off");
282 mbim_device_caps_request(void)
284 mbim_setup_command_msg(basic_connect
, MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_DEVICE_CAPS
, 0);
286 return mbim_send_command_msg();
290 mbim_pin_state_request(void)
292 mbim_setup_command_msg(basic_connect
, MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_PIN
, 0);
294 return mbim_send_command_msg();
298 mbim_registration_request(void)
301 struct mbim_basic_connect_register_state_s
*rs
=
302 (struct mbim_basic_connect_register_state_s
*) mbim_setup_command_msg(basic_connect
,
303 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_REGISTER_STATE
,
304 sizeof(struct mbim_basic_connect_register_state_s
));
306 rs
->registeraction
= htole32(MBIM_REGISTER_ACTION_AUTOMATIC
);
308 mbim_setup_command_msg(basic_connect
, MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_REGISTER_STATE
, 0);
311 return mbim_send_command_msg();
315 mbim_subscriber_request(void)
317 mbim_setup_command_msg(basic_connect
, MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_SUBSCRIBER_READY_STATUS
, 0);
319 return mbim_send_command_msg();
323 _mbim_attach_request(int action
)
325 struct mbim_basic_connect_packet_service_s
*ps
=
326 (struct mbim_basic_connect_packet_service_s
*) mbim_setup_command_msg(basic_connect
,
327 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_PACKET_SERVICE
,
328 sizeof(struct mbim_basic_connect_packet_service_s
));
330 ps
->packetserviceaction
= htole32(action
);
332 return mbim_send_command_msg();
336 mbim_attach_request(void)
338 return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_ATTACH
);
342 mbim_detach_request(void)
344 return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_DETACH
);
348 mbim_connect_request(void)
351 struct mbim_basic_connect_connect_s
*c
=
352 (struct mbim_basic_connect_connect_s
*) mbim_setup_command_msg(basic_connect
,
353 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_CONNECT
,
354 sizeof(struct mbim_basic_connect_connect_s
));
356 c
->activationcommand
= htole32(MBIM_ACTIVATION_COMMAND_ACTIVATE
);
357 c
->iptype
= htole32(MBIM_CONTEXT_IP_TYPE_DEFAULT
);
358 memcpy(c
->contexttype
, uuid_context_type_internet
, 16);
360 apn
= index(*_argv
, ':');
366 if (!strcmp(*_argv
, "ipv4"))
367 c
->iptype
= htole32(MBIM_CONTEXT_IP_TYPE_IPV4
);
368 else if (!strcmp(*_argv
, "ipv6"))
369 c
->iptype
= htole32(MBIM_CONTEXT_IP_TYPE_IPV6
);
370 else if (!strcmp(*_argv
, "ipv4v6"))
371 c
->iptype
= htole32(MBIM_CONTEXT_IP_TYPE_IPV4V6
);
373 mbim_encode_string(&c
->accessstring
, apn
);
376 if (!strcmp(_argv
[1], "pap"))
377 c
->authprotocol
= htole32(MBIM_AUTH_PROTOCOL_PAP
);
378 else if (!strcmp(_argv
[1], "chap"))
379 c
->authprotocol
= htole32(MBIM_AUTH_PROTOCOL_CHAP
);
380 else if (!strcmp(_argv
[1], "mschapv2"))
381 c
->authprotocol
= htole32(MBIM_AUTH_PROTOCOL_MSCHAPV2
);
383 if (c
->authprotocol
) {
384 mbim_encode_string(&c
->username
, _argv
[2]);
385 mbim_encode_string(&c
->password
, _argv
[3]);
388 return mbim_send_command_msg();
392 mbim_disconnect_request(void)
394 struct mbim_basic_connect_connect_s
*c
=
395 (struct mbim_basic_connect_connect_s
*) mbim_setup_command_msg(basic_connect
,
396 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_CONNECT
,
397 sizeof(struct mbim_basic_connect_connect_s
));
399 c
->activationcommand
= htole32(MBIM_ACTIVATION_COMMAND_DEACTIVATE
);
400 memcpy(c
->contexttype
, uuid_context_type_internet
, 16);
404 return mbim_send_command_msg();
408 mbim_pin_sanitize(char *pin
)
412 while (*pin
&& !isdigit(*pin
))
417 while (*pin
&& isdigit(*pin
))
426 mbim_pin_unlock_request(void)
428 struct mbim_basic_connect_pin_s
*p
=
429 (struct mbim_basic_connect_pin_s
*) mbim_setup_command_msg(basic_connect
,
430 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_PIN
,
431 sizeof(struct mbim_basic_connect_pin_s
));
432 char *pin
= mbim_pin_sanitize(_argv
[0]);
434 if (!pin
|| !strlen(pin
)) {
435 fprintf(stderr
, "failed to sanitize the pincode\n");
439 p
->pintype
= htole32(MBIM_PIN_TYPE_PIN1
);
440 p
->pinoperation
= htole32(MBIM_PIN_OPERATION_ENTER
);
441 mbim_encode_string(&p
->pin
, _argv
[0]);
443 return mbim_send_command_msg();
447 mbim_config_request(void)
449 mbim_setup_command_msg(basic_connect
,
450 MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_IP_CONFIGURATION
,
451 sizeof(struct mbim_basic_connect_ip_configuration_q
));
453 return mbim_send_command_msg();
457 mbim_radio_request(void)
460 struct mbim_basic_connect_radio_state_s
*rs
=
461 (struct mbim_basic_connect_radio_state_s
*) mbim_setup_command_msg(basic_connect
,
462 MBIM_MESSAGE_COMMAND_TYPE_SET
, MBIM_CMD_BASIC_CONNECT_RADIO_STATE
,
463 sizeof(struct mbim_basic_connect_radio_state_r
));
465 if (!strcmp(_argv
[0], "off"))
466 rs
->radiostate
= htole32(MBIM_RADIO_SWITCH_STATE_OFF
);
468 rs
->radiostate
= htole32(MBIM_RADIO_SWITCH_STATE_ON
);
470 mbim_setup_command_msg(basic_connect
,
471 MBIM_MESSAGE_COMMAND_TYPE_QUERY
, MBIM_CMD_BASIC_CONNECT_RADIO_STATE
,
472 sizeof(struct mbim_basic_connect_radio_state_r
));
474 return mbim_send_command_msg();
477 static struct mbim_handler handlers
[] = {
478 { "caps", 0, mbim_device_caps_request
, mbim_device_caps_response
},
479 { "pinstate", 0, mbim_pin_state_request
, mbim_pin_state_response
},
480 { "unlock", 1, mbim_pin_unlock_request
, mbim_pin_state_response
},
481 { "registration", 0, mbim_registration_request
, mbim_registration_response
},
482 { "subscriber", 0, mbim_subscriber_request
, mbim_subscriber_response
},
483 { "attach", 0, mbim_attach_request
, mbim_attach_response
},
484 { "detach", 0, mbim_detach_request
, mbim_attach_response
},
485 { "connect", 0, mbim_connect_request
, mbim_connect_response
},
486 { "disconnect", 0, mbim_disconnect_request
, mbim_connect_response
},
487 { "config", 0, mbim_config_request
, mbim_config_response
},
488 { "radio", 0, mbim_radio_request
, mbim_radio_response
},
494 fprintf(stderr
, "Usage: umbim <caps|pinstate|unlock|registration|subscriber|attach|detach|connect|disconnect|config|radio> [options]\n"
496 #ifdef LIBQMI_MBIM_PROXY
497 " -p use mbim-proxy\n"
499 " -d <device> the device (/dev/cdc-wdmX)\n"
500 " -t <transaction> the transaction id\n"
507 main(int argc
, char **argv
)
509 char *cmd
, *device
= NULL
;
512 #ifdef LIBQMI_MBIM_PROXY
516 while ((ch
= getopt(argc
, argv
, "pnvd:t:")) != -1) {
529 transaction_id
= atoi(optarg
);
531 #ifdef LIBQMI_MBIM_PROXY
541 if (!device
|| optind
== argc
)
547 _argc
= argc
- optind
;
548 _argv
= &argv
[optind
];
550 for (i
= 0; i
< ARRAY_SIZE(handlers
); i
++)
551 if (!strcmp(cmd
, handlers
[i
].name
))
552 current_handler
= &handlers
[i
];
554 if (!current_handler
|| (optind
+ current_handler
->argc
> argc
))
559 #ifdef LIBQMI_MBIM_PROXY
561 mbim_proxy_open(device
);
566 mbim_send_open_msg();
567 else if (current_handler
->request() < 0)