umbctl.c revision 1.2.4.2 1 1.2.4.2 christos /* $NetBSD: umbctl.c,v 1.2.4.2 2019/06/10 22:05:36 christos Exp $ */
2 1.2.4.2 christos /*
3 1.2.4.2 christos * Copyright (c) 2018 Pierre Pronchery <khorben (at) defora.org>
4 1.2.4.2 christos *
5 1.2.4.2 christos * All rights reserved.
6 1.2.4.2 christos *
7 1.2.4.2 christos * Redistribution and use in source and binary forms, with or without
8 1.2.4.2 christos * modification, are permitted provided that the following conditions
9 1.2.4.2 christos * are met:
10 1.2.4.2 christos * 1. Redistributions of source code must retain the above copyright
11 1.2.4.2 christos * notice, this list of conditions and the following disclaimer.
12 1.2.4.2 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.2.4.2 christos * notice, this list of conditions and the following disclaimer in the
14 1.2.4.2 christos * documentation and/or other materials provided with the distribution.
15 1.2.4.2 christos *
16 1.2.4.2 christos * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
17 1.2.4.2 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.2.4.2 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.2.4.2 christos * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.2.4.2 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.2.4.2 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.2.4.2 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.2.4.2 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.2.4.2 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.2.4.2 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.2.4.2 christos */
27 1.2.4.2 christos
28 1.2.4.2 christos
29 1.2.4.2 christos
30 1.2.4.2 christos #include <sys/endian.h>
31 1.2.4.2 christos #include <sys/ioctl.h>
32 1.2.4.2 christos #include <sys/socket.h>
33 1.2.4.2 christos
34 1.2.4.2 christos #include <net/if.h>
35 1.2.4.2 christos
36 1.2.4.2 christos #include <ctype.h>
37 1.2.4.2 christos #include <errno.h>
38 1.2.4.2 christos #include <stdarg.h>
39 1.2.4.2 christos #include <stdio.h>
40 1.2.4.2 christos #include <string.h>
41 1.2.4.2 christos #include <unistd.h>
42 1.2.4.2 christos
43 1.2.4.2 christos #include <dev/usb/mbim.h>
44 1.2.4.2 christos #include <dev/usb/if_umbreg.h>
45 1.2.4.2 christos
46 1.2.4.2 christos
47 1.2.4.2 christos /* constants */
48 1.2.4.2 christos static const struct umb_valdescr _umb_regstate[] =
49 1.2.4.2 christos MBIM_REGSTATE_DESCRIPTIONS;
50 1.2.4.2 christos
51 1.2.4.2 christos static const struct umb_valdescr _umb_dataclass[] =
52 1.2.4.2 christos MBIM_DATACLASS_DESCRIPTIONS;
53 1.2.4.2 christos
54 1.2.4.2 christos static const struct umb_valdescr _umb_state[] =
55 1.2.4.2 christos UMB_INTERNAL_STATE_DESCRIPTIONS;
56 1.2.4.2 christos
57 1.2.4.2 christos static const struct umb_valdescr _umb_regmode[] =
58 1.2.4.2 christos {
59 1.2.4.2 christos { MBIM_REGMODE_UNKNOWN, "unknown" },
60 1.2.4.2 christos { MBIM_REGMODE_AUTOMATIC, "automatic" },
61 1.2.4.2 christos { MBIM_REGMODE_MANUAL, "manual" },
62 1.2.4.2 christos { 0, NULL }
63 1.2.4.2 christos };
64 1.2.4.2 christos
65 1.2.4.2 christos static const struct umb_valdescr _umb_ber[] =
66 1.2.4.2 christos {
67 1.2.4.2 christos { UMB_BER_EXCELLENT, "excellent" },
68 1.2.4.2 christos { UMB_BER_VERYGOOD, "very good" },
69 1.2.4.2 christos { UMB_BER_GOOD, "good" },
70 1.2.4.2 christos { UMB_BER_OK, "ok" },
71 1.2.4.2 christos { UMB_BER_MEDIUM, "medium" },
72 1.2.4.2 christos { UMB_BER_BAD, "bad" },
73 1.2.4.2 christos { UMB_BER_VERYBAD, "very bad" },
74 1.2.4.2 christos { UMB_BER_EXTREMELYBAD, "extremely bad" },
75 1.2.4.2 christos { 0, NULL }
76 1.2.4.2 christos };
77 1.2.4.2 christos
78 1.2.4.2 christos
79 1.2.4.2 christos /* prototypes */
80 1.2.4.2 christos static int _char_to_utf16(const char * in, uint16_t * out, size_t outlen);
81 1.2.4.2 christos static int _error(int ret, char const * format, ...);
82 1.2.4.2 christos static int _umbctl(char const * ifname, int verbose, int argc, char * argv[]);
83 1.2.4.2 christos static int _umbctl_file(char const * ifname, char const * filename, int verbose,
84 1.2.4.2 christos int argc, char * argv[]);
85 1.2.4.2 christos static void _umbctl_info(char const * ifname, struct umb_info * umbi);
86 1.2.4.2 christos static int _umbctl_ioctl(char const * ifname, int fd, unsigned long request,
87 1.2.4.2 christos struct ifreq * ifr);
88 1.2.4.2 christos static int _umbctl_set(char const * ifname, struct umb_parameter * umbp,
89 1.2.4.2 christos int argc, char * argv[]);
90 1.2.4.2 christos static int _umbctl_socket(void);
91 1.2.4.2 christos static int _usage(void);
92 1.2.4.2 christos static void _utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen);
93 1.2.4.2 christos
94 1.2.4.2 christos
95 1.2.4.2 christos /* functions */
96 1.2.4.2 christos /* char_to_utf16 */
97 1.2.4.2 christos /* this function is from OpenBSD's ifconfig(8) */
98 1.2.4.2 christos static int _char_to_utf16(const char * in, uint16_t * out, size_t outlen)
99 1.2.4.2 christos {
100 1.2.4.2 christos int n = 0;
101 1.2.4.2 christos uint16_t c;
102 1.2.4.2 christos
103 1.2.4.2 christos for (;;) {
104 1.2.4.2 christos c = *in++;
105 1.2.4.2 christos
106 1.2.4.2 christos if (c == '\0') {
107 1.2.4.2 christos /*
108 1.2.4.2 christos * NUL termination is not required, but zero out the
109 1.2.4.2 christos * residual buffer
110 1.2.4.2 christos */
111 1.2.4.2 christos memset(out, 0, outlen);
112 1.2.4.2 christos return n;
113 1.2.4.2 christos }
114 1.2.4.2 christos if (outlen < sizeof(*out))
115 1.2.4.2 christos return -1;
116 1.2.4.2 christos
117 1.2.4.2 christos *out++ = htole16(c);
118 1.2.4.2 christos n += sizeof(*out);
119 1.2.4.2 christos outlen -= sizeof(*out);
120 1.2.4.2 christos }
121 1.2.4.2 christos }
122 1.2.4.2 christos
123 1.2.4.2 christos
124 1.2.4.2 christos /* error */
125 1.2.4.2 christos __printflike(2, 3) static int _error(int ret, char const * format, ...)
126 1.2.4.2 christos {
127 1.2.4.2 christos va_list ap;
128 1.2.4.2 christos
129 1.2.4.2 christos fputs("umbctl: ", stderr);
130 1.2.4.2 christos va_start(ap, format);
131 1.2.4.2 christos vfprintf(stderr, format, ap);
132 1.2.4.2 christos va_end(ap);
133 1.2.4.2 christos fputs("\n", stderr);
134 1.2.4.2 christos return ret;
135 1.2.4.2 christos }
136 1.2.4.2 christos
137 1.2.4.2 christos
138 1.2.4.2 christos /* umbctl */
139 1.2.4.2 christos static int _umbctl(char const * ifname, int verbose, int argc, char * argv[])
140 1.2.4.2 christos {
141 1.2.4.2 christos int fd;
142 1.2.4.2 christos struct ifreq ifr;
143 1.2.4.2 christos struct umb_info umbi;
144 1.2.4.2 christos struct umb_parameter umbp;
145 1.2.4.2 christos
146 1.2.4.2 christos if((fd = _umbctl_socket()) < 0)
147 1.2.4.2 christos return 2;
148 1.2.4.2 christos memset(&ifr, 0, sizeof(ifr));
149 1.2.4.2 christos strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
150 1.2.4.2 christos if(argc != 0)
151 1.2.4.2 christos {
152 1.2.4.2 christos memset(&umbp, 0, sizeof(umbp));
153 1.2.4.2 christos ifr.ifr_data = &umbp;
154 1.2.4.2 christos if(_umbctl_ioctl(ifname, fd, SIOCGUMBPARAM, &ifr) != 0
155 1.2.4.2 christos || _umbctl_set(ifname, &umbp, argc, argv) != 0
156 1.2.4.2 christos || _umbctl_ioctl(ifname, fd, SIOCSUMBPARAM,
157 1.2.4.2 christos &ifr) != 0)
158 1.2.4.2 christos {
159 1.2.4.2 christos close(fd);
160 1.2.4.2 christos return 2;
161 1.2.4.2 christos }
162 1.2.4.2 christos }
163 1.2.4.2 christos if(argc == 0 || verbose > 0)
164 1.2.4.2 christos {
165 1.2.4.2 christos ifr.ifr_data = &umbi;
166 1.2.4.2 christos if(_umbctl_ioctl(ifname, fd, SIOCGUMBINFO, &ifr) != 0)
167 1.2.4.2 christos {
168 1.2.4.2 christos close(fd);
169 1.2.4.2 christos return 3;
170 1.2.4.2 christos }
171 1.2.4.2 christos _umbctl_info(ifname, &umbi);
172 1.2.4.2 christos }
173 1.2.4.2 christos if(close(fd) != 0)
174 1.2.4.2 christos return _error(2, "%s: %s", ifname, strerror(errno));
175 1.2.4.2 christos return 0;
176 1.2.4.2 christos }
177 1.2.4.2 christos
178 1.2.4.2 christos
179 1.2.4.2 christos /* umbctl_file */
180 1.2.4.2 christos static int _umbctl_file(char const * ifname, char const * filename, int verbose,
181 1.2.4.2 christos int argc, char * argv[])
182 1.2.4.2 christos {
183 1.2.4.2 christos int fd;
184 1.2.4.2 christos struct ifreq ifr;
185 1.2.4.2 christos struct umb_info umbi;
186 1.2.4.2 christos struct umb_parameter umbp;
187 1.2.4.2 christos FILE * fp;
188 1.2.4.2 christos char buf[512];
189 1.2.4.2 christos int eof;
190 1.2.4.2 christos char * tokens[3] = { buf, NULL, NULL };
191 1.2.4.2 christos char * p;
192 1.2.4.2 christos
193 1.2.4.2 christos if((fp = fopen(filename, "r")) == NULL)
194 1.2.4.2 christos return _error(2, "%s: %s", filename, strerror(errno));
195 1.2.4.2 christos memset(&umbp, 0, sizeof(umbp));
196 1.2.4.2 christos while(fgets(buf, sizeof(buf), fp) != NULL)
197 1.2.4.2 christos {
198 1.2.4.2 christos if(buf[0] == '#')
199 1.2.4.2 christos continue;
200 1.2.4.2 christos buf[sizeof(buf) - 1] = '\0';
201 1.2.4.2 christos if((p = strstr(buf, "=")) != NULL)
202 1.2.4.2 christos {
203 1.2.4.2 christos tokens[1] = p + 1;
204 1.2.4.2 christos *p = '\0';
205 1.2.4.2 christos } else
206 1.2.4.2 christos tokens[1] = NULL;
207 1.2.4.2 christos if(_umbctl_set(ifname, &umbp, (p != NULL) ? 2 : 1, tokens) != 0)
208 1.2.4.2 christos break;
209 1.2.4.2 christos }
210 1.2.4.2 christos eof = feof(fp);
211 1.2.4.2 christos if(fclose(fp) != 0 || !eof)
212 1.2.4.2 christos return _error(2, "%s: %s", filename, strerror(errno));
213 1.2.4.2 christos if((fd = _umbctl_socket()) < 0)
214 1.2.4.2 christos return 2;
215 1.2.4.2 christos memset(&ifr, 0, sizeof(ifr));
216 1.2.4.2 christos strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
217 1.2.4.2 christos ifr.ifr_data = &umbp;
218 1.2.4.2 christos if(_umbctl_ioctl(ifname, fd, SIOCGUMBPARAM, &ifr) != 0
219 1.2.4.2 christos || _umbctl_set(ifname, &umbp, argc, argv) != 0
220 1.2.4.2 christos || _umbctl_ioctl(ifname, fd, SIOCSUMBPARAM, &ifr) != 0)
221 1.2.4.2 christos {
222 1.2.4.2 christos close(fd);
223 1.2.4.2 christos return 2;
224 1.2.4.2 christos }
225 1.2.4.2 christos if(verbose > 0)
226 1.2.4.2 christos {
227 1.2.4.2 christos ifr.ifr_data = &umbi;
228 1.2.4.2 christos if(_umbctl_ioctl(ifname, fd, SIOCGUMBINFO, &ifr) != 0)
229 1.2.4.2 christos {
230 1.2.4.2 christos close(fd);
231 1.2.4.2 christos return 3;
232 1.2.4.2 christos }
233 1.2.4.2 christos _umbctl_info(ifname, &umbi);
234 1.2.4.2 christos }
235 1.2.4.2 christos if(close(fd) != 0)
236 1.2.4.2 christos return _error(2, "%s: %s", ifname, strerror(errno));
237 1.2.4.2 christos return 0;
238 1.2.4.2 christos }
239 1.2.4.2 christos
240 1.2.4.2 christos
241 1.2.4.2 christos /* umbctl_info */
242 1.2.4.2 christos static void _umbctl_info(char const * ifname, struct umb_info * umbi)
243 1.2.4.2 christos {
244 1.2.4.2 christos char provider[UMB_PROVIDERNAME_MAXLEN + 1];
245 1.2.4.2 christos char pn[UMB_PHONENR_MAXLEN + 1];
246 1.2.4.2 christos char roaming[UMB_ROAMINGTEXT_MAXLEN + 1];
247 1.2.4.2 christos char apn[UMB_APN_MAXLEN + 1];
248 1.2.4.2 christos char fwinfo[UMB_FWINFO_MAXLEN + 1];
249 1.2.4.2 christos char hwinfo[UMB_HWINFO_MAXLEN + 1];
250 1.2.4.2 christos
251 1.2.4.2 christos _utf16_to_char(umbi->provider, UMB_PROVIDERNAME_MAXLEN,
252 1.2.4.2 christos provider, sizeof(provider));
253 1.2.4.2 christos _utf16_to_char(umbi->pn, UMB_PHONENR_MAXLEN, pn, sizeof(pn));
254 1.2.4.2 christos _utf16_to_char(umbi->roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
255 1.2.4.2 christos roaming, sizeof(roaming));
256 1.2.4.2 christos _utf16_to_char(umbi->apn, UMB_APN_MAXLEN, apn, sizeof(apn));
257 1.2.4.2 christos _utf16_to_char(umbi->fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof(fwinfo));
258 1.2.4.2 christos _utf16_to_char(umbi->hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof(hwinfo));
259 1.2.4.2 christos printf("%s: state %s, mode %s, registration %s\n"
260 1.2.4.2 christos "\tprovider \"%s\", dataclass %s, signal %s\n"
261 1.2.4.2 christos "\tphone number \"%s\", roaming \"%s\" (%s)\n"
262 1.2.4.2 christos "\tAPN \"%s\", TX %" PRIu64 ", RX %" PRIu64 "\n"
263 1.2.4.2 christos "\tfirmware \"%s\", hardware \"%s\"\n",
264 1.2.4.2 christos ifname, umb_val2descr(_umb_state, umbi->state),
265 1.2.4.2 christos umb_val2descr(_umb_regmode, umbi->regmode),
266 1.2.4.2 christos umb_val2descr(_umb_regstate, umbi->regstate), provider,
267 1.2.4.2 christos umb_val2descr(_umb_dataclass, umbi->cellclass),
268 1.2.4.2 christos umb_val2descr(_umb_ber, umbi->ber), pn, roaming,
269 1.2.4.2 christos umbi->enable_roaming ? "allowed" : "denied",
270 1.2.4.2 christos apn, umbi->uplink_speed, umbi->downlink_speed,
271 1.2.4.2 christos fwinfo, hwinfo);
272 1.2.4.2 christos }
273 1.2.4.2 christos
274 1.2.4.2 christos
275 1.2.4.2 christos /* umbctl_ioctl */
276 1.2.4.2 christos static int _umbctl_ioctl(char const * ifname, int fd, unsigned long request,
277 1.2.4.2 christos struct ifreq * ifr)
278 1.2.4.2 christos {
279 1.2.4.2 christos if(ioctl(fd, request, ifr) != 0)
280 1.2.4.2 christos return _error(-1, "%s: %s", ifname, strerror(errno));
281 1.2.4.2 christos return 0;
282 1.2.4.2 christos }
283 1.2.4.2 christos
284 1.2.4.2 christos
285 1.2.4.2 christos /* umbctl_set */
286 1.2.4.2 christos /* callbacks */
287 1.2.4.2 christos static int _set_apn(char const *, struct umb_parameter *, char const *);
288 1.2.4.2 christos static int _set_username(char const *, struct umb_parameter *, char const *);
289 1.2.4.2 christos static int _set_password(char const *, struct umb_parameter *, char const *);
290 1.2.4.2 christos static int _set_pin(char const *, struct umb_parameter *, char const *);
291 1.2.4.2 christos static int _set_puk(char const *, struct umb_parameter *, char const *);
292 1.2.4.2 christos static int _set_roaming_allow(char const *, struct umb_parameter *,
293 1.2.4.2 christos char const *);
294 1.2.4.2 christos static int _set_roaming_deny(char const *, struct umb_parameter *,
295 1.2.4.2 christos char const *);
296 1.2.4.2 christos
297 1.2.4.2 christos static int _umbctl_set(char const * ifname, struct umb_parameter * umbp,
298 1.2.4.2 christos int argc, char * argv[])
299 1.2.4.2 christos {
300 1.2.4.2 christos struct
301 1.2.4.2 christos {
302 1.2.4.2 christos char const * name;
303 1.2.4.2 christos int (*callback)(char const *,
304 1.2.4.2 christos struct umb_parameter *, char const *);
305 1.2.4.2 christos int parameter;
306 1.2.4.2 christos } callbacks[] =
307 1.2.4.2 christos {
308 1.2.4.2 christos { "apn", _set_apn, 1 },
309 1.2.4.2 christos { "username", _set_username, 1 },
310 1.2.4.2 christos { "password", _set_password, 1 },
311 1.2.4.2 christos { "pin", _set_pin, 1 },
312 1.2.4.2 christos { "puk", _set_puk, 1 },
313 1.2.4.2 christos { "roaming", _set_roaming_allow, 0 },
314 1.2.4.2 christos { "-roaming", _set_roaming_deny, 0 },
315 1.2.4.2 christos };
316 1.2.4.2 christos int i;
317 1.2.4.2 christos size_t j;
318 1.2.4.2 christos
319 1.2.4.2 christos for(i = 0; i < argc; i++)
320 1.2.4.2 christos {
321 1.2.4.2 christos for(j = 0; j < sizeof(callbacks) / sizeof(*callbacks); j++)
322 1.2.4.2 christos if(strcmp(argv[i], callbacks[j].name) == 0)
323 1.2.4.2 christos {
324 1.2.4.2 christos if(callbacks[j].parameter && i + 1 == argc)
325 1.2.4.2 christos return _error(-1, "%s: Incomplete"
326 1.2.4.2 christos " parameter", argv[i]);
327 1.2.4.2 christos if(callbacks[j].callback(ifname, umbp,
328 1.2.4.2 christos callbacks[j].parameter
329 1.2.4.2 christos ? argv[i + 1] : NULL))
330 1.2.4.2 christos return -1;
331 1.2.4.2 christos if(callbacks[j].parameter)
332 1.2.4.2 christos i++;
333 1.2.4.2 christos break;
334 1.2.4.2 christos }
335 1.2.4.2 christos if(j == sizeof(callbacks) / sizeof(*callbacks))
336 1.2.4.2 christos return _error(-1, "%s: Unknown parameter", argv[i]);
337 1.2.4.2 christos }
338 1.2.4.2 christos return 0;
339 1.2.4.2 christos }
340 1.2.4.2 christos
341 1.2.4.2 christos static int _set_apn(char const * ifname, struct umb_parameter * umbp,
342 1.2.4.2 christos char const * apn)
343 1.2.4.2 christos {
344 1.2.4.2 christos umbp->apnlen = _char_to_utf16(apn, umbp->apn, sizeof(umbp->apn));
345 1.2.4.2 christos if(umbp->apnlen < 0 || (size_t)umbp->apnlen > sizeof(umbp->apn))
346 1.2.4.2 christos return _error(-1, "%s: %s", ifname, "APN too long");
347 1.2.4.2 christos return 0;
348 1.2.4.2 christos }
349 1.2.4.2 christos
350 1.2.4.2 christos static int _set_username(char const * ifname, struct umb_parameter * umbp,
351 1.2.4.2 christos char const * username)
352 1.2.4.2 christos {
353 1.2.4.2 christos umbp->usernamelen = _char_to_utf16(username, umbp->username,
354 1.2.4.2 christos sizeof(umbp->username));
355 1.2.4.2 christos if(umbp->usernamelen < 0
356 1.2.4.2 christos || (size_t)umbp->usernamelen > sizeof(umbp->username))
357 1.2.4.2 christos return _error(-1, "%s: %s", ifname, "Username too long");
358 1.2.4.2 christos return 0;
359 1.2.4.2 christos }
360 1.2.4.2 christos
361 1.2.4.2 christos static int _set_password(char const * ifname, struct umb_parameter * umbp,
362 1.2.4.2 christos char const * password)
363 1.2.4.2 christos {
364 1.2.4.2 christos umbp->passwordlen = _char_to_utf16(password, umbp->password,
365 1.2.4.2 christos sizeof(umbp->password));
366 1.2.4.2 christos if(umbp->passwordlen < 0
367 1.2.4.2 christos || (size_t)umbp->passwordlen > sizeof(umbp->password))
368 1.2.4.2 christos return _error(-1, "%s: %s", ifname, "Password too long");
369 1.2.4.2 christos return 0;
370 1.2.4.2 christos }
371 1.2.4.2 christos
372 1.2.4.2 christos static int _set_pin(char const * ifname, struct umb_parameter * umbp,
373 1.2.4.2 christos char const * pin)
374 1.2.4.2 christos {
375 1.2.4.2 christos umbp->is_puk = 0;
376 1.2.4.2 christos umbp->op = MBIM_PIN_OP_ENTER;
377 1.2.4.2 christos umbp->pinlen = _char_to_utf16(pin, umbp->pin, sizeof(umbp->pin));
378 1.2.4.2 christos if(umbp->pinlen < 0 || (size_t)umbp->pinlen
379 1.2.4.2 christos > sizeof(umbp->pin))
380 1.2.4.2 christos return _error(-1, "%s: %s", ifname, "PIN code too long");
381 1.2.4.2 christos return 0;
382 1.2.4.2 christos }
383 1.2.4.2 christos
384 1.2.4.2 christos static int _set_puk(char const * ifname, struct umb_parameter * umbp,
385 1.2.4.2 christos char const * puk)
386 1.2.4.2 christos {
387 1.2.4.2 christos umbp->is_puk = 1;
388 1.2.4.2 christos umbp->op = MBIM_PIN_OP_ENTER;
389 1.2.4.2 christos umbp->pinlen = _char_to_utf16(puk, umbp->pin, sizeof(umbp->pin));
390 1.2.4.2 christos if(umbp->pinlen < 0 || (size_t)umbp->pinlen > sizeof(umbp->pin))
391 1.2.4.2 christos return _error(-1, "%s: %s", ifname, "PUK code too long");
392 1.2.4.2 christos return 0;
393 1.2.4.2 christos }
394 1.2.4.2 christos
395 1.2.4.2 christos static int _set_roaming_allow(char const * ifname, struct umb_parameter * umbp,
396 1.2.4.2 christos char const * unused)
397 1.2.4.2 christos {
398 1.2.4.2 christos (void) ifname;
399 1.2.4.2 christos (void) unused;
400 1.2.4.2 christos
401 1.2.4.2 christos umbp->roaming = 1;
402 1.2.4.2 christos return 0;
403 1.2.4.2 christos }
404 1.2.4.2 christos
405 1.2.4.2 christos static int _set_roaming_deny(char const * ifname, struct umb_parameter * umbp,
406 1.2.4.2 christos char const * unused)
407 1.2.4.2 christos {
408 1.2.4.2 christos (void) ifname;
409 1.2.4.2 christos (void) unused;
410 1.2.4.2 christos
411 1.2.4.2 christos umbp->roaming = 0;
412 1.2.4.2 christos return 0;
413 1.2.4.2 christos }
414 1.2.4.2 christos
415 1.2.4.2 christos
416 1.2.4.2 christos /* umbctl_socket */
417 1.2.4.2 christos static int _umbctl_socket(void)
418 1.2.4.2 christos {
419 1.2.4.2 christos int fd;
420 1.2.4.2 christos
421 1.2.4.2 christos if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
422 1.2.4.2 christos return _error(-1, "socket: %s", strerror(errno));
423 1.2.4.2 christos return fd;
424 1.2.4.2 christos }
425 1.2.4.2 christos
426 1.2.4.2 christos
427 1.2.4.2 christos /* usage */
428 1.2.4.2 christos static int _usage(void)
429 1.2.4.2 christos {
430 1.2.4.2 christos fputs("Usage: umbctl [-v] ifname [parameter[=value]] [...]\n"
431 1.2.4.2 christos " umbctl -f config-file ifname [...]\n",
432 1.2.4.2 christos stderr);
433 1.2.4.2 christos return 1;
434 1.2.4.2 christos }
435 1.2.4.2 christos
436 1.2.4.2 christos
437 1.2.4.2 christos /* utf16_to_char */
438 1.2.4.2 christos static void _utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
439 1.2.4.2 christos {
440 1.2.4.2 christos uint16_t c;
441 1.2.4.2 christos
442 1.2.4.2 christos while (outlen > 0) {
443 1.2.4.2 christos c = inlen > 0 ? htole16(*in) : 0;
444 1.2.4.2 christos if (c == 0 || --outlen == 0) {
445 1.2.4.2 christos /* always NUL terminate result */
446 1.2.4.2 christos *out = '\0';
447 1.2.4.2 christos break;
448 1.2.4.2 christos }
449 1.2.4.2 christos *out++ = isascii(c) ? (char)c : '?';
450 1.2.4.2 christos in++;
451 1.2.4.2 christos inlen--;
452 1.2.4.2 christos }
453 1.2.4.2 christos }
454 1.2.4.2 christos
455 1.2.4.2 christos
456 1.2.4.2 christos /* main */
457 1.2.4.2 christos int main(int argc, char * argv[])
458 1.2.4.2 christos {
459 1.2.4.2 christos int o;
460 1.2.4.2 christos char const * filename = NULL;
461 1.2.4.2 christos int verbose = 0;
462 1.2.4.2 christos
463 1.2.4.2 christos while((o = getopt(argc, argv, "f:v")) != -1)
464 1.2.4.2 christos switch(o)
465 1.2.4.2 christos {
466 1.2.4.2 christos case 'f':
467 1.2.4.2 christos filename = optarg;
468 1.2.4.2 christos break;
469 1.2.4.2 christos case 'v':
470 1.2.4.2 christos verbose++;
471 1.2.4.2 christos break;
472 1.2.4.2 christos default:
473 1.2.4.2 christos return _usage();
474 1.2.4.2 christos }
475 1.2.4.2 christos if(optind == argc)
476 1.2.4.2 christos return _usage();
477 1.2.4.2 christos if(filename != NULL)
478 1.2.4.2 christos return _umbctl_file(argv[optind], filename, verbose,
479 1.2.4.2 christos argc - optind - 1, &argv[optind + 1]);
480 1.2.4.2 christos return _umbctl(argv[optind], verbose, argc - optind - 1,
481 1.2.4.2 christos &argv[optind + 1]);
482 1.2.4.2 christos }
483