Esempio n. 1
0
static int foo(void)
{
	struct osmo_fsm_inst *fi;

	LOGP(DMAIN, LOGL_INFO, "Checking FSM allocation\n");
	fi = osmo_fsm_inst_alloc(&fsm, g_ctx, NULL, LOGL_DEBUG, NULL);
	OSMO_ASSERT(fi);
	OSMO_ASSERT(fi->fsm == &fsm);
	OSMO_ASSERT(!strncmp(osmo_fsm_inst_name(fi), fsm.name, strlen(fsm.name)));
	OSMO_ASSERT(fi->state == ST_NULL);
	OSMO_ASSERT(fi->log_level == LOGL_DEBUG);

	/* Try invalid state transition */
	osmo_fsm_inst_dispatch(fi, EV_B, (void *) 42);
	OSMO_ASSERT(fi->state == ST_NULL);

	/* Legitimate state transition */
	osmo_fsm_inst_dispatch(fi, EV_A, (void *) 23);
	OSMO_ASSERT(fi->state == ST_ONE);

	/* Legitimate transition with timer */
	fsm.timer_cb = test_fsm_tmr_cb;
	osmo_fsm_inst_dispatch(fi, EV_B, (void *) 42);
	OSMO_ASSERT(fi->state == ST_TWO);


	return 0;
}
Esempio n. 2
0
static int m3ua_rx_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
	int event;

	/* map from the M3UA message class and message type to the XUA
	 * ASP FSM event number */
	event = xua_msg_event_map(xua, m3ua_aspxm_map,
				  ARRAY_SIZE(m3ua_aspxm_map));
	if (event < 0)
		return M3UA_ERR_UNSUPP_MSG_TYPE;

	/* deliver that event to the ASP FSM */
	if (osmo_fsm_inst_dispatch(asp->fi, event, xua) < 0)
		return M3UA_ERR_UNEXPECTED_MSG;

	return 0;
}
Esempio n. 3
0
/*! \brief Repeat last SID if possible in case of DTX
 *  \param[in] lchan Logical channel on which we check scheduling
 *  \param[in] dst Buffer to copy last SID into
 *  \returns Number of bytes copied + 1 (to accommodate for extra byte with
 *           payload type), 0 if there's nothing to copy
 */
uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
{
	/* FIXME: add EFR support */
	if (lchan->tch_mode == GSM48_CMODE_SPEECH_EFR)
		return 0;

	if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
		if (dtx_sched_optional(lchan, fn))
			return 0;
	} else
		if (dtx_amr_sid_optional(lchan, fn))
			return 0;

	if (lchan->tch.dtx.len) {
		if (dtx_dl_amr_enabled(lchan)) {
			if ((lchan->type == GSM_LCHAN_TCH_H &&
			     lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2) ||
			    (lchan->type == GSM_LCHAN_TCH_F &&
			     lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1)) {
				/* advance FSM in case we've just sent SID FIRST
				   to restore silence after FACCH interruption */
				osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
						       E_SID_U, (void *)lchan);
				dtx_sti_unset(lchan);
			} else if (lchan->tch.dtx.dl_amr_fsm->state ==
				   ST_SID_U) {
				/* enforce SID UPDATE for next repetition: it
				   might have been altered by FACCH handling */
				dtx_sti_set(lchan);
			lchan->tch.dtx.is_update = true;
			}
		}
		memcpy(dst, lchan->tch.dtx.cache, lchan->tch.dtx.len);
		lchan->tch.dtx.fn = fn;
		return lchan->tch.dtx.len + 1;
	}

	LOGP(DL1C, LOGL_DEBUG, "Have to send %s frame on TCH but SID buffer "
	     "is empty - sent nothing\n",
	     get_value_string(gsm48_chan_mode_names, lchan->tch_mode));

	return 0;
}
Esempio n. 4
0
/*! \brief Send a given xUA message via a given M3UA Application Server
 *  \param[in] as Application Server through which to send \ref xua
 *  \param[in] xua xUA message to be sent
 *  \return 0 on success; negative on error */
int m3ua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua)
{
	struct msgb *msg;
	int rc;

	OSMO_ASSERT(as->cfg.proto == OSMO_SS7_ASP_PROT_M3UA);

	/* Add RC for this AS */
	if (as->cfg.routing_key.context)
		xua_msg_add_u32(xua, M3UA_IEI_ROUTE_CTX, as->cfg.routing_key.context);

	msg = m3ua_to_msg(xua);
	if (!msg)
		return -1;

	/* send the msg to the AS for transmission.  The AS FSM might
	 * (depending on its state) enqueue it before trnsmission */
	rc = osmo_fsm_inst_dispatch(as->fi, XUA_AS_E_TRANSFER_REQ, msg);
	if (rc < 0)
		msgb_free(msg);
	return rc;
}
Esempio n. 5
0
/*! \brief allocate a new instance of a specified FSM as child of
 *  other FSM instance
 *
 *  This is like \ref osmo_fsm_inst_alloc but using the parent FSM as
 *  talloc context, and inheriting the log level of the parent.
 *
 *  \param[in] fsm Descriptor of the to-be-allocated FSM
 *  \param[in] parent Parent FSM instance
 *  \param[in] parent_term_event Event to be sent to parent when terminating
 *  \returns newly-allocated, initialized and registered FSM instance
 */
struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm,
						struct osmo_fsm_inst *parent,
						uint32_t parent_term_event)
{
	struct osmo_fsm_inst *fi;

	fi = osmo_fsm_inst_alloc(fsm, parent, NULL, parent->log_level,
				 parent->id);
	if (!fi) {
		/* indicate immediate termination to caller */
		osmo_fsm_inst_dispatch(parent, parent_term_event, NULL);
		return NULL;
	}

	LOGPFSM(fi, "is child of %s\n", osmo_fsm_inst_name(parent));

	fi->proc.parent = parent;
	fi->proc.parent_term_event = parent_term_event;
	llist_add(&fi->proc.child, &parent->proc.children);

	return fi;
}
Esempio n. 6
0
/*! \brief Send signal to FSM: with proper check if DIX is enabled for this lchan
 *  \param[in] lchan Logical channel on which we check scheduling
 *  \param[in] e DTX DL AMR FSM Event
 */
void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e)
{
	if (dtx_dl_amr_enabled(lchan))
		osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, e,
				       (void *)lchan);
}
Esempio n. 7
0
/*! \brief Check current state of DTX DL AMR FSM and dispatch necessary events
 *  \param[in] lchan Logical channel on which we check scheduling
 *  \param[in] rtp_pl buffer with RTP data
 *  \param[in] rtp_pl_len length of rtp_pl
 *  \param[in] fn Frame Number for which we check scheduling
 *  \param[in] l1_payload buffer where CMR and CMI prefix should be added
 *  \param[in] marker RTP Marker bit
 *  \param[out] len Length of expected L1 payload
 *  \param[out] ft_out Frame Type to be populated after decoding
 *  \returns 0 in case of success; negative on error
 */
int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
			size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload,
			bool marker, uint8_t *len, uint8_t *ft_out)
{
	uint8_t cmr;
	enum osmo_amr_type ft;
	enum osmo_amr_quality bfi;
	int8_t sti, cmi;
	int rc;

	if (dtx_dl_amr_enabled(lchan)) {
		if (lchan->type == GSM_LCHAN_TCH_H &&
		    lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 && !rtp_pl) {
			*len = 3; /* SID-FIRST P1 -> P2 completion */
			memcpy(l1_payload, lchan->tch.dtx.cache, 2);
			dtx_dispatch(lchan, E_SID_U);
			return 0;
		}
	}

	if (!rtp_pl_len)
		return -EBADMSG;

	rc = osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti);
	if (rc < 0) {
		LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu)\n",
		     rtp_pl_len);
		return rc;
	}

	/* only needed for old sysmo firmware: */
	*ft_out = ft;

	/* CMI in downlink tells the L1 encoder which encoding function
	 * it will use, so we have to use the frame type */
	if (osmo_amr_is_speech(ft))
		cmi = ft;

	/* populate L1 payload with CMR/CMI - might be ignored by caller: */
	amr_set_mode_pref(l1_payload, &lchan->tch.amr_mr, cmi, cmr);

	/* populate DTX cache with CMR/CMI - overwrite cache which will be
	   either updated or invalidated by caller anyway: */
	amr_set_mode_pref(lchan->tch.dtx.cache, &lchan->tch.amr_mr, cmi, cmr);
	*len = 3 + rtp_pl_len;

	/* DTX DL is not enabled, move along */
	if (!lchan->ts->trx->bts->dtxd)
		return 0;

	if (osmo_amr_is_speech(ft)) {
		/* AMR HR - Inhibition */
		if (lchan->type == GSM_LCHAN_TCH_H && marker &&
		    lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1)
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
						      E_INHIB, (void *)lchan);
		/* AMR FR & HR - generic */
		if (marker && (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 ||
			       lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 ||
			       lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U ))
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
						      E_ONSET, (void *)lchan);
		return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE,
					      (void *)lchan);
	}

	if (ft == AMR_SID) {
		if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE) {
			/* SID FIRST/UPDATE scheduling logic relies on SID FIRST
			   being sent first hence we have to force caching of SID
			   as FIRST regardless of actually decoded type */
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false);
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
						      E_SID_F, (void *)lchan);
		} else
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti);
		return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
					      sti ? E_SID_U : E_SID_F,
					      (void *)lchan);
	}

	if (ft != AMR_NO_DATA) {
		LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft);
		return -ENOTSUP;
	}

	if (marker)
		osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE,
				       (void *)lchan);
	*len = 0;
	return 0;
}