Merge branch 'zecke/features/no-queue'

Let's get bigger exposure of the new implementation
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 51d68d2..30a397c 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -119,7 +119,6 @@
 
 	/* Are we part of a special "silent" call */
 	int silent_call;
-	int put_channel;
 
 	/* bsc structures */
 	struct osmo_bsc_sccp_con *sccp_con;
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 290cc44..7d6c776 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -22,6 +22,8 @@
 struct sgsn_mm_ctx;
 struct sgsn_subscriber_data;
 
+struct subscr_request;
+
 struct gsm_subscriber_group {
 	struct gsm_network *net;
 
@@ -66,7 +68,7 @@
 	struct llist_head entry;
 
 	/* pending requests */
-	int in_callback;
+	int is_paging;
 	struct llist_head requests;
 
 	/* GPRS/SGSN related fields */
@@ -101,19 +103,11 @@
 struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
 					const char *imsi);
 int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
-void subscr_put_channel(struct gsm_subscriber *subscr);
-void subscr_get_channel(struct gsm_subscriber *subscr,
-                        int type, gsm_cbfn *cbfn, void *param);
 struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
 					     uint32_t tmsi);
 struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
 					     const char *imsi);
 
-int subscr_pending_requests(struct gsm_subscriber *subscr);
-int subscr_pending_clear(struct gsm_subscriber *subscr);
-int subscr_pending_dump(struct gsm_subscriber *subscr, struct vty *vty);
-int subscr_pending_kick(struct gsm_subscriber *subscr);
-
 char *subscr_name(struct gsm_subscriber *subscr);
 
 int subscr_purge_inactive(struct gsm_subscriber_group *sgrp);
@@ -121,6 +115,13 @@
 void subscr_expire(struct gsm_subscriber_group *sgrp);
 int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts);
 
+/*
+ * Paging handling with authentication
+ */
+struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
+                        int type, gsm_cbfn *cbfn, void *param);
+void subscr_remove_request(struct subscr_request *req);
+
 /* internal */
 struct gsm_subscriber *subscr_alloc(void);
 extern struct llist_head active_subscribers;
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 82891b8..6ef1612 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -36,7 +36,7 @@
 	int tch_recv;
 
 	/* is thats one paging? */
-	struct gsm_network **paging_request;
+	struct subscr_request *paging_request;
 
 	union {
 		struct {
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index 2d08af7..8bc10e6 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -366,13 +366,19 @@
 	llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
 				 entry) {
 		if (req->subscr == subscr) {
-			if (conn && req->cbfn) {
+			gsm_cbfn *cbfn = req->cbfn;
+			void *param = req->cbfn_param;
+
+			/* now give up the data structure */
+			paging_remove_request(&bts->paging, req);
+			req = NULL;
+
+			if (conn && cbfn) {
 				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
-				req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
-					  msg, conn, req->cbfn_param);
+				cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
+					  msg, conn, param);
 			} else
 				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
-			paging_remove_request(&bts->paging, req);
 			break;
 		}
 	}
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 941090c..5609602 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1384,68 +1384,42 @@
 
 /* call-back from paging the B-end of the connection */
 static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
-			      struct msgb *msg, void *_conn, void *param)
+			      struct msgb *msg, void *_conn, void *_transt)
 {
-	int found = 0;
 	struct gsm_subscriber_connection *conn = _conn;
-	struct gsm_network **paging_request = param, *net;
-	struct gsm_trans *transt, *tmp;
+	struct gsm_trans *transt = _transt;
 
-	if (hooknum != GSM_HOOK_RR_PAGING)
-		return -EINVAL;
-
-	net = *paging_request;
-	if (!net) {
-		DEBUGP(DCC, "Error Network not set!\n");
-		return -EINVAL;
-	}
+	OSMO_ASSERT(!transt->conn);
+	OSMO_ASSERT(conn);
 
 	/* check all tranactions (without lchan) for subscriber */
-	llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
-		if (transt->paging_request != paging_request || transt->conn)
-			continue;
-		switch (event) {
-		case GSM_PAGING_SUCCEEDED:
-			if (!conn) // paranoid
-				break;
-			DEBUGP(DCC, "Paging subscr %s succeeded!\n",
-				transt->subscr->extension);
-			found = 1;
-			/* Assign lchan */
-			if (!transt->conn) {
-				transt->paging_request = NULL;
-				transt->conn = conn;
-				conn->put_channel = 1;
-			}
-			/* send SETUP request to called party */
-			gsm48_cc_tx_setup(transt, &transt->cc.msg);
-			break;
-		case GSM_PAGING_EXPIRED:
-		case GSM_PAGING_BUSY:
-			DEBUGP(DCC, "Paging subscr %s expired!\n",
-				transt->subscr->extension);
-			/* Temporarily out of order */
-			found = 1;
-			mncc_release_ind(transt->net, transt,
-					 transt->callref,
-					 GSM48_CAUSE_LOC_PRN_S_LU,
-					 GSM48_CC_CAUSE_DEST_OOO);
-			transt->callref = 0;
-			transt->paging_request = NULL;
-			trans_free(transt);
-			break;
-		}
+	switch (event) {
+	case GSM_PAGING_SUCCEEDED:
+		DEBUGP(DCC, "Paging subscr %s succeeded!\n", transt->subscr->extension);
+		/* Assign lchan */
+		transt->conn = conn;
+		/* send SETUP request to called party */
+		gsm48_cc_tx_setup(transt, &transt->cc.msg);
+		break;
+	case GSM_PAGING_EXPIRED:
+	case GSM_PAGING_BUSY:
+		DEBUGP(DCC, "Paging subscr %s expired!\n",
+			transt->subscr->extension);
+		/* Temporarily out of order */
+		mncc_release_ind(transt->net, transt,
+				 transt->callref,
+				 GSM48_CAUSE_LOC_PRN_S_LU,
+				 GSM48_CC_CAUSE_DEST_OOO);
+		transt->callref = 0;
+		transt->paging_request = NULL;
+		trans_free(transt);
+		break;
+	default:
+		LOGP(DCC, LOGL_ERROR, "Unknown paging event %d\n", event);
+		break;
 	}
 
-	talloc_free(paging_request);
-
-	/*
-	 * FIXME: The queue needs to be kicked. This is likely to go through a RF
-	 * failure and then the subscr will be poke again. This needs a lot of fixing
-	 * in the subscriber queue code.
-	 */
-	if (!found && conn)
-		conn->put_channel = 1;
+	transt->paging_request = NULL;
 	return 0;
 }
 
@@ -3124,19 +3098,16 @@
 			/* store setup informations until paging was successfull */
 			memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
 
-			/* Get a channel */
-			trans->paging_request = talloc_zero(subscr->group->net,
-							    struct gsm_network*);
+			/* Request a channel */
+			trans->paging_request = subscr_request_channel(subscr,
+							RSL_CHANNEED_TCH_F, setup_trig_pag_evt,
+							trans);
 			if (!trans->paging_request) {
 				LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
 				subscr_put(subscr);
 				trans_free(trans);
 				return 0;
 			}
-
-			*trans->paging_request = subscr->group->net;
-			subscr_get_channel(subscr, RSL_CHANNEED_TCH_F, setup_trig_pag_evt, trans->paging_request);
-
 			subscr_put(subscr);
 			return 0;
 		}
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index bcc25e4..1b2a42c 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -938,6 +938,7 @@
 			   struct gsm_sms *sms)
 {
 	struct gsm_subscriber_connection *conn;
+	void *res;
 
 	/* check if we already have an open lchan to the subscriber.
 	 * if yes, send the SMS this way */
@@ -947,7 +948,12 @@
 	}
 
 	/* if not, we have to start paging */
-	subscr_get_channel(subscr, RSL_CHANNEED_SDCCH, paging_cb_send_sms, sms);
+	res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
+					paging_cb_send_sms, sms);
+	if (!res) {
+		send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
+		sms_free(sms);
+	}
 	return 0;
 }
 
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index c444fe0..4559de5 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -56,28 +56,11 @@
 struct subscr_request {
 	struct llist_head entry;
 
-	/* back reference */
-	struct gsm_subscriber *subscr;
-
-	/* the requested channel type */
-	int channel_type;
-
-	/* what did we do */
-	int state;
-
 	/* the callback data */
 	gsm_cbfn *cbfn;
 	void *param;
 };
 
-enum {
-	REQ_STATE_INITIAL,
-	REQ_STATE_QUEUED,
-	REQ_STATE_PAGED,
-	REQ_STATE_FAILED_START,
-	REQ_STATE_DISPATCHED,
-};
-
 static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
 						int type, const char *ident)
 {
@@ -94,16 +77,14 @@
 static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
                                   struct msgb *msg, void *data, void *param)
 {
-	struct subscr_request *request;
+	struct subscr_request *request, *tmp;
 	struct gsm_subscriber_connection *conn = data;
 	struct gsm_subscriber *subscr = param;
 	struct paging_signal_data sig_data;
 
-	/* There is no request anymore... */
-	if (llist_empty(&subscr->requests))
-		return -1;
+	OSMO_ASSERT(subscr->is_paging);
 
-	/* Dispatch signal */
+	/* Inform parts of the system we don't know */
 	sig_data.subscr = subscr;
 	sig_data.bts	= conn ? conn->bts : NULL;
 	sig_data.conn	= conn;
@@ -116,34 +97,22 @@
 	);
 
 	/*
-	 * FIXME: What to do with paging requests coming during
-	 * this callback? We must be sure to not start paging when
-	 * we have an active connection to a subscriber and to make
-	 * the subscr_put_channel work as required...
+	 * Stop paging on all other BTS. E.g. if this is
+	 * the first timeout on a BTS then the others will
+	 * timeout soon as well. Let's just stop everything
+	 * and forget we wanted to page.
 	 */
-	request = (struct subscr_request *)subscr->requests.next;
-	request->state = REQ_STATE_DISPATCHED;
-	llist_del(&request->entry);
-	subscr->in_callback = 1;
-	request->cbfn(hooknum, event, msg, data, request->param);
-	subscr->in_callback = 0;
+	paging_request_stop(NULL, subscr, NULL, NULL);
+	subscr->is_paging = 0;
 
-	if (event != GSM_PAGING_SUCCEEDED) {
-		/*
-		 *  This is a workaround for a bigger issue. We have
-		 *  issued paging that might involve multiple BTSes
-		 *  and one of them have failed now. We will stop the
-		 *  other paging requests as well as the next timeout
-		 *  would work on the next paging request and the queue
-		 *  will do bad things. This should be fixed by counting
-		 *  the outstanding results.
-		 */
-		paging_request_stop(NULL, subscr, NULL, NULL);
-		subscr_put_channel(subscr);
+	llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
+		llist_del(&request->entry);
+		request->cbfn(hooknum, event, msg, data, request->param);
+		talloc_free(request);
 	}
 
+	/* balanced with the moment we start paging */
 	subscr_put(subscr);
-	talloc_free(request);
 	return 0;
 }
 
@@ -194,86 +163,43 @@
 	return gsm48_secure_channel(conn, pr->key_seq, subscr_paging_sec_cb, param);
 }
 
-
-static void subscr_send_paging_request(struct gsm_subscriber *subscr)
+struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
+			int channel_type, gsm_cbfn *cbfn, void *param)
 {
-	struct subscr_request *request;
 	int rc;
-	struct gsm_network *net = subscr->group->net;
-
-	assert(!llist_empty(&subscr->requests));
-
-	request = (struct subscr_request *)subscr->requests.next;
-	request->state = REQ_STATE_PAGED;
-	rc = paging_request(net, subscr, request->channel_type,
-			    subscr_paging_cb, subscr);
-
-	/* paging failed, quit now */
-	if (rc <= 0) {
-		request->state = REQ_STATE_FAILED_START;
-		subscr_paging_cb(GSM_HOOK_RR_PAGING, GSM_PAGING_BUSY,
-				 NULL, NULL, subscr);
-	}
-}
-
-void subscr_get_channel(struct gsm_subscriber *subscr,
-			int type, gsm_cbfn *cbfn, void *param)
-{
 	struct subscr_request *request;
 
-	request = talloc(tall_sub_req_ctx, struct subscr_request);
-	if (!request) {
-		if (cbfn)
-			cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM,
-				NULL, NULL, param);
-		return;
+	/* Start paging.. we know it is async so we can do it before */
+	if (!subscr->is_paging) {
+		LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
+			subscr_name(subscr));
+		rc = paging_request(subscr->group->net, subscr, channel_type,
+				    subscr_paging_cb, subscr);
+		if (rc <= 0) {
+			LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
+				subscr_name(subscr), rc);
+			return NULL;
+		}
+		/* reduced on the first paging callback */
+		subscr_get(subscr);
+		subscr->is_paging = 1;
 	}
 
-	memset(request, 0, sizeof(*request));
-	request->subscr = subscr_get(subscr);
-	request->channel_type = type;
+	/* TODO: Stop paging in case of memory allocation failure */
+	request = talloc_zero(subscr, struct subscr_request);
+	if (!request)
+		return NULL;
+
 	request->cbfn = cbfn;
 	request->param = param;
-	request->state = REQ_STATE_INITIAL;
-
-	/*
-	 * FIXME: We might be able to assign more than one
-	 * channel, e.g. voice and SMS submit at the same
-	 * time.
-	 */
-	if (!subscr->in_callback && llist_empty(&subscr->requests)) {
-		/* add to the list, send a request */
-		llist_add_tail(&request->entry, &subscr->requests);
-		subscr_send_paging_request(subscr);
-	} else {
-		/* this will be picked up later, from subscr_put_channel */
-		llist_add_tail(&request->entry, &subscr->requests);
-		request->state = REQ_STATE_QUEUED;
-	}
+	llist_add_tail(&request->entry, &subscr->requests);
+	return request;
 }
 
-void subscr_put_channel(struct gsm_subscriber *subscr)
+void subscr_remove_request(struct subscr_request *request)
 {
-	/*
-	 * FIXME: Continue with other requests now... by checking
-	 * the gsm_subscriber inside the gsm_lchan. Drop the ref count
-	 * of the lchan after having asked the next requestee to handle
-	 * the channel.
-	 */
-	/*
-	 * FIXME: is the lchan is of a different type we could still
-	 * issue an immediate assignment for another channel and then
-	 * close this one.
-	 */
-	/*
-	 * Currently we will drop the last ref of the lchan which
-	 * will result in a channel release on RSL and we will start
-	 * the paging. This should work most of the time as the MS
-	 * will listen to the paging requests before we timeout
-	 */
-
-	if (subscr && !llist_empty(&subscr->requests))
-		subscr_send_paging_request(subscr);
+	llist_del(&request->entry);
+	talloc_free(request);
 }
 
 struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
@@ -443,48 +369,3 @@
 {
 	db_subscriber_expire(sgrp->net, subscr_expire_callback);
 }
-
-int subscr_pending_requests(struct gsm_subscriber *sub)
-{
-	struct subscr_request *req;
-	int pending = 0;
-
-	llist_for_each_entry(req, &sub->requests, entry)
-		pending += 1;
-
-	return pending;
-}
-
-int subscr_pending_clear(struct gsm_subscriber *sub)
-{
-	int deleted = 0;
-	struct subscr_request *req, *tmp;
-
-	llist_for_each_entry_safe(req, tmp, &sub->requests, entry) {
-		subscr_put(req->subscr);
-		llist_del(&req->entry);
-		talloc_free(req);
-		deleted += 1;
-	}
-
-	return deleted;
-}
-
-int subscr_pending_dump(struct gsm_subscriber *sub, struct vty *vty)
-{
-	struct subscr_request *req;
-
-	vty_out(vty, "Pending Requests for Subscriber %llu.%s", sub->id, VTY_NEWLINE);
-	llist_for_each_entry(req, &sub->requests, entry) {
-		vty_out(vty, "Channel type: %d State: %d Sub: %llu.%s",
-			req->channel_type, req->state, req->subscr->id, VTY_NEWLINE);
-	}
-
-	return 0;
-}
-
-int subscr_pending_kick(struct gsm_subscriber *sub)
-{
-	subscr_put_channel(sub);
-	return 0;
-}
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index a5a463b..5c3461b 100644
--- a/openbsc/src/libmsc/mncc_builtin.c
+++ b/openbsc/src/libmsc/mncc_builtin.c
@@ -69,7 +69,7 @@
 {
 	/* FIXME: check codec capabilities of the phone */
 
-	if (setup->lchan_type == GSM_LCHAN_TCH_F)
+	if (setup->lchan_type != GSM_LCHAN_TCH_H)
 		return mncc_int.def_codec[0];
 	else
 		return mncc_int.def_codec[1];
diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c
index f3badb7..b4facff 100644
--- a/openbsc/src/libmsc/osmo_msc.c
+++ b/openbsc/src/libmsc/osmo_msc.c
@@ -39,10 +39,6 @@
 static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
 {
 	gsm0408_clear_request(conn, cause);
-	if (conn->put_channel) {
-		conn->put_channel = 0;
-		subscr_put_channel(conn->subscr);
-	}
 	return 1;
 }
 
@@ -173,9 +169,5 @@
 
 	conn->in_release = 1;
 	gsm0808_clear(conn);
-	if (conn->put_channel) {
-		conn->put_channel = 0;
-		subscr_put_channel(conn->subscr);
-	}
 	subscr_con_free(conn);
 }
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index 2101ae9..a750362 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -98,11 +98,8 @@
 		break;
 	}
 
-	/* FIXME: implement a sane way to stop this. */
-	if (!trans->conn && trans->paging_request) {
-		LOGP(DNM, LOGL_ERROR,
-		     "Transaction freed while paging for sub: %llu\n",
-		     trans->subscr->id);
+	if (trans->paging_request) {
+		subscr_remove_request(trans->paging_request);
 		trans->paging_request = NULL;
 	}
 
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 558db5e..6cf51a3 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -55,7 +55,7 @@
 
 extern struct gsm_network *gsmnet_from_vty(struct vty *v);
 
-static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
+static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
 {
 	int rc;
 	struct gsm_auth_info ainfo;
@@ -107,11 +107,8 @@
 			"%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
 	expire_time[sizeof(expire_time) - 1] = '\0';
 	vty_out(vty, "    Expiration Time: %s%s", expire_time, VTY_NEWLINE);
-
-	if (pending)
-		vty_out(vty, "    Pending: %d%s",
-			subscr_pending_requests(subscr), VTY_NEWLINE);
-
+	vty_out(vty, "    Paging: %s paging%s",
+		subscr->is_paging ? "is" : "not", VTY_NEWLINE);
 	vty_out(vty, "    Use count: %u%s", subscr->use_count, VTY_NEWLINE);
 }
 
@@ -127,7 +124,7 @@
 
 	llist_for_each_entry(subscr, &active_subscribers, entry) {
 		vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
-		subscr_dump_full_vty(vty, subscr, 0);
+		subscr_dump_full_vty(vty, subscr);
 	}
 
 	return CMD_SUCCESS;
@@ -215,7 +212,7 @@
 		return CMD_WARNING;
 	}
 
-	subscr_dump_full_vty(vty, subscr, 1);
+	subscr_dump_full_vty(vty, subscr);
 
 	subscr_put(subscr);
 
@@ -241,7 +238,7 @@
 	}
 
 	/* Show info about the created subscriber. */
-	subscr_dump_full_vty(vty, subscr, 0);
+	subscr_dump_full_vty(vty, subscr);
 
 	subscr_put(subscr);
 
@@ -596,71 +593,6 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(ena_subscr_clear,
-      ena_subscr_clear_cmd,
-      "subscriber " SUBSCR_TYPES " ID clear-requests",
-	SUBSCR_HELP "Clear the paging requests for this subscriber\n")
-{
-	int del;
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	struct gsm_subscriber *subscr =
-			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
-	if (!subscr) {
-		vty_out(vty, "%% No subscriber found for %s %s%s",
-			argv[0], argv[1], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	del = subscr_pending_clear(subscr);
-	vty_out(vty, "Cleared %d pending requests.%s", del, VTY_NEWLINE);
-	subscr_put(subscr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(ena_subscr_pend,
-      ena_subscr_pend_cmd,
-      "subscriber " SUBSCR_TYPES " ID show-pending",
-	SUBSCR_HELP "Clear the paging requests for this subscriber\n")
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	struct gsm_subscriber *subscr =
-			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
-	if (!subscr) {
-		vty_out(vty, "%% No subscriber found for %s %s%s",
-			argv[0], argv[1], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	subscr_pending_dump(subscr, vty);
-	subscr_put(subscr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(ena_subscr_kick,
-      ena_subscr_kick_cmd,
-      "subscriber " SUBSCR_TYPES " ID kick-pending",
-	SUBSCR_HELP "Clear the paging requests for this subscriber\n")
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	struct gsm_subscriber *subscr =
-			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
-	if (!subscr) {
-		vty_out(vty, "%% No subscriber found for %s %s%s",
-			argv[0], argv[1], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	subscr_pending_kick(subscr);
-	subscr_put(subscr);
-
-	return CMD_SUCCESS;
-}
-
 DEFUN(ena_subscr_handover,
       ena_subscr_handover_cmd,
       "subscriber " SUBSCR_TYPES " ID handover BTS_NR",
@@ -1139,9 +1071,6 @@
 	install_element(ENABLE_NODE, &ena_subscr_extension_cmd);
 	install_element(ENABLE_NODE, &ena_subscr_authorized_cmd);
 	install_element(ENABLE_NODE, &ena_subscr_a3a8_cmd);
-	install_element(ENABLE_NODE, &ena_subscr_clear_cmd);
-	install_element(ENABLE_NODE, &ena_subscr_pend_cmd);
-	install_element(ENABLE_NODE, &ena_subscr_kick_cmd);
 	install_element(ENABLE_NODE, &ena_subscr_handover_cmd);
 	install_element(ENABLE_NODE, &subscriber_purge_cmd);
 	install_element(ENABLE_NODE, &smsqueue_trigger_cmd);
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 2369339..cd6a1fd 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -31,6 +31,8 @@
 
 static int s_end = 0;
 static struct gsm_subscriber_connection s_conn;
+static void *s_data;
+static gsm_cbfn *s_cbfn;
 
 /* our handler */
 static int subscr_cb(unsigned int hook, unsigned int event, struct msgb *msg, void *data, void *param)
@@ -48,7 +50,8 @@
 /* mock object for testing, directly invoke the cb... maybe later through the timer */
 int paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscriber, int type, gsm_cbfn *cbfn, void *data)
 {
-	cbfn(101, 200, (void*)0x1323L, &s_conn, data);
+	s_data = data;
+	s_cbfn = cbfn;
 
 	/* claim we have patched */
 	return 1;
@@ -80,11 +83,10 @@
 	OSMO_ASSERT(subscr->group->net == network);
 
 	/* Ask for a channel... */
-	subscr_get_channel(subscr, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
+	subscr_request_channel(subscr, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
+	s_cbfn(101, 200, (void*)0x1323L, &s_conn, s_data);
 
-	while (!s_end) {
-		osmo_select_main(0);
-	}
+	OSMO_ASSERT(s_end);
 
 	return EXIT_SUCCESS;
 }