Ejemplo n.º 1
0
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;
	}

	memset(request, 0, sizeof(*request));
	request->subscr = subscr_get(subscr);
	request->channel_type = type;
	request->cbfn = cbfn;
	request->param = param;

	/*
	 * 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);
	}
}
Ejemplo n.º 2
0
/**
 * Adds a primitive to the end of transmit queue of a particular
 * timeslot, whose index is parsed from chan_nr.
 *
 * @param  trx     TRX instance
 * @param  prim    to be enqueued primitive
 * @param  chan_nr RSL channel description
 * @return         zero in case of success, otherwise a error number
 */
int sched_prim_push(struct trx_instance *trx,
	struct trx_ts_prim *prim, uint8_t chan_nr)
{
	struct trx_ts *ts;
	uint8_t tn;

	/* Determine TS index */
	tn = chan_nr & 0x7;
	if (tn > 7) {
		LOGP(DSCH, LOGL_ERROR, "Incorrect TS index %u\n", tn);
		return -EINVAL;
	}

	/* Check whether required timeslot is allocated and configured */
	ts = trx->ts_list[tn];
	if (ts == NULL || ts->mf_layout == NULL) {
		LOGP(DSCH, LOGL_ERROR, "Timeslot %u isn't configured\n", tn);
		return -EINVAL;
	}

	/**
	 * Change talloc context of primitive
	 * from trx to the parent ts
	 */
	talloc_steal(ts, prim);

	/* Add primitive to TS transmit queue */
	llist_add_tail(&prim->list, &ts->tx_prims);

	return 0;
}
Ejemplo n.º 3
0
static int telnet_new_connection(struct osmo_fd *fd, unsigned int what)
{
	struct telnet_connection *connection;
	struct sockaddr_in sockaddr;
	socklen_t len = sizeof(sockaddr);
	int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);

	if (new_connection < 0) {
		LOGP(0, LOGL_ERROR, "telnet accept failed\n");
		return new_connection;
	}

	connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
	connection->priv = fd->data;
	connection->fd.data = connection;
	connection->fd.fd = new_connection;
	connection->fd.when = BSC_FD_READ;
	connection->fd.cb = client_data;
	osmo_fd_register(&connection->fd);
	llist_add_tail(&connection->entry, &active_connections);

	print_welcome(new_connection);

	connection->vty = vty_create(new_connection, connection);
	if (!connection->vty) {
		LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
		close(new_connection);
		talloc_free(connection);
		return -1;
	}

	return 0;
}
Ejemplo n.º 4
0
/*! \brief register a FSM with the core
 *
 *  A FSM descriptor needs to be registered with the core before any
 *  instances can be created for it.
 *
 *  \param[in] fsm Descriptor of Finite State Machine to be registered
 *  \returns 0 on success; negative on error
 */
int osmo_fsm_register(struct osmo_fsm *fsm)
{
	/* FIXME:check for duplicate name? */
	llist_add_tail(&fsm->list, &g_fsms);
	INIT_LLIST_HEAD(&fsm->instances);

	return 0;
}
Ejemplo n.º 5
0
void req_ctx_enqueue(struct llist_head *list, struct req_ctx *rctx)
{
	unsigned long flags;

	/* FIXME: do we need this kind of locking, we're UP! */
	local_irq_save(flags);
	llist_add_tail(&rctx->list, list);
	local_irq_restore(flags);
}
/* register a cipher with the core */
int gprs_cipher_register(struct gprs_cipher_impl *ciph)
{
	if (ciph->algo >= ARRAY_SIZE(selected_ciphers))
		return -ERANGE;

	llist_add_tail(&ciph->list, &gprs_ciphers);

	/* check if we want to select this implementation over others */
	if (!selected_ciphers[ciph->algo] ||
	    (selected_ciphers[ciph->algo]->priority > ciph->priority))
		selected_ciphers[ciph->algo] = ciph;

	return 0;
}
Ejemplo n.º 7
0
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
{
	struct gsm_subscriber_connection *conn;

	conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection);
	if (!conn)
		return NULL;

	/* Configure the time and start it so it will be closed */
	conn->lchan = lchan;
	conn->bts = lchan->ts->trx->bts;
	lchan->conn = conn;
	llist_add_tail(&conn->entry, &sub_connections);
	return conn;
}
Ejemplo n.º 8
0
struct gsm_subscriber *subscr_alloc(void)
{
	struct gsm_subscriber *s;

	s = talloc_zero(tall_subscr_ctx, struct gsm_subscriber);
	if (!s)
		return NULL;

	llist_add_tail(&s->entry, &active_subscribers);
	s->use_count = 1;
	s->tmsi = GSM_RESERVED_TMSI;

	INIT_LLIST_HEAD(&s->requests);

	return s;
}
Ejemplo n.º 9
0
static struct osmo_config_entry *
alloc_entry(struct osmo_config_list *entries,
	    const char *mcc, const char *mnc,
	    const char *option, const char *text)
{
	struct osmo_config_entry *entry =
		talloc_zero(entries, struct osmo_config_entry);
	if (!entry)
		return NULL;

	entry->mcc = talloc_strdup(entry, mcc);
	entry->mnc = talloc_strdup(entry, mnc);
	entry->option = talloc_strdup(entry, option);
	entry->text = talloc_strdup(entry, text);

	llist_add_tail(&entry->list, &entries->entry);
	return entry;
}
Ejemplo n.º 10
0
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
{
    struct mgcp_trunk_config *trunk;

    trunk = talloc_zero(cfg, struct mgcp_trunk_config);
    if (!trunk) {
        LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
        return NULL;
    }

    trunk->cfg = cfg;
    trunk->trunk_type = MGCP_TRUNK_E1;
    trunk->trunk_nr = nr;
    trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
    trunk->audio_payload = 126;
    trunk->number_endpoints = 33;
    llist_add_tail(&trunk->entry, &cfg->trunks);
    return trunk;
}
Ejemplo n.º 11
0
/* called for the master (listening) socket of the instance, allocates a new client */
static int l1ctl_sock_accept_cb(struct osmo_fd *ofd, unsigned int what)
{

	struct l1ctl_sock_inst *lsi = ofd->data;
	struct l1ctl_sock_client *lsc;
	int fd, rc;

	fd = accept(ofd->fd, NULL, NULL);
	if (fd < 0) {
		LOGP(DL1C, LOGL_ERROR, "Failed to accept connection to l2.\n");
		return -1;
	}

	lsc = talloc_zero(lsi, struct l1ctl_sock_client);
	if (!lsc) {
		close(fd);
		LOGP(DL1C, LOGL_ERROR, "Failed to allocate L1CTL client\n");
		return -1;
	}

	lsc->l1ctl_sock = lsi;
	lsc->ofd.fd = fd;
	lsc->ofd.when = BSC_FD_READ;
	lsc->ofd.cb = l1ctl_sock_data_cb;
	lsc->ofd.data = lsc;
	if (lsi->accept_cb) {
		rc = lsi->accept_cb(lsc);
		if (rc < 0) {
			talloc_free(lsc);
			close(fd);
			return rc;
		}
	}

	LOGP(DL1C, LOGL_INFO, "Accepted client (fd=%u) from server (fd=%u)\n", fd, ofd->fd);
	if (osmo_fd_register(&lsc->ofd) != 0) {
		LOGP(DL1C, LOGL_ERROR, "Failed to register the l2 connection fd.\n");
		talloc_free(lsc);
		return -1;
	}
	llist_add_tail(&lsc->list, &lsi->clients);
	return 0;
}
Ejemplo n.º 12
0
/* enqueue some data into the tx_queue of a given subchannel */
int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const u_int8_t *data,
			int len)
{
	struct mux_subch *sch = &mx->subch[s_nr];
	int list_len = llist_len(&sch->tx_queue);
	struct subch_txq_entry *tqe = talloc_zero_size(tall_tqe_ctx,
							sizeof(*tqe) + len);
	if (!tqe)
		return -ENOMEM;

	tqe->bit_len = len;
	memcpy(tqe->bits, data, len);

	if (list_len > 2)
		tx_queue_evict(sch, list_len-2);

	llist_add_tail(&tqe->list, &sch->tx_queue);

	return 0;
}
Ejemplo n.º 13
0
/* add a new ctrl command */
static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd,
	const char *fmt, ...)
{
	struct trx_ctrl_msg *tcm;
	va_list ap;
	int l, pending = 0;

	if (!transceiver_available &&
	    !(!strcmp(cmd, "POWEROFF") || !strcmp(cmd, "POWERON"))) {
		LOGP(DTRX, LOGL_ERROR, "CTRL %s ignored: No clock from "
		     "transceiver, please fix!\n", cmd);
		return -EIO;
	}

	if (!llist_empty(&l1h->trx_ctrl_list))
		pending = 1;

	/* create message */
	tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg);
	if (!tcm)
		return -ENOMEM;
	if (fmt && fmt[0]) {
		l = snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s ", cmd);
		va_start(ap, fmt);
		vsnprintf(tcm->cmd + l, sizeof(tcm->cmd) - l - 1, fmt, ap);
		va_end(ap);
	} else
		snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s", cmd);
	tcm->cmd_len = strlen(cmd);
	tcm->critical = critical;
	llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);
	LOGP(DTRX, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd);

	/* send message, if no pending message */
	if (!pending)
		trx_ctrl_send(l1h);

	return 0;
}
Ejemplo n.º 14
0
struct xua_msg *m3ua_xfer_from_data(const struct m3ua_data_hdr *data_hdr,
				    const uint8_t *data, unsigned int data_len)
{
	struct xua_msg *xua = xua_msg_alloc();
	struct xua_msg_part *data_part;

	xua->hdr = XUA_HDR(M3UA_MSGC_XFER, M3UA_XFER_DATA);
	/* Network Appearance: Optional */
	/* Routing Context: Conditional */
	/* Protocol Data: Mandatory */
	data_part = talloc_zero(xua, struct xua_msg_part);
	OSMO_ASSERT(data_part);
	data_part->tag = M3UA_IEI_PROT_DATA;
	data_part->len = sizeof(*data_hdr) + data_len;
	data_part->dat = talloc_size(data_part, data_part->len);
	OSMO_ASSERT(data_part->dat);
	memcpy(data_part->dat, data_hdr, sizeof(*data_hdr));
	memcpy(data_part->dat+sizeof(*data_hdr), data, data_len);
	llist_add_tail(&data_part->entry, &xua->headers);
	/* Correlation Id: Optional */

	return xua;
}
Ejemplo n.º 15
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;
}
Ejemplo n.º 16
0
/* generate paging message for given gsm time */
int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt,
		   int *is_empty)
{
	struct llist_head *group_q;
	int group;
	int len;

	*is_empty = 0;
	ps->bts->load.ccch.pch_total += 1;

	group = get_pag_subch_nr(ps, gt);
	if (group < 0) {
		LOGP(DPAG, LOGL_ERROR,
		     "Paging called for GSM wrong time: FN %d/%d/%d/%d.\n",
		     gt->fn, gt->t1, gt->t2, gt->t3);
		return -1;
	}

	group_q = &ps->paging_queue[group];

	/* There is nobody to be paged, send Type1 with two empty ID */
	if (llist_empty(group_q)) {
		//DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n");
		len = fill_paging_type_1(out_buf, empty_id_lv, 0,
					 NULL, 0);
		*is_empty = 1;
	} else {
		struct paging_record *pr[4];
		unsigned int num_pr = 0, imm_ass = 0;
		time_t now = time(NULL);
		unsigned int i, num_imsi = 0;

		ps->bts->load.ccch.pch_used += 1;

		/* get (if we have) up to four paging records */
		for (i = 0; i < ARRAY_SIZE(pr); i++) {
			if (llist_empty(group_q))
				break;
			pr[i] = dequeue_pr(group_q);

			/* check for IMM.ASS */
			if (pr[i]->type == PAGING_RECORD_IMM_ASS) {
				imm_ass = 1;
				break;
			}

			num_pr++;

			/* count how many IMSIs are among them */
			if (pr_is_imsi(pr[i]))
				num_imsi++;
		}

		/* if we have an IMMEDIATE ASSIGNMENT */
		if (imm_ass) {
			/* re-add paging records */
			for (i = 0; i < num_pr; i++)
				llist_add(&pr[i]->list, group_q);

			/* get message and free record */
			memcpy(out_buf, pr[num_pr]->u.imm_ass.msg,
							GSM_MACBLOCK_LEN);
			pcu_tx_pch_data_cnf(gt->fn, pr[num_pr]->u.imm_ass.msg,
							GSM_MACBLOCK_LEN);
			talloc_free(pr[num_pr]);
			return GSM_MACBLOCK_LEN;
		}

		/* make sure the TMSIs are ahead of the IMSIs in the array */
		sort_pr_tmsi_imsi(pr, num_pr);

		if (num_pr == 4 && num_imsi == 0) {
			/* No IMSI: easy case, can use TYPE 3 */
			DEBUGP(DPAG, "Tx PAGING TYPE 3 (4 TMSI)\n");
			len = fill_paging_type_3(out_buf,
						 pr[0]->u.paging.identity_lv,
						 pr[0]->u.paging.chan_needed,
						 pr[1]->u.paging.identity_lv,
						 pr[1]->u.paging.chan_needed,
						 pr[2]->u.paging.identity_lv,
						 pr[2]->u.paging.chan_needed,
						 pr[3]->u.paging.identity_lv,
						 pr[3]->u.paging.chan_needed);
		} else if (num_pr >= 3 && num_imsi <= 1) {
			/* 3 or 4, of which only up to 1 is IMSI */
			DEBUGP(DPAG, "Tx PAGING TYPE 2 (2 TMSI,1 xMSI)\n");
			len = fill_paging_type_2(out_buf,
						 pr[0]->u.paging.identity_lv,
						 pr[0]->u.paging.chan_needed,
						 pr[1]->u.paging.identity_lv,
						 pr[1]->u.paging.chan_needed,
						 pr[2]->u.paging.identity_lv);
			if (num_pr == 4) {
				/* re-add #4 for next time */
				llist_add(&pr[3]->list, group_q);
				pr[3] = NULL;
			}
		} else if (num_pr == 1) {
			DEBUGP(DPAG, "Tx PAGING TYPE 1 (1 xMSI,1 empty)\n");
			len = fill_paging_type_1(out_buf,
						 pr[0]->u.paging.identity_lv,
						 pr[0]->u.paging.chan_needed,
						 NULL, 0);
		} else {
			/* 2 (any type) or
			 * 3 or 4, of which only 2 will be sent */
			DEBUGP(DPAG, "Tx PAGING TYPE 1 (2 xMSI)\n");
			len = fill_paging_type_1(out_buf,
						 pr[0]->u.paging.identity_lv,
						 pr[0]->u.paging.chan_needed,
						 pr[1]->u.paging.identity_lv,
						 pr[1]->u.paging.chan_needed);
			if (num_pr >= 3) {
				/* re-add #4 for next time */
				llist_add(&pr[2]->list, group_q);
				pr[2] = NULL;
			}
			if (num_pr == 4) {
				/* re-add #4 for next time */
				llist_add(&pr[3]->list, group_q);
				pr[3] = NULL;
			}
		}

		for (i = 0; i < num_pr; i++) {
			/* skip those that we might have re-added above */
			if (pr[i] == NULL)
				continue;
			rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_SENT);
			/* check if we can expire the paging record,
			 * or if we need to re-queue it */
			if (pr[i]->u.paging.expiration_time <= now) {
				talloc_free(pr[i]);
				ps->num_paging--;
				LOGP(DPAG, LOGL_INFO, "Removed paging record, queue_len=%u\n",
					ps->num_paging);
			} else
				llist_add_tail(&pr[i]->list, group_q);
		}
	}
	memset(out_buf+len, 0x2B, GSM_MACBLOCK_LEN-len);
	return len;
}
Ejemplo n.º 17
0
/*! \brief Enqueue message buffer to tail of a queue
 * \param[in] queue linked list header of queue
 * \param[in] msg message buffer to be added to the queue
 *
 * The function will append the specified message buffer \a msg to the
 * queue implemented by \ref llist_head \a queue
 */
void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
{
	llist_add_tail(&msg->list, queue);
}