int lwm2m_data_parse(lwm2m_uri_t * uriP, uint8_t * buffer, size_t bufferLen, lwm2m_media_type_t format, lwm2m_data_t ** dataP) { int res; LOG_ARG("format: %s, bufferLen: %d", STR_MEDIA_TYPE(format), bufferLen); LOG_URI(uriP); switch (format) { case LWM2M_CONTENT_TEXT: if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) return 0; *dataP = lwm2m_data_new(1); if (*dataP == NULL) return 0; (*dataP)->id = uriP->resourceId; (*dataP)->type = LWM2M_TYPE_STRING; res = prv_setBuffer(*dataP, buffer, bufferLen); if (res == 0) { lwm2m_data_free(1, *dataP); *dataP = NULL; } return res; case LWM2M_CONTENT_OPAQUE: if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) return 0; *dataP = lwm2m_data_new(1); if (*dataP == NULL) return 0; (*dataP)->id = uriP->resourceId; (*dataP)->type = LWM2M_TYPE_OPAQUE; res = prv_setBuffer(*dataP, buffer, bufferLen); if (res == 0) { lwm2m_data_free(1, *dataP); *dataP = NULL; } return res; #ifdef LWM2M_OLD_CONTENT_FORMAT_SUPPORT case LWM2M_CONTENT_TLV_OLD: #endif case LWM2M_CONTENT_TLV: return tlv_parse(buffer, bufferLen, dataP); #ifdef LWM2M_SUPPORT_JSON #ifdef LWM2M_OLD_CONTENT_FORMAT_SUPPORT case LWM2M_CONTENT_JSON_OLD: #endif case LWM2M_CONTENT_JSON: return json_parse(uriP, buffer, bufferLen, dataP); #endif default: return 0; } }
static int dump_fcp_template_msg(struct msgb *msg) { struct tlv_parsed tp; int rc; rc = tlv_parse(&tp, &ts102221_fcp_tlv_def, msgb_apdu_de(msg)+2, msgb_apdu_le(msg)-2, 0, 0); if (rc < 0) return rc; return dump_fcp_template(&tp); }
void handle_rr(struct session_info *s, struct gsm48_hdr *dtap, unsigned len, uint32_t fn) { struct gsm48_system_information_type_6 *si6; struct tlv_parsed tp; s->rat = RAT_GSM; assert(s->new_msg); if (!len) { return; } switch (dtap->msg_type) { case GSM48_MT_RR_SYSINFO_1: SET_MSG_INFO(s, "SYSTEM INFO 1"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_2: SET_MSG_INFO(s, "SYSTEM INFO 2"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_2bis: SET_MSG_INFO(s, "SYSTEM INFO 2bis"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_2ter: SET_MSG_INFO(s, "SYSTEM INFO 2ter"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_2quater: SET_MSG_INFO(s, "SYSTEM INFO 2quater"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_3: SET_MSG_INFO(s, "SYSTEM INFO 3"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_4: SET_MSG_INFO(s, "SYSTEM INFO 4"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_5: SET_MSG_INFO(s, "SYSTEM INFO 5"); rand_check((uint8_t *)dtap, 18, &s->si5, s->cipher); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_5bis: SET_MSG_INFO(s, "SYSTEM INFO 5bis"); rand_check((uint8_t *)dtap, 18, &s->si5bis, s->cipher); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_5ter: SET_MSG_INFO(s, "SYSTEM INFO 5ter"); rand_check((uint8_t *)dtap, 18, &s->si5ter, s->cipher); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_6: SET_MSG_INFO(s, "SYSTEM INFO 6"); rand_check((uint8_t *)dtap, 18, &s->si6, s->cipher); si6 = (struct gsm48_system_information_type_6 *) dtap; handle_lai(s, (uint8_t*)&si6->lai, htons(si6->cell_identity)); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_SYSINFO_13: SET_MSG_INFO(s, "SYSTEM INFO 13"); handle_sysinfo(s, dtap, len); break; case GSM48_MT_RR_CHAN_REL: SET_MSG_INFO(s, "CHANNEL RELEASE"); if (s->cipher && !s->fc.enc_rand) s->fc.predict++; s->release = 1; s->rr_cause = dtap->data[0]; if ((len > 3) && ((dtap->data[1] & 0xf0) == 0xc0)) s->have_gprs = 1; session_reset(&s[0], 0); if (auto_reset) { s[1].new_msg = NULL; } break; case GSM48_MT_RR_CLSM_ENQ: SET_MSG_INFO(s, "CLASSMARK ENQUIRY"); break; case GSM48_MT_RR_MEAS_REP: SET_MSG_INFO(s, "MEASUREMENT REPORT"); break; case GSM48_MT_RR_CLSM_CHG: SET_MSG_INFO(s, "CLASSMARK CHANGE"); handle_classmark(s, &dtap->data[1], 2); break; case GSM48_MT_RR_PAG_REQ_1: SET_MSG_INFO(s, "PAGING REQ 1"); handle_paging1(dtap, len); break; case GSM48_MT_RR_PAG_REQ_2: SET_MSG_INFO(s, "PAGING REQ 2"); handle_paging2(dtap, len); break; case GSM48_MT_RR_PAG_REQ_3: SET_MSG_INFO(s, "PAGING REQ 3"); handle_paging3(); break; case GSM48_MT_RR_IMM_ASS: SET_MSG_INFO(s, "IMM ASSIGNMENT"); break; case GSM48_MT_RR_IMM_ASS_EXT: SET_MSG_INFO(s, "IMM ASSIGNMENT EXT"); break; case GSM48_MT_RR_IMM_ASS_REJ: SET_MSG_INFO(s, "IMM ASSIGNMENT REJECT"); break; case GSM48_MT_RR_PAG_RESP: session_reset(s, 1); SET_MSG_INFO(s, "PAGING RESPONSE"); handle_pag_resp(s, dtap->data); break; case GSM48_MT_RR_HANDO_CMD: SET_MSG_INFO(s, "HANDOVER COMMAND"); parse_assignment(dtap, len, s->cell_arfcns, &s->ga); s->handover = 1; s->use_jump = 2; break; case GSM48_MT_RR_HANDO_COMPL: SET_MSG_INFO(s, "HANDOVER COMPLETE"); break; case GSM48_MT_RR_ASS_CMD: SET_MSG_INFO(s, "ASSIGNMENT COMMAND"); if ((s->fc.enc-s->fc.enc_null-s->fc.enc_si) == 1) s->forced_ho = 1; parse_assignment(dtap, len, s->cell_arfcns, &s->ga); s->assignment = 1; s->use_jump = 1; break; case GSM48_MT_RR_ASS_COMPL: SET_MSG_INFO(s, "ASSIGNMENT COMPLETE"); s->assign_complete = 1; break; case GSM48_MT_RR_CIPH_M_COMPL: SET_MSG_INFO(s, "CIPHER MODE COMPLETE"); if (s->cipher_missing < 0) { s->cipher_missing = 0; } else { s->cipher_missing = 1; } if (!s->cm_comp_first_fn) { if (fn) { s->cm_comp_first_fn = fn; } else { s->cm_comp_first_fn = GSM_MAX_FN; } } if (fn) { s->cm_comp_last_fn = fn; } else { s->cm_comp_last_fn = GSM_MAX_FN; } s->cm_comp_count++; if (dtap->data[0] == 0x2b) return; /* get IMEISV */ tlv_parse(&tp, &gsm48_rr_att_tlvdef, dtap->data, len-2, 0, 0); if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) { uint8_t *v = (uint8_t *) TLVP_VAL(&tp, GSM48_IE_MOBILE_ID); handle_mi(s, &v[1], v[0], 0); s->cmc_imeisv = 1; } break; case GSM48_MT_RR_GPRS_SUSP_REQ: SET_MSG_INFO(s, "GPRS SUSPEND"); s->have_gprs = 1; //tlli //rai (lai+rac) break; case GSM48_MT_RR_CIPH_M_CMD: if (!s->cm_cmd_fn) { if (fn) { s->cm_cmd_fn = fn; } else { s->cm_cmd_fn = GSM_MAX_FN; } } if (dtap->data[0] & 1) { s->cipher = 1 + ((dtap->data[0]>>1) & 7); if (!not_zero(s->key, 8)) s->decoded = 0; } SET_MSG_INFO(s, "CIPHER MODE COMMAND, A5/%u", s->cipher); if (dtap->data[0] & 0x10) { s->cmc_imeisv = 1; if (s->cipher && !s->fc.enc_rand) s->fc.predict++; } s->cipher_missing = -1; break; case 0x60: SET_MSG_INFO(s, "UTRAN CLASSMARK"); break; default: SET_MSG_INFO(s, "UNKNOWN RR (%02x)", dtap->msg_type); s->unknown = 1; }
void handle_cc(struct session_info *s, struct gsm48_hdr *dtap, unsigned len, uint8_t ul) { struct tlv_parsed tp; s->call = 1; s->call_presence = 1; switch (dtap->msg_type & 0x3f) { case 0x01: SET_MSG_INFO(s, "CALL ALERTING"); break; case 0x02: SET_MSG_INFO(s, "CALL PROCEEDING"); if (s->cipher && !s->fc.enc_rand && !ul) s->fc.predict++; if (!ul) s->mo = 1; break; case 0x03: SET_MSG_INFO(s, "CALL PROGRESS"); break; case 0x05: SET_MSG_INFO(s, "CALL SETUP"); if (!ul) s->mt = 1; else s->mo = 1; /* get MSISDN */ tlv_parse(&tp, &gsm48_att_tlvdef, dtap->data, len-2, 0, 0); if (TLVP_PRESENT(&tp, GSM48_IE_CALLING_BCD)) { uint8_t *v = (uint8_t *) TLVP_VAL(&tp, GSM48_IE_CALLING_BCD); uint8_t v_len = TLVP_LEN(&tp, GSM48_IE_CALLING_BCD); handle_address(v, v_len, s->msisdn, 0); } if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) { uint8_t *v = (uint8_t *) TLVP_VAL(&tp, GSM48_IE_CALLED_BCD); uint8_t v_len = TLVP_LEN(&tp, GSM48_IE_CALLED_BCD); handle_address(v, v_len, s->msisdn, 0); } break; case 0x07: SET_MSG_INFO(s, "CALL CONNECT"); break; case 0x08: SET_MSG_INFO(s, "CALL CONFIRMED"); if (ul) s->mt = 1; else s->mo = 1; break; case 0x0f: SET_MSG_INFO(s, "CALL CONNECT ACK"); break; case 0x25: SET_MSG_INFO(s, "CALL DISCONNECT"); break; case 0x2a: SET_MSG_INFO(s, "CALL RELEASE COMPLETE"); break; case 0x2d: SET_MSG_INFO(s, "CALL RELEASE"); break; case 0x3a: SET_MSG_INFO(s, "CALL FACILITY"); break; case 0x3d: SET_MSG_INFO(s, "CALL STATUS"); break; default: SET_MSG_INFO(s, "UNKNOWN CC (%02x)", dtap->msg_type & 0x3f); s->unknown = 1; } }
/* * Handle the assignment request message. * * See §3.2.1.1 for the message type */ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int length) { struct msgb *resp; struct osmo_msc_data *msc; struct tlv_parsed tp; uint8_t *data; uint8_t timeslot; uint8_t multiplex; enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN; int i, supported, port, full_rate = -1; if (!conn->conn) { LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); return -1; } tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0); if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) { LOGP(DMSC, LOGL_ERROR, "Mandatory channel type not present.\n"); goto reject; } if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n"); goto reject; } conn->cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE))); timeslot = conn->cic & 0x1f; multiplex = (conn->cic & ~0x1f) >> 5; /* * Currently we only support a limited subset of all * possible channel types. The limitation ends by not using * multi-slot, limiting the channel coding, speech... */ if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) { LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n", TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE)); goto reject; } /* * Try to figure out if we support the proposed speech codecs. For * now we will always pick the full rate codecs. */ data = (uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE); if ((data[0] & 0xf) != 0x1) { LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]); goto reject; } /* * go through the list of preferred codecs of our gsm network * and try to find it among the permitted codecs. If we found * it we will send chan_mode to the right mode and break the * inner loop. The outer loop will exit due chan_mode having * the correct value. */ full_rate = 0; msc = conn->msc; for (supported = 0; chan_mode == GSM48_CMODE_SIGN && supported < msc->audio_length; ++supported) { int perm_val = audio_support_to_gsm88(msc->audio_support[supported]); for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) { if ((data[i] & 0x7f) == perm_val) { chan_mode = gsm88_to_chan_mode(perm_val); full_rate = (data[i] & 0x4) == 0; break; } else if ((data[i] & 0x80) == 0x00) { break; } } } if (chan_mode == GSM48_CMODE_SIGN) { LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n"); goto reject; } /* map it to a MGCP Endpoint and a RTP port */ port = mgcp_timeslot_to_endpoint(multiplex, timeslot); conn->rtp_port = rtp_calculate_port(port, msc->rtp_base); return gsm0808_assign_req(conn->conn, chan_mode, full_rate); reject: resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); if (!resp) { LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n"); return -1; } bsc_queue_for_msc(conn, resp); return -1; }
/* * GSM 08.08 § 3.4.7 cipher mode handling. We will have to pick * the cipher to be used for this. In case we are already using * a cipher we will have to send cipher mode reject to the MSC, * otherwise we will have to pick something that we and the MS * is supporting. Currently we are doing it in a rather static * way by picking one ecnryption or no encrytpion. */ static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int payload_length) { uint16_t len; struct gsm_network *network = NULL; const uint8_t *data; struct tlv_parsed tp; struct msgb *resp; int reject_cause = -1; int include_imeisv = 1; if (!conn->conn) { LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); goto reject; } if (conn->ciphering_handled) { LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n"); goto reject; } conn->ciphering_handled = 1; tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0); if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) { LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n"); goto reject; } /* * check if our global setting is allowed * - Currently we check for A5/0 and A5/1 * - Copy the key if that is necessary * - Otherwise reject */ len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION); if (len < 1) { LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n"); goto reject; } network = conn->conn->bts->network; data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION); if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)) include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1; if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) { gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv); } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) { gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv); } else { LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n"); goto reject; } return 0; reject: resp = gsm0808_create_cipher_reject(reject_cause); if (!resp) { LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n"); return -1; } bsc_queue_for_msc(conn, resp); return -1; }
/* GSM 08.08 § 3.2.1.19 */ static int bssmap_handle_paging(struct osmo_msc_data *msc, struct msgb *msg, unsigned int payload_length) { struct gsm_subscriber *subscr; struct tlv_parsed tp; char mi_string[GSM48_MI_SIZE]; uint32_t tmsi = GSM_RESERVED_TMSI; unsigned int lac = GSM_LAC_RESERVED_ALL_BTS; uint8_t data_length; const uint8_t *data; uint8_t chan_needed = RSL_CHANNEED_ANY; tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0); if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) { LOGP(DMSC, LOGL_ERROR, "Mandatory IMSI not present.\n"); return -1; } else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) { LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n"); return -1; } if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) { LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER LIST not present.\n"); return -1; } if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI) && TLVP_LEN(&tp, GSM0808_IE_TMSI) == 4) { tmsi = ntohl(tlvp_val32_unal(&tp, GSM0808_IE_TMSI)); } /* * parse the IMSI */ gsm48_mi_to_string(mi_string, sizeof(mi_string), TLVP_VAL(&tp, GSM0808_IE_IMSI), TLVP_LEN(&tp, GSM0808_IE_IMSI)); /* * parse the cell identifier list */ data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); /* * Support paging to all network or one BTS at one LAC */ if (data_length == 3 && data[0] == CELL_IDENT_LAC) { lac = ntohs(read_data16(&data[1])); } else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) { LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", osmo_hexdump(data, data_length)); return -1; } if (TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_NEEDED) && TLVP_LEN(&tp, GSM0808_IE_CHANNEL_NEEDED) == 1) chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03; if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) { LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n"); } subscr = subscr_get_or_create(msc->network->subscr_group, mi_string); if (!subscr) { LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string); return -1; } subscr->lac = lac; subscr->tmsi = tmsi; LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac); bsc_grace_paging_request(subscr, chan_needed, msc); return 0; }
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++) {