All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCHv4 3/3] Mobile broadband provider info plugin
  2011-08-25 11:23 ` [PATCHv4 3/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
@ 2011-08-24  1:04   ` Denis Kenzior
  2011-08-30 12:57     ` Oleg Zhurakivskyy
  0 siblings, 1 reply; 6+ messages in thread
From: Denis Kenzior @ 2011-08-24  1:04 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 19153 bytes --]

Hi Oleg,

On 08/25/2011 06:23 AM, Oleg Zhurakivskyy wrote:
> ---
>  plugins/mobile-broadband-provider-info.c |  604 ++++++++++++++++++++++++++++++
>  1 files changed, 604 insertions(+), 0 deletions(-)
>  create mode 100644 plugins/mobile-broadband-provider-info.c
> 
> diff --git a/plugins/mobile-broadband-provider-info.c b/plugins/mobile-broadband-provider-info.c
> new file mode 100644
> index 0000000..dbe2962
> --- /dev/null
> +++ b/plugins/mobile-broadband-provider-info.c
> @@ -0,0 +1,604 @@
> +/*
> + *
> + *  oFono - Open Source Telephony
> + *
> + *  Copyright (C) 2008-2011  Intel Corporation. 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 version 2 as
> + *  published by the Free Software Foundation.
> + *
> + *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <glib.h>
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#include <ofono/types.h>
> +#include <ofono/log.h>
> +#include <ofono/plugin.h>
> +#include <ofono/modem.h>
> +#include <ofono/gprs-provision.h>
> +
> +#define MAX_APS	3
> +
> +#define _(x) case x: return (#x)
> +
> +enum element_type {
> +	ELEMENT_NETWORK_ID,
> +	ELEMENT_GSM,
> +	ELEMENT_APN,
> +	ELEMENT_USAGE,
> +	ELEMENT_PLAN,
> +	ELEMENT_NAME,
> +	ELEMENT_USERNAME,
> +	ELEMENT_PASSWORD,
> +	ELEMENT_NONE,
> +};
> +
> +struct provider_info {
> +	struct ofono_gprs_provision_data settings[MAX_APS];
> +	struct ofono_gprs_provision_data *ap;
> +	int ap_count;
> +	const char *match_mcc;
> +	const char *match_mnc;
> +	const char *match_spn;
> +	enum element_type element;
> +	gboolean match_found;
> +	gboolean ap_ignore;
> +	gboolean ap_internet_configured;
> +	gboolean ap_mms_configured;
> +	gboolean ap_wap_configured;
> +};
> +
> +static struct provider_info provider_info;
> +
> +static const char *element_type_name(enum element_type element)
> +{
> +	switch (element) {
> +		_(ELEMENT_NETWORK_ID);
> +		_(ELEMENT_GSM);
> +		_(ELEMENT_APN);
> +		_(ELEMENT_USAGE);
> +		_(ELEMENT_PLAN);
> +		_(ELEMENT_NAME);
> +		_(ELEMENT_USERNAME);
> +		_(ELEMENT_PASSWORD);
> +		_(ELEMENT_NONE);
> +	}

Just a small nitpick, but please add an empty line here

> +	return "ELEMENT_<UNKNOWN>";
> +}
> +
> +static const char *ap_type_name(enum ofono_gprs_context_type ap_type)
> +{
> +	switch (ap_type) {
> +		_(OFONO_GPRS_CONTEXT_TYPE_ANY);
> +		_(OFONO_GPRS_CONTEXT_TYPE_INTERNET);
> +		_(OFONO_GPRS_CONTEXT_TYPE_MMS);
> +		_(OFONO_GPRS_CONTEXT_TYPE_WAP);
> +		_(OFONO_GPRS_CONTEXT_TYPE_IMS);
> +	}

Ditto, empty line here please

> +	return "OFONO_GPRS_CONTEXT_TYPE_<UNKNOWN>";
> +}
> +
> +static enum element_type element_type(const gchar *element)
> +{
> +	switch (element[0]) {
> +	case 'a':
> +		if (g_str_equal(element, "apn") == TRUE)
> +			return ELEMENT_APN;
> +		break;
> +	case 'g':
> +		if (g_str_equal(element, "gsm") == TRUE)
> +			return ELEMENT_GSM;
> +		break;
> +	case 'n':
> +		if (g_str_equal(element, "name") == TRUE)
> +			return ELEMENT_NAME;
> +		if (g_str_equal(element, "network-id") == TRUE)
> +			return ELEMENT_NETWORK_ID;
> +		break;
> +	case 'p':
> +		if (g_str_equal(element, "plan") == TRUE)
> +			return ELEMENT_PLAN;
> +		if (g_str_equal(element, "password") == TRUE)
> +			return ELEMENT_PASSWORD;
> +		break;
> +	case 'u':
> +		if (g_str_equal(element, "usage") == TRUE)
> +			return ELEMENT_USAGE;
> +		if (g_str_equal(element, "username") == TRUE)
> +			return ELEMENT_USERNAME;
> +	}
> +
> +	return ELEMENT_NONE;
> +}
> +
> +static void element_network_id_parse(struct provider_info *data,
> +					const gchar **attribute_names,
> +					const gchar **attribute_values)
> +{
> +	const char *mcc = NULL, *mnc = NULL;
> +	int i;
> +
> +	for (i = 0; attribute_names[i]; i++) {
> +		if (g_str_equal(attribute_names[i], "mcc") == TRUE)
> +			mcc = attribute_values[i];
> +		if (g_str_equal(attribute_names[i], "mnc") == TRUE)
> +			mnc = attribute_values[i];
> +	}
> +
> +	if (g_strcmp0(mcc, data->match_mcc) == 0 &&
> +			g_strcmp0(mnc, data->match_mnc) == 0)
> +		data->match_found = TRUE;
> +}
> +
> +static struct ofono_gprs_provision_data *ap_new(struct provider_info *data)
> +{
> +	if (data->ap_count < MAX_APS)
> +		return data->settings + data->ap_count++;
> +
> +	return NULL;
> +}
> +
> +static void ap_value_free(char **value)
> +{
> +	if (*value == NULL)
> +		return;

g_free already checks for NULL values, so this is entirely unnecessary.

> +
> +	g_free(*value);
> +
> +	*value = NULL;
> +}
> +
> +static void ap_delete(struct provider_info *data)
> +{
> +	struct ofono_gprs_provision_data *ap = data->ap;
> +
> +	ap_value_free(&ap->name);
> +
> +	ap_value_free(&ap->apn);
> +
> +	ap_value_free(&ap->username);
> +
> +	ap_value_free(&ap->password);
> +
> +	ap->type = OFONO_GPRS_CONTEXT_TYPE_ANY;
> +
> +	data->ap_count--;
> +
> +	data->ap--;
> +}
> +
> +static void element_apn_parse(struct provider_info *data,
> +				const gchar **attribute_names,
> +				const gchar **attribute_values)
> +{
> +	const char *apn = NULL;
> +	int i;
> +
> +	for (i = 0; attribute_names[i]; i++) {
> +		if (g_str_equal(attribute_names[i], "value") == TRUE)
> +			apn = attribute_values[i];
> +	}
> +
> +	data->ap = ap_new(data);
> +	if (data->ap == NULL) {
> +		DBG("AP '%s', MAX_APS %d reached, AP ignored", apn, MAX_APS);
> +		data->match_found = FALSE;
> +		return;
> +	}
> +
> +	data->ap->apn = g_strdup(apn);

The code might be nicer written like this:

data->ap = ap_new(...);
if (data->ap ...) {
	...
}

for (i = 0; attribute...)
	if (...)
		data->ap->apn = g_strdup(attribute_values[i]);

This allows you to omit the apn variable and initialize it.  In general
we frown on the initialization of variables unless absolutely necessary
(see previous discussions for reasons why, basically this tends to hide
errors that the compiler can detect otherwise)

However, I'm still wondering whether setting data->match_found is
enough.  Here's the example I'm thinking of:

<provider>
	<name>Major Operator</name>
	<network-id mcc="555" mnc="55"/>
	<apn>...</apn>
</provider>

<provider>
	<name>MVNO running on Major Operator</name>
	<network-id mcc="555" mnc="55"/>
	<apn>...</apn>
</provider>

If the Major Operator provides MAX_APN apns, then wouldn't this cause us
to return the APNs from Major Operator, even though this is a conflict
and we might potentially want APNs from MVNO?

If this is indeed such a conflicted case then we need to let the user
decide, not return any results as they're potentially erroneous.

> +}
> +
> +static void element_usage_parse(struct provider_info *data,
> +				const gchar **attribute_names,
> +				const gchar **attribute_values)
> +{
> +	struct ofono_gprs_provision_data *ap = data->ap;
> +	const char *usage = NULL;
> +	int i;
> +
> +	for (i = 0; attribute_names[i]; i++) {
> +		if (g_str_equal(attribute_names[i], "type") == TRUE)
> +			usage = attribute_values[i];
> +	}
> +
> +	if (usage == NULL) {
> +		DBG("AP '%s', no type, AP ignored", ap->apn);
> +		data->ap_ignore = TRUE;
> +		return;
> +	}
> +
> +	if (g_str_equal(usage, "internet") == TRUE)
> +		ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
> +	else if (g_str_equal(usage, "mms") == TRUE)
> +		ap->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
> +	else if (g_str_equal(usage, "wap") == TRUE)
> +		ap->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
> +}
> +
> +static void element_plan_parse(struct provider_info *data,
> +				const gchar **attribute_names,
> +				const gchar **attribute_values)
> +{
> +	const char *plan = NULL;
> +	int i;
> +
> +	for (i = 0; attribute_names[i]; i++) {
> +		if (g_str_equal(attribute_names[i], "type") == TRUE)
> +			plan = attribute_values[i];
> +	}
> +
> +	if (plan != NULL && g_str_equal(plan, "postpaid") == TRUE)
> +		return;
> +
> +	DBG("AP '%s', plan '%s', plan is not postpaid, AP ignored",
> +		data->ap->apn, plan);

Is there a reason why we're ignoring prepaid APNs?

> +
> +	data->ap_ignore = TRUE;
> +}
> +
> +static void element_start_parse(GMarkupParseContext *context,
> +				const gchar *element_name,
> +				const gchar **attribute_names,
> +				const gchar **attribute_values,
> +				gpointer user_data, GError **error)
> +{
> +	struct provider_info *data = user_data;
> +
> +	data->element = element_type(element_name);
> +
> +	if (data->element == ELEMENT_NETWORK_ID)
> +		element_network_id_parse(data, attribute_names,
> +						attribute_values);
> +
> +	if (data->match_found == FALSE || data->ap_ignore == TRUE)
> +		return;
> +
> +	DBG("%s: '%s'", element_type_name(data->element), element_name);
> +
> +	switch (data->element) {
> +	case ELEMENT_APN:
> +		element_apn_parse(data, attribute_names, attribute_values);
> +		break;
> +	case ELEMENT_USAGE:
> +		element_usage_parse(data, attribute_names, attribute_values);
> +		break;
> +	case ELEMENT_PLAN:
> +		element_plan_parse(data, attribute_names, attribute_values);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static gchar *body_text_parse(const gchar *text, gsize text_len)
> +{
> +	gchar *body = g_strndup(text, text_len);
> +	gchar *print = NULL;
> +	int i;
> +
> +	for (i = 0; body && body[i]; i++) {
> +		if (g_ascii_isprint(body[i])) {
> +			print = g_strescape(body, NULL);
> +			break;
> +		}
> +	}
> +
> +	if (body)
> +		g_free(body);
> +
> +	return print;
> +}
> +
> +static void element_body_parse(GMarkupParseContext *context,
> +				const gchar *text, gsize text_len,
> +				gpointer user_data, GError **error)
> +{
> +	struct provider_info *data = user_data;
> +	struct ofono_gprs_provision_data *ap = data->ap;
> +	gchar *body;
> +
> +	if (data->match_found == FALSE || text_len == 0 ||
> +			data->ap_ignore == TRUE)
> +		return;
> +
> +	body = body_text_parse(text, text_len);
> +	if (body == NULL)
> +		return;
> +
> +	DBG("%s: '%s'", element_type_name(data->element), body);
> +
> +	switch (data->element) {
> +	case ELEMENT_USERNAME:
> +		ap->username = g_strdup(body);
> +		break;
> +	case ELEMENT_PASSWORD:
> +		ap->password = g_strdup(body);
> +		break;
> +	case ELEMENT_NAME:
> +		if (g_strcmp0(body, data->match_spn) == 0) {
> +			ap->name = g_strdup(body);
> +			break;
> +		}
> +
> +		DBG("AP '%s', SPN '%s', is not our SPN, AP ignored", ap->apn,
> +			body);
> +		data->ap_ignore = TRUE;

This one is actually tricky.  Looking at the provider info I don't think
SPN really corresponds with the name in the database, so this might lead
to strange results.

Also, depending on the SIM / provider, the SPN might actually be empty
(e.g. the provider is relying on NITZ name updates or simply screwed up
the provisioning)

The other problem is that some hardware might not enable reading of
elementary EFs, in which case the SPN might be NULL.

In both cases this check is probably not what you want.

Also, you set data->ap_ignore to TRUE here but reset it to FALSE in
end_element for the <apn> tag.  Wouldn't this result in invalid behavior
if the database has multiple APNs?

> +		break;
> +	default:
> +		break;
> +	}
> +
> +	g_free(body);
> +}
> +
> +static gboolean *ap_type_configured_flag_get(struct provider_info *data,
> +					struct ofono_gprs_provision_data *ap)
> +{
> +	gboolean *flag = NULL;
> +
> +	switch (ap->type) {
> +	case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
> +		flag = &data->ap_internet_configured;
> +		break;
> +	case OFONO_GPRS_CONTEXT_TYPE_MMS:
> +		flag = &data->ap_mms_configured;
> +		break;
> +	case OFONO_GPRS_CONTEXT_TYPE_WAP:
> +		flag = &data->ap_wap_configured;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return flag;

This sounds way too complicated.  Are you sure you can't simply use a
bitfield with the enum value for the bit offset?

> +}
> +
> +static gboolean ap_type_valid(struct ofono_gprs_provision_data *ap)
> +{
> +	switch (ap->type) {
> +	case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
> +	case OFONO_GPRS_CONTEXT_TYPE_MMS:
> +	case OFONO_GPRS_CONTEXT_TYPE_WAP:
> +		return TRUE;
> +	default:
> +		break;
> +	}
> +
> +	return FALSE;
> +}
> +
> +static gboolean ap_type_configured(struct provider_info *data,
> +					struct ofono_gprs_provision_data *ap)
> +{
> +	gboolean *flag = ap_type_configured_flag_get(data, ap);
> +
> +	if (flag == NULL)
> +		return FALSE;
> +
> +	return *flag;
> +}
> +
> +static void ap_type_mark_configured(struct provider_info *data,
> +					struct ofono_gprs_provision_data *ap)
> +{
> +	gboolean *flag = ap_type_configured_flag_get(data, ap);
> +
> +	if (flag != NULL)
> +		*flag = TRUE;
> +}
> +
> +static gboolean ap_ignore(struct provider_info *data,
> +				struct ofono_gprs_provision_data *ap)
> +{
> +	if (data->ap_ignore == TRUE)
> +		return TRUE;
> +
> +	if (ap_type_valid(ap) == FALSE) {
> +		DBG("AP '%s', type isn't supported or present, AP ignored",
> +			ap->apn);
> +		return TRUE;
> +	}
> +
> +	if (ap_type_configured(data, ap) == TRUE) {
> +		DBG("AP '%s', type %s is already configured, AP ignored",
> +			ap->apn, ap_type_name(ap->type));
> +		return TRUE;

To me again this sounds wrong.  If we have a duplicate then we can't
simply ignore it, we need to fail the entire operation.  Or am I not
seeing something here?

> +	}
> +
> +	return FALSE;
> +}
> +
> +static void element_end_parse(GMarkupParseContext *context,
> +				const gchar *element_name,
> +				gpointer user_data, GError **error)
> +{
> +	struct provider_info *data = user_data;
> +	struct ofono_gprs_provision_data *ap = data->ap;
> +	enum element_type element;
> +
> +	if (data->match_found == FALSE)
> +		return;
> +
> +	element = element_type(element_name);
> +
> +	if (data->ap_ignore == FALSE)
> +		DBG("%s: '%s'", element_type_name(element), element_name);
> +
> +	switch (element) {
> +	case ELEMENT_APN:
> +		if (ap_ignore(data, ap))
> +			ap_delete(data);
> +		else
> +			ap_type_mark_configured(data, ap);
> +
> +		data->ap_ignore = FALSE;
> +		break;
> +	case ELEMENT_GSM:
> +		data->match_found = FALSE;
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static void parser_error(GMarkupParseContext *context,
> +				GError *error, gpointer user_data)
> +{
> +	ofono_error("Error parsing %s: %s", PROVIDER_DATABASE, error->message);
> +}
> +
> +static const GMarkupParser parser = {
> +	element_start_parse,
> +	element_end_parse,
> +	element_body_parse,
> +	NULL,
> +	parser_error,
> +};
> +
> +static void parse_database(const char *data, ssize_t size,
> +	struct provider_info *provider_info)
> +{
> +	GMarkupParseContext *context;
> +	gboolean result;
> +
> +	provider_info->match_found = FALSE;
> +
> +	context = g_markup_parse_context_new(&parser,
> +						G_MARKUP_TREAT_CDATA_AS_TEXT,
> +						provider_info, NULL);
> +
> +	result = g_markup_parse_context_parse(context, data, size, NULL);
> +	if (result == TRUE)
> +		result = g_markup_parse_context_end_parse(context, NULL);
> +
> +	g_markup_parse_context_free(context);
> +}
> +
> +static int provider_info_lookup(struct provider_info *data, const char *mcc,
> +				const char *mnc, const char *spn)
> +{
> +	struct stat st;
> +	char *map;
> +	int fd;
> +
> +	fd = open(PROVIDER_DATABASE, O_RDONLY);
> +	if (fd < 0) {
> +		ofono_error("Error: open(%s): %s", PROVIDER_DATABASE,
> +				strerror(errno));
> +		return -errno;
> +	}
> +
> +	if (fstat(fd, &st) < 0) {
> +		ofono_error("Error: fstat(%s): %s", PROVIDER_DATABASE,
> +				strerror(errno));
> +		close(fd);
> +		return -errno;
> +	}
> +
> +	map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
> +	if (map == MAP_FAILED) {
> +		ofono_error("Error: mmap(%s): %s", PROVIDER_DATABASE,
> +				strerror(errno));
> +		close(fd);
> +		return -errno;
> +	}
> +
> +	data->match_mcc = mcc;
> +	data->match_mnc = mnc;
> +	data->match_spn = spn;
> +
> +	parse_database(map, st.st_size, data);
> +
> +	munmap(map, st.st_size);
> +
> +	close(fd);
> +
> +	return data->ap_count;
> +}
> +
> +static int mobile_broadband_provider_info_get(const char *mcc,
> +				const char *mnc, const char *spn,
> +				struct ofono_gprs_provision_data **settings,
> +				int *count)
> +{
> +	struct ofono_gprs_provision_data *aps;
> +	int ap_count;
> +	int i;
> +
> +	DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
> +
> +	ap_count = provider_info_lookup(&provider_info, mcc, mnc, spn);
> +	if (ap_count <= 0)
> +		return -ENOENT;
> +
> +	DBG("Found %d APs", ap_count);
> +
> +	aps = g_try_malloc_n(ap_count,
> +				sizeof(struct ofono_gprs_provision_data));
> +	if (aps == NULL) {
> +		ofono_error("Error provisioning APNs: memory exhausted");
> +		return -ENOMEM;
> +	}
> +
> +	memcpy(aps, provider_info.settings,
> +		sizeof(struct ofono_gprs_provision_data) * ap_count);
> +
> +	*settings = aps;
> +	*count = ap_count;
> +
> +	for (i = 0; i < ap_count; aps++, i++) {
> +		DBG("Name: '%s'", aps->name);
> +		DBG("APN: '%s'", aps->apn);
> +		DBG("Type: %s", ap_type_name(aps->type));
> +		DBG("Username: '%s'", aps->username);
> +		DBG("Password: '%s'", aps->password);
> +	}
> +

You are not freeing the used up settings when this function exits and I
don't see how they're freed otherwise.  Am I missing something or would
this function eventually stop working if called repeatedly (e.g.
multiple SIMs removed / inserted)?

> +	return 0;
> +}
> +
> +static struct ofono_gprs_provision_driver provision_driver = {
> +	.name		= "Mobile Broadband Provider Info",
> +	.get_settings	= mobile_broadband_provider_info_get
> +};
> +
> +static int mobile_broadband_provider_info_init(void)
> +{
> +	return ofono_gprs_provision_driver_register(&provision_driver);
> +}
> +
> +static void mobile_broadband_provider_info_exit(void)
> +{
> +	ofono_gprs_provision_driver_unregister(&provision_driver);
> +}
> +
> +OFONO_PLUGIN_DEFINE(mobile_broadband_provider_info,
> +			"Mobile Broadband Provider Info Plugin",
> +			VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
> +			mobile_broadband_provider_info_init,
> +			mobile_broadband_provider_info_exit)

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCHv4 0/3] Mobile broadband provider info plugin
@ 2011-08-25 11:23 Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 1/3] Mobile broadband provider info plugin makefile changes Oleg Zhurakivskyy
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Oleg Zhurakivskyy @ 2011-08-25 11:23 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 800 bytes --]

Hello,

Please find the mobile broadband provider info plugin ("Internet Access Provider database" TODO item).

If enabled, the plugin reads mobile-broadband-provider-info database entries (PROVIDER_DATABASE) and returns GRPS context settings to oFono provisioning module.

Regards,
Oleg

Oleg Zhurakivskyy (3):
  Mobile broadband provider info plugin makefile changes
  Mobile broadband provider info plugin autoconf support
  Mobile broadband provider info plugin

 Makefile.am                              |    7 +
 configure.ac                             |   19 +-
 plugins/mobile-broadband-provider-info.c |  604 ++++++++++++++++++++++++++++++
 3 files changed, 624 insertions(+), 6 deletions(-)
 create mode 100644 plugins/mobile-broadband-provider-info.c

-- 
1.7.4.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCHv4 1/3] Mobile broadband provider info plugin makefile changes
  2011-08-25 11:23 [PATCHv4 0/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
@ 2011-08-25 11:23 ` Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 2/3] Mobile broadband provider info plugin autoconf support Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 3/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
  2 siblings, 0 replies; 6+ messages in thread
From: Oleg Zhurakivskyy @ 2011-08-25 11:23 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 857 bytes --]

---
 Makefile.am |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 6f5d921..7df0fd3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -358,6 +358,11 @@ builtin_libadd += @BLUEZ_LIBS@
 endif
 endif
 
+if PROVIDER_INFO
+builtin_modules += mobile_broadband_provider_info
+builtin_sources += plugins/mobile-broadband-provider-info.c
+endif
+
 if MAINTAINER_MODE
 builtin_modules += example_history
 builtin_sources += examples/history.c
@@ -365,8 +370,10 @@ builtin_sources += examples/history.c
 builtin_modules += example_nettime
 builtin_sources += examples/nettime.c
 
+if !PROVIDER_INFO
 builtin_modules += example_provision
 builtin_sources += examples/provision.c
+endif
 
 builtin_modules += example_emulator
 builtin_sources += examples/emulator.c
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv4 2/3] Mobile broadband provider info plugin autoconf support
  2011-08-25 11:23 [PATCHv4 0/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 1/3] Mobile broadband provider info plugin makefile changes Oleg Zhurakivskyy
@ 2011-08-25 11:23 ` Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 3/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
  2 siblings, 0 replies; 6+ messages in thread
From: Oleg Zhurakivskyy @ 2011-08-25 11:23 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1480 bytes --]

---
 configure.ac |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/configure.ac b/configure.ac
index a6b4094..966237c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -197,14 +197,21 @@ AC_SUBST(BLUEZ_CFLAGS)
 AC_SUBST(BLUEZ_LIBS)
 AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
 
-AC_MSG_CHECKING([for mobile-broadband-provider-info])
-PKG_CHECK_EXISTS(mobile-broadband-provider-info,
-	_PKG_CONFIG(PROVIDER_DATABASE, [variable=database],
+AC_ARG_ENABLE(provider-info, AC_HELP_STRING([--enable-provider-info],
+				[enable mobile provider database support]),
+					[enable_provider_info=${enableval}])
+if (test "${enable_provider_info}" == "yes"); then
+	AC_MSG_CHECKING([for mobile-broadband-provider-info])
+	PKG_CHECK_EXISTS(mobile-broadband-provider-info,
+			_PKG_CONFIG(PROVIDER_DATABASE, [variable=database],
 					[mobile-broadband-provider-info])
-	AC_DEFINE_UNQUOTED(PROVIDER_DATABASE, "$pkg_cv_PROVIDER_DATABASE",
+		AC_DEFINE_UNQUOTED(PROVIDER_DATABASE,
+					"$pkg_cv_PROVIDER_DATABASE",
 					[Mobile provider database])
-	AC_MSG_RESULT([yes]),
-	AC_MSG_RESULT([no]))
+		AC_MSG_RESULT([yes]),
+		AC_MSG_ERROR(mobile-broadband-provider-info package is required))
+fi
+AM_CONDITIONAL(PROVIDER_INFO, test "${enable_provider_info}" == "yes")
 
 AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
 			[don't install configuration and data files]),
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv4 3/3] Mobile broadband provider info plugin
  2011-08-25 11:23 [PATCHv4 0/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 1/3] Mobile broadband provider info plugin makefile changes Oleg Zhurakivskyy
  2011-08-25 11:23 ` [PATCHv4 2/3] Mobile broadband provider info plugin autoconf support Oleg Zhurakivskyy
@ 2011-08-25 11:23 ` Oleg Zhurakivskyy
  2011-08-24  1:04   ` Denis Kenzior
  2 siblings, 1 reply; 6+ messages in thread
From: Oleg Zhurakivskyy @ 2011-08-25 11:23 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 15232 bytes --]

---
 plugins/mobile-broadband-provider-info.c |  604 ++++++++++++++++++++++++++++++
 1 files changed, 604 insertions(+), 0 deletions(-)
 create mode 100644 plugins/mobile-broadband-provider-info.c

diff --git a/plugins/mobile-broadband-provider-info.c b/plugins/mobile-broadband-provider-info.c
new file mode 100644
index 0000000..dbe2962
--- /dev/null
+++ b/plugins/mobile-broadband-provider-info.c
@@ -0,0 +1,604 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. 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 version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/types.h>
+#include <ofono/log.h>
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-provision.h>
+
+#define MAX_APS	3
+
+#define _(x) case x: return (#x)
+
+enum element_type {
+	ELEMENT_NETWORK_ID,
+	ELEMENT_GSM,
+	ELEMENT_APN,
+	ELEMENT_USAGE,
+	ELEMENT_PLAN,
+	ELEMENT_NAME,
+	ELEMENT_USERNAME,
+	ELEMENT_PASSWORD,
+	ELEMENT_NONE,
+};
+
+struct provider_info {
+	struct ofono_gprs_provision_data settings[MAX_APS];
+	struct ofono_gprs_provision_data *ap;
+	int ap_count;
+	const char *match_mcc;
+	const char *match_mnc;
+	const char *match_spn;
+	enum element_type element;
+	gboolean match_found;
+	gboolean ap_ignore;
+	gboolean ap_internet_configured;
+	gboolean ap_mms_configured;
+	gboolean ap_wap_configured;
+};
+
+static struct provider_info provider_info;
+
+static const char *element_type_name(enum element_type element)
+{
+	switch (element) {
+		_(ELEMENT_NETWORK_ID);
+		_(ELEMENT_GSM);
+		_(ELEMENT_APN);
+		_(ELEMENT_USAGE);
+		_(ELEMENT_PLAN);
+		_(ELEMENT_NAME);
+		_(ELEMENT_USERNAME);
+		_(ELEMENT_PASSWORD);
+		_(ELEMENT_NONE);
+	}
+	return "ELEMENT_<UNKNOWN>";
+}
+
+static const char *ap_type_name(enum ofono_gprs_context_type ap_type)
+{
+	switch (ap_type) {
+		_(OFONO_GPRS_CONTEXT_TYPE_ANY);
+		_(OFONO_GPRS_CONTEXT_TYPE_INTERNET);
+		_(OFONO_GPRS_CONTEXT_TYPE_MMS);
+		_(OFONO_GPRS_CONTEXT_TYPE_WAP);
+		_(OFONO_GPRS_CONTEXT_TYPE_IMS);
+	}
+	return "OFONO_GPRS_CONTEXT_TYPE_<UNKNOWN>";
+}
+
+static enum element_type element_type(const gchar *element)
+{
+	switch (element[0]) {
+	case 'a':
+		if (g_str_equal(element, "apn") == TRUE)
+			return ELEMENT_APN;
+		break;
+	case 'g':
+		if (g_str_equal(element, "gsm") == TRUE)
+			return ELEMENT_GSM;
+		break;
+	case 'n':
+		if (g_str_equal(element, "name") == TRUE)
+			return ELEMENT_NAME;
+		if (g_str_equal(element, "network-id") == TRUE)
+			return ELEMENT_NETWORK_ID;
+		break;
+	case 'p':
+		if (g_str_equal(element, "plan") == TRUE)
+			return ELEMENT_PLAN;
+		if (g_str_equal(element, "password") == TRUE)
+			return ELEMENT_PASSWORD;
+		break;
+	case 'u':
+		if (g_str_equal(element, "usage") == TRUE)
+			return ELEMENT_USAGE;
+		if (g_str_equal(element, "username") == TRUE)
+			return ELEMENT_USERNAME;
+	}
+
+	return ELEMENT_NONE;
+}
+
+static void element_network_id_parse(struct provider_info *data,
+					const gchar **attribute_names,
+					const gchar **attribute_values)
+{
+	const char *mcc = NULL, *mnc = NULL;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_str_equal(attribute_names[i], "mcc") == TRUE)
+			mcc = attribute_values[i];
+		if (g_str_equal(attribute_names[i], "mnc") == TRUE)
+			mnc = attribute_values[i];
+	}
+
+	if (g_strcmp0(mcc, data->match_mcc) == 0 &&
+			g_strcmp0(mnc, data->match_mnc) == 0)
+		data->match_found = TRUE;
+}
+
+static struct ofono_gprs_provision_data *ap_new(struct provider_info *data)
+{
+	if (data->ap_count < MAX_APS)
+		return data->settings + data->ap_count++;
+
+	return NULL;
+}
+
+static void ap_value_free(char **value)
+{
+	if (*value == NULL)
+		return;
+
+	g_free(*value);
+
+	*value = NULL;
+}
+
+static void ap_delete(struct provider_info *data)
+{
+	struct ofono_gprs_provision_data *ap = data->ap;
+
+	ap_value_free(&ap->name);
+
+	ap_value_free(&ap->apn);
+
+	ap_value_free(&ap->username);
+
+	ap_value_free(&ap->password);
+
+	ap->type = OFONO_GPRS_CONTEXT_TYPE_ANY;
+
+	data->ap_count--;
+
+	data->ap--;
+}
+
+static void element_apn_parse(struct provider_info *data,
+				const gchar **attribute_names,
+				const gchar **attribute_values)
+{
+	const char *apn = NULL;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_str_equal(attribute_names[i], "value") == TRUE)
+			apn = attribute_values[i];
+	}
+
+	data->ap = ap_new(data);
+	if (data->ap == NULL) {
+		DBG("AP '%s', MAX_APS %d reached, AP ignored", apn, MAX_APS);
+		data->match_found = FALSE;
+		return;
+	}
+
+	data->ap->apn = g_strdup(apn);
+}
+
+static void element_usage_parse(struct provider_info *data,
+				const gchar **attribute_names,
+				const gchar **attribute_values)
+{
+	struct ofono_gprs_provision_data *ap = data->ap;
+	const char *usage = NULL;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_str_equal(attribute_names[i], "type") == TRUE)
+			usage = attribute_values[i];
+	}
+
+	if (usage == NULL) {
+		DBG("AP '%s', no type, AP ignored", ap->apn);
+		data->ap_ignore = TRUE;
+		return;
+	}
+
+	if (g_str_equal(usage, "internet") == TRUE)
+		ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
+	else if (g_str_equal(usage, "mms") == TRUE)
+		ap->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
+	else if (g_str_equal(usage, "wap") == TRUE)
+		ap->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
+}
+
+static void element_plan_parse(struct provider_info *data,
+				const gchar **attribute_names,
+				const gchar **attribute_values)
+{
+	const char *plan = NULL;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_str_equal(attribute_names[i], "type") == TRUE)
+			plan = attribute_values[i];
+	}
+
+	if (plan != NULL && g_str_equal(plan, "postpaid") == TRUE)
+		return;
+
+	DBG("AP '%s', plan '%s', plan is not postpaid, AP ignored",
+		data->ap->apn, plan);
+
+	data->ap_ignore = TRUE;
+}
+
+static void element_start_parse(GMarkupParseContext *context,
+				const gchar *element_name,
+				const gchar **attribute_names,
+				const gchar **attribute_values,
+				gpointer user_data, GError **error)
+{
+	struct provider_info *data = user_data;
+
+	data->element = element_type(element_name);
+
+	if (data->element == ELEMENT_NETWORK_ID)
+		element_network_id_parse(data, attribute_names,
+						attribute_values);
+
+	if (data->match_found == FALSE || data->ap_ignore == TRUE)
+		return;
+
+	DBG("%s: '%s'", element_type_name(data->element), element_name);
+
+	switch (data->element) {
+	case ELEMENT_APN:
+		element_apn_parse(data, attribute_names, attribute_values);
+		break;
+	case ELEMENT_USAGE:
+		element_usage_parse(data, attribute_names, attribute_values);
+		break;
+	case ELEMENT_PLAN:
+		element_plan_parse(data, attribute_names, attribute_values);
+		break;
+	default:
+		break;
+	}
+}
+
+static gchar *body_text_parse(const gchar *text, gsize text_len)
+{
+	gchar *body = g_strndup(text, text_len);
+	gchar *print = NULL;
+	int i;
+
+	for (i = 0; body && body[i]; i++) {
+		if (g_ascii_isprint(body[i])) {
+			print = g_strescape(body, NULL);
+			break;
+		}
+	}
+
+	if (body)
+		g_free(body);
+
+	return print;
+}
+
+static void element_body_parse(GMarkupParseContext *context,
+				const gchar *text, gsize text_len,
+				gpointer user_data, GError **error)
+{
+	struct provider_info *data = user_data;
+	struct ofono_gprs_provision_data *ap = data->ap;
+	gchar *body;
+
+	if (data->match_found == FALSE || text_len == 0 ||
+			data->ap_ignore == TRUE)
+		return;
+
+	body = body_text_parse(text, text_len);
+	if (body == NULL)
+		return;
+
+	DBG("%s: '%s'", element_type_name(data->element), body);
+
+	switch (data->element) {
+	case ELEMENT_USERNAME:
+		ap->username = g_strdup(body);
+		break;
+	case ELEMENT_PASSWORD:
+		ap->password = g_strdup(body);
+		break;
+	case ELEMENT_NAME:
+		if (g_strcmp0(body, data->match_spn) == 0) {
+			ap->name = g_strdup(body);
+			break;
+		}
+
+		DBG("AP '%s', SPN '%s', is not our SPN, AP ignored", ap->apn,
+			body);
+		data->ap_ignore = TRUE;
+		break;
+	default:
+		break;
+	}
+
+	g_free(body);
+}
+
+static gboolean *ap_type_configured_flag_get(struct provider_info *data,
+					struct ofono_gprs_provision_data *ap)
+{
+	gboolean *flag = NULL;
+
+	switch (ap->type) {
+	case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
+		flag = &data->ap_internet_configured;
+		break;
+	case OFONO_GPRS_CONTEXT_TYPE_MMS:
+		flag = &data->ap_mms_configured;
+		break;
+	case OFONO_GPRS_CONTEXT_TYPE_WAP:
+		flag = &data->ap_wap_configured;
+		break;
+	default:
+		break;
+	}
+
+	return flag;
+}
+
+static gboolean ap_type_valid(struct ofono_gprs_provision_data *ap)
+{
+	switch (ap->type) {
+	case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
+	case OFONO_GPRS_CONTEXT_TYPE_MMS:
+	case OFONO_GPRS_CONTEXT_TYPE_WAP:
+		return TRUE;
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+static gboolean ap_type_configured(struct provider_info *data,
+					struct ofono_gprs_provision_data *ap)
+{
+	gboolean *flag = ap_type_configured_flag_get(data, ap);
+
+	if (flag == NULL)
+		return FALSE;
+
+	return *flag;
+}
+
+static void ap_type_mark_configured(struct provider_info *data,
+					struct ofono_gprs_provision_data *ap)
+{
+	gboolean *flag = ap_type_configured_flag_get(data, ap);
+
+	if (flag != NULL)
+		*flag = TRUE;
+}
+
+static gboolean ap_ignore(struct provider_info *data,
+				struct ofono_gprs_provision_data *ap)
+{
+	if (data->ap_ignore == TRUE)
+		return TRUE;
+
+	if (ap_type_valid(ap) == FALSE) {
+		DBG("AP '%s', type isn't supported or present, AP ignored",
+			ap->apn);
+		return TRUE;
+	}
+
+	if (ap_type_configured(data, ap) == TRUE) {
+		DBG("AP '%s', type %s is already configured, AP ignored",
+			ap->apn, ap_type_name(ap->type));
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void element_end_parse(GMarkupParseContext *context,
+				const gchar *element_name,
+				gpointer user_data, GError **error)
+{
+	struct provider_info *data = user_data;
+	struct ofono_gprs_provision_data *ap = data->ap;
+	enum element_type element;
+
+	if (data->match_found == FALSE)
+		return;
+
+	element = element_type(element_name);
+
+	if (data->ap_ignore == FALSE)
+		DBG("%s: '%s'", element_type_name(element), element_name);
+
+	switch (element) {
+	case ELEMENT_APN:
+		if (ap_ignore(data, ap))
+			ap_delete(data);
+		else
+			ap_type_mark_configured(data, ap);
+
+		data->ap_ignore = FALSE;
+		break;
+	case ELEMENT_GSM:
+		data->match_found = FALSE;
+		break;
+	default:
+		break;
+	}
+}
+
+static void parser_error(GMarkupParseContext *context,
+				GError *error, gpointer user_data)
+{
+	ofono_error("Error parsing %s: %s", PROVIDER_DATABASE, error->message);
+}
+
+static const GMarkupParser parser = {
+	element_start_parse,
+	element_end_parse,
+	element_body_parse,
+	NULL,
+	parser_error,
+};
+
+static void parse_database(const char *data, ssize_t size,
+	struct provider_info *provider_info)
+{
+	GMarkupParseContext *context;
+	gboolean result;
+
+	provider_info->match_found = FALSE;
+
+	context = g_markup_parse_context_new(&parser,
+						G_MARKUP_TREAT_CDATA_AS_TEXT,
+						provider_info, NULL);
+
+	result = g_markup_parse_context_parse(context, data, size, NULL);
+	if (result == TRUE)
+		result = g_markup_parse_context_end_parse(context, NULL);
+
+	g_markup_parse_context_free(context);
+}
+
+static int provider_info_lookup(struct provider_info *data, const char *mcc,
+				const char *mnc, const char *spn)
+{
+	struct stat st;
+	char *map;
+	int fd;
+
+	fd = open(PROVIDER_DATABASE, O_RDONLY);
+	if (fd < 0) {
+		ofono_error("Error: open(%s): %s", PROVIDER_DATABASE,
+				strerror(errno));
+		return -errno;
+	}
+
+	if (fstat(fd, &st) < 0) {
+		ofono_error("Error: fstat(%s): %s", PROVIDER_DATABASE,
+				strerror(errno));
+		close(fd);
+		return -errno;
+	}
+
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (map == MAP_FAILED) {
+		ofono_error("Error: mmap(%s): %s", PROVIDER_DATABASE,
+				strerror(errno));
+		close(fd);
+		return -errno;
+	}
+
+	data->match_mcc = mcc;
+	data->match_mnc = mnc;
+	data->match_spn = spn;
+
+	parse_database(map, st.st_size, data);
+
+	munmap(map, st.st_size);
+
+	close(fd);
+
+	return data->ap_count;
+}
+
+static int mobile_broadband_provider_info_get(const char *mcc,
+				const char *mnc, const char *spn,
+				struct ofono_gprs_provision_data **settings,
+				int *count)
+{
+	struct ofono_gprs_provision_data *aps;
+	int ap_count;
+	int i;
+
+	DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
+
+	ap_count = provider_info_lookup(&provider_info, mcc, mnc, spn);
+	if (ap_count <= 0)
+		return -ENOENT;
+
+	DBG("Found %d APs", ap_count);
+
+	aps = g_try_malloc_n(ap_count,
+				sizeof(struct ofono_gprs_provision_data));
+	if (aps == NULL) {
+		ofono_error("Error provisioning APNs: memory exhausted");
+		return -ENOMEM;
+	}
+
+	memcpy(aps, provider_info.settings,
+		sizeof(struct ofono_gprs_provision_data) * ap_count);
+
+	*settings = aps;
+	*count = ap_count;
+
+	for (i = 0; i < ap_count; aps++, i++) {
+		DBG("Name: '%s'", aps->name);
+		DBG("APN: '%s'", aps->apn);
+		DBG("Type: %s", ap_type_name(aps->type));
+		DBG("Username: '%s'", aps->username);
+		DBG("Password: '%s'", aps->password);
+	}
+
+	return 0;
+}
+
+static struct ofono_gprs_provision_driver provision_driver = {
+	.name		= "Mobile Broadband Provider Info",
+	.get_settings	= mobile_broadband_provider_info_get
+};
+
+static int mobile_broadband_provider_info_init(void)
+{
+	return ofono_gprs_provision_driver_register(&provision_driver);
+}
+
+static void mobile_broadband_provider_info_exit(void)
+{
+	ofono_gprs_provision_driver_unregister(&provision_driver);
+}
+
+OFONO_PLUGIN_DEFINE(mobile_broadband_provider_info,
+			"Mobile Broadband Provider Info Plugin",
+			VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+			mobile_broadband_provider_info_init,
+			mobile_broadband_provider_info_exit)
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCHv4 3/3] Mobile broadband provider info plugin
  2011-08-24  1:04   ` Denis Kenzior
@ 2011-08-30 12:57     ` Oleg Zhurakivskyy
  0 siblings, 0 replies; 6+ messages in thread
From: Oleg Zhurakivskyy @ 2011-08-30 12:57 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1046 bytes --]

Hello Denis,

On 08/24/2011 04:04 AM, Denis Kenzior wrote:
> However, I'm still wondering whether setting data->match_found is
> enough.  Here's the example I'm thinking of:
>
> <provider>
> 	<name>Major Operator</name>
> 	<network-id mcc="555" mnc="55"/>
> 	<apn>...</apn>
> </provider>
>
> <provider>
> 	<name>MVNO running on Major Operator</name>
> 	<network-id mcc="555" mnc="55"/>
> 	<apn>...</apn>
> </provider>
>
> If the Major Operator provides MAX_APN apns, then wouldn't this cause us
> to return the APNs from Major Operator, even though this is a conflict
> and we might potentially want APNs from MVNO?
>
> If this is indeed such a conflicted case then we need to let the user
> decide, not return any results as they're potentially erroneous.

Thanks for the comments. Please take a look at the PATCHv5 on the list, which 
addresses this and other issues too.

Regards,
Oleg
-- 
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki
Business Identity Code: 0357606 - 4
Domiciled in Helsinki

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-08-30 12:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-25 11:23 [PATCHv4 0/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
2011-08-25 11:23 ` [PATCHv4 1/3] Mobile broadband provider info plugin makefile changes Oleg Zhurakivskyy
2011-08-25 11:23 ` [PATCHv4 2/3] Mobile broadband provider info plugin autoconf support Oleg Zhurakivskyy
2011-08-25 11:23 ` [PATCHv4 3/3] Mobile broadband provider info plugin Oleg Zhurakivskyy
2011-08-24  1:04   ` Denis Kenzior
2011-08-30 12:57     ` Oleg Zhurakivskyy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.