static void print_state(struct tlv_parsed *tp) { if (TLVP_PRESENT(tp, NM_ATT_BS11_BTS_STATE)) { uint8_t phase, mbccu; if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 1) { phase = *TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE); printf("PHASE: %u %-20s ", phase & 0xf, bts_phase_name(phase)); } if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 2) { mbccu = *(TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE)+1); printf("MBCCU0: %-11s MBCCU1: %-11s ", mbccu_load_name(mbccu & 0xf), mbccu_load_name(mbccu >> 4)); } }
static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn) { const char *token; int len; if (!conn->nat->ussd_token) { LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n"); bsc_nat_ussd_destroy(conn); return; } token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); if (strncmp(conn->nat->ussd_token, token, len) != 0) { LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n", conn->queue.bfd.fd); bsc_nat_ussd_destroy(conn); return; } /* it is authenticated now */ if (conn->nat->ussd_con && conn->nat->ussd_con != conn) bsc_nat_ussd_destroy(conn->nat->ussd_con); LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n"); osmo_timer_del(&conn->auth_timeout); conn->authorized = 1; conn->nat->ussd_con = conn; }
static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn) { const char *token; int len; if (!conn->nat->ussd_token) { LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n"); bsc_nat_ussd_destroy(conn); return; } token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); /* last byte should be a NULL */ if (strlen(conn->nat->ussd_token) != len - 1) goto disconnect; /* compare everything including the null byte */ if (memcmp(conn->nat->ussd_token, token, len) != 0) goto disconnect; /* it is authenticated now */ if (conn->nat->ussd_con && conn->nat->ussd_con != conn) bsc_nat_ussd_destroy(conn->nat->ussd_con); LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n"); osmo_timer_del(&conn->auth_timeout); conn->authorized = 1; conn->nat->ussd_con = conn; return; disconnect: LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n", conn->queue.bfd.fd); bsc_nat_ussd_destroy(conn); }
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 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
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; }
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; }
/* generate a PDP context based on the IE's from the 04.08 message, * and send the GTP create pdp context request to the GGSN */ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, uint16_t nsapi, struct tlv_parsed *tp) { struct sgsn_pdp_ctx *pctx; struct pdp_t *pdp; uint64_t imsi_ui64; int rc; LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n"); pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi); if (!pctx) { LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n"); return NULL; } imsi_ui64 = imsi_str2gtp(mmctx->imsi); rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL); if (rc) { LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n"); return NULL; } pdp->priv = pctx; pctx->lib = pdp; pctx->ggsn = ggsn; //pdp->peer = /* sockaddr_in of GGSN (receive) */ //pdp->ipif = /* not used by library */ pdp->version = ggsn->gtp_version; pdp->hisaddr0 = ggsn->remote_addr; pdp->hisaddr1 = ggsn->remote_addr; //pdp->cch_pdp = 512; /* Charging Flat Rate */ /* MS provided APN, subscription not verified */ pdp->selmode = 0x01; /* IMSI, TEID/TEIC, FLLU/FLLC, TID, NSAPI set in pdp_newpdp */ /* FIXME: MSISDN in BCD format from mmctx */ //pdp->msisdn.l/.v /* End User Address from GMM requested PDP address */ pdp->eua.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_PDP_ADDR); if (pdp->eua.l > sizeof(pdp->eua.v)) pdp->eua.l = sizeof(pdp->eua.v); memcpy(pdp->eua.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_PDP_ADDR), pdp->eua.l); /* Highest 4 bits of first byte need to be set to 1, otherwise * the IE is identical with the 04.08 PDP Address IE */ pdp->eua.v[0] |= 0xf0; /* APN name from GMM */ pdp->apn_use.l = TLVP_LEN(tp, GSM48_IE_GSM_APN); if (pdp->apn_use.l > sizeof(pdp->apn_use.v)) pdp->apn_use.l = sizeof(pdp->apn_use.v); memcpy(pdp->apn_use.v, TLVP_VAL(tp, GSM48_IE_GSM_APN), pdp->apn_use.l); /* Protocol Configuration Options from GMM */ pdp->pco_req.l = TLVP_LEN(tp, GSM48_IE_GSM_PROTO_CONF_OPT); if (pdp->pco_req.l > sizeof(pdp->pco_req.v)) pdp->pco_req.l = sizeof(pdp->pco_req.v); memcpy(pdp->pco_req.v, TLVP_VAL(tp, GSM48_IE_GSM_PROTO_CONF_OPT), pdp->pco_req.l); /* QoS options from GMM */ pdp->qos_req.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS); if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) pdp->qos_req.l = sizeof(pdp->qos_req.v); memcpy(pdp->qos_req.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS), pdp->qos_req.l); /* SGSN address for control plane */ pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); /* SGSN address for user plane */ pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); /* change pdp state to 'requested' */ pctx->state = PDP_STATE_CR_REQ; rc = gtp_create_context_req(ggsn->gsn, pdp, pctx); /* FIXME */ return pctx; }
/* 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; }
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; }
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++) {
/* generate a PDP context based on the IE's from the 04.08 message, * and send the GTP create pdp context request to the GGSN */ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, uint16_t nsapi, struct tlv_parsed *tp) { struct gprs_ra_id raid; struct sgsn_pdp_ctx *pctx; struct pdp_t *pdp; uint64_t imsi_ui64; size_t qos_len; const uint8_t *qos; int rc; LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n"); pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi); if (!pctx) { LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n"); return NULL; } imsi_ui64 = imsi_str2gtp(mmctx->imsi); rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL); if (rc) { LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n"); return NULL; } pdp->priv = pctx; pctx->lib = pdp; pctx->ggsn = ggsn; //pdp->peer = /* sockaddr_in of GGSN (receive) */ //pdp->ipif = /* not used by library */ pdp->version = ggsn->gtp_version; pdp->hisaddr0 = ggsn->remote_addr; pdp->hisaddr1 = ggsn->remote_addr; //pdp->cch_pdp = 512; /* Charging Flat Rate */ /* MS provided APN, subscription was verified by the caller */ pdp->selmode = 0xFC | 0x00; /* IMSI, TEID/TEIC, FLLU/FLLC, TID, NSAPI set in pdp_newpdp */ /* Put the MSISDN in case we have it */ if (mmctx->subscr) { pdp->msisdn.l = mmctx->subscr->sgsn_data->msisdn_len; if (pdp->msisdn.l > sizeof(pdp->msisdn.v)) pdp->msisdn.l = sizeof(pdp->msisdn.v); memcpy(pdp->msisdn.v, mmctx->subscr->sgsn_data->msisdn, pdp->msisdn.l); } /* End User Address from GMM requested PDP address */ pdp->eua.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_PDP_ADDR); if (pdp->eua.l > sizeof(pdp->eua.v)) pdp->eua.l = sizeof(pdp->eua.v); memcpy(pdp->eua.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_PDP_ADDR), pdp->eua.l); /* Highest 4 bits of first byte need to be set to 1, otherwise * the IE is identical with the 04.08 PDP Address IE */ pdp->eua.v[0] |= 0xf0; /* APN name from GMM */ pdp->apn_use.l = TLVP_LEN(tp, GSM48_IE_GSM_APN); if (pdp->apn_use.l > sizeof(pdp->apn_use.v)) pdp->apn_use.l = sizeof(pdp->apn_use.v); memcpy(pdp->apn_use.v, TLVP_VAL(tp, GSM48_IE_GSM_APN), pdp->apn_use.l); /* Protocol Configuration Options from GMM */ pdp->pco_req.l = TLVP_LEN(tp, GSM48_IE_GSM_PROTO_CONF_OPT); if (pdp->pco_req.l > sizeof(pdp->pco_req.v)) pdp->pco_req.l = sizeof(pdp->pco_req.v); memcpy(pdp->pco_req.v, TLVP_VAL(tp, GSM48_IE_GSM_PROTO_CONF_OPT), pdp->pco_req.l); /* QoS options from GMM or remote */ if (TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS) > 0) { qos_len = TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS); qos = TLVP_VAL(tp, OSMO_IE_GSM_SUB_QOS); } else { qos_len = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS); qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS); } if (qos_len <= 3) { pdp->qos_req.l = qos_len + 1; if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) pdp->qos_req.l = sizeof(pdp->qos_req.v); pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */ memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1); } else { pdp->qos_req.l = qos_len; if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) pdp->qos_req.l = sizeof(pdp->qos_req.v); memcpy(pdp->qos_req.v, qos, pdp->qos_req.l); } /* SGSN address for control plane */ pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); /* SGSN address for user plane */ pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); /* Assume we are a GERAN system */ pdp->rattype.l = 1; pdp->rattype.v[0] = 2; pdp->rattype_given = 1; /* Include RAI and ULI all the time */ pdp->rai_given = 1; pdp->rai.l = 6; raid = mmctx->ra; raid.lac = 0xFFFE; raid.rac = 0xFF; gsm48_construct_ra(pdp->rai.v, &raid); pdp->userloc_given = 1; pdp->userloc.l = 8; pdp->userloc.v[0] = 0; /* CGI for GERAN */ bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->cell_id); /* include the IMEI(SV) */ pdp->imeisv_given = 1; gsm48_encode_bcd_number(&pdp->imeisv.v[0], 8, 0, mmctx->imei); pdp->imeisv.l = pdp->imeisv.v[0]; memmove(&pdp->imeisv.v[0], &pdp->imeisv.v[1], 8); /* change pdp state to 'requested' */ pctx->state = PDP_STATE_CR_REQ; rc = gtp_create_context_req(ggsn->gsn, pdp, pctx); /* FIXME */ return pctx; }