diff options
Diffstat (limited to 'src/gsmd')
| -rw-r--r-- | src/gsmd/Makefile.am | 2 | ||||
| -rw-r--r-- | src/gsmd/ext_response.c | 213 | ||||
| -rw-r--r-- | src/gsmd/gsmd.c | 2 | ||||
| -rw-r--r-- | src/gsmd/operator_cache.c | 99 | ||||
| -rw-r--r-- | src/gsmd/unsolicited.c | 24 | ||||
| -rw-r--r-- | src/gsmd/vendor_ti.c | 44 | 
6 files changed, 377 insertions, 7 deletions
diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am index b431ec5..940f610 100644 --- a/src/gsmd/Makefile.am +++ b/src/gsmd/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = -std=gnu99  sbin_PROGRAMS = gsmd  gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \ -	       vendor_ti.c talloc.c +	       vendor_ti.c talloc.c operator_cache.c ext_response.c  #gsmd_LDADD = ../libgsmd/libgsmd.la  #gsmd_LDFLAGS = -dynamic diff --git a/src/gsmd/ext_response.c b/src/gsmd/ext_response.c new file mode 100644 index 0000000..5b31c8d --- /dev/null +++ b/src/gsmd/ext_response.c @@ -0,0 +1,213 @@ +/* gsmd extended response parser + * + * (C) 2007 by OpenMoko, Inc. + * Written by Harald Welte <laforge@openmoko.org> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */  + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> + +#include "gsmd.h" + +#include <gsmd/gsmd.h> +#include <gsmd/atcmd.h> +#include <gsmd/extrsp.h> +#include <gsmd/talloc.h> + +int extrsp_supports(const struct gsm_extrsp *er, int index, int value) +{ +	int i; + +	if (index >= er->num_tokens) +		return -EINVAL; +	if (er->tokens[index].type != GSMD_ECMD_RTT_RANGE) +		return -EINVAL; + +	for (i = 0; i < er->tokens[index].u.range.num_items; i++) { +		struct gsm_extrsp_range_item *ri =  +			&er->tokens[index].u.range.item[i]; +		if (value >= ri->min && value <= ri->max) +			return 1; +	} + +	return 0; +} + +enum parser_state { +	IDLE, +	TOKEN_STRING, +	TOKEN_STRING_LASTQUOTE, +	TOKEN_NUMERIC, +	TOKEN_RANGE, +}; +		 +/* parse a comma-separated list, possibly containing quote values */ +struct gsm_extrsp *extrsp_parse(const void *ctx, const char *input) +{ +	const char *cur = input; +	struct gsm_extrsp *er; +	int cur_tok = 0; +	enum parser_state state = IDLE; +	char buf[512]; +	char *cur_buf = buf; +	struct gsm_extrsp_tok *cur_token; + +	if (!input || strlen(input) == 0) +		return NULL; + +	er = talloc(ctx, struct gsm_extrsp); +	if (!er) +		return NULL; +	memset(er, 0, sizeof(*er)); + +	while (*cur) { +		cur_token = &er->tokens[er->num_tokens]; + +		switch (state) { +		case IDLE: +			memset(buf, 0, sizeof(buf)); +			cur_buf = buf; + +			if (isblank(*cur)) +				break; +			else if (*cur == '"') { +				cur_token->type = GSMD_ECMD_RTT_STRING; +				state = TOKEN_STRING; +			} else if (*cur == '(') { +				cur_token->type = GSMD_ECMD_RTT_RANGE; +				state = TOKEN_RANGE; +			} else if (isdigit(*cur)) { +				cur_token->type = GSMD_ECMD_RTT_NUMERIC; +				*cur_buf = *cur; +				cur_buf++; +				state = TOKEN_NUMERIC; +			} else if (*cur == ',') { +				cur_token->type = GSMD_ECMD_RTT_EMPTY; +				er->num_tokens++; +				state = IDLE; +			} +			break; +		case TOKEN_NUMERIC: +			if (*cur == ',') { +				/* end of number */ +				cur_token->u.numeric = atoi(buf); +				er->num_tokens++; +				state = IDLE; +			} else if (isdigit(*cur)) { +				*cur_buf = *cur; +				cur_buf++; +			} else { +				/* ERORR */ +			} +			break; +		case TOKEN_STRING: +			if (*cur == '"') { +				int len = strlen(buf); +				if (len > sizeof(cur_token->u.string)-1) +					len = sizeof(cur_token->u.string)-1; + +				/* end of string token */ +				strncpy(cur_token->u.string, buf, len); +				er->num_tokens++; +				state = TOKEN_STRING_LASTQUOTE; +			} else { +				*cur_buf = *cur; +				cur_buf++; +			} +			break; +		case TOKEN_STRING_LASTQUOTE: +			if (*cur == ',') +				state = IDLE; +			else { +				/* ERROR */ +			} +			break; +		case TOKEN_RANGE: +			if (isdigit(*cur)) { +				*cur_buf = *cur; +				cur_buf++; +			} else if (*cur == '-') { +				/* previous number has completed */ +				cur_token->u.range.item[cur_token->u.range.num_items].min = atoi(buf); +				memset(buf, 0, sizeof(buf)); +				cur_buf = buf; +			} else if (*cur == ',') { +				/* previous number has completed */ +				cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf); +				cur_token->u.range.num_items++; +			} else if (*cur == ')') { +				/* previous number has completed */ +				cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf); +				cur_token->u.range.num_items++; +				state = TOKEN_STRING_LASTQUOTE; +				er->num_tokens++; +			} else { +				/* ERROR */ +			} +			break; +		} +		cur++; +	} + +	//extrsp_dump(er); +	return er; +} + +static const char *er_tok_names[] = { +	[GSMD_ECMD_RTT_EMPTY]	= "EMPTY", +	[GSMD_ECMD_RTT_NUMERIC]	= "NUMERIC", +	[GSMD_ECMD_RTT_STRING]	= "STRING", +	[GSMD_ECMD_RTT_RANGE]	= "RANGE", +}; + +void extrsp_dump(const struct gsm_extrsp *er) +{ +	int i; + +	DEBUGP("entering(er=%p, num_tokens=%u)\n", er, er->num_tokens); +	for (i = 0; i < er->num_tokens; i++) { +		const struct gsm_extrsp_tok *tok = &er->tokens[i]; +		DEBUGP("Token %u: %s: ", i, er_tok_names[tok->type]); +		switch (tok->type) { +		case GSMD_ECMD_RTT_EMPTY: +			DEBUGP("\n"); +			break; +		case GSMD_ECMD_RTT_NUMERIC: +			DEBUGP("%d\n", tok->u.numeric); +			break; +		case GSMD_ECMD_RTT_STRING: +			DEBUGP("%s\n", tok->u.string); +			break; +		case GSMD_ECMD_RTT_RANGE: { +			int j; +			for (j = 0; j < tok->u.range.num_items; j++) +				DEBUGP("%d-%d, ", tok->u.range.item[j].min, +					tok->u.range.item[j].max); +			} +			 +			break; +		} +	} + +} diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c index 6c72f97..8254ae0 100644 --- a/src/gsmd/gsmd.c +++ b/src/gsmd/gsmd.c @@ -282,6 +282,8 @@ int main(int argc, char **argv)  	gsmd_initsettings(&g); +	gsmd_opname_init(&g); +  	while (1) {  		int ret = gsmd_select_main();  		if (ret == 0) diff --git a/src/gsmd/operator_cache.c b/src/gsmd/operator_cache.c new file mode 100644 index 0000000..e680706 --- /dev/null +++ b/src/gsmd/operator_cache.c @@ -0,0 +1,99 @@ +/* gsmd cache of operator names + * + * (C) 2006-2007 by OpenMoko, Inc. + * Written by Harald Welte <laforge@openmoko.org> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */  + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "gsmd.h" + +#include <common/linux_list.h> +#include <gsmd/gsmd.h> +#include <gsmd/talloc.h> + +static void *__opc_ctx; + +struct opname { +	struct llist_head list; +	struct { +		u_int16_t mcc;	/* mobile country code */ +		u_int8_t mnc;	/* mobile network code */ +	} numeric; +	char alnum_long[16+1]; +	//char alnum_short[8+1]; +}; + +/* add an entry to the operator name list, overwrite existing entries for + * same mcc/mnc */ +static int _opname_add(struct gsmd *g, struct opname *op) +{ +	struct opname *cur, *cur2; + +	llist_for_each_entry_safe(cur, cur2, &g->operators, list) { +		if (op->numeric.mcc == cur->numeric.mcc && +		    op->numeric.mnc == cur->numeric.mnc) { +			llist_del(&cur->list); +			talloc_free(cur); +		} +	} +	llist_add_tail(&op->list, &g->operators); + +	return 0; +} + +int gsmd_opname_add(struct gsmd *g, const char *numeric_bcd_string, +		    const char *alnum_long) +{ +	struct opname *op; +	char mcc[3+1]; +	char mnc[2+1]; + +	if (strlen(numeric_bcd_string) != 5) +		return -EINVAL; + +	op = talloc(__opc_ctx, struct opname); +	if (!op) +		return -ENOMEM; +	 +	memset(mcc, 0, sizeof(mcc)); +	memset(mnc, 0, sizeof(mnc)); + +	strncpy(mcc, numeric_bcd_string, 3); +	strncpy(mnc, numeric_bcd_string+3, 2); + +	strncpy(op->alnum_long, alnum_long, sizeof(op->alnum_long-1)); +	op->numeric.mcc = atoi(mcc); +	op->numeric.mnc = atoi(mnc); + +	return _opname_add(g, op); +} + +int gsmd_opname_init(struct gsmd *g) +{ +	INIT_LLIST_HEAD(&g->operators); + +	__opc_ctx = talloc_named_const(gsmd_tallocs, 1, "operator_cache"); + +	return 0; +} diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index 82f45f4..c355c71 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -31,6 +31,7 @@  #include <gsmd/usock.h>  #include <gsmd/event.h> +#include <gsmd/extrsp.h>  #include <gsmd/ts0707.h>  #include <gsmd/unsolicited.h>  #include <gsmd/talloc.h> @@ -308,6 +309,28 @@ static int ctzv_parse(char *buf, int len, const char *param,  	return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE);  } +static int copn_parse(char *buf, int len, const char *param, +		      struct gsmd *gsmd) +{ +	struct gsm_extrsp *er = extrsp_parse(gsmd_tallocs, param); +	int rc = 0; + +	if (!er) +		return -ENOMEM; + +	extrsp_dump(er); + +	if (er->num_tokens == 2 && +	    er->tokens[0].type == GSMD_ECMD_RTT_STRING && +	    er->tokens[1].type == GSMD_ECMD_RTT_STRING) +		rc = gsmd_opname_add(gsmd, er->tokens[0].u.string, +				     er->tokens[1].u.string); + +	talloc_free(er); + +	return rc; +} +  static const struct gsmd_unsolicit gsm0707_unsolicit[] = {  	{ "RING",	&ring_parse },  	{ "+CRING", 	&cring_parse }, @@ -320,6 +343,7 @@ static const struct gsmd_unsolicit gsm0707_unsolicit[] = {  	{ "+CLIP",	&clip_parse },  	{ "+COLP",	&colp_parse },  	{ "+CTZV",	&ctzv_parse },	/* Timezone */ +	{ "+COPN",	&copn_parse },  /* operator names, treat as unsolicited */  	/*  	{ "+CKEV",	&ckev_parse },  	{ "+CDEV",	&cdev_parse }, diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c index 6617edf..0cc0783 100644 --- a/src/gsmd/vendor_ti.c +++ b/src/gsmd/vendor_ti.c @@ -23,6 +23,7 @@  #include <stdlib.h>  #include <unistd.h>  #include <string.h> +#include <stdio.h>  #include <errno.h>  #include "gsmd.h" @@ -30,6 +31,9 @@  #include <gsmd/gsmd.h>  #include <gsmd/usock.h>  #include <gsmd/event.h> +#include <gsmd/talloc.h> +#include <gsmd/extrsp.h> +#include <gsmd/atcmd.h>  #include <gsmd/vendorplugin.h>  #include <gsmd/unsolicited.h> @@ -214,7 +218,7 @@ out_send:  	return 0;  out_free_io: -	free(ucmd); +	talloc_free(ucmd);  	return -EIO;  } @@ -237,7 +241,26 @@ static const struct gsmd_unsolicit ticalypso_unsolicit[] = {  static int cpi_detect_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)  { +	struct gsmd *g = ctx; +	struct gsm_extrsp *er; + +	if (strncmp(resp, "%CPI: ", 6)) +		return -EINVAL; +	resp += 6; +	er = extrsp_parse(cmd, resp); +	if (!er) +		return -EINVAL; + +	if (extrsp_supports(er, 0, 3)) +		return gsmd_simplecmd(g, "AT%CPI=3"); +	else if (extrsp_supports(er, 0, 2)) +		return gsmd_simplecmd(g, "AT%CPI=2"); +	else +		DEBUGP("Call Progress Indication mode 2 or 3 not supported!!\n"); + +	talloc_free(er); +	return 0;  }  static int ticalypso_detect(struct gsmd *g) @@ -249,16 +272,25 @@ static int ticalypso_detect(struct gsmd *g)  static int ticalypso_initsettings(struct gsmd *g)  {  	int rc; +	struct gsmd_atcmd *cmd; +  	/* use +CTZR: to report time zone changes */  	rc |= gsmd_simplecmd(g, "AT+CTZR=1"); -	/* enable %CPI: call progress indication */ -	rc = gsmd_simplecmd(g, "AT\%CPI=3"); +	/* use %CTZV: Report time and date */ +	rc |= gsmd_simplecmd(g, "AT%CTZV=1"); +	/* use %CGREG */ +	//rc |= gsmd_simplecmd(g, "AT%CGREG=3");  	/* enable %CPRI: ciphering indications */ -	rc |= gsmd_simplecmd(g, "AT\%CPRI=1"); +	rc |= gsmd_simplecmd(g, "AT%CPRI=1");  	/* enable %CSQ: signal quality reports */ -	rc |= gsmd_simplecmd(g, "AT\%CSQ=1"); +	rc |= gsmd_simplecmd(g, "AT%CSQ=1");  	/* send unsolicited commands at any time */ -	rc |= gsmd_simplecmd(g, "AT\%CUNS=0"); +	rc |= gsmd_simplecmd(g, "AT%CUNS=0"); + +	/* enable %CPI: call progress indication */ +	cmd = atcmd_fill("AT%CPI=?", 9, &cpi_detect_cb, g, 0); +	if (cmd) +		atcmd_submit(g, cmd);  	return rc;  }  | 
