void test_replay_gprs_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh; struct gprs_llc_hdr_parsed ph; uint32_t tlli; if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) return; gprs_llc_hdr_parse(&ph, TLVP_VAL(tp, BSSGP_IE_LLC_PDU), TLVP_LEN(tp, BSSGP_IE_LLC_PDU)); budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg); tlli = ntohl(budh->tlli); /* all messages we should get, should be for a foreign tlli */ OSMO_ASSERT(gprs_tlli_type(tlli) == TLLI_FOREIGN); printf("TLLI(0x%08x) is foreign!\n", tlli); OSMO_ASSERT(ph.cmd == GPRS_LLC_UI); OSMO_ASSERT(ph.sapi == 1); OSMO_ASSERT(ph.seq_tx == next_wanted_nu++); /* this test just wants to see messages... no further data is sent */ if (next_wanted_nu == 6) { printf("GPRS attach with increasing N(U) done.\n"); gprs_test_success(pcu); } }
static int dump_fcp_template(struct tlv_parsed *tp) { int i; for (i = 0; i < ARRAY_SIZE(tp->lv); i++) { if (TLVP_PRESENT(tp, i)) printf("Tag 0x%02x (%s): %s\n", i, get_value_string(ts102221_fcp_vals, i), osmo_hexdump(TLVP_VAL(tp, i), TLVP_LEN(tp, i))); } return 0; }
static int ussd_read_cb(struct osmo_fd *bfd) { struct bsc_nat_ussd_con *conn = bfd->data; struct msgb *msg = NULL; struct ipaccess_head *hh; int ret; ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg); if (ret <= 0) { if (ret == -EAGAIN) return 0; LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); bsc_nat_ussd_destroy(conn); return -1; } LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); hh = (struct ipaccess_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { struct tlv_parsed tvp; int ret; ret = ipa_ccm_idtag_parse(&tvp, (unsigned char *) msg->l2h + 2, msgb_l2len(msg) - 2); if (ret < 0) { LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " "message with malformed TLVs\n"); msgb_free(msg); return ret; } if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) ussd_auth_con(&tvp, conn); } else if (msg->l2h[0] == IPAC_MSGT_PING) { LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n"); ussd_pong(conn); } else { LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]); } msgb_free(msg); } else if (hh->proto == IPAC_PROTO_SCCP) { forward_sccp(conn->nat, msg); } else { msgb_free(msg); } return 0; }
static int ussd_read_cb(struct osmo_fd *bfd) { int error; struct bsc_nat_ussd_con *conn = bfd->data; struct msgb *msg = ipaccess_read_msg(bfd, &error); struct ipaccess_head *hh; if (!msg) { LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); bsc_nat_ussd_destroy(conn); return -1; } LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); hh = (struct ipaccess_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { struct tlv_parsed tvp; int ret; ret = ipaccess_idtag_parse(&tvp, (unsigned char *) msg->l2h + 2, msgb_l2len(msg) - 2); if (ret < 0) { LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " "message with malformed TLVs\n"); return ret; } if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) ussd_auth_con(&tvp, conn); } msgb_free(msg); } else if (hh->proto == IPAC_PROTO_SCCP) { forward_sccp(conn->nat, msg); } else { msgb_free(msg); } return 0; }
static int parse_imsi(struct tlv_parsed *tp, char *imsi) { uint8_t imsi_len; uint8_t *bcd_imsi; int i, j; if (!TLVP_PRESENT(tp, BSSGP_IE_IMSI)) return -EINVAL; imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI); bcd_imsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_IMSI); if ((bcd_imsi[0] & 0x08)) imsi_len = imsi_len * 2 - 1; else imsi_len = (imsi_len - 1) * 2; for (i = 0, j = 0; j < imsi_len && j < 15; j++) { if (!(j & 1)) { imsi[j] = (bcd_imsi[i] >> 4) + '0'; i++; } else
static int unit_data_ind(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; uint8_t ch_type, ch_subch, ch_ts; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); if (state != SCAN_STATE_READ && state != SCAN_STATE_RACH) { return -EINVAL; } rsl_dec_chan_nr(rllh->chan_nr, &ch_type, &ch_subch, &ch_ts); switch (ch_type) { case RSL_CHAN_PCH_AGCH: return pch_agch(ms, msg); case RSL_CHAN_BCCH: return bcch(ms, msg); #if 0 case RSL_CHAN_Bm_ACCHs: case RSL_CHAN_Lm_ACCHs: case RSL_CHAN_SDCCH4_ACCH: case RSL_CHAN_SDCCH8_ACCH: return rx_acch(ms, msg); #endif default: LOGP(DRSL, LOGL_NOTICE, "RSL with chan_nr 0x%02x unknown.\n", rllh->chan_nr); return -EINVAL; } }
static int rslms_rx_udata_ind(struct msgb *msg, struct osmocom_ms *ms) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; int rc = 0; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); if (rllh->chan_nr == RSL_CHAN_PCH_AGCH) { rc = gsm48_rx_ccch(msg, ms); } else if (rllh->chan_nr == RSL_CHAN_BCCH) { rc = gsm48_rx_bcch(msg, ms); } return rc; }
static int unit_data_ind(struct osmocom_ms *ms, struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); struct tlv_parsed tv; uint8_t ch_type, ch_subch, ch_ts; DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n", rllh->chan_nr, rllh->link_id); rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n"); return -EIO; } msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); rsl_dec_chan_nr(rllh->chan_nr, &ch_type, &ch_subch, &ch_ts); switch (ch_type) { case RSL_CHAN_BCCH: return bcch(ms, msg); default: return 0; } }
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; } }
int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg) { struct tlv_parsed tlvp; uint8_t msg_type = *(msg->l2h); struct ipaccess_unit unit_data = {}; char *unitid; int len, rc; /* shared CCM handling on both server and client */ rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd); switch (rc) { case -1: /* error in IPA CCM processing */ goto err; case 1: /* IPA CCM message that was handled in _base */ return 0; case 0: /* IPA CCM message that we need to handle */ break; default: /* Error */ LOGIPA(conn, LOGL_ERROR, "Unexpected return from " "ipa_ccm_rcvmsg_base: %d\n", rc); goto err; } switch (msg_type) { case IPAC_MSGT_ID_RESP: rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1); if (rc < 0) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with " "malformed TLVs\n"); goto err; } if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without " "unit ID\n"); goto err; } len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT); if (len < 1) { LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short" "unit ID\n"); goto err; } unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT); unitid[len-1] = '\0'; ipa_parse_unitid(unitid, &unit_data); /* FIXME */ rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data); if (rc < 0) goto err; break; default: LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n"); break; } return 0; err: /* in case of any error, we close the connection */ ipa_server_conn_destroy(conn); return -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; }
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, struct gprs_gb_parse_context *parse_ctx) { struct bssgp_normal_hdr *bgph; struct bssgp_ud_hdr *budh = NULL; struct tlv_parsed *tp = &parse_ctx->bssgp_tp; uint8_t pdu_type; uint8_t *data; size_t data_len; int rc; if (bssgp_len < sizeof(struct bssgp_normal_hdr)) return 0; bgph = (struct bssgp_normal_hdr *)bssgp; pdu_type = bgph->pdu_type; if (pdu_type == BSSGP_PDUT_UL_UNITDATA || pdu_type == BSSGP_PDUT_DL_UNITDATA) { if (bssgp_len < sizeof(struct bssgp_ud_hdr)) return 0; budh = (struct bssgp_ud_hdr *)bssgp; bgph = NULL; data = budh->data; data_len = bssgp_len - sizeof(*budh); } else { data = bgph->data; data_len = bssgp_len - sizeof(*bgph); } if (bssgp_tlv_parse(tp, data, data_len) < 0) return 0; parse_ctx->pdu_type = pdu_type; parse_ctx->bud_hdr = budh; parse_ctx->bgp_hdr = bgph; parse_ctx->bssgp_data = data; parse_ctx->bssgp_data_len = data_len; if (budh) parse_ctx->tlli_enc = (uint8_t *)&budh->tlli; if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID); if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) { parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI); parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI); } if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) { if (parse_ctx->tlli_enc) /* This is TLLI old, don't confuse it with TLLI current */ parse_ctx->old_tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI); else parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI); } if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS) parse_ctx->ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI); if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU); size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx); if (!rc) return 0; parse_ctx->llc = llc; parse_ctx->llc_len = llc_len; } if (parse_ctx->tlli_enc) { uint32_t tmp_tlli; memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli)); parse_ctx->tlli = ntohl(tmp_tlli); } return 1; }
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++) {
/* Parse a single GMM-PAGING.req to a given NSEI/NS-BVCI */ int bssgp_rx_paging(struct bssgp_paging_info *pinfo, struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; uint8_t ra[6]; int rc, data_len; memset(ra, 0, sizeof(ra)); data_len = msgb_bssgp_len(msg) - sizeof(*bgph); rc = bssgp_tlv_parse(&tp, bgph->data, data_len); if (rc < 0) goto err_mand_ie; switch (bgph->pdu_type) { case BSSGP_PDUT_PAGING_PS: pinfo->mode = BSSGP_PAGING_PS; break; case BSSGP_PDUT_PAGING_CS: pinfo->mode = BSSGP_PAGING_CS; break; default: return -EINVAL; } /* IMSI */ if (!TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) goto err_mand_ie; if (!pinfo->imsi) pinfo->imsi = talloc_zero_size(pinfo, GSM_IMSI_LENGTH); gsm48_mi_to_string(pinfo->imsi, GSM_IMSI_LENGTH, TLVP_VAL(&tp, BSSGP_IE_IMSI), TLVP_LEN(&tp, BSSGP_IE_IMSI)); /* DRX Parameters */ if (!TLVP_PRESENT(&tp, BSSGP_IE_DRX_PARAMS)) goto err_mand_ie; pinfo->drx_params = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_DRX_PARAMS)); /* Scope */ if (TLVP_PRESENT(&tp, BSSGP_IE_BSS_AREA_ID)) { pinfo->scope = BSSGP_PAGING_BSS_AREA; } else if (TLVP_PRESENT(&tp, BSSGP_IE_LOCATION_AREA)) { pinfo->scope = BSSGP_PAGING_LOCATION_AREA; memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_LOCATION_AREA), TLVP_LEN(&tp, BSSGP_IE_LOCATION_AREA)); gsm48_parse_ra(&pinfo->raid, ra); } else if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) { pinfo->scope = BSSGP_PAGING_ROUTEING_AREA; memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), TLVP_LEN(&tp, BSSGP_IE_ROUTEING_AREA)); gsm48_parse_ra(&pinfo->raid, ra); } else if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { pinfo->scope = BSSGP_PAGING_BVCI; pinfo->bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); } else return -EINVAL; /* QoS profile mandatory for PS */ if (pinfo->mode == BSSGP_PAGING_PS) { if (!TLVP_PRESENT(&tp, BSSGP_IE_QOS_PROFILE)) goto err_cond_ie; if (TLVP_LEN(&tp, BSSGP_IE_QOS_PROFILE) < 3) goto err; memcpy(&pinfo->qos, TLVP_VAL(&tp, BSSGP_IE_QOS_PROFILE), 3); } /* Optional (P-)TMSI */ if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI) && TLVP_LEN(&tp, BSSGP_IE_TMSI) >= 4) if (!pinfo->ptmsi) pinfo->ptmsi = talloc_zero_size(pinfo, sizeof(uint32_t)); *(pinfo->ptmsi) = ntohl(*(uint32_t *) TLVP_VAL(&tp, BSSGP_IE_TMSI)); return 0; err_mand_ie: err_cond_ie: err: /* FIXME */ return 0; }