forked from sailfishos/ofono
		
	[ofono] Added filter_check to ofono_gprs_filter. JB#41665
It checks if ofono_gprs_filter allows mobile data in general, not just for the particular context.
This commit is contained in:
		@@ -22,12 +22,14 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
#include <ofono/types.h>
 | 
			
		||||
 | 
			
		||||
struct ofono_gprs;
 | 
			
		||||
struct ofono_gprs_context;
 | 
			
		||||
struct ofono_gprs_primary_context;
 | 
			
		||||
 | 
			
		||||
/* If ctx is NULL then activation gets cancelled */
 | 
			
		||||
typedef void (*ofono_gprs_filter_activate_cb_t)
 | 
			
		||||
		(const struct ofono_gprs_primary_context *ctx, void *data);
 | 
			
		||||
typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
 | 
			
		||||
 | 
			
		||||
#define OFONO_GPRS_FILTER_PRIORITY_LOW     (-100)
 | 
			
		||||
#define OFONO_GPRS_FILTER_PRIORITY_DEFAULT (0)
 | 
			
		||||
@@ -38,7 +40,7 @@ typedef void (*ofono_gprs_filter_activate_cb_t)
 | 
			
		||||
 * even if struct ofono_gprs_filter gets extended with new callbacks.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define OFONO_GPRS_FILTER_API_VERSION      (0)
 | 
			
		||||
#define OFONO_GPRS_FILTER_API_VERSION      (1)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The filter callbacks either invoke the completion callback directly
 | 
			
		||||
@@ -59,6 +61,9 @@ struct ofono_gprs_filter {
 | 
			
		||||
				const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
				ofono_gprs_filter_activate_cb_t cb,
 | 
			
		||||
				void *data);
 | 
			
		||||
	/* API version 1 */
 | 
			
		||||
	unsigned int (*filter_check)(struct ofono_gprs *gprs,
 | 
			
		||||
				ofono_gprs_filter_check_cb_t cb, void *data);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter);
 | 
			
		||||
 
 | 
			
		||||
@@ -18,57 +18,67 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_request;
 | 
			
		||||
struct gprs_filter_request_fn {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	gboolean (*can_process)(const struct ofono_gprs_filter *filter);
 | 
			
		||||
	guint (*process)(const struct ofono_gprs_filter *filter,
 | 
			
		||||
					struct gprs_filter_request *req);
 | 
			
		||||
	void (*complete)(struct gprs_filter_request *req, gboolean allow);
 | 
			
		||||
	void (*free)(struct gprs_filter_request *req);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_request {
 | 
			
		||||
	int refcount;
 | 
			
		||||
	struct gprs_filter_chain *chain;
 | 
			
		||||
	struct ofono_gprs_context *gc;
 | 
			
		||||
	const struct gprs_filter_request_fn *fn;
 | 
			
		||||
	GSList *filter_link;
 | 
			
		||||
	guint pending_id;
 | 
			
		||||
	guint next_id;
 | 
			
		||||
	struct ofono_gprs_primary_context ctx;
 | 
			
		||||
	gprs_filter_activate_cb_t act;
 | 
			
		||||
	ofono_destroy_func destroy;
 | 
			
		||||
	void* user_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* There's no need to support more than one request at a time */
 | 
			
		||||
struct gprs_filter_request_activate {
 | 
			
		||||
	struct gprs_filter_request req;
 | 
			
		||||
	struct ofono_gprs_primary_context ctx;
 | 
			
		||||
	gprs_filter_activate_cb_t cb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_request_check {
 | 
			
		||||
	struct gprs_filter_request req;
 | 
			
		||||
	ofono_gprs_filter_check_cb_t cb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_chain {
 | 
			
		||||
	struct ofono_gprs_context *gc;
 | 
			
		||||
	struct gprs_filter_request *req;
 | 
			
		||||
	struct ofono_gprs *gprs;
 | 
			
		||||
	GSList *req_list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GSList *gprs_filter_list = NULL;
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_process(struct gprs_filter_request *req);
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_copy_context(struct ofono_gprs_primary_context *dest,
 | 
			
		||||
				const struct ofono_gprs_primary_context *src)
 | 
			
		||||
static void gprs_filter_request_init(struct gprs_filter_request *req,
 | 
			
		||||
		const struct gprs_filter_request_fn *fn,
 | 
			
		||||
		struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
 | 
			
		||||
		ofono_destroy_func destroy, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	dest->cid = src->cid;
 | 
			
		||||
	dest->proto = src->proto;
 | 
			
		||||
	dest->auth_method = src->auth_method;
 | 
			
		||||
	strncpy(dest->apn, src->apn, OFONO_GPRS_MAX_APN_LENGTH);
 | 
			
		||||
	strncpy(dest->username, src->username, OFONO_GPRS_MAX_USERNAME_LENGTH);
 | 
			
		||||
	strncpy(dest->password, src->password, OFONO_GPRS_MAX_PASSWORD_LENGTH);
 | 
			
		||||
	dest->apn[OFONO_GPRS_MAX_APN_LENGTH] = 0;
 | 
			
		||||
	dest->username[OFONO_GPRS_MAX_USERNAME_LENGTH] = 0;
 | 
			
		||||
	dest->password[OFONO_GPRS_MAX_PASSWORD_LENGTH] = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gprs_filter_request *gprs_filter_request_new
 | 
			
		||||
	(struct gprs_filter_chain *chain,
 | 
			
		||||
		const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
				gprs_filter_activate_cb_t act,
 | 
			
		||||
				ofono_destroy_func destroy, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request *req = g_new0(struct gprs_filter_request, 1);
 | 
			
		||||
 | 
			
		||||
	req->chain = chain;
 | 
			
		||||
	req->fn = fn;
 | 
			
		||||
	req->gc = gc;
 | 
			
		||||
	req->filter_link = gprs_filter_list;
 | 
			
		||||
	gprs_filter_copy_context(&req->ctx, ctx);
 | 
			
		||||
	req->act = act;
 | 
			
		||||
	req->destroy = destroy;
 | 
			
		||||
	req->user_data = user_data;
 | 
			
		||||
	return req;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The list holds an implicit reference to the message. The reference
 | 
			
		||||
	 * is released by gprs_filter_request_free when the message is removed
 | 
			
		||||
	 * from the list.
 | 
			
		||||
	 */
 | 
			
		||||
	req->refcount = 1;
 | 
			
		||||
	chain->req_list = g_slist_append(chain->req_list, req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_cancel(struct gprs_filter_request *req)
 | 
			
		||||
@@ -89,21 +99,94 @@ static void gprs_filter_request_cancel(struct gprs_filter_request *req)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_dispose(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	/* May be invoked several times per request */
 | 
			
		||||
	if (req->destroy) {
 | 
			
		||||
		ofono_destroy_func destroy = req->destroy;
 | 
			
		||||
 | 
			
		||||
		req->destroy = NULL;
 | 
			
		||||
		destroy(req->user_data);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_free(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	if (req->destroy) {
 | 
			
		||||
		req->destroy(req->user_data);
 | 
			
		||||
	gprs_filter_request_dispose(req);
 | 
			
		||||
	req->fn->free(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define gprs_filter_request_ref(req) ((req)->refcount++, req)
 | 
			
		||||
 | 
			
		||||
static int gprs_filter_request_unref(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	const int refcount = --(req->refcount);
 | 
			
		||||
 | 
			
		||||
	if (!refcount) {
 | 
			
		||||
		gprs_filter_request_free(req);
 | 
			
		||||
	}
 | 
			
		||||
	return refcount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_free1(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request *req = data;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * This is a g_slist_free_full() callback for use by
 | 
			
		||||
	 * __ofono_gprs_filter_chain_free(), meaning that the
 | 
			
		||||
	 * chain is no more. Zero the pointer to it in case if
 | 
			
		||||
	 * this is not the last reference.
 | 
			
		||||
	 */
 | 
			
		||||
	req->chain = NULL;
 | 
			
		||||
	gprs_filter_request_unref(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_dequeue(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_chain *chain = req->chain;
 | 
			
		||||
	GSList *l;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Single-linked list is not particularly good at searching
 | 
			
		||||
	 * and removing the elements but since it should be pretty
 | 
			
		||||
	 * short (typically just one request), it's not worth optimization.
 | 
			
		||||
	 */
 | 
			
		||||
	if (chain && (l = g_slist_find(chain->req_list, req)) != NULL) {
 | 
			
		||||
		gprs_filter_request_free1(l->data);
 | 
			
		||||
		chain->req_list = g_slist_delete_link(chain->req_list, l);
 | 
			
		||||
	}
 | 
			
		||||
	g_free(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_complete(struct gprs_filter_request *req,
 | 
			
		||||
							gboolean allow)
 | 
			
		||||
{
 | 
			
		||||
	req->chain->req = NULL;
 | 
			
		||||
	gprs_filter_request_cancel(req);
 | 
			
		||||
	req->act(allow ? &req->ctx : NULL, req->user_data);
 | 
			
		||||
	gprs_filter_request_free(req);
 | 
			
		||||
	gprs_filter_request_ref(req);
 | 
			
		||||
	req->fn->complete(req, allow);
 | 
			
		||||
	gprs_filter_request_dispose(req);
 | 
			
		||||
	gprs_filter_request_dequeue(req);
 | 
			
		||||
	gprs_filter_request_unref(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_process(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	GSList *l = req->filter_link;
 | 
			
		||||
	const struct ofono_gprs_filter *f = l->data;
 | 
			
		||||
	const struct gprs_filter_request_fn *fn = req->fn;
 | 
			
		||||
 | 
			
		||||
	while (f && !fn->can_process(f)) {
 | 
			
		||||
		l = l->next;
 | 
			
		||||
		f = l ? l->data : NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gprs_filter_request_ref(req);
 | 
			
		||||
	if (f) {
 | 
			
		||||
		req->filter_link = l;
 | 
			
		||||
		req->pending_id = fn->process(f, req);
 | 
			
		||||
	} else {
 | 
			
		||||
		gprs_filter_request_complete(req, TRUE);
 | 
			
		||||
	}
 | 
			
		||||
	gprs_filter_request_unref(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_next(struct gprs_filter_request *req,
 | 
			
		||||
@@ -113,7 +196,7 @@ static void gprs_filter_request_next(struct gprs_filter_request *req,
 | 
			
		||||
	req->next_id = g_idle_add(fn, req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean gprs_filter_continue_cb(gpointer data)
 | 
			
		||||
static gboolean gprs_filter_request_continue_cb(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request *req = data;
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +210,7 @@ static gboolean gprs_filter_continue_cb(gpointer data)
 | 
			
		||||
	return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean gprs_filter_cancel_cb(gpointer data)
 | 
			
		||||
static gboolean gprs_filter_request_disallow_cb(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request *req = data;
 | 
			
		||||
 | 
			
		||||
@@ -136,91 +219,185 @@ static gboolean gprs_filter_cancel_cb(gpointer data)
 | 
			
		||||
	return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_activate_cb
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * gprs_filter_request_activate
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_copy_context(struct ofono_gprs_primary_context *dest,
 | 
			
		||||
				const struct ofono_gprs_primary_context *src)
 | 
			
		||||
{
 | 
			
		||||
	dest->cid = src->cid;
 | 
			
		||||
	dest->proto = src->proto;
 | 
			
		||||
	dest->auth_method = src->auth_method;
 | 
			
		||||
	strncpy(dest->apn, src->apn, OFONO_GPRS_MAX_APN_LENGTH);
 | 
			
		||||
	strncpy(dest->username, src->username, OFONO_GPRS_MAX_USERNAME_LENGTH);
 | 
			
		||||
	strncpy(dest->password, src->password, OFONO_GPRS_MAX_PASSWORD_LENGTH);
 | 
			
		||||
	dest->apn[OFONO_GPRS_MAX_APN_LENGTH] = 0;
 | 
			
		||||
	dest->username[OFONO_GPRS_MAX_USERNAME_LENGTH] = 0;
 | 
			
		||||
	dest->password[OFONO_GPRS_MAX_PASSWORD_LENGTH] = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gprs_filter_request_activate *gprs_filter_request_activate_cast
 | 
			
		||||
					(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	return (struct gprs_filter_request_activate *)req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean gprs_filter_request_activate_can_process
 | 
			
		||||
					(const struct ofono_gprs_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	return f->filter_activate != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_activate_cb
 | 
			
		||||
		(const struct ofono_gprs_primary_context *ctx, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request *req = data;
 | 
			
		||||
	struct gprs_filter_request_activate *act = data;
 | 
			
		||||
	struct gprs_filter_request *req = &act->req;
 | 
			
		||||
	const struct ofono_gprs_filter *filter = req->filter_link->data;
 | 
			
		||||
 | 
			
		||||
	if (ctx) {
 | 
			
		||||
		if (ctx != &req->ctx) {
 | 
			
		||||
		if (ctx != &act->ctx) {
 | 
			
		||||
			/* The filter may have updated context settings */
 | 
			
		||||
			gprs_filter_copy_context(&req->ctx, ctx);
 | 
			
		||||
			gprs_filter_copy_context(&act->ctx, ctx);
 | 
			
		||||
		}
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_continue_cb);
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_request_continue_cb);
 | 
			
		||||
	} else {
 | 
			
		||||
		DBG("%s not allowing to activate mobile data", filter->name);
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_cancel_cb);
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_process(struct gprs_filter_request *req)
 | 
			
		||||
static guint gprs_filter_request_activate_process
 | 
			
		||||
				(const struct ofono_gprs_filter *f,
 | 
			
		||||
					struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	GSList *l = req->filter_link;
 | 
			
		||||
	const struct ofono_gprs_filter *f = l->data;
 | 
			
		||||
	struct gprs_filter_request_activate *act =
 | 
			
		||||
		gprs_filter_request_activate_cast(req);
 | 
			
		||||
 | 
			
		||||
	while (f && !f->filter_activate) {
 | 
			
		||||
		l = l->next;
 | 
			
		||||
		f = l ? l->data : NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (f) {
 | 
			
		||||
		guint id;
 | 
			
		||||
 | 
			
		||||
		req->filter_link = l;
 | 
			
		||||
		id = f->filter_activate(req->chain->gc, &req->ctx,
 | 
			
		||||
						gprs_filter_activate_cb, req);
 | 
			
		||||
		if (id) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * If f->filter_activate returns zero, the request
 | 
			
		||||
			 * may have already been deallocated. It's only
 | 
			
		||||
			 * guaranteed to be alive if f->filter_activate
 | 
			
		||||
			 * returns non-zero id.
 | 
			
		||||
			 */
 | 
			
		||||
			req->pending_id = id;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		gprs_filter_request_complete(req, TRUE);
 | 
			
		||||
	}
 | 
			
		||||
	return f->filter_activate(req->gc, &act->ctx,
 | 
			
		||||
				gprs_filter_request_activate_cb, act);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
 | 
			
		||||
static void gprs_filter_request_activate_complete
 | 
			
		||||
			(struct gprs_filter_request *req, gboolean allow)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request_activate *act =
 | 
			
		||||
		gprs_filter_request_activate_cast(req);
 | 
			
		||||
 | 
			
		||||
	act->cb(allow ? &act->ctx : NULL, req->user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_activate_free(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	g_slice_free1(sizeof(struct gprs_filter_request_activate), req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gprs_filter_request *gprs_filter_request_activate_new
 | 
			
		||||
	(struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
 | 
			
		||||
		const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
		gprs_filter_activate_cb_t act, ofono_destroy_func destroy,
 | 
			
		||||
		void *user_data)
 | 
			
		||||
		gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
 | 
			
		||||
		void *data)
 | 
			
		||||
{
 | 
			
		||||
	if (chain && gprs_filter_list && ctx && act) {
 | 
			
		||||
		if (!chain->req) {
 | 
			
		||||
			chain->req = gprs_filter_request_new(chain, ctx,
 | 
			
		||||
						act, destroy, user_data);
 | 
			
		||||
			gprs_filter_request_process(chain->req);
 | 
			
		||||
			return;
 | 
			
		||||
		} else {
 | 
			
		||||
			/*
 | 
			
		||||
			 * This shouldn't be happening - ofono core
 | 
			
		||||
			 * makes sure that the next context activation
 | 
			
		||||
			 * request is not submitted until the previous
 | 
			
		||||
			 * has completed.
 | 
			
		||||
			 */
 | 
			
		||||
			ctx = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (act) {
 | 
			
		||||
		act(ctx, user_data);
 | 
			
		||||
	}
 | 
			
		||||
	if (destroy) {
 | 
			
		||||
		destroy(user_data);
 | 
			
		||||
	static const struct gprs_filter_request_fn activate_fn = {
 | 
			
		||||
		.name = "activate",
 | 
			
		||||
		.can_process = gprs_filter_request_activate_can_process,
 | 
			
		||||
		.process = gprs_filter_request_activate_process,
 | 
			
		||||
		.complete = gprs_filter_request_activate_complete,
 | 
			
		||||
		.free = gprs_filter_request_activate_free
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct gprs_filter_request_activate *act =
 | 
			
		||||
		g_slice_new0(struct gprs_filter_request_activate);
 | 
			
		||||
	struct gprs_filter_request *req = &act->req;
 | 
			
		||||
 | 
			
		||||
	gprs_filter_request_init(req, &activate_fn, chain, gc, destroy, data);
 | 
			
		||||
	gprs_filter_copy_context(&act->ctx, ctx);
 | 
			
		||||
	act->cb = cb;
 | 
			
		||||
	return req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * gprs_filter_request_check
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static struct gprs_filter_request_check *gprs_filter_request_check_cast
 | 
			
		||||
					(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	return (struct gprs_filter_request_check *)req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean gprs_filter_request_check_can_process
 | 
			
		||||
					(const struct ofono_gprs_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	return f->api_version >= 1 && f->filter_check != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_check_cb(ofono_bool_t allow, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_request_check *check = data;
 | 
			
		||||
	struct gprs_filter_request *req = &check->req;
 | 
			
		||||
	const struct ofono_gprs_filter *filter = req->filter_link->data;
 | 
			
		||||
 | 
			
		||||
	if (allow) {
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_request_continue_cb);
 | 
			
		||||
	} else {
 | 
			
		||||
		DBG("%s not allowing mobile data", filter->name);
 | 
			
		||||
		gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new
 | 
			
		||||
					(struct ofono_gprs_context *gc)
 | 
			
		||||
static guint gprs_filter_request_check_process
 | 
			
		||||
				(const struct ofono_gprs_filter *f,
 | 
			
		||||
					struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	return f->filter_check(req->chain->gprs, gprs_filter_request_check_cb,
 | 
			
		||||
					gprs_filter_request_check_cast(req));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_check_complete
 | 
			
		||||
			(struct gprs_filter_request *req, gboolean allow)
 | 
			
		||||
{
 | 
			
		||||
	gprs_filter_request_check_cast(req)->cb(allow, req->user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_filter_request_check_free(struct gprs_filter_request *req)
 | 
			
		||||
{
 | 
			
		||||
	g_slice_free1(sizeof(struct gprs_filter_request_check), req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gprs_filter_request *gprs_filter_request_check_new
 | 
			
		||||
	(struct gprs_filter_chain *chain, gprs_filter_check_cb_t cb,
 | 
			
		||||
				ofono_destroy_func destroy, void *data)
 | 
			
		||||
{
 | 
			
		||||
	static const struct gprs_filter_request_fn check_fn = {
 | 
			
		||||
		.name = "check",
 | 
			
		||||
		.can_process = gprs_filter_request_check_can_process,
 | 
			
		||||
		.process = gprs_filter_request_check_process,
 | 
			
		||||
		.complete = gprs_filter_request_check_complete,
 | 
			
		||||
		.free = gprs_filter_request_check_free
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct gprs_filter_request_check *check =
 | 
			
		||||
		g_slice_new0(struct gprs_filter_request_check);
 | 
			
		||||
	struct gprs_filter_request *req = &check->req;
 | 
			
		||||
 | 
			
		||||
	gprs_filter_request_init(req, &check_fn, chain, NULL, destroy, data);
 | 
			
		||||
	check->cb = cb;
 | 
			
		||||
	return req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * gprs_filter_chain
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp)
 | 
			
		||||
{
 | 
			
		||||
	struct gprs_filter_chain *chain = NULL;
 | 
			
		||||
 | 
			
		||||
	if (gc) {
 | 
			
		||||
	if (gp) {
 | 
			
		||||
		chain = g_new0(struct gprs_filter_chain, 1);
 | 
			
		||||
		chain->gc = gc;
 | 
			
		||||
		chain->gprs = gp;
 | 
			
		||||
	}
 | 
			
		||||
	return chain;
 | 
			
		||||
}
 | 
			
		||||
@@ -228,22 +405,100 @@ struct gprs_filter_chain *__ofono_gprs_filter_chain_new
 | 
			
		||||
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain)
 | 
			
		||||
{
 | 
			
		||||
	if (chain) {
 | 
			
		||||
		if (chain->req) {
 | 
			
		||||
			gprs_filter_request_complete(chain->req, TRUE);
 | 
			
		||||
		}
 | 
			
		||||
		__ofono_gprs_filter_chain_cancel(chain, NULL);
 | 
			
		||||
		g_free(chain);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain)
 | 
			
		||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
 | 
			
		||||
					struct ofono_gprs_context *gc)
 | 
			
		||||
{
 | 
			
		||||
	if (chain && chain->req) {
 | 
			
		||||
		gprs_filter_request_cancel(chain->req);
 | 
			
		||||
		gprs_filter_request_free(chain->req);
 | 
			
		||||
		chain->req = NULL;
 | 
			
		||||
	if (chain) {
 | 
			
		||||
		GSList *l, *canceled;
 | 
			
		||||
 | 
			
		||||
		/* Move canceled requests to a separate list */
 | 
			
		||||
		if (gc) {
 | 
			
		||||
			GSList *prev = NULL;
 | 
			
		||||
 | 
			
		||||
			canceled = NULL;
 | 
			
		||||
			l = chain->req_list;
 | 
			
		||||
			while (l) {
 | 
			
		||||
				GSList *next = l->next;
 | 
			
		||||
				struct gprs_filter_request *req = l->data;
 | 
			
		||||
 | 
			
		||||
				if (req->gc == gc) {
 | 
			
		||||
					/* This one will get canceled */
 | 
			
		||||
					l->next = canceled;
 | 
			
		||||
					canceled = l;
 | 
			
		||||
					if (prev) {
 | 
			
		||||
						prev->next = next;
 | 
			
		||||
					} else {
 | 
			
		||||
						chain->req_list = next;
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					/* This one survives */
 | 
			
		||||
					prev = l;
 | 
			
		||||
				}
 | 
			
		||||
				l = next;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Everything is getting canceled */
 | 
			
		||||
			canceled = chain->req_list;
 | 
			
		||||
			chain->req_list = NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Actually cancel each request */
 | 
			
		||||
		for (l = canceled; l; l = l->next) {
 | 
			
		||||
			gprs_filter_request_cancel(l->data);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* And deallocate them */
 | 
			
		||||
		g_slist_free_full(canceled, gprs_filter_request_free1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
 | 
			
		||||
		struct ofono_gprs_context *gc,
 | 
			
		||||
		const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
		gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
 | 
			
		||||
		void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	if (chain && gprs_filter_list && ctx && cb) {
 | 
			
		||||
		gprs_filter_request_process
 | 
			
		||||
			(gprs_filter_request_activate_new(chain, gc, ctx,
 | 
			
		||||
						cb, destroy, user_data));
 | 
			
		||||
	} else {
 | 
			
		||||
		if (cb) {
 | 
			
		||||
			cb(ctx, user_data);
 | 
			
		||||
		}
 | 
			
		||||
		if (destroy) {
 | 
			
		||||
			destroy(user_data);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
 | 
			
		||||
		gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
 | 
			
		||||
		void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	if (chain && gprs_filter_list && cb) {
 | 
			
		||||
		gprs_filter_request_process
 | 
			
		||||
			(gprs_filter_request_check_new(chain, cb, destroy,
 | 
			
		||||
								user_data));
 | 
			
		||||
	} else {
 | 
			
		||||
		if (cb) {
 | 
			
		||||
			cb(TRUE, user_data);
 | 
			
		||||
		}
 | 
			
		||||
		if (destroy) {
 | 
			
		||||
			destroy(user_data);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * ofono_gprs_filter
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns 0 if both are equal;
 | 
			
		||||
 * <0 if a comes before b;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										105
									
								
								ofono/src/gprs.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								ofono/src/gprs.c
									
									
									
									
									
								
							@@ -85,6 +85,7 @@ struct ofono_gprs {
 | 
			
		||||
	void *driver_data;
 | 
			
		||||
	struct ofono_atom *atom;
 | 
			
		||||
	unsigned int spn_watch;
 | 
			
		||||
	struct gprs_filter_chain *filters;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipv4_settings {
 | 
			
		||||
@@ -117,7 +118,6 @@ struct ofono_gprs_context {
 | 
			
		||||
	void *driver_data;
 | 
			
		||||
	struct context_settings *settings;
 | 
			
		||||
	struct ofono_atom *atom;
 | 
			
		||||
	struct gprs_filter_chain *filters;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct pri_context {
 | 
			
		||||
@@ -375,7 +375,9 @@ static void release_context(struct pri_context *ctx)
 | 
			
		||||
	if (ctx == NULL || ctx->gprs == NULL || ctx->context_driver == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	__ofono_gprs_filter_chain_cancel(ctx->context_driver->filters);
 | 
			
		||||
	__ofono_gprs_filter_chain_cancel(ctx->gprs->filters,
 | 
			
		||||
						ctx->context_driver);
 | 
			
		||||
 | 
			
		||||
	gprs_cid_release(ctx->gprs, ctx->context.cid);
 | 
			
		||||
	ctx->context.cid = 0;
 | 
			
		||||
	ctx->context_driver->inuse = FALSE;
 | 
			
		||||
@@ -1055,16 +1057,17 @@ static DBusMessage *pri_provision_context(DBusConnection *conn,
 | 
			
		||||
	for (i = 0; i < count; i++) {
 | 
			
		||||
		const struct ofono_gprs_provision_data *ap = settings + i;
 | 
			
		||||
		if (ap->type == ctx->type && ap_valid(ap)) {
 | 
			
		||||
			if ((!ctx->active &&
 | 
			
		||||
				!ctx->pending && !ctx->gprs->pending) ||
 | 
			
		||||
					!pri_deactivation_required(ctx, ap)) {
 | 
			
		||||
			if (ctx->pending || ctx->gprs->pending) {
 | 
			
		||||
				/* Context is being messed with */
 | 
			
		||||
				reply = __ofono_error_busy(msg);
 | 
			
		||||
			} else if (ctx->active &&
 | 
			
		||||
					pri_deactivation_required(ctx, ap)) {
 | 
			
		||||
				/* Context needs to be deactivated first */
 | 
			
		||||
				reply = __ofono_error_busy(msg);
 | 
			
		||||
			} else {
 | 
			
		||||
				/* Re-provision the context */
 | 
			
		||||
				pri_reset_context_properties(ctx, ap);
 | 
			
		||||
				reply =  dbus_message_new_method_return(msg);
 | 
			
		||||
			} else {
 | 
			
		||||
				/* Context should be inactive */
 | 
			
		||||
				if (ctx->gprs->pending || ctx->pending)
 | 
			
		||||
					reply = __ofono_error_busy(msg);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
@@ -1554,11 +1557,40 @@ static DBusMessage *pri_set_auth_method(struct pri_context *ctx,
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_context_activate(const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
								void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct pri_context *pri = data;
 | 
			
		||||
struct pri_request_data {
 | 
			
		||||
	struct pri_context *pri;
 | 
			
		||||
	DBusMessage *msg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct pri_request_data *pri_request_new(struct pri_context *pri)
 | 
			
		||||
{
 | 
			
		||||
	struct pri_request_data *data = g_new0(struct pri_request_data, 1);
 | 
			
		||||
 | 
			
		||||
	data->pri = pri;
 | 
			
		||||
	data->msg = pri->pending;
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pri_request_free(void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct pri_request_data *data = user_data;
 | 
			
		||||
	struct pri_context *pri = data->pri;
 | 
			
		||||
 | 
			
		||||
	if (pri->pending && pri->pending == data->msg) {
 | 
			
		||||
		__ofono_dbus_pending_reply(&pri->pending,
 | 
			
		||||
				__ofono_error_canceled(pri->pending));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_free(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pri_activate_filt(const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
							void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct pri_request_data *data = user_data;
 | 
			
		||||
	struct pri_context *pri = data->pri;
 | 
			
		||||
 | 
			
		||||
	data->msg = NULL;
 | 
			
		||||
	if (ctx) {
 | 
			
		||||
		struct ofono_gprs_context *gc = pri->context_driver;
 | 
			
		||||
 | 
			
		||||
@@ -1625,9 +1657,9 @@ static DBusMessage *pri_set_property(DBusConnection *conn,
 | 
			
		||||
		ctx->pending = dbus_message_ref(msg);
 | 
			
		||||
 | 
			
		||||
		if (value)
 | 
			
		||||
			__ofono_gprs_filter_chain_activate(gc->filters,
 | 
			
		||||
					&ctx->context, gprs_context_activate,
 | 
			
		||||
					NULL, ctx);
 | 
			
		||||
			__ofono_gprs_filter_chain_activate(gc->gprs->filters,
 | 
			
		||||
				gc, &ctx->context, pri_activate_filt,
 | 
			
		||||
				pri_request_free, pri_request_new(ctx));
 | 
			
		||||
		else
 | 
			
		||||
			gc->driver->deactivate_primary(gc, ctx->context.cid,
 | 
			
		||||
						pri_deactivate_callback, ctx);
 | 
			
		||||
@@ -1911,14 +1943,8 @@ static void release_active_contexts(struct ofono_gprs *gprs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gprs_attached_update(struct ofono_gprs *gprs)
 | 
			
		||||
static void gprs_set_attached(struct ofono_gprs *gprs, ofono_bool_t attached)
 | 
			
		||||
{
 | 
			
		||||
	ofono_bool_t attached;
 | 
			
		||||
 | 
			
		||||
	attached = gprs->driver_attached &&
 | 
			
		||||
		(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
 | 
			
		||||
			gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
 | 
			
		||||
 | 
			
		||||
	if (attached == gprs->attached)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
@@ -1945,6 +1971,32 @@ void gprs_attached_update(struct ofono_gprs *gprs)
 | 
			
		||||
	gprs_set_attached_property(gprs, attached);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_attached_check_cb(ofono_bool_t allow, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	gprs_set_attached((struct ofono_gprs *)user_data, allow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gprs_attached_update(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	ofono_bool_t attached = gprs->driver_attached &&
 | 
			
		||||
		(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
 | 
			
		||||
			gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
 | 
			
		||||
 | 
			
		||||
	if (!attached) {
 | 
			
		||||
		/* Cancel all other checks - nothing is allowed if we are
 | 
			
		||||
		 * not attached */
 | 
			
		||||
		__ofono_gprs_filter_chain_cancel(gprs->filters, NULL);
 | 
			
		||||
 | 
			
		||||
		/* We are done synchronously */
 | 
			
		||||
		gprs_set_attached(gprs, FALSE);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* This implicitely cancels the previous check if it's still
 | 
			
		||||
		 * running, so that we never have two simultanous checks. */
 | 
			
		||||
		__ofono_gprs_filter_chain_check(gprs->filters,
 | 
			
		||||
					gprs_attached_check_cb, NULL, gprs);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void registration_status_cb(const struct ofono_error *error,
 | 
			
		||||
					int status, void *data)
 | 
			
		||||
{
 | 
			
		||||
@@ -3100,7 +3152,9 @@ static void gprs_context_remove(struct ofono_atom *atom)
 | 
			
		||||
	if (gc->driver && gc->driver->remove)
 | 
			
		||||
		gc->driver->remove(gc);
 | 
			
		||||
 | 
			
		||||
	__ofono_gprs_filter_chain_free(gc->filters);
 | 
			
		||||
	if (gc->gprs)
 | 
			
		||||
		__ofono_gprs_filter_chain_cancel(gc->gprs->filters, gc);
 | 
			
		||||
 | 
			
		||||
	g_free(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3132,7 +3186,6 @@ struct ofono_gprs_context *ofono_gprs_context_create(struct ofono_modem *modem,
 | 
			
		||||
		if (drv->probe(gc, vendor, data) < 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		gc->filters = __ofono_gprs_filter_chain_new(gc);
 | 
			
		||||
		gc->driver = drv;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
@@ -3417,6 +3470,7 @@ static void gprs_remove(struct ofono_atom *atom)
 | 
			
		||||
	if (gprs->driver && gprs->driver->remove)
 | 
			
		||||
		gprs->driver->remove(gprs);
 | 
			
		||||
 | 
			
		||||
	__ofono_gprs_filter_chain_free(gprs->filters);
 | 
			
		||||
	g_free(gprs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3453,6 +3507,7 @@ struct ofono_gprs *ofono_gprs_create(struct ofono_modem *modem,
 | 
			
		||||
	gprs->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
 | 
			
		||||
	gprs->netreg_status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
 | 
			
		||||
	gprs->pid_map = idmap_new(MAX_CONTEXTS);
 | 
			
		||||
	gprs->filters = __ofono_gprs_filter_chain_new(gprs);
 | 
			
		||||
 | 
			
		||||
	return gprs;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -596,15 +596,19 @@ struct gprs_filter_chain;
 | 
			
		||||
 | 
			
		||||
typedef void (*gprs_filter_activate_cb_t)
 | 
			
		||||
	(const struct ofono_gprs_primary_context *ctx, void *user_data);
 | 
			
		||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new
 | 
			
		||||
					(struct ofono_gprs_context *gc);
 | 
			
		||||
typedef void (*gprs_filter_check_cb_t)(ofono_bool_t allow, void *user_data);
 | 
			
		||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp);
 | 
			
		||||
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain);
 | 
			
		||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain);
 | 
			
		||||
 | 
			
		||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
 | 
			
		||||
		struct ofono_gprs_context *gc);
 | 
			
		||||
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
 | 
			
		||||
		struct ofono_gprs_context *gc,
 | 
			
		||||
		const struct ofono_gprs_primary_context *ctx,
 | 
			
		||||
		gprs_filter_activate_cb_t act, ofono_destroy_func destroy,
 | 
			
		||||
		void *user_data);
 | 
			
		||||
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
 | 
			
		||||
		gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
 | 
			
		||||
		void *user_data);
 | 
			
		||||
 | 
			
		||||
#include <ofono/sim-mnclength.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user