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