Exemple #1
0
/**
 * Dequeues a TCH or FACCH frame, prioritizing the second.
 * In case if a FACCH frame is found, a TCH frame is being
 * dropped (i.e. replaced).
 *
 * @param  queue a transmit queue to take a prim from
 * @return       a FACCH or TCH primitive, otherwise NULL
 */
static struct trx_ts_prim *sched_prim_dequeue_tch(struct llist_head *queue)
{
	struct trx_ts_prim *facch = NULL;
	struct trx_ts_prim *tch = NULL;
	struct trx_ts_prim *i;

	/* Attempt to find a pair of FACCH and TCH frames */
	llist_for_each_entry(i, queue, list) {
		/* Find one FACCH frame */
		if (!facch && PRIM_IS_FACCH(i))
			facch = i;

		/* Find one TCH frame */
		if (!tch && PRIM_IS_TCH(i))
			tch = i;

		/* If both are found */
		if (facch && tch)
			break;
	}

	/* Prioritize FACCH */
	if (facch && tch) {
		/* We found a pair, dequeue both */
		llist_del(&facch->list);
		llist_del(&tch->list);

		/* Drop TCH */
		talloc_free(tch);

		/* FACCH replaces TCH */
		return facch;
	} else if (facch) {
		/* Only FACCH was found */
		llist_del(&facch->list);
		return facch;
	} else if (tch) {
		/* Only TCH was found */
		llist_del(&tch->list);
		return tch;
	}

	/**
	 * Nothing was found,
	 * e.g. only SACCH frames are in queue
	 */
	return NULL;
}
/*
 * We got the channel assigned and can now hand this channel
 * over to one of our callbacks.
 */
static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
			     struct msgb *msg, void *data, void *param)
{
	struct subscr_request *request;
	struct gsm_subscriber *subscr = (struct gsm_subscriber *)param;

	/* There is no request anymore... */
	if (llist_empty(&subscr->requests))
		return -1;

	/*
	 * 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...
	 */
	request = (struct subscr_request *)subscr->requests.next;
	llist_del(&request->entry);
	subscr->in_callback = 1;
	request->cbfn(hooknum, event, msg, data, request->param);
	subscr->in_callback = 0;

	subscr_put(subscr);
	talloc_free(request);
	return 0;
}
Exemple #3
0
/*! \brief delete a given instance of a FSM
 *  \param[in] fsm The FSM to be un-registered and deleted
 */
void osmo_fsm_inst_free(struct osmo_fsm_inst *fi)
{
	LOGPFSM(fi, "Deallocated\n");
	osmo_timer_del(&fi->timer);
	llist_del(&fi->list);
	talloc_free(fi);
}
Exemple #4
0
/* TODO: move subscriber put here... */
void subscr_con_free(struct gsm_subscriber_connection *conn)
{
	if (!conn)
		return;


	if (conn->subscr) {
		subscr_put(conn->subscr);
		conn->subscr = NULL;
	}


	if (conn->ho_lchan) {
		LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
		conn->ho_lchan->conn = NULL;
	}

	if (conn->lchan) {
		LOGP(DNM, LOGL_ERROR, "The lchan should have been cleared.\n");
		conn->lchan->conn = NULL;
	}

	if (conn->secondary_lchan) {
		LOGP(DNM, LOGL_ERROR, "The secondary_lchan should have been cleared.\n");
		conn->secondary_lchan->conn = NULL;
	}

	llist_del(&conn->entry);
	talloc_free(conn);
}
Exemple #5
0
/*! \brief Terminate FSM instance with given cause
 *
 *  This safely terminates the given FSM instance by first iterating
 *  over all children and sending them a termination event.  Next, it
 *  calls the FSM descriptors cleanup function (if any), followed by
 *  releasing any memory associated with the FSM instance.
 *
 *  Finally, the parent FSM instance (if any) is notified using the
 *  parent termination event configured at time of FSM instance start.
 *
 *  \param[in] fi FSM instance to be terminated
 *  \param[in] cause Cause / reason for termination
 *  \param[in] data Opaque event data to be passed with the parent term event
 *  \param[in] file Calling source file (from osmo_fsm_inst_term macro)
 *  \param[in] line Calling source line (from osmo_fsm_inst_term macro)
 */
void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
			 enum osmo_fsm_term_cause cause, void *data,
			 const char *file, int line)
{
	struct osmo_fsm_inst *parent;
	uint32_t parent_term_event = fi->proc.parent_term_event;

	LOGPFSMSRC(fi, file, line, "Terminating (cause = %s)\n",
		   osmo_fsm_term_cause_name(cause));

	_osmo_fsm_inst_term_children(fi, OSMO_FSM_TERM_PARENT, NULL,
				     file, line);

	/* delete ourselves from the parent */
	parent = fi->proc.parent;
	if (parent)
		LOGPFSMSRC(fi, file, line, "Removing from parent %s\n",
			   osmo_fsm_inst_name(parent));
	llist_del(&fi->proc.child);

	/* call destructor / clean-up function */
	if (fi->fsm->cleanup)
		fi->fsm->cleanup(fi, cause);

	LOGPFSMSRC(fi, file, line, "Freeing instance\n");
	/* Fetch parent again in case it has changed. */
	parent = fi->proc.parent;
	osmo_fsm_inst_free(fi);

	/* indicate our termination to the parent */
	if (parent && cause != OSMO_FSM_TERM_PARENT)
		_osmo_fsm_inst_dispatch(parent, parent_term_event, data,
					file, line);
}
Exemple #6
0
static int ipa_client_write_default_cb(struct ipa_client_conn *link)
{
	struct osmo_fd *ofd = link->ofd;
	struct msgb *msg;
	struct llist_head *lh;
	int ret;

	LOGIPA(link, LOGL_DEBUG, "sending data\n");

	if (llist_empty(&link->tx_queue)) {
		ofd->when &= ~BSC_FD_WRITE;
		return 0;
	}
	lh = link->tx_queue.next;
	llist_del(lh);
	msg = llist_entry(lh, struct msgb, list);

	ret = send(link->ofd->fd, msg->data, msg->len, 0);
	if (ret < 0) {
		if (errno == EPIPE || errno == ENOTCONN) {
			ipa_client_conn_close(link);
			if (link->updown_cb)
				link->updown_cb(link, 0);
		}
		LOGIPA(link, LOGL_ERROR, "error to send\n");
	}
	msgb_free(msg);
	return 0;
}
Exemple #7
0
void		llist_erase(t_vector *vec, int at, void (*destruct)())
{
  void		*strct;

  strct = llist_del(vec, at);
  if (strct)
    destruct(strct);
}
Exemple #8
0
/**
 * Flushes a queue of primitives
 *
 * @param list list of prims going to be flushed
 */
void sched_prim_flush_queue(struct llist_head *list)
{
	struct trx_ts_prim *prim, *prim_next;

	llist_for_each_entry_safe(prim, prim_next, list, list) {
		llist_del(&prim->list);
		talloc_free(prim);
	}
Exemple #9
0
static struct paging_record *dequeue_pr(struct llist_head *group_q)
{
	struct paging_record *pr;

	pr = llist_entry(group_q->next, struct paging_record, list);
	llist_del(&pr->list);

	return pr;
}
Exemple #10
0
static void l1ctl_client_destroy(struct l1ctl_sock_client *lsc)
{
	struct l1ctl_sock_inst *lsi = lsc->l1ctl_sock;
	if (lsi->close_cb)
		lsi->close_cb(lsc);
	osmo_fd_close(&lsc->ofd);
	llist_del(&lsc->list);
	talloc_free(lsc);
}
Exemple #11
0
/*! \brief Dequeue message buffer from head of queue
 * \param[in] queue linked list header of queue
 * \returns message buffer (if any) or NULL if queue empty
 *
 * The function will remove the first message buffer from the queue
 * implemented by \ref llist_head \a queue.
 */
struct msgb *msgb_dequeue(struct llist_head *queue)
{
	struct llist_head *lh;

	if (llist_empty(queue))
		return NULL;

	lh = queue->next;
	llist_del(lh);
	
	return llist_entry(lh, struct msgb, list);
}
Exemple #12
0
void paging_reset(struct paging_state *ps)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(ps->paging_queue); i++) {
		struct llist_head *queue = &ps->paging_queue[i];
		struct paging_record *pr, *pr2;
		llist_for_each_entry_safe(pr, pr2, queue, list) {
			llist_del(&pr->list);
			talloc_free(pr);
			ps->num_paging--;
		}
	}
/* evict the 'num_evict' number of oldest entries in the queue */
static void tx_queue_evict(struct mux_subch *sch, int num_evict)
{
	struct subch_txq_entry *tqe;
	int i;

	for (i = 0; i < num_evict; i++) {
		if (llist_empty(&sch->tx_queue))
			return;

		tqe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list);
		llist_del(&tqe->list);
		talloc_free(tqe);
	}
}
/*! \brief close a telnet connection */
int telnet_close_client(struct osmo_fd *fd)
{
	struct telnet_connection *conn = (struct telnet_connection*)fd->data;

	close(fd->fd);
	osmo_fd_unregister(fd);

	if (conn->dbg) {
		log_del_target(conn->dbg);
		talloc_free(conn->dbg);
	}

	llist_del(&conn->entry);
	talloc_free(conn);
	return 0;
}
Exemple #15
0
struct req_ctx *req_ctx_dequeue(struct llist_head *list)
{
	unsigned long flags;
	struct req_ctx *rctx;

	local_irq_save(flags);
	if (llist_empty(list)) {
		local_irq_restore(flags);
		return NULL;
	}

	rctx = llist_entry(list->next, struct req_ctx, list);
	llist_del(&rctx->list);
	local_irq_restore(flags);

	return rctx;
}
/* return the requested number of bits from the specified subchannel */
static int get_subch_bits(struct subch_mux *mx, int subch,
			  u_int8_t *bits, int num_requested)
{
	struct mux_subch *sch = &mx->subch[subch];
	int num_bits = 0;

	while (num_bits < num_requested) {
		struct subch_txq_entry *txe;
		int num_bits_left;
		int num_bits_thistime;

		/* make sure we have a valid entry at top of tx queue.
		 * if not, add an idle frame */
		if (llist_empty(&sch->tx_queue))
			alloc_add_idle_frame(mx, subch);
	
		if (llist_empty(&sch->tx_queue))
			return -EIO;

		txe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list);
		num_bits_left = txe->bit_len - txe->next_bit;

		if (num_bits_left < num_requested)
			num_bits_thistime = num_bits_left;
		else
			num_bits_thistime = num_requested;

		/* pull the bits from the txe */
		memcpy(bits + num_bits, txe->bits + txe->next_bit, num_bits_thistime);
		txe->next_bit += num_bits_thistime;

		/* free the tx_queue entry if it is fully consumed */
		if (txe->next_bit >= txe->bit_len) {
			llist_del(&txe->list);
			talloc_free(txe);
		}

		/* increment global number of bits dequeued */
		num_bits += num_bits_thistime;
	}

	return num_requested;
}
Exemple #17
0
/**
 * Dequeues a single primitive of required type
 * from a specified transmit queue.
 *
 * @param  queue      a transmit queue to take a prim from
 * @param  lchan_type required primitive type
 * @return            a primitive or NULL if not found
 */
struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,
	enum trx_lchan_type lchan_type)
{
	struct trx_ts_prim *prim;

	/* There is nothing to dequeue */
	if (llist_empty(queue))
		return NULL;

	/* TCH requires FACCH prioritization, so handle it separately */
	if (CHAN_IS_TCH(lchan_type))
		return sched_prim_dequeue_tch(queue);

	llist_for_each_entry(prim, queue, list) {
		if (prim->chan == lchan_type) {
			llist_del(&prim->list);
			return prim;
		}
	}

	return NULL;
}
Exemple #18
0
static void subscr_free(struct gsm_subscriber *subscr)
{
	llist_del(&subscr->entry);
	talloc_free(subscr);
}
Exemple #19
0
static int atcmd_done(struct gsmd *g, struct gsmd_atcmd *cmd,
	const char *buf, u_int8_t channel)
{
	int rc = 0;
#if ENABLE_TIMEOUTS
	remove_channel_timeout(g, channel);
#endif
	if (!cmd) {
		gsmd_log(GSMD_ERROR, "* Null cmd? *\n");
		return -1;
	}

	if (!cmd->cb) {
		gsmd_log(GSMD_NOTICE, "command without cb!!!\n");
	} else {
		cmd->flags = ATCMD_FINAL_CB_FLAG;
		/* send final result code if there is no information
		 * response in mlbuf */
		if (g->mlbuf_len[channel]) {
			cmd->resp = g->mlbuf[channel];
			cmd->resplen = g->mlbuf_len[channel];
			cmd->resp[cmd->resplen] = 0;
		} else {
			cmd->resp = (char*) buf;
			cmd->resplen = strlen(buf);
		}
		DEBUGP("Calling final cmd->cb() %d <%s>(%d) <%d>\n",
			g->mlbuf_len[channel],cmd->resp,cmd->resplen,cmd->ret);
		rc = cmd->cb(cmd, cmd->ctx, cmd->resp);
		if (rc < 0) {
			gsmd_log(GSMD_ERROR, "Failed to create response for client\n");
		}
		DEBUGP("Clearing mlbuf\n");
		g->mlbuf_len[channel] = 0;
		g->mlbuf[channel][0] = 0;
	}

	/* remove from list of currently executing cmds */
	llist_del(&cmd->list);
#if ENABLE_TIMEOUTS
	if (TIMEOUT_ERRORCODE == cmd->ret && STATUS_OK == g->modem_status)
		check_channel(g,channel);
#endif
	atcmd_free(cmd);

	/* We're finished with the current command, but if still have pending
	* command(s) then pop off the first pending */
	if (llist_empty(&g->busy_atcmds[channel])) {
		struct gsmd_atcmd *cur = NULL;
		u_int32_t initial_delay_secs = 0;
		if (!llist_empty(&g->pending_atcmds[channel])) {
			gsmd_log(GSMD_INFO, "cmds pending\n");
			cur = llist_entry(g->pending_atcmds[channel].next,
				struct gsmd_atcmd, list);
			if (cur) {
				initial_delay_secs = cur->initial_delay_secs;
			} else {
				gsmd_log(GSMD_ERROR, "First pending is null?\n");
			}
		}
		if (g->pin_status) {
			if (cur) {
				if (cur->flags & ATCMD_PIN_SENSITIVE) {
					gsmd_log(GSMD_INFO, "pin_status %d\n",g->pin_status);
					if (g->sim_status == GSM0707_CME_SIM_NOT_INSERTED) {
						gsmd_log(GSMD_INFO, "sim not inserted\n");
						/* allow the modem to fail the cmd */
						wake_pending_after_delay(
							g,channel,initial_delay_secs);
					} else {
						gsmd_log(GSMD_INFO, "* pin sensitive cmd delayed *\n");
						g->pin_sensitive_cmds_waiting = 1;
					}
				} else {
					gsmd_log(GSMD_INFO, "wake pending after %d\n", initial_delay_secs);
					wake_pending_after_delay(g,channel,initial_delay_secs);
				}
			}
		} else {
			if (g->pin_sensitive_cmds_waiting) {
				if (cur && (cur->flags & ATCMD_PIN_SENSITIVE)) {
					u_int8_t ch_iter = 0;
					gsmd_log(GSMD_INFO, "chk chnls for pin delayed cmds\n");
					for (ch_iter = 0; ch_iter < g->number_channels; ch_iter++) {
						if (ch_iter == channel)
							continue;
						if (!llist_empty(&g->pending_atcmds[ch_iter])) {
							struct gsmd_atcmd *cur2 =
								llist_entry(g->pending_atcmds[ch_iter].next,
									struct gsmd_atcmd, list);
							if (cur2 && (cur2->flags & ATCMD_PIN_SENSITIVE)) {
								gsmd_log(GSMD_INFO, "* waking chnl %d *\n",
									ch_iter);
								wake_pending_after_delay(
									g, ch_iter, initial_delay_secs);
							}
						}
					}
					g->pin_sensitive_cmds_waiting = 0;
				}
			}

			gsmd_log(GSMD_INFO, "wake pending after %d secs\n", initial_delay_secs);
			wake_pending_after_delay(g, channel,initial_delay_secs);
		}
Exemple #20
0
/* get response from ctrl socket */
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
{
	struct trx_l1h *l1h = ofd->data;
	struct phy_instance *pinst = l1h->phy_inst;
	char buf[1500];
	int len, resp;

	len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
	if (len <= 0)
		return len;
	buf[len] = '\0';

	if (!strncmp(buf, "RSP ", 4)) {
		struct trx_ctrl_msg *tcm;
		char *p;
		int rsp_len = 0;

		/* calculate the length of response item */
		p = strchr(buf + 4, ' ');
		if (p)
			rsp_len = p - buf - 4;
		else
			rsp_len = strlen(buf) - 4;

		LOGP(DTRX, LOGL_INFO, "Response message: '%s'\n", buf);

		/* abort timer and send next message, if any */
		if (osmo_timer_pending(&l1h->trx_ctrl_timer))
			osmo_timer_del(&l1h->trx_ctrl_timer);

		/* get command for response message */
		if (llist_empty(&l1h->trx_ctrl_list)) {
			LOGP(DTRX, LOGL_NOTICE, "Response message without "
				"command\n");
			return -EINVAL;
		}
		tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg,
			list);

		/* check if respose matches command */
		if (rsp_len != tcm->cmd_len) {
			notmatch:
			LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
				"Response message '%s' does not match command "
				"message '%s'\n", buf, tcm->cmd);
			goto rsp_error;
		}
		if (!!strncmp(buf + 4, tcm->cmd + 4, rsp_len))
			goto notmatch;

		/* check for response code */
		sscanf(p + 1, "%d", &resp);
		if (resp) {
			LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
				"transceiver (%s) rejected TRX command "
				"with response: '%s'\n",
				phy_instance_name(pinst), buf);
rsp_error:
			if (tcm->critical) {
				bts_shutdown(pinst->trx->bts, "SIGINT");
				/* keep tcm list, so process is stopped */
				return -EIO;
			}
		}

		/* remove command from list */
		llist_del(&tcm->list);
		talloc_free(tcm);

		trx_ctrl_send(l1h);
	} else
Exemple #21
0
void rate_ctr_group_free(struct rate_ctr_group *grp)
{
	llist_del(&grp->list);
	talloc_free(grp);
}
Exemple #22
0
struct llist *llist_kill(struct llist *l)
{
	while( ! llist_del(l) );
	free(l);
	return (struct llist *)0;
}
Exemple #23
0
int bsc_msc_connect(struct bsc_msc_connection *con)
{
	struct bsc_msc_dest *dest;
	struct osmo_fd *fd;
	struct sockaddr_in sin;
	int on = 1, ret;

	if (llist_empty(con->dests)) {
		LOGP(DMSC, LOGL_ERROR,
			"No MSC(%s) connections configured.\n",
			con->name);
		connection_loss(con);
		return -1;
	}

	/* TODO: Why are we not using the libosmocore soecket
	 * abstraction, or libosmo-netif? */

	/* move to the next connection */
	dest = (struct bsc_msc_dest *) con->dests->next;
	llist_del(&dest->list);
	llist_add_tail(&dest->list, con->dests);

	LOGP(DMSC, LOGL_NOTICE,
		"Attempting to connect MSC(%s) at %s:%d\n",
		con->name, dest->ip, dest->port);

	con->is_connected = 0;

	msgb_free(con->pending_msg);
	con->pending_msg = NULL;

	fd = &con->write_queue.bfd;
	fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	fd->priv_nr = 1;

	if (fd->fd < 0) {
		perror("Creating TCP socket failed");
		return fd->fd;
	}

	/* make it non blocking */
	setnonblocking(fd);

	/* set the socket priority */
	ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
			 &dest->dscp, sizeof(dest->dscp));
	if (ret != 0)
		LOGP(DMSC, LOGL_ERROR,
			"Failed to set DSCP to %d on MSC(%s). %s\n",
			dest->dscp, con->name, strerror(errno));

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(dest->port);
	inet_aton(dest->ip, &sin.sin_addr);

	ret = setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	if (ret != 0)
		LOGP(DMSC, LOGL_ERROR,
		     "Failed to set SO_REUSEADDR socket option\n");
	ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));

	if (ret == -1 && errno == EINPROGRESS) {
		LOGP(DMSC, LOGL_ERROR,
			"MSC(%s) Connection in progress\n", con->name);
		fd->when = BSC_FD_WRITE;
		fd->cb = msc_connection_connect;
		con->timeout_timer.cb = msc_con_timeout;
		con->timeout_timer.data = con;
		osmo_timer_schedule(&con->timeout_timer, 20, 0);
	} else if (ret < 0) {
		perror("Connection failed");
		connection_loss(con);
		return ret;
	} else {
		fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
		fd->cb = osmo_wqueue_bfd_cb;
		con->is_connected = 1;
		if (con->connected)
			con->connected(con);
	}

	ret = osmo_fd_register(fd);
	if (ret < 0) {
		perror("Registering the fd failed");
		close(fd->fd);
		return ret;
	}

	return ret;
}
Exemple #24
0
/*! \brief unregister a FSM from the core
 *
 *  Once the FSM descriptor is unregistered, active instances can still
 *  use it, but no new instances may be created for it.
 *
 *  \param[in] fsm Descriptor of Finite State Machine to be removed
 */
void osmo_fsm_unregister(struct osmo_fsm *fsm)
{
	llist_del(&fsm->list);
}