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