static void handle_ass_fail(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct bsc_api *api = conn->bts->network->bsc_api; uint8_t *rr_failure; struct gsm48_hdr *gh; if (conn->lchan != msg->lchan) { LOGP(DMSC, LOGL_ERROR, "Assignment failure should occur on primary lchan.\n"); return; } /* stop the timer and release it */ osmo_timer_del(&conn->T10); lchan_release(conn->secondary_lchan, 0, 1); conn->secondary_lchan = NULL; gh = msgb_l3(msg); if (msgb_l3len(msg) - sizeof(*gh) != 1) { LOGP(DMSC, LOGL_ERROR, "assignemnt failure unhandled: %lu\n", msgb_l3len(msg) - sizeof(*gh)); rr_failure = NULL; } else { rr_failure = &gh->data[0]; } api->assign_fail(conn, GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, rr_failure); }
/** * Messages coming back from the MSC. */ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct osmo_msc_data *msc; struct gsm_network *net; struct gsm48_loc_area_id *lai; struct gsm48_hdr *gh; uint8_t mtype; if (msgb_l3len(msg) < sizeof(*gh)) { LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n"); return -1; } gh = (struct gsm48_hdr *) msgb_l3(msg); mtype = gh->msg_type & 0xbf; net = conn->bts->network; msc = conn->sccp_con->msc; if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { if (msc->core_ncc != -1 || msc->core_mcc != -1) { if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) { lai = (struct gsm48_loc_area_id *) &gh->data[0]; gsm48_generate_lai(lai, net->country_code, net->network_code, conn->bts->location_area_code); } } if (conn->sccp_con->new_subscriber) send_welcome_ussd(conn); } return 0; }
static void handle_lu_request(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh; struct gsm48_loc_upd_req *lu; struct gsm48_loc_area_id lai; struct gsm_network *net; if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) { LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg)); return; } net = conn->bts->network; gh = msgb_l3(msg); lu = (struct gsm48_loc_upd_req *) gh->data; gsm48_generate_lai(&lai, net->country_code, net->network_code, conn->bts->location_area_code); if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) { LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); conn->sccp_con->new_subscriber = 1; } }
/* receive BCCH at RR layer */ static int bcch(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_system_information_type_header *sih = msgb_l3(msg); struct gsm48_sysinfo *s = &g_sysinfo; if (msgb_l3len(msg) != 23) { LOGP(DRR, LOGL_NOTICE, "Invalid BCCH message length\n"); return -EINVAL; } switch (sih->system_information) { case GSM48_MT_RR_SYSINFO_1: LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n"); gsm48_decode_sysinfo1(s, (struct gsm48_system_information_type_1 *) sih, msgb_l3len(msg)); return try_cbch(ms, s); case GSM48_MT_RR_SYSINFO_4: LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4\n"); gsm48_decode_sysinfo4(s, (struct gsm48_system_information_type_4 *) sih, msgb_l3len(msg)); return try_cbch(ms, s); default: return 0; } }
static void handle_ass_compl(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh; struct bsc_api *api = conn->bts->network->bsc_api; if (conn->secondary_lchan != msg->lchan) { LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n"); return; } gh = msgb_l3(msg); if (msgb_l3len(msg) - sizeof(*gh) != 1) { LOGP(DMSC, LOGL_ERROR, "Assignment Compl invalid: %lu\n", msgb_l3len(msg) - sizeof(*gh)); return; } /* swap channels */ osmo_timer_del(&conn->T10); lchan_release(conn->lchan, 0, 1); conn->lchan = conn->secondary_lchan; conn->secondary_lchan = NULL; if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN) rsl_ipacc_crcx(conn->lchan); api->assign_compl(conn, gh->data[0], lchan_to_chosen_channel(conn->lchan), conn->lchan->encr.alg_id, chan_mode_to_speech(conn->lchan)); }
/* * I get called from the LAPDm code when something was sent my way... */ static int bts_to_ms_tx_cb(struct msgb *in_msg, struct lapdm_entity *le, void *_ctx) { struct lapdm_polling_state *state = _ctx; printf("%s: MS->BTS(us) message %d\n", __func__, msgb_length(in_msg)); if (state->bts_read == 0) { printf("BTS: Verifying CM request.\n"); ASSERT(msgb_l3len(in_msg) == ARRAY_SIZE(cm_padded)); ASSERT(memcmp(in_msg->l3h, cm_padded, ARRAY_SIZE(cm_padded)) == 0); } else if (state->bts_read == 1) { printf("BTS: Verifying dummy message.\n"); ASSERT(msgb_l3len(in_msg) == ARRAY_SIZE(dummy1)); ASSERT(memcmp(in_msg->l3h, dummy1, ARRAY_SIZE(dummy1)) == 0); } else { printf("BTS: Do not know to verify: %d\n", state->bts_read); } state->bts_read += 1; msgb_free(in_msg); return 0; }
static int ms_to_bts_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *_ctx) { struct lapdm_polling_state *state = _ctx; printf("%s: BTS->MS(us) message %d\n", __func__, msgb_length(msg)); if (state->ms_read == 0) { struct abis_rsl_rll_hdr hdr; printf("MS: Verifying incoming primitive.\n"); ASSERT(msg->len == sizeof(struct abis_rsl_rll_hdr) + 3); /* verify the header */ memset(&hdr, 0, sizeof(hdr)); rsl_init_rll_hdr(&hdr, RSL_MT_EST_CONF); hdr.c.msg_discr |= ABIS_RSL_MDISC_TRANSP; ASSERT(memcmp(msg->data, &hdr, sizeof(hdr)) == 0); /* Verify the added RSL_IE_L3_INFO but we have a bug here */ ASSERT(msg->data[6] == RSL_IE_L3_INFO); #warning "RSL_IE_L3_INFO 16 bit length is wrong" /* ASSERT(msg->data[7] == 0x0 && msg->data[8] == 0x9c); */ /* this should be 0x0 and 0x0... but we have a bug */ } else if (state->ms_read == 1) { printf("MS: Verifying incoming MM message: %d\n", msgb_l3len(msg)); ASSERT(msgb_l3len(msg) == 3); ASSERT(memcmp(msg->l3h, &mm[12], msgb_l3len(msg)) == 0); } else { printf("MS: Do not know to verify: %d\n", state->ms_read); } state->ms_read += 1; msgb_free(msg); return 0; }
/* string tokenizer for the poor */ static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length) { int i, found = 0; int whitespace = 1; for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) { /* if we have a space we found an end */ if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { if (!whitespace) { ++found; whitespace = 1; ptrs->length = i - ptrs->start - 1; ++ptrs; --ptrs_length; } else { /* skip any number of whitespace */ } /* line end... stop */ if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') break; } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { /* line end, be done */ break; } else if (whitespace) { whitespace = 0; ptrs->start = i; } } if (ptrs_length == 0) return -1; return found; }
static struct msgb *create_empty_msg(void) { struct msgb *msg; msg = msgb_from_array(NULL, 0); ASSERT(msgb_l3len(msg) == 0); rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, 0, 0, 1); return msg; }
/* we will need to stop the paging request */ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; struct gsm48_hdr *gh; struct gsm48_pag_resp *resp; struct gsm_subscriber *subscr; if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) { LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg)); return -1; } gh = msgb_l3(msg); resp = (struct gsm48_pag_resp *) &gh->data[0]; gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh), mi_string, &mi_type); DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n", mi_type, mi_string); switch (mi_type) { case GSM_MI_TYPE_TMSI: subscr = subscr_active_by_tmsi(conn->bts->network, tmsi_from_string(mi_string)); break; case GSM_MI_TYPE_IMSI: subscr = subscr_active_by_imsi(conn->bts->network, mi_string); break; default: subscr = NULL; break; } if (!subscr) { LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n"); return -1; } paging_request_stop(conn->bts, subscr, conn, msg); subscr_put(subscr); return 0; }
static struct msgb *create_mm_id_req(void) { struct msgb *msg; msg = msgb_from_array(mm, sizeof(mm)); msg->l2h = msg->data + 3; ASSERT(msgb_l2len(msg) == 12); msg->l3h = msg->l2h + 6; ASSERT(msgb_l3len(msg) == 6); return msg; }
static int check_manuf(struct msgb *msg, struct abis_om_hdr *omh, size_t msg_size) { int type; size_t size; if (msg_size < 1) { LOGP(DL1C, LOGL_ERROR, "No ManId Length Indicator %zu\n", msg_size); return -1; } if (omh->data[0] >= msg_size - 1) { LOGP(DL1C, LOGL_ERROR, "Insufficient message space for this ManId Length %d %zu\n", omh->data[0], msg_size - 1); return -1; } if (omh->data[0] == sizeof(abis_nm_ipa_magic) && strncmp(abis_nm_ipa_magic, (const char *)omh->data + 1, sizeof(abis_nm_ipa_magic)) == 0) { type = OML_MSG_TYPE_IPA; size = sizeof(abis_nm_ipa_magic) + 1; } else if (omh->data[0] == sizeof(abis_nm_osmo_magic) && strncmp(abis_nm_osmo_magic, (const char *) omh->data + 1, sizeof(abis_nm_osmo_magic)) == 0) { type = OML_MSG_TYPE_OSMO; size = sizeof(abis_nm_osmo_magic) + 1; } else { LOGP(DL1C, LOGL_ERROR, "Manuf Label Unknown\n"); return -1; } /* we have verified that the vendor string fits */ msg->l3h = omh->data + size; if (check_fom(omh, msgb_l3len(msg)) != 0) return -1; return type; }
/** * \brief Verify the structure of the OML message and set l3h * * This function verifies that the data in \param in msg is a proper * OML message. This code assumes that msg->l2h points to the * beginning of the OML message. In the successful case the msg->l3h * will be set and will point to the FOM header. The value is undefined * in all other cases. * * \param msg The message to analyze starting from msg->l2h. * \return In case the structure is correct a positive number will be * returned and msg->l3h will point to the FOM. The number is a * classification of the vendor type of the message. */ int msg_verify_oml_structure(struct msgb *msg) { struct abis_om_hdr *omh; if (msgb_l2len(msg) < sizeof(*omh)) { LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", msgb_l2len(msg), sizeof(*omh)); return -1; } omh = (struct abis_om_hdr *) msg->l2h; if (omh->mdisc != ABIS_OM_MDISC_FOM && omh->mdisc != ABIS_OM_MDISC_MANUF) { LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n", omh->mdisc); return -1; } if (omh->placement != ABIS_OM_PLACEMENT_ONLY) { LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n", omh->placement, ABIS_OM_PLACEMENT_ONLY); return -1; } if (omh->sequence != 0) { LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n", omh->sequence); return -1; } if (omh->mdisc == ABIS_OM_MDISC_MANUF) return check_manuf(msg, omh, msgb_l2len(msg) - sizeof(*omh)); msg->l3h = omh->data; if (check_fom(omh, msgb_l3len(msg)) != 0) return -1; return OML_MSG_TYPE_ETSI; }
static void handle_classmark_chg(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; struct gsm48_hdr *gh = msgb_l3(msg); unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); uint8_t cm2_len, cm3_len = 0; uint8_t *cm2, *cm3 = NULL; DEBUGP(DRR, "CLASSMARK CHANGE "); /* classmark 2 */ cm2_len = gh->data[0]; cm2 = &gh->data[1]; DEBUGPC(DRR, "CM2(len=%u) ", cm2_len); if (payload_len > cm2_len + 1) { /* we must have a classmark3 */ if (gh->data[cm2_len+1] != 0x20) { DEBUGPC(DRR, "ERR CM3 TAG\n"); return; } if (cm2_len > 3) { DEBUGPC(DRR, "CM2 too long!\n"); return; } cm3_len = gh->data[cm2_len+2]; cm3 = &gh->data[cm2_len+3]; if (cm3_len > 14) { DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len); return; } DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len); } api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len); }
static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; const char *trans_id; struct mgcp_trunk_config *tcfg; struct mgcp_endpoint *endp; int error_code = 400; found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return create_err_response(510, "CRCX", trans_id); tcfg = endp->tcfg; if (endp->allocated) { if (tcfg->force_realloc) { LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n", ENDPOINT_NUMBER(endp)); mgcp_free_endp(endp); if (cfg->realloc_cb) cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp)); } else { LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); return create_err_response(400, "CRCX", trans_id); } } /* parse CallID C: and LocalParameters L: */ MSG_TOKENIZE_START switch (msg->l3h[line_start]) { case 'L': endp->local_options = talloc_strdup(tcfg->endpoints, (const char *)&msg->l3h[line_start + 3]); break; case 'C': endp->callid = talloc_strdup(tcfg->endpoints, (const char *)&msg->l3h[line_start + 3]); break; case 'M': if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], &endp->conn_mode) != 0) { error_code = 517; goto error2; } endp->orig_mode = endp->conn_mode; break; default: LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; } MSG_TOKENIZE_END /* initialize */ endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0; /* set to zero until we get the info */ memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr)); /* bind to the port now */ if (allocate_ports(endp) != 0) goto error2; /* assign a local call identifier or fail */ endp->ci = generate_call_id(cfg); if (endp->ci == CI_UNUSED) goto error2; endp->allocated = 1; endp->bts_end.payload_type = tcfg->audio_payload; /* policy CB */ if (cfg->policy_cb) { switch (cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) { case MGCP_POLICY_REJECT: LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n", ENDPOINT_NUMBER(endp)); mgcp_free_endp(endp); return create_err_response(400, "CRCX", trans_id); break; case MGCP_POLICY_DEFER: /* stop processing */ create_transcoder(endp); return NULL; break; case MGCP_POLICY_CONT: /* just continue */ break; } } LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->net_end.local_port, endp->bts_end.local_port); if (cfg->change_cb) cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX); create_transcoder(endp); return create_response_with_sdp(endp, "CRCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", osmo_hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); return create_err_response(error_code, "CRCX", trans_id); error2: mgcp_free_endp(endp); LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); return create_err_response(error_code, "CRCX", trans_id); }
static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; const char *trans_id; struct mgcp_endpoint *endp; int error_code = 500; int silent = 0; found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return create_err_response(510, "MDCX", trans_id); if (endp->ci == CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); return create_err_response(400, "MDCX", trans_id); } MSG_TOKENIZE_START switch (msg->l3h[line_start]) { case 'C': { if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) goto error3; break; } case 'I': { if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) goto error3; break; } case 'L': /* skip */ break; case 'M': if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], &endp->conn_mode) != 0) { error_code = 517; goto error3; } endp->orig_mode = endp->conn_mode; break; case 'Z': silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0; break; case '\0': /* SDP file begins */ break; case 'a': case 'o': case 's': case 't': case 'v': /* skip these SDP attributes */ break; case 'm': { int port; int payload; const char *param = (const char *)&msg->l3h[line_start]; if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) { endp->net_end.rtp_port = htons(port); endp->net_end.rtcp_port = htons(port + 1); endp->net_end.payload_type = payload; } break; } case 'c': { char ipv4[16]; const char *param = (const char *)&msg->l3h[line_start]; if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) { inet_aton(ipv4, &endp->net_end.addr); } break; } default: LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; } MSG_TOKENIZE_END /* policy CB */ if (cfg->policy_cb) { switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) { case MGCP_POLICY_REJECT: LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n", ENDPOINT_NUMBER(endp)); if (silent) goto out_silent; return create_err_response(400, "MDCX", trans_id); break; case MGCP_POLICY_DEFER: /* stop processing */ return NULL; break; case MGCP_POLICY_CONT: /* just continue */ break; } } /* modify */ LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port)); if (cfg->change_cb) cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX); if (silent) goto out_silent; return create_response_with_sdp(endp, "MDCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", osmo_hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); return create_err_response(error_code, "MDCX", trans_id); error3: return create_err_response(error_code, "MDCX", trans_id); out_silent: return NULL; }
static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; const char *trans_id; struct mgcp_endpoint *endp; int error_code = 400; int silent = 0; found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return create_err_response(error_code, "DLCX", trans_id); if (!endp->allocated) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); return create_err_response(400, "DLCX", trans_id); } MSG_TOKENIZE_START switch (msg->l3h[line_start]) { case 'C': { if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) goto error3; break; } case 'I': { if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) goto error3; break; case 'Z': silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0; break; } default: LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; } MSG_TOKENIZE_END /* policy CB */ if (cfg->policy_cb) { switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) { case MGCP_POLICY_REJECT: LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n", ENDPOINT_NUMBER(endp)); if (silent) goto out_silent; return create_err_response(400, "DLCX", trans_id); break; case MGCP_POLICY_DEFER: /* stop processing */ delete_transcoder(endp); return NULL; break; case MGCP_POLICY_CONT: /* just continue */ break; } } /* free the connection */ LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port)); delete_transcoder(endp); mgcp_free_endp(endp); if (cfg->change_cb) cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX); if (silent) goto out_silent; return create_ok_response(250, "DLCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", osmo_hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); return create_err_response(error_code, "DLCX", trans_id); error3: return create_err_response(error_code, "DLCX", trans_id); out_silent: return NULL; }
/* receive BCCH at RR layer */ static int bcch(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_sysinfo *s = &sysinfo; struct gsm48_system_information_type_header *sih = msgb_l3(msg); uint8_t ccch_mode; if (msgb_l3len(msg) != 23) { LOGP(DRR, LOGL_NOTICE, "Invalid BCCH message length\n"); return -EINVAL; } switch (sih->system_information) { case GSM48_MT_RR_SYSINFO_1: if (!memcmp(sih, s->si1_msg, sizeof(s->si1_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n"); gsm48_decode_sysinfo1(s, (struct gsm48_system_information_type_1 *) sih, msgb_l3len(msg)); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_2: if (!memcmp(sih, s->si2_msg, sizeof(s->si2_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2\n"); gsm48_decode_sysinfo2(s, (struct gsm48_system_information_type_2 *) sih, msgb_l3len(msg)); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_2bis: if (!memcmp(sih, s->si2b_msg, sizeof(s->si2b_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2bis\n"); gsm48_decode_sysinfo2bis(s, (struct gsm48_system_information_type_2bis *) sih, msgb_l3len(msg)); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_2ter: if (!memcmp(sih, s->si2t_msg, sizeof(s->si2t_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2ter\n"); gsm48_decode_sysinfo2ter(s, (struct gsm48_system_information_type_2ter *) sih, msgb_l3len(msg)); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_3: if (!memcmp(sih, s->si3_msg, sizeof(s->si3_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3\n"); gsm48_decode_sysinfo3(s, (struct gsm48_system_information_type_3 *) sih, msgb_l3len(msg)); ccch_mode = (s->ccch_conf == 1) ? CCCH_MODE_COMBINED : CCCH_MODE_NON_COMBINED; LOGP(DRR, LOGL_INFO, "Changing CCCH_MODE to %d\n", ccch_mode); l1ctl_tx_ccch_mode_req(ms, ccch_mode); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_4: if (!memcmp(sih, s->si4_msg, sizeof(s->si4_msg))) return 0; LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4\n"); gsm48_decode_sysinfo4(s, (struct gsm48_system_information_type_4 *) sih, msgb_l3len(msg)); return new_sysinfo(); default: return -EINVAL; } }
static void dispatch_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; struct gsm48_hdr *gh; uint8_t pdisc; int rc; if (msgb_l3len(msg) < sizeof(*gh)) { LOGP(DMSC, LOGL_ERROR, "Message too short for a GSM48 header.\n"); return; } gh = msgb_l3(msg); pdisc = gh->proto_discr & 0x0f; /* the idea is to handle all RR messages here, and only hand * MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING * RESPONSE or CM SERVICE REQUEST will not be covered here, as * they are only possible in the first L3 message of each L2 * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg() * will call api->compl_l3() for it */ switch (pdisc) { case GSM48_PDISC_RR: switch (gh->msg_type) { case GSM48_MT_RR_GPRS_SUSP_REQ: DEBUGP(DRR, "GRPS SUSPEND REQUEST\n"); break; case GSM48_MT_RR_STATUS: LOGP(DRR, LOGL_NOTICE, "RR STATUS (cause: %s)\n", rr_cause_name(gh->data[0])); break; case GSM48_MT_RR_MEAS_REP: /* This shouldn't actually end up here, as RSL treats * L3 Info of 08.58 MEASUREMENT REPORT different by calling * directly into gsm48_parse_meas_rep */ LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); break; case GSM48_MT_RR_HANDO_COMPL: handle_rr_ho_compl(msg); break; case GSM48_MT_RR_HANDO_FAIL: handle_rr_ho_fail(msg); break; case GSM48_MT_RR_CIPH_M_COMPL: if (api->cipher_mode_compl) api->cipher_mode_compl(conn, msg, conn->lchan->encr.alg_id); break; case GSM48_MT_RR_ASS_COMPL: handle_ass_compl(conn, msg); break; case GSM48_MT_RR_ASS_FAIL: handle_ass_fail(conn, msg); break; case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: osmo_timer_del(&conn->T10); rc = gsm48_rx_rr_modif_ack(msg); if (rc < 0) { api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); } else if (rc >= 0) { api->assign_compl(conn, 0, lchan_to_chosen_channel(conn->lchan), conn->lchan->encr.alg_id, chan_mode_to_speech(conn->lchan)); } break; case GSM48_MT_RR_CLSM_CHG: handle_classmark_chg(conn, msg); break; case GSM48_MT_RR_APP_INFO: /* Passing RR APP INFO to MSC, not quite * according to spec */ if (api->dtap) api->dtap(conn, link_id, msg); break; default: /* Normally, a MSC should never receive RR * messages, but we'd rather forward what we * don't know than drop it... */ LOGP(DRR, LOGL_NOTICE, "BSC: Passing unknown 04.08 " "RR message type 0x%02x to MSC\n", gh->msg_type); if (api->dtap) api->dtap(conn, link_id, msg); } break; default: if (api->dtap) api->dtap(conn, link_id, msg); break; } }