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