void parse_assignment(struct gsm48_hdr *hdr, unsigned len, struct gsm_sysinfo_freq *cell_arfcns, struct gsm_assignment *ga)
{
	struct gsm48_ass_cmd *ac;
	struct gsm48_ho_cmd *hoc;
	struct gsm48_chan_desc *cd = NULL;
	int payload_len = 0; 
	uint8_t *payload_data = NULL;
	struct tlv_parsed tp;
	uint8_t *ma = 0;
	uint8_t ma_len;
	uint8_t ch_type, ch_subch, ch_ts;
	unsigned i, mask;

	if (!ga)
		return;

	memset(ga, 0, sizeof(*ga));

	/* handover */
	if (hdr->msg_type == 0x2b) {
		if (len < (sizeof(*hdr) + sizeof(*hoc))) {
			return;
		}
		hoc = (struct gsm48_ho_cmd *) hdr->data;
		cd = &hoc->chan_desc;
		payload_len = len - sizeof(*hdr) - sizeof(*hoc);
		payload_data = hoc->data;
		ga->bcch_arfcn = hoc->cell_desc.arfcn_lo;
		ga->bcch_arfcn |= (hoc->cell_desc.arfcn_hi << 8);
	}

	/* assignment */
	if (hdr->msg_type == 0x2e) {
		if (len < (sizeof(*hdr) + sizeof(*ac))) {
			return;
		}
		ac = (struct gsm48_ass_cmd *) hdr->data;
		cd = &ac->chan_desc;
		payload_len = len - sizeof(*hdr) - sizeof(*ac);
		payload_data = ac->data;
	}

	if (!cd)
		return;

	if (!payload_len)
		return;
		
	/* Parse TLV in the message */
	tlv_parse(&tp, &gsm48_rr_att_tlvdef, payload_data, payload_len, 0, 0);

	ma_len = 0;
	ma = NULL;
	mask = 0;

	/* Cell channel description */
	if (TLVP_PRESENT(&tp, GSM48_IE_CELL_CH_DESC)) {
		const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_CELL_CH_DESC);
		uint8_t len = TLVP_LEN(&tp, GSM48_IE_CELL_CH_DESC);
		gsm48_decode_freq_list(cell_arfcns, (uint8_t *) v, len, 0xff, 0x02);
		mask = 0x02;
	} else if (TLVP_PRESENT(&tp, GSM48_IE_MA_AFTER)) {
		/* Mobile allocation */
		const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_MA_AFTER);
		uint8_t len = TLVP_LEN(&tp, GSM48_IE_MA_AFTER);

		ma_len = len;
		ma = (uint8_t *) v;
		mask = 0x01;
	} else if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_L_AFTER)) {
		/* Frequency list after time */
		const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_FREQ_L_AFTER);
		uint8_t len = TLVP_LEN(&tp, GSM48_IE_FREQ_L_AFTER);
		gsm48_decode_freq_list(cell_arfcns, (uint8_t *) v, len, 0xff, 0x04);
		ma_len = 0;
		ma = NULL;
		mask = 0x04;
	} else {
		/* Use the old one */
		for (i=0; i<1024; i++) {
			cell_arfcns[i].mask &= ~0x02;
			if (cell_arfcns[i].mask & 0x01) {
				cell_arfcns[i].mask |= 0x02;
				mask = 0x02;
			}
		}
	}

	/* Channel mode (HR/FR/EFR/AMR) */
	if (TLVP_PRESENT(&tp, GSM48_IE_CHANMODE_1)) {
		const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_CHANMODE_1);
		//uint8_t len = TLVP_LEN(&tp, GSM48_IE_CHANMODE_1);
		ga->chan_mode = v[0];
	}

	/* Multirate configuration */
	if (TLVP_PRESENT(&tp, GSM48_IE_MUL_RATE_CFG)) {
		const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_MUL_RATE_CFG);
		//uint8_t len = TLVP_LEN(&tp, GSM48_IE_MUL_RATE_CFG);
		ga->rate_conf = v[1];
	}

	rsl_dec_chan_nr(cd->chan_nr, &ch_type, &ch_subch, &ch_ts);

	ga->h = cd->h0.h;
	ga->chan_nr = cd->chan_nr;

	if (!ga->h) {
		/* Non-Hopping */
		uint16_t arfcn = cd->h0.arfcn_low | (cd->h0.arfcn_high << 8);

		ga->tsc = cd->h0.tsc;
		ga->h0.band_arfcn = arfcn;
	} else {
		/* Hopping */
		uint16_t arfcn;
		int i, j, k;

		ga->tsc = cd->h1.tsc;
		ga->h1.maio = cd->h1.maio_low | (cd->h1.maio_high << 2);;
		ga->h1.hsn = cd->h1.hsn;
		ga->h1.ma_len = 0;

		/* decode mobile allocation */
		if (ma) {
			if (ma_len == 0) {
				return;
			}
			for (i=1, j=0; i<=1024; i++) {
				arfcn = i & 1023;
				if (cell_arfcns[arfcn].mask & mask) {
					k = ma_len - (j>>3) - 1;
					if (ma[k] & (1 << (j&7))) {
						ga->h1.ma[ga->h1.ma_len++] = arfcn;
					}
					j++;
				}
			}
			if (ga->h1.ma_len == 0) {
				/* cell information not found */
				/* just compute ma_len */
				for (i=0; i<(ma_len*8); i++){
					int k = i/8;
	
					if (ma[k] & (1 << (i&7))) {
						ga->h1.ma_len++;
					}
				}
			}
		} else {
			for (i=1; i<=1024; i++) {
Example #2
0
static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
{
	struct gsm48_system_information_type_header *si_hdr;
	si_hdr = (struct gsm48_system_information_type_header *) data;

	/* GSM 05.02 §6.3.1.3 Mapping of BCCH data */
	switch (si_hdr->system_information) {
	case GSM48_MT_RR_SYSINFO_1:
#ifdef BCCH_TC_CHECK
		if (tc != 0)
			LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
#endif
		if (!app_state.has_si1) {
			struct gsm48_system_information_type_1 *si1 =
				(struct gsm48_system_information_type_1 *)data;

			gsm48_decode_freq_list(app_state.cell_arfcns,
			                       si1->cell_channel_description,
					       sizeof(si1->cell_channel_description),
					       0xff, 0x01);

			app_state.has_si1 = 1;
			LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
		}
		break;
	case GSM48_MT_RR_SYSINFO_2:
#ifdef BCCH_TC_CHECK
		if (tc != 1)
			LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_3:
#ifdef BCCH_TC_CHECK
		if (tc != 2 && tc != 6)
			LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
#endif
		if (app_state.ccch_mode == CCCH_MODE_NONE) {
			struct gsm48_system_information_type_3 *si3 =
				(struct gsm48_system_information_type_3 *)data;

			if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
				app_state.ccch_mode = CCCH_MODE_COMBINED;
			else
				app_state.ccch_mode = CCCH_MODE_NON_COMBINED;

			l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
		}
		break;
	case GSM48_MT_RR_SYSINFO_4:
#ifdef BCCH_TC_CHECK
		if (tc != 3 && tc != 7)
			LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_5:
		break;
	case GSM48_MT_RR_SYSINFO_6:
		break;
	case GSM48_MT_RR_SYSINFO_7:
#ifdef BCCH_TC_CHECK
		if (tc != 7)
			LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_8:
#ifdef BCCH_TC_CHECK
		if (tc != 3)
			LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_9:
#ifdef BCCH_TC_CHECK
		if (tc != 4)
			LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_13:
#ifdef BCCH_TC_CHECK
		if (tc != 4 && tc != 0)
			LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_16:
#ifdef BCCH_TC_CHECK
		if (tc != 6)
			LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_17:
#ifdef BCCH_TC_CHECK
		if (tc != 2)
			LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_2bis:
#ifdef BCCH_TC_CHECK
		if (tc != 5)
			LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_2ter:
#ifdef BCCH_TC_CHECK
		if (tc != 5 && tc != 4)
			LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
#endif
		break;
	case GSM48_MT_RR_SYSINFO_5bis:
		break;
	case GSM48_MT_RR_SYSINFO_5ter:
		break;
	default:
		LOGP(DRR, LOGL_ERROR, "Unknown SI: %d\n",
		     si_hdr->system_information);
		break;
	};
}
Example #3
0
static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
{
	struct gsm48_system_information_type_header *si_hdr;
	si_hdr = (struct gsm48_system_information_type_header *) data;

	/* GSM 05.02 §6.3.1.3 Mapping of BCCH data */
	switch (si_hdr->system_information) {
	case GSM48_MT_RR_SYSINFO_1:
		fprintf(stderr, "\tSI1");
#ifdef BCCH_TC_CHECK
		if (tc != 0)
			fprintf(stderr, " on wrong TC");
#endif
		if (!app_state.has_si1) {
			struct gsm48_system_information_type_1 *si1 =
				(struct gsm48_system_information_type_1 *)data;

			gsm48_decode_freq_list(&app_state.cell_arfcns,
			                       si1->cell_channel_description,
					       sizeof(si1->cell_channel_description),
					       0xff, 0x01);

			app_state.has_si1 = 1;
		}
		break;
	case GSM48_MT_RR_SYSINFO_2:
		fprintf(stderr, "\tSI2");
#ifdef BCCH_TC_CHECK
		if (tc != 1)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_3:
		fprintf(stderr, "\tSI3");
#ifdef BCCH_TC_CHECK
		if (tc != 2 && tc != 6)
			fprintf(stderr, " on wrong TC");
#endif
		if (app_state.ccch_mode == CCCH_MODE_NONE) {
			struct gsm48_system_information_type_3 *si3 =
				(struct gsm48_system_information_type_3 *)data;

			if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
				app_state.ccch_mode = CCCH_MODE_COMBINED;
			else
				app_state.ccch_mode = CCCH_MODE_NON_COMBINED;

			l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
		}
		break;
	case GSM48_MT_RR_SYSINFO_4:
		fprintf(stderr, "\tSI4");
#ifdef BCCH_TC_CHECK
		if (tc != 3 && tc != 7)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_5:
		fprintf(stderr, "\tSI5");
		break;
	case GSM48_MT_RR_SYSINFO_6:
		fprintf(stderr, "\tSI6");
		break;
	case GSM48_MT_RR_SYSINFO_7:
		fprintf(stderr, "\tSI7");
#ifdef BCCH_TC_CHECK
		if (tc != 7)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_8:
		fprintf(stderr, "\tSI8");
#ifdef BCCH_TC_CHECK
		if (tc != 3)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_9:
		fprintf(stderr, "\tSI9");
#ifdef BCCH_TC_CHECK
		if (tc != 4)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_13:
		fprintf(stderr, "\tSI13");
#ifdef BCCH_TC_CHECK
		if (tc != 4 && tc != 0)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_16:
		fprintf(stderr, "\tSI16");
#ifdef BCCH_TC_CHECK
		if (tc != 6)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_17:
		fprintf(stderr, "\tSI17");
#ifdef BCCH_TC_CHECK
		if (tc != 2)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_2bis:
		fprintf(stderr, "\tSI2bis");
#ifdef BCCH_TC_CHECK
		if (tc != 5)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_2ter:
		fprintf(stderr, "\tSI2ter");
#ifdef BCCH_TC_CHECK
		if (tc != 5 && tc != 4)
			fprintf(stderr, " on wrong TC");
#endif
		break;
	case GSM48_MT_RR_SYSINFO_5bis:
		fprintf(stderr, "\tSI5bis");
		break;
	case GSM48_MT_RR_SYSINFO_5ter:
		fprintf(stderr, "\tSI5ter");
		break;
	default:
		fprintf(stderr, "\tUnknown SI");
		break;
	};

	fprintf(stderr, "\n");
}