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++) {
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; }; }
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"); }