Esempio n. 1
0
/**
 * Messages coming back from the MSC.
 */
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
	struct osmo_msc_data *msc;
	struct gsm_network *net;
	struct gsm48_loc_area_id *lai;
	struct gsm48_hdr *gh;
	uint8_t mtype;

	if (msgb_l3len(msg) < sizeof(*gh)) {
		LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n");
		return -1;
	}

	gh = (struct gsm48_hdr *) msgb_l3(msg);
	mtype = gh->msg_type & 0xbf;
	net = conn->bts->network;
	msc = conn->sccp_con->msc;

	if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
		if (msc->core_ncc != -1 || msc->core_mcc != -1) {
			if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
				lai = (struct gsm48_loc_area_id *) &gh->data[0];
				gsm48_generate_lai(lai, net->country_code,
						   net->network_code,
						   conn->bts->location_area_code);
			}
		}

		if (conn->sccp_con->new_subscriber)
			send_welcome_ussd(conn);
	}

	return 0;
}
Esempio n. 2
0
static void handle_ass_compl(struct gsm_subscriber_connection *conn,
			     struct msgb *msg)
{
	struct gsm48_hdr *gh;
	struct bsc_api *api = conn->bts->network->bsc_api;

	if (conn->secondary_lchan != msg->lchan) {
		LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n");
		return;
	}

	gh = msgb_l3(msg);
	if (msgb_l3len(msg) - sizeof(*gh) != 1) {
		LOGP(DMSC, LOGL_ERROR, "Assignment Compl invalid: %lu\n",
		     msgb_l3len(msg) - sizeof(*gh));
		return;
	}

	/* swap channels */
	osmo_timer_del(&conn->T10);

	lchan_release(conn->lchan, 0, 1);
	conn->lchan = conn->secondary_lchan;
	conn->secondary_lchan = NULL;

	if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
		rsl_ipacc_crcx(conn->lchan);

	api->assign_compl(conn, gh->data[0],
			  lchan_to_chosen_channel(conn->lchan),
			  conn->lchan->encr.alg_id,
			  chan_mode_to_speech(conn->lchan));
}
/* 9.1.20 IMMEDIATE ASSIGNMENT REJECT is received */
static int imm_ass_rej(struct osmocom_ms *ms, struct msgb *msg)
{
	struct gsm48_imm_ass_rej *ia = msgb_l3(msg);
	int i;
	struct gsm48_req_ref *req_ref;

	LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT REJECT:\n");

	if (state != SCAN_STATE_RACH) {
		LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
		return 0;
	}

	for (i = 0; i < 4; i++) {
		/* request reference */
		req_ref = (struct gsm48_req_ref *)
				(((uint8_t *)&ia->req_ref1) + i * 4);
		LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT REJECT "
			"(ref 0x%02x)\n", req_ref->ra);
		if (match_ra(ms, req_ref)) {
			return ta_result(0xff);
		}
	}

	return 0;
}
/* receive BCCH at RR layer */
static int bcch(struct osmocom_ms *ms, struct msgb *msg)
{
	struct gsm48_system_information_type_header *sih = msgb_l3(msg);
	struct gsm48_sysinfo *s = &g_sysinfo;

	if (msgb_l3len(msg) != 23) {
		LOGP(DRR, LOGL_NOTICE, "Invalid BCCH message length\n");
		return -EINVAL;
	}
	switch (sih->system_information) {
	case GSM48_MT_RR_SYSINFO_1:
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
		gsm48_decode_sysinfo1(s,
			(struct gsm48_system_information_type_1 *) sih,
			msgb_l3len(msg));
		return try_cbch(ms, s);
	case GSM48_MT_RR_SYSINFO_4:
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4\n");
		gsm48_decode_sysinfo4(s,
			(struct gsm48_system_information_type_4 *) sih,
			msgb_l3len(msg));
		return try_cbch(ms, s);
	default:
		return 0;
	}
}
Esempio n. 5
0
static void handle_lu_request(struct gsm_subscriber_connection *conn,
			      struct msgb *msg)
{
	struct gsm48_hdr *gh;
	struct gsm48_loc_upd_req *lu;
	struct gsm48_loc_area_id lai;
	struct gsm_network *net;

	if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
		LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
		return;
	}

	net = conn->bts->network;

	gh = msgb_l3(msg);
	lu = (struct gsm48_loc_upd_req *) gh->data;

	gsm48_generate_lai(&lai, net->country_code, net->network_code,
			   conn->bts->location_area_code);

	if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
		LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
		conn->sccp_con->new_subscriber = 1;
	}
}
Esempio n. 6
0
static void handle_ass_fail(struct gsm_subscriber_connection *conn,
			    struct msgb *msg)
{
	struct bsc_api *api = conn->bts->network->bsc_api;
	uint8_t *rr_failure;
	struct gsm48_hdr *gh;


	if (conn->lchan != msg->lchan) {
		LOGP(DMSC, LOGL_ERROR, "Assignment failure should occur on primary lchan.\n");
		return;
	}

	/* stop the timer and release it */
	osmo_timer_del(&conn->T10);
	lchan_release(conn->secondary_lchan, 0, 1);
	conn->secondary_lchan = NULL;

	gh = msgb_l3(msg);
	if (msgb_l3len(msg) - sizeof(*gh) != 1) {
		LOGP(DMSC, LOGL_ERROR, "assignemnt failure unhandled: %lu\n",
		     msgb_l3len(msg) - sizeof(*gh));
		rr_failure = NULL;
	} else {
		rr_failure = &gh->data[0];
	}

	api->assign_fail(conn,
			 GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE,
			 rr_failure);
}
Esempio n. 7
0
/* Chapter 9.1.16 Handover complete */
static void handle_rr_ho_compl(struct msgb *msg)
{
	struct lchan_signal_data sig;
	struct gsm48_hdr *gh = msgb_l3(msg);

	DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n",
		rr_cause_name(gh->data[0]));

	sig.lchan = msg->lchan;
	sig.mr = NULL;
	osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig);
	/* FIXME: release old channel */
}
Esempio n. 8
0
/* Chapter 9.1.17 Handover Failure */
static void handle_rr_ho_fail(struct msgb *msg)
{
	struct lchan_signal_data sig;
	struct gsm48_hdr *gh = msgb_l3(msg);

	DEBUGP(DRR, "HANDOVER FAILED cause = %s\n",
		rr_cause_name(gh->data[0]));

	sig.lchan = msg->lchan;
	sig.mr = NULL;
	osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig);
	/* FIXME: release allocated new channel */
}
Esempio n. 9
0
/**
 * This is used to scan a message for extra functionality of the BSC. This
 * includes scanning for location updating requests/acceptd and then send
 * a welcome USSD message to the subscriber.
 */
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
	struct gsm48_hdr *gh = msgb_l3(msg);
	uint8_t pdisc = gh->proto_discr & 0x0f;
	uint8_t mtype = gh->msg_type & 0xbf;

	if (pdisc == GSM48_PDISC_MM) {
		if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST)
			handle_lu_request(conn, msg);
	} else if (pdisc == GSM48_PDISC_RR) {
		if (mtype == GSM48_MT_RR_PAG_RESP)
			handle_page_resp(conn, msg);
	}

	return 0;
}
Esempio n. 10
0
/* 9.1.18 IMMEDIATE ASSIGNMENT is received */
static int imm_ass(struct osmocom_ms *ms, struct msgb *msg)
{
	struct gsm48_imm_ass *ia = msgb_l3(msg);

	LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT:\n");

	if (state != SCAN_STATE_RACH) {
		LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
		return 0;
	}

	/* request ref */
	if (match_ra(ms, &ia->req_ref)) {
		return ta_result(ia->timing_advance);
	}
	LOGP(DRR, LOGL_INFO, "Request, but not for us.\n");

	return 0;
}
Esempio n. 11
0
/* we will need to stop the paging request */
static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
	uint8_t mi_type;
	char mi_string[GSM48_MI_SIZE];
	struct gsm48_hdr *gh;
	struct gsm48_pag_resp *resp;
	struct gsm_subscriber *subscr;

	if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
		LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
		return -1;
	}

	gh = msgb_l3(msg);
	resp = (struct gsm48_pag_resp *) &gh->data[0];

	gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
				mi_string, &mi_type);
	DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
		mi_type, mi_string);

	switch (mi_type) {
	case GSM_MI_TYPE_TMSI:
		subscr = subscr_active_by_tmsi(conn->bts->network,
					       tmsi_from_string(mi_string));
		break;
	case GSM_MI_TYPE_IMSI:
		subscr = subscr_active_by_imsi(conn->bts->network, mi_string);
		break;
	default:
		subscr = NULL;
		break;
	}

	if (!subscr) {
		LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
		return -1;
	}

	paging_request_stop(conn->bts, subscr, conn, msg);
	subscr_put(subscr);
	return 0;
}
Esempio n. 12
0
/* receive CCCH at RR layer */
static int pch_agch(struct osmocom_ms *ms, struct msgb *msg)
{
	struct gsm48_system_information_type_header *sih = msgb_l3(msg);

	switch (sih->system_information) {
	case GSM48_MT_RR_PAG_REQ_1:
	case GSM48_MT_RR_PAG_REQ_2:
	case GSM48_MT_RR_PAG_REQ_3:
		return 0;
	case GSM48_MT_RR_IMM_ASS:
		return imm_ass(ms, msg);
	case GSM48_MT_RR_IMM_ASS_EXT:
		return imm_ass_ext(ms, msg);
	case GSM48_MT_RR_IMM_ASS_REJ:
		return imm_ass_rej(ms, msg);
	default:
		return -EINVAL;
	}
}
Esempio n. 13
0
/* Take a B4 format message from L1 and create RSLms UNIT DATA IND */
static int send_rslms_rll_l3_ui(struct lapdm_msg_ctx *mctx, struct msgb *msg)
{
	uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg);
	struct abis_rsl_rll_hdr *rllh;

	/* Add the RSL + RLL header */
	msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
	msgb_push(msg, 2 + 2);
	rsl_rll_push_hdr(msg, RSL_MT_UNIT_DATA_IND, mctx->chan_nr,
		mctx->link_id, 1);
	rllh = (struct abis_rsl_rll_hdr *)msgb_l2(msg);

	rllh->data[0] = RSL_IE_TIMING_ADVANCE;
	rllh->data[1] = mctx->ta_ind;

	rllh->data[2] = RSL_IE_MS_POWER;
	rllh->data[3] = mctx->tx_power_ind;
	
	return rslms_sendmsg(msg, mctx->dl->entity);
}
Esempio n. 14
0
/* decide if we need to reroute a message as part of a silent call */
int silent_call_reroute(struct msgb *msg)
{
	struct gsm48_hdr *gh = msgb_l3(msg);
	u_int8_t pdisc = gh->proto_discr & 0x0f;
	int i;

	/* if we're not part of a silent call, never reroute */
	if (!msg->lchan->silent_call)
		return 0;

	/* check if we are a special message that is handled in openbsc */
	for (i = 0; i < ARRAY_SIZE(silent_call_accept); i++) {
		if (silent_call_accept[i].pdisc == pdisc &&
		    silent_call_accept[i].msg_type == gh->msg_type)
			return 0;
	}

	/* otherwise, reroute */
	return 1;
}
Esempio n. 15
0
static void handle_classmark_chg(struct gsm_subscriber_connection *conn,
				 struct msgb *msg)
{
	struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
	struct gsm48_hdr *gh = msgb_l3(msg);
	unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
	uint8_t cm2_len, cm3_len = 0;
	uint8_t *cm2, *cm3 = NULL;

	DEBUGP(DRR, "CLASSMARK CHANGE ");

	/* classmark 2 */
	cm2_len = gh->data[0];
	cm2 = &gh->data[1];
	DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);

	if (payload_len > cm2_len + 1) {
		/* we must have a classmark3 */
		if (gh->data[cm2_len+1] != 0x20) {
			DEBUGPC(DRR, "ERR CM3 TAG\n");
			return;
		}
		if (cm2_len > 3) {
			DEBUGPC(DRR, "CM2 too long!\n");
			return;
		}

		cm3_len = gh->data[cm2_len+2];
		cm3 = &gh->data[cm2_len+3];
		if (cm3_len > 14) {
			DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
			return;
		}
		DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
	}
	api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
}
Esempio n. 16
0
static void dispatch_dtap(struct gsm_subscriber_connection *conn,
			  uint8_t link_id, struct msgb *msg)
{
	struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
	struct gsm48_hdr *gh;
	uint8_t pdisc;
	int rc;

	if (msgb_l3len(msg) < sizeof(*gh)) {
		LOGP(DMSC, LOGL_ERROR, "Message too short for a GSM48 header.\n");
		return;
	}

	gh = msgb_l3(msg);
	pdisc = gh->proto_discr & 0x0f;

	/* the idea is to handle all RR messages here, and only hand
	 * MM/CC/SMS-CP/LCS up to the MSC.  Some messages like PAGING
	 * RESPONSE or CM SERVICE REQUEST will not be covered here, as
	 * they are only possible in the first L3 message of each L2
	 * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg()
	 * will call api->compl_l3() for it */
	switch (pdisc) {
	case GSM48_PDISC_RR:
		switch (gh->msg_type) {
		case GSM48_MT_RR_GPRS_SUSP_REQ:
			DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
			break;
		case GSM48_MT_RR_STATUS:
			LOGP(DRR, LOGL_NOTICE, "RR STATUS (cause: %s)\n",
				rr_cause_name(gh->data[0]));
			break;
		case GSM48_MT_RR_MEAS_REP:
			/* This shouldn't actually end up here, as RSL treats
			* L3 Info of 08.58 MEASUREMENT REPORT different by calling
			* directly into gsm48_parse_meas_rep */
			LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? ");
			break;
		case GSM48_MT_RR_HANDO_COMPL:
			handle_rr_ho_compl(msg);
			break;
		case GSM48_MT_RR_HANDO_FAIL:
			handle_rr_ho_fail(msg);
			break;
		case GSM48_MT_RR_CIPH_M_COMPL:
			if (api->cipher_mode_compl)
				api->cipher_mode_compl(conn, msg,
						conn->lchan->encr.alg_id);
			break;
		case GSM48_MT_RR_ASS_COMPL:
			handle_ass_compl(conn, msg);
			break;
		case GSM48_MT_RR_ASS_FAIL:
			handle_ass_fail(conn, msg);
			break;
		case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
			osmo_timer_del(&conn->T10);
			rc = gsm48_rx_rr_modif_ack(msg);
			if (rc < 0) {
				api->assign_fail(conn,
						 GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
						 NULL);
			} else if (rc >= 0) {
				api->assign_compl(conn, 0,
						  lchan_to_chosen_channel(conn->lchan),
						  conn->lchan->encr.alg_id,
						  chan_mode_to_speech(conn->lchan));
			}
			break;
		case GSM48_MT_RR_CLSM_CHG:
			handle_classmark_chg(conn, msg);
			break;
		case GSM48_MT_RR_APP_INFO:
			/* Passing RR APP INFO to MSC, not quite
			 * according to spec */
			if (api->dtap)
				api->dtap(conn, link_id, msg);
			break;
		default:
			/* Normally, a MSC should never receive RR
			 * messages, but we'd rather forward what we
			 * don't know than drop it... */
			LOGP(DRR, LOGL_NOTICE, "BSC: Passing unknown 04.08 "
			     "RR message type 0x%02x to MSC\n", gh->msg_type);
			if (api->dtap)
				api->dtap(conn, link_id, msg);
		}
		break;
	default:
		if (api->dtap)
			api->dtap(conn, link_id, msg);
		break;
	}
}
Esempio n. 17
0
static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
{
	struct gsm48_imm_ass *ia = msgb_l3(msg);
	uint8_t ch_type, ch_subch, ch_ts;
	int rv;

	/* Discard packet TBF assignement */
	if (ia->page_mode & 0xf0)
		return 0;

	/* FIXME: compare RA and GSM time with when we sent RACH req */

	rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);

	if (!ia->chan_desc.h0.h) {
		/* Non-hopping */
		uint16_t arfcn;

		arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);

		DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
			"ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
			ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
			ia->chan_desc.h0.tsc);

		if (ch_ts >= 4) {
			DEBUGPC(DRR, "UNSUPPORTED!\n");
			return 0;
		}

		/* request L1 to go to dedicated mode on assigned channel */
		rv = l1ctl_tx_dm_est_req_h0(ms,
			arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc);
	} else {
		/* Hopping */
		uint8_t maio, hsn, ma_len;
		uint16_t ma[64], arfcn;
		int i, j, k;

		hsn = ia->chan_desc.h1.hsn;
		maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);

		DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
			"HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
			ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
			ia->chan_desc.h1.tsc);

		/* decode mobile allocation */
		ma_len = 0;
		for (i=1, j=0; i<=1024; i++) {
			arfcn = i & 1023;
			if (app_state.cell_arfcns[arfcn].mask & 0x01) {
				k = ia->mob_alloc_len - (j>>3) - 1;
				if (ia->mob_alloc[k] & (1 << (j&7))) {
					ma[ma_len++] = arfcn;
				}
				j++;
			}
		}

		if (ch_ts >= 4) {
			DEBUGPC(DRR, "UNSUPPORTED!\n");
			return 0;
		}

		/* request L1 to go to dedicated mode on assigned channel */
		rv = l1ctl_tx_dm_est_req_h1(ms,
			maio, hsn, ma, ma_len,
			ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc);
	}
Esempio n. 18
0
/**
 * This method used to send a l1ctl_tx_dm_est_req_h0 or
 * a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
 * assignment. The code has been removed.
 */
static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
{
	struct gsm48_imm_ass *ia = msgb_l3(msg);
	uint8_t ch_type, ch_subch, ch_ts;
	int rv;

	/* Discard packet TBF assignement */
	if (ia->page_mode & 0xf0)
		return 0;

	/* If we're not ready yet, or just busy ... */
	if ((!app_state.has_si1) || (app_state.dch_state != DCH_NONE))
		return 0;

	rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);

	if (!ia->chan_desc.h0.h) {
		/* Non-hopping */
		uint16_t arfcn;

		arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);

		LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
			"ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
			ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
			ia->chan_desc.h0.tsc);

		/* request L1 to go to dedicated mode on assigned channel */
		rv = l1ctl_tx_dm_est_req_h0(ms,
			arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
			GSM48_CMODE_SIGN, 0);
	} else {
		/* Hopping */
		uint8_t maio, hsn, ma_len;
		uint16_t ma[64], arfcn;
		int i, j, k;

		hsn = ia->chan_desc.h1.hsn;
		maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);

		LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
			"HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
			ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
			ia->chan_desc.h1.tsc);

		/* decode mobile allocation */
		ma_len = 0;
		for (i=1, j=0; i<=1024; i++) {
			arfcn = i & 1023;
			if (app_state.cell_arfcns[arfcn].mask & 0x01) {
				k = ia->mob_alloc_len - (j>>3) - 1;
				if (ia->mob_alloc[k] & (1 << (j&7))) {
					ma[ma_len++] = arfcn;
				}
				j++;
			}
		}

		/* request L1 to go to dedicated mode on assigned channel */
		rv = l1ctl_tx_dm_est_req_h1(ms,
			maio, hsn, ma, ma_len,
			ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
			GSM48_CMODE_SIGN, 0);
	}
Esempio n. 19
0
/* receive BCCH at RR layer */
static int bcch(struct osmocom_ms *ms, struct msgb *msg)
{
	struct gsm48_sysinfo *s = &sysinfo;
	struct gsm48_system_information_type_header *sih = msgb_l3(msg);
	uint8_t ccch_mode;

	if (msgb_l3len(msg) != 23) {
		LOGP(DRR, LOGL_NOTICE, "Invalid BCCH message length\n");
		return -EINVAL;
	}
	switch (sih->system_information) {
	case GSM48_MT_RR_SYSINFO_1:
		if (!memcmp(sih, s->si1_msg, sizeof(s->si1_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
		gsm48_decode_sysinfo1(s,
			(struct gsm48_system_information_type_1 *) sih,
			msgb_l3len(msg));
		return new_sysinfo();
	case GSM48_MT_RR_SYSINFO_2:
		if (!memcmp(sih, s->si2_msg, sizeof(s->si2_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2\n");
		gsm48_decode_sysinfo2(s,
			(struct gsm48_system_information_type_2 *) sih,
			msgb_l3len(msg));
		return new_sysinfo();
	case GSM48_MT_RR_SYSINFO_2bis:
		if (!memcmp(sih, s->si2b_msg, sizeof(s->si2b_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2bis\n");
		gsm48_decode_sysinfo2bis(s,
			(struct gsm48_system_information_type_2bis *) sih,
			msgb_l3len(msg));
		return new_sysinfo();
	case GSM48_MT_RR_SYSINFO_2ter:
		if (!memcmp(sih, s->si2t_msg, sizeof(s->si2t_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2ter\n");
		gsm48_decode_sysinfo2ter(s,
			(struct gsm48_system_information_type_2ter *) sih,
			msgb_l3len(msg));
		return new_sysinfo();
	case GSM48_MT_RR_SYSINFO_3:
		if (!memcmp(sih, s->si3_msg, sizeof(s->si3_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3\n");
		gsm48_decode_sysinfo3(s,
			(struct gsm48_system_information_type_3 *) sih,
			msgb_l3len(msg));
		ccch_mode = (s->ccch_conf == 1) ? CCCH_MODE_COMBINED :
			CCCH_MODE_NON_COMBINED;
		LOGP(DRR, LOGL_INFO, "Changing CCCH_MODE to %d\n", ccch_mode);
		l1ctl_tx_ccch_mode_req(ms, ccch_mode);
		return new_sysinfo();
	case GSM48_MT_RR_SYSINFO_4:
		if (!memcmp(sih, s->si4_msg, sizeof(s->si4_msg)))
			return 0;
		LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4\n");
		gsm48_decode_sysinfo4(s,
			(struct gsm48_system_information_type_4 *) sih,
			msgb_l3len(msg));
		return new_sysinfo();
	default:
		return -EINVAL;
	}
}