add gpl license
[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
28 #include <libubox/utils.h>
29 #include <libubox/uloop.h>
30
31 #include "mbim.h"
32
33 #include "data/mbim-service-basic-connect.h"
34
35 int return_code = -1;
36 int verbose;
37
38 struct mbim_handler *current_handler;
39 static uint8_t uuid_context_type_internet[16] = { 0x7E, 0x5E, 0x2A, 0x7E, 0x4E, 0x6F, 0x72, 0x72, 0x73, 0x6B, 0x65, 0x6E, 0x7E, 0x5E, 0x2A, 0x7E };
40 static int _argc;
41 static char **_argv;
42
43 static int
44 mbim_device_caps_response(void *buffer, int len)
45 {
46         struct mbim_basic_connect_device_caps_r *caps = (struct mbim_basic_connect_device_caps_r *) buffer;
47         char *deviceid, *firmwareinfo, *hardwareinfo;
48
49         if (len < sizeof(struct mbim_basic_connect_device_caps_r)) {
50                 fprintf(stderr, "message not long enough\n");
51                 return -1;
52         }
53
54         deviceid = mbim_get_string(&caps->deviceid, buffer);
55         firmwareinfo = mbim_get_string(&caps->firmwareinfo, buffer);
56         hardwareinfo = mbim_get_string(&caps->hardwareinfo, buffer);
57
58         printf("  devicetype: %04X - %s\n", le32toh(caps->devicetype),
59                 mbim_enum_string(mbim_device_type_values, le32toh(caps->devicetype)));
60         printf("  cellularclass: %04X\n", le32toh(caps->cellularclass));
61         printf("  voiceclass: %04X - %s\n", le32toh(caps->voiceclass),
62                 mbim_enum_string(mbim_voice_class_values, le32toh(caps->voiceclass)));
63         printf("  simclass: %04X\n", le32toh(caps->simclass));
64         printf("  dataclass: %04X\n", le32toh(caps->dataclass));
65         printf("  smscaps: %04X\n", le32toh(caps->smscaps));
66         printf("  controlcaps: %04X\n", le32toh(caps->controlcaps));
67         printf("  maxsessions: %04X\n", le32toh(caps->maxsessions));
68         printf("  deviceid: %s\n", deviceid);
69         printf("  firmwareinfo: %s\n", firmwareinfo);
70         printf("  hardwareinfo: %s\n", hardwareinfo);
71
72         return 0;
73 }
74
75 static int
76 mbim_pin_state_response(void *buffer, int len)
77 {
78         struct mbim_basic_connect_pin_r *pin = (struct mbim_basic_connect_pin_r *) buffer;
79
80         if (len < sizeof(struct mbim_basic_connect_pin_r)) {
81                 fprintf(stderr, "message not long enough\n");
82                 return -1;
83         }
84
85         if (le32toh(pin->pinstate) != MBIM_PIN_STATE_UNLOCKED) {
86                 fprintf(stderr, "required pin: %d - %s\n",
87                         le32toh(pin->pintype), mbim_enum_string(mbim_pin_type_values, le32toh(pin->pintype)));
88                 fprintf(stderr, "remaining attempts: %d\n", le32toh(pin->remainingattempts));
89                 return le32toh(pin->pintype);
90         }
91
92         fprintf(stderr, "Pin Unlocked\n");
93
94         return 0;
95 }
96
97 static int
98 mbim_registration_response(void *buffer, int len)
99 {
100         struct mbim_basic_connect_register_state_r *state = (struct mbim_basic_connect_register_state_r *) buffer;
101         char *provider_id, *provider_name, *roamingtext;
102
103         if (len < sizeof(struct mbim_basic_connect_register_state_r)) {
104                 fprintf(stderr, "message not long enough\n");
105                 return -1;
106         }
107
108         provider_id = mbim_get_string(&state->providerid, buffer);
109         provider_name = mbim_get_string(&state->providername, buffer);
110         roamingtext = mbim_get_string(&state->roamingtext, buffer);
111
112         printf("  nwerror: %04X - %s\n", le32toh(state->nwerror),
113                 mbim_enum_string(mbim_nw_error_values, le32toh(state->nwerror)));
114         printf("  registerstate: %04X - %s\n", le32toh(state->registerstate),
115                 mbim_enum_string(mbim_register_state_values, le32toh(state->registerstate)));
116         printf("  registermode: %04X - %s\n", le32toh(state->registermode),
117                 mbim_enum_string(mbim_register_mode_values, le32toh(state->registermode)));
118         printf("  availabledataclasses: %04X - %s\n", le32toh(state->availabledataclasses),
119                 mbim_enum_string(mbim_data_class_values, le32toh(state->availabledataclasses)));
120         printf("  currentcellularclass: %04X - %s\n", le32toh(state->currentcellularclass),
121                 mbim_enum_string(mbim_cellular_class_values, le32toh(state->currentcellularclass)));
122         printf("  provider_id: %s\n", provider_id);
123         printf("  provider_name: %s\n", provider_name);
124         printf("  roamingtext: %s\n", roamingtext);
125
126         if (le32toh(state->registerstate) == MBIM_REGISTER_STATE_HOME)
127                 return 0;
128
129         return le32toh(state->registerstate);
130 }
131
132 static int
133 mbim_subscriber_response(void *buffer, int len)
134 {
135         struct mbim_basic_connect_subscriber_ready_status_r *state = (struct mbim_basic_connect_subscriber_ready_status_r *) buffer;
136         char *subscriberid, *simiccid;
137         int nr;
138
139         if (len < sizeof(struct mbim_basic_connect_subscriber_ready_status_r)) {
140                 fprintf(stderr, "message not long enough\n");
141                 return -1;
142         }
143
144         subscriberid = mbim_get_string(&state->subscriberid, buffer);
145         simiccid = mbim_get_string(&state->simiccid, buffer);
146
147         printf("  readystate: %04X - %s\n", le32toh(state->readystate),
148                 mbim_enum_string(mbim_subscriber_ready_state_values, le32toh(state->readystate)));
149         printf("  simiccid: %s\n", simiccid);
150         printf("  subscriberid: %s\n", subscriberid);
151         if (le32toh(state->readyinfo) & MBIM_READY_INFO_FLAG_PROTECT_UNIQUE_ID)
152                 printf("  dont display subscriberID: 1\n");
153         for (nr = 0; nr < le32toh(state->telephonenumberscount); nr++) {
154                 struct mbim_string *str = buffer + le32toh(state->telephonenumbers) + (nr * sizeof(struct mbim_string));
155                 char *number = mbim_get_string(str, buffer);
156                 printf("  number: %s\n", number);
157         }
158
159         if (MBIM_SUBSCRIBER_READY_STATE_INITIALIZED == le32toh(state->readystate))
160                 return 0;
161
162         return le32toh(state->readystate);
163 }
164
165 static int
166 mbim_attach_response(void *buffer, int len)
167 {
168         struct mbim_basic_connect_packet_service_r *ps = (struct mbim_basic_connect_packet_service_r *) buffer;
169
170         if (len < sizeof(struct mbim_basic_connect_packet_service_r)) {
171                 fprintf(stderr, "message not long enough\n");
172                 return -1;
173         }
174
175         printf("  nwerror: %04X - %s\n", le32toh(ps->nwerror),
176                 mbim_enum_string(mbim_nw_error_values, le32toh(ps->nwerror)));
177         printf("  packetservicestate: %04X - %s\n", le32toh(ps->packetservicestate),
178                 mbim_enum_string(mbim_packet_service_state_values, le32toh(ps->packetservicestate)));
179         printf("  uplinkspeed: %"PRIu64"\n", le64toh(ps->uplinkspeed));
180         printf("  downlinkspeed: %"PRIu64"\n", le64toh(ps->downlinkspeed));
181
182         if (MBIM_PACKET_SERVICE_STATE_ATTACHED == le32toh(ps->packetservicestate))
183                 return 0;
184
185         return le32toh(ps->packetservicestate);
186 }
187
188 static int
189 mbim_connect_response(void *buffer, int len)
190 {
191         struct mbim_basic_connect_connect_r *c = (struct mbim_basic_connect_connect_r *) buffer;
192
193         if (len < sizeof(struct mbim_basic_connect_connect_r)) {
194                 fprintf(stderr, "message not long enough\n");
195                 return -1;
196         }
197
198         printf("  sessionid: %d\n", le32toh(c->sessionid));
199         printf("  activationstate: %04X - %s\n", le32toh(c->activationstate),
200                 mbim_enum_string(mbim_activation_state_values, le32toh(c->activationstate)));
201         printf("  voicecallstate: %04X - %s\n", le32toh(c->voicecallstate),
202                 mbim_enum_string(mbim_voice_call_state_values, le32toh(c->voicecallstate)));
203         printf("  nwerror: %04X - %s\n", le32toh(c->nwerror),
204                 mbim_enum_string(mbim_nw_error_values, le32toh(c->nwerror)));
205         printf("  iptype: %04X - %s\n", le32toh(c->iptype),
206                 mbim_enum_string(mbim_context_ip_type_values, le32toh(c->iptype)));
207
208         if (MBIM_ACTIVATION_STATE_ACTIVATED == le32toh(c->activationstate))
209                 return 0;
210
211         return le32toh(c->activationstate);
212 }
213
214 static int
215 mbim_config_response(void *buffer, int len)
216 {
217         struct mbim_basic_connect_ip_configuration_r *ip = (struct mbim_basic_connect_ip_configuration_r *) buffer;
218         char ipv4[16];
219         int i;
220
221         if (len < sizeof(struct mbim_basic_connect_ip_configuration_r)) {
222                 fprintf(stderr, "message not long enough\n");
223                 return -1;
224         }
225
226         if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS)
227                 for (i = 0; i < le32toh(ip->ipv4addresscount); i++) {
228                         mbim_get_ipv4(buffer, ipv4, ip->ipv4address + (i * 4));
229                         printf("  ipv4address: %s\n", ipv4);
230                 }
231         if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS) {
232                 mbim_get_ipv4(buffer, ipv4, ip->ipv4gateway);
233                 printf("  ipv4gateway: %s\n", ipv4);
234         }
235         if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU)
236                 printf("  ipv4mtu: %d\n", le32toh(ip->ipv4mtu));
237         if (le32toh(ip->ipv4configurationavailable) & MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS)
238                 for (i = 0; i < le32toh(ip->ipv4dnsservercount); i++) {
239                         mbim_get_ipv4(buffer, ipv4, ip->ipv4dnsserver + (i * 4));
240                         printf("  ipv4dnsserver: %s\n", ipv4);
241                 }
242
243         printf("  ipv6configurationavailable: %04X\n", le32toh(ip->ipv6configurationavailable));
244
245         return 0;
246 }
247
248 static int
249 mbim_device_caps_request(void)
250 {
251         mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_DEVICE_CAPS, 0);
252
253         return mbim_send_command_msg();
254 }
255
256 static int
257 mbim_pin_state_request(void)
258 {
259         mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_PIN, 0);
260
261         return mbim_send_command_msg();
262 }
263
264 static int
265 mbim_registration_request(void)
266 {
267         mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_REGISTER_STATE, 0);
268
269         return mbim_send_command_msg();
270 }
271
272 static int
273 mbim_subscriber_request(void)
274 {
275         mbim_setup_command_msg(basic_connect, MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_SUBSCRIBER_READY_STATUS, 0);
276
277         return mbim_send_command_msg();
278 }
279
280 static int
281 _mbim_attach_request(int action)
282 {
283         struct mbim_basic_connect_packet_service_s *ps =
284                 (struct mbim_basic_connect_packet_service_s *) mbim_setup_command_msg(basic_connect,
285                         MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_PACKET_SERVICE,
286                         sizeof(struct mbim_basic_connect_packet_service_s));
287
288         ps->packetserviceaction = htole32(action);
289
290         return mbim_send_command_msg();
291 }
292
293 static int
294 mbim_attach_request(void)
295 {
296         return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_ATTACH);
297 }
298
299 static int
300 mbim_detach_request(void)
301 {
302         return _mbim_attach_request(MBIM_PACKET_SERVICE_ACTION_DETACH);
303 }
304
305 static int
306 mbim_connect_request(void)
307 {
308         struct mbim_basic_connect_connect_s *c =
309                 (struct mbim_basic_connect_connect_s *) mbim_setup_command_msg(basic_connect,
310                         MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_CONNECT,
311                         sizeof(struct mbim_basic_connect_connect_s));
312
313         c->activationcommand = htole32(MBIM_ACTIVATION_COMMAND_ACTIVATE);
314         c->iptype = htole32(MBIM_CONTEXT_IP_TYPE_DEFAULT);
315         memcpy(c->contexttype, uuid_context_type_internet, 16);
316         if (_argc > 0)
317                 mbim_encode_string(&c->accessstring, *_argv);
318
319         return mbim_send_command_msg();
320 }
321
322 static int
323 mbim_disconnect_request(void)
324 {
325         struct mbim_basic_connect_connect_s *c =
326                 (struct mbim_basic_connect_connect_s *) mbim_setup_command_msg(basic_connect,
327                         MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_CONNECT,
328                         sizeof(struct mbim_basic_connect_connect_s));
329
330         c->activationcommand = htole32(MBIM_ACTIVATION_COMMAND_DEACTIVATE);
331         memcpy(c->contexttype, uuid_context_type_internet, 16);
332
333         no_close = 0;
334
335         return mbim_send_command_msg();
336 }
337
338 static int
339 mbim_pin_unlock_request(void)
340 {
341         struct mbim_basic_connect_pin_s *p =
342                 (struct mbim_basic_connect_pin_s *) mbim_setup_command_msg(basic_connect,
343                         MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_BASIC_CONNECT_PIN,
344                         sizeof(struct mbim_basic_connect_pin_s));
345
346         p->pintype = htole32(MBIM_PIN_TYPE_PIN1);
347         p->pinoperation = htole32(MBIM_PIN_OPERATION_ENTER);
348         mbim_encode_string(&p->pin, _argv[0]);
349
350         return mbim_send_command_msg();
351 }
352
353 static int
354 mbim_config_request(void)
355 {
356         mbim_setup_command_msg(basic_connect,
357                 MBIM_MESSAGE_COMMAND_TYPE_QUERY, MBIM_CMD_BASIC_CONNECT_IP_CONFIGURATION,
358                 sizeof(struct mbim_basic_connect_ip_configuration_q));
359
360         return mbim_send_command_msg();
361 }
362
363 static struct mbim_handler handlers[] = {
364         { "caps", 0, mbim_device_caps_request, mbim_device_caps_response },
365         { "pinstate", 0, mbim_pin_state_request, mbim_pin_state_response },
366         { "unlock", 1, mbim_pin_unlock_request, mbim_pin_state_response },
367         { "registration", 0, mbim_registration_request, mbim_registration_response },
368         { "subscriber", 0, mbim_subscriber_request, mbim_subscriber_response },
369         { "attach", 0, mbim_attach_request, mbim_attach_response },
370         { "detach", 0, mbim_detach_request, mbim_attach_response },
371         { "connect", 0, mbim_connect_request, mbim_connect_response },
372         { "disconnect", 0, mbim_disconnect_request, mbim_connect_response },
373         { "config", 0, mbim_config_request, mbim_config_response },
374 };
375
376 static int
377 usage(void)
378 {
379         fprintf(stderr, "Usage: mbim <caps|pinstate|unlock|connect|disconnect> [options]\n"
380                 "Options:\n"
381                 "    -d <device>        the device (/dev/cdc-wdmX)\n"
382                 "    -t <transaction>   the transaction id\n"
383                 "    -n                 no close\n\n"
384                 "    -v                 verbose\n\n");
385         return 1;
386 }
387
388 int
389 main(int argc, char **argv)
390 {
391         char *cmd, *device = NULL;
392         int no_open = 0, ch, i;
393
394         while ((ch = getopt(argc, argv, "nvd:t:")) != -1) {
395                 switch (ch) {
396                 case 'v':
397                         verbose = 1;
398                         break;
399                 case 'n':
400                         no_close = 1;
401                         break;
402                 case 'd':
403                         device = optarg;
404                         break;
405                 case 't':
406                         no_open = 1;
407                         transaction_id = atoi(optarg);
408                         break;
409                 default:
410                         return usage();
411                 }
412         }
413
414         if (!device || optind == argc)
415                 return usage();
416
417         cmd = argv[optind];
418         optind++;
419
420         _argc = argc - optind;
421         _argv = &argv[optind];
422
423         for (i = 0; i < ARRAY_SIZE(handlers); i++)
424                 if (!strcmp(cmd, handlers[i].name))
425                         current_handler = &handlers[i];
426
427         if (!current_handler || (optind + current_handler->argc > argc))
428                 return usage();
429
430         uloop_init();
431
432         mbim_open(device);
433         if (!no_open)
434                 mbim_send_open_msg();
435         else if (current_handler->request() < 0)
436                 return -1;
437
438         uloop_run();
439         uloop_done();
440
441         return return_code;
442 }