void bsc_msc_lost(struct bsc_msc_connection *con) { osmo_wqueue_clear(&con->write_queue); osmo_timer_del(&con->timeout_timer); osmo_timer_del(&con->reconnect_timer); if (con->write_queue.bfd.fd >= 0) osmo_fd_unregister(&con->write_queue.bfd); connection_loss(con); }
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); }
/*! \brief delete a given instance of a FSM * \param[in] fsm The FSM to be un-registered and deleted */ void osmo_fsm_inst_free(struct osmo_fsm_inst *fi) { LOGPFSM(fi, "Deallocated\n"); osmo_timer_del(&fi->timer); llist_del(&fi->list); talloc_free(fi); }
/* clear instance */ void gsm411_smr_clear(struct gsm411_smr_inst *inst) { LOGP(DLSMS, LOGL_INFO, SMR_LOG_STR "clearing SMR instance\n", inst->id); osmo_timer_del(&inst->rp_timer); }
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); }
static void handle_release(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan) { int destruct = 1; if (conn->secondary_lchan == lchan) { osmo_timer_del(&conn->T10); conn->secondary_lchan = NULL; bsc->assign_fail(conn, GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, NULL); } /* clear the connection now */ if (bsc->clear_request) destruct = bsc->clear_request(conn, 0); /* now give up all channels */ if (conn->lchan == lchan) conn->lchan = NULL; if (conn->ho_lchan == lchan) { bsc_clear_handover(conn, 0); conn->ho_lchan = NULL; } lchan->conn = NULL; gsm0808_clear(conn); if (destruct) subscr_con_free(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); 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 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)); }
static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg) { /* free stored msg */ if (inst->cp_msg) { msgb_free(inst->cp_msg); inst->cp_msg = NULL; } LOGP(DLSMS, LOGL_INFO, "Received CP-ACK\n"); /* 5.3.2.1 enter MM Connection established */ new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED); /* 5.3.2.1: Reset Timer TC1* */ osmo_timer_del(&inst->cp_timer); /* pending release? */ if (inst->cp_rel) { struct msgb *nmsg; LOGP(DLSMS, LOGL_INFO, "We have pending release.\n"); new_cp_state(inst, GSM411_CPS_IDLE); /* release MM connection */ nmsg = gsm411_msgb_alloc(); return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); } return 0; }
static void new_rp_state(struct gsm411_smr_inst *inst, enum gsm411_rp_state state) { LOGP(DLSMS, LOGL_INFO, SMR_LOG_STR "new RP state %s -> %s\n", inst->id, smr_state_names[inst->rp_state], smr_state_names[state]); inst->rp_state = state; /* stop timer when going idle */ if (state == GSM411_RPS_IDLE) osmo_timer_del(&inst->rp_timer); }
/* called in the case of a non blocking connect */ static int msc_connection_connect(struct osmo_fd *fd, unsigned int what) { int rc; int val; struct bsc_msc_connection *con; struct osmo_wqueue *queue; socklen_t len = sizeof(val); queue = container_of(fd, struct osmo_wqueue, bfd); con = container_of(queue, struct bsc_msc_connection, write_queue); if ((what & BSC_FD_WRITE) == 0) { LOGP(DMSC, LOGL_ERROR, "MSC(%s) Callback but not writable.\n", con->name); return -1; } /* From here on we will either be connected or reconnect */ osmo_timer_del(&con->timeout_timer); /* check the socket state */ rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len); if (rc != 0) { LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC(%s) socket failed.\n", con->name); goto error; } if (val != 0) { LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC(%s): %d\n", con->name, val); goto error; } /* go to full operation */ fd->cb = osmo_wqueue_bfd_cb; fd->when = BSC_FD_READ | BSC_FD_EXCEPT; con->is_connected = 1; LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC(%s).\n", con->name); if (con->connected) con->connected(con); return 0; error: osmo_fd_unregister(fd); connection_loss(con); return -1; }
static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con) { if (con->nat->ussd_con == con) { bsc_close_ussd_connections(con->nat); con->nat->ussd_con = NULL; } close(con->queue.bfd.fd); osmo_fd_unregister(&con->queue.bfd); osmo_timer_del(&con->auth_timeout); osmo_wqueue_clear(&con->queue); talloc_free(con); }
/* clear instance */ void gsm411_smc_clear(struct gsm411_smc_inst *inst) { LOGP(DLSMS, LOGL_INFO, "Clear SMC instance\n"); osmo_timer_del(&inst->cp_timer); /* free stored msg */ if (inst->cp_msg) { LOGP(DLSMS, LOGL_INFO, "Dropping pending message\n"); msgb_free(inst->cp_msg); inst->cp_msg = NULL; } }
/* clear instance */ void gsm411_smc_clear(struct gsm411_smc_inst *inst) { LOGP(DLSMS, LOGL_INFO, SMC_LOG_STR "clearing instance\n", inst->id); osmo_timer_del(&inst->cp_timer); /* free stored msg */ if (inst->cp_msg) { LOGP(DLSMS, LOGL_INFO, SMC_LOG_STR "dropping pending message\n", inst->id); msgb_free(inst->cp_msg); inst->cp_msg = NULL; } }
static void timer_fired(void *_data) { unsigned long data = (unsigned long) _data; printf("Fired timer: %lu\n", data); if (data == 1) { osmo_timer_schedule(&timer_one, 3, 0); osmo_timer_del(&timer_two); } else if (data == 2) { printf("Should not be fired... bug in del_timer\n"); } else if (data == 3) { printf("Timer fired not registering again\n"); } else { printf("wtf... wrong data\n"); } }
/* * Release all occupied RF Channels but stay around for more. */ int gsm0808_clear(struct gsm_subscriber_connection *conn) { if (conn->ho_lchan) bsc_clear_handover(conn, 1); if (conn->secondary_lchan) lchan_release(conn->secondary_lchan, 0, 1); if (conn->lchan) lchan_release(conn->lchan, 1, 0); conn->lchan = NULL; conn->secondary_lchan = NULL; conn->ho_lchan = NULL; conn->bts = NULL; osmo_timer_del(&conn->T10); return 0; }
/*! \brief perform a state change of the given FSM instance * * Best invoke via the osmo_fsm_inst_state_chg() macro which logs the source * file where the state change was effected. Alternatively, you may pass \a * file as NULL to use the normal file/line indication instead. * * All changes to the FSM instance state must be made via this * function. It verifies that the existing state actually permits a * transiiton to new_state. * * timeout_secs and T are optional parameters, and only have any effect * if timeout_secs is not 0. If the timeout function is used, then the * new_state is entered, and the FSM instances timer is set to expire * in timeout_secs functions. At that time, the FSM's timer_cb * function will be called for handling of the timeout by the user. * * \param[in] fi FSM instance whose state is to change * \param[in] new_state The new state into which we should change * \param[in] timeout_secs Timeout in seconds (if !=0) * \param[in] T Timer number (if \ref timeout_secs != 0) * \param[in] file Calling source file (from osmo_fsm_inst_state_chg macro) * \param[in] line Calling source line (from osmo_fsm_inst_state_chg macro) * \returns 0 on success; negative on error */ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state, unsigned long timeout_secs, int T, const char *file, int line) { struct osmo_fsm *fsm = fi->fsm; uint32_t old_state = fi->state; const struct osmo_fsm_state *st = &fsm->states[fi->state]; /* validate if new_state is a valid state */ if (!(st->out_state_mask & (1 << new_state))) { LOGPFSMLSRC(fi, LOGL_ERROR, file, line, "transition to state %s not permitted!\n", osmo_fsm_state_name(fsm, new_state)); return -EPERM; } /* delete the old timer */ osmo_timer_del(&fi->timer); if (st->onleave) st->onleave(fi, new_state); LOGPFSMSRC(fi, file, line, "state_chg to %s\n", osmo_fsm_state_name(fsm, new_state)); fi->state = new_state; st = &fsm->states[new_state]; if (timeout_secs) { fi->T = T; osmo_timer_schedule(&fi->timer, timeout_secs, 0); } /* Call 'onenter' last, user might terminate FSM from there */ if (st->onenter) st->onenter(fi, old_state); return 0; }
static void release_wlc(struct wait_l1_conf *wlc) { osmo_timer_del(&wlc->timer); talloc_free(wlc); }
static void stop_timer(void) { if (osmo_timer_pending(&timer)) osmo_timer_del(&timer); }
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; } }
/* get response from ctrl socket */ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) { struct trx_l1h *l1h = ofd->data; struct phy_instance *pinst = l1h->phy_inst; char buf[1500]; int len, resp; len = recv(ofd->fd, buf, sizeof(buf) - 1, 0); if (len <= 0) return len; buf[len] = '\0'; if (!strncmp(buf, "RSP ", 4)) { struct trx_ctrl_msg *tcm; char *p; int rsp_len = 0; /* calculate the length of response item */ p = strchr(buf + 4, ' '); if (p) rsp_len = p - buf - 4; else rsp_len = strlen(buf) - 4; LOGP(DTRX, LOGL_INFO, "Response message: '%s'\n", buf); /* abort timer and send next message, if any */ if (osmo_timer_pending(&l1h->trx_ctrl_timer)) osmo_timer_del(&l1h->trx_ctrl_timer); /* get command for response message */ if (llist_empty(&l1h->trx_ctrl_list)) { LOGP(DTRX, LOGL_NOTICE, "Response message without " "command\n"); return -EINVAL; } tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list); /* check if respose matches command */ if (rsp_len != tcm->cmd_len) { notmatch: LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE, "Response message '%s' does not match command " "message '%s'\n", buf, tcm->cmd); goto rsp_error; } if (!!strncmp(buf + 4, tcm->cmd + 4, rsp_len)) goto notmatch; /* check for response code */ sscanf(p + 1, "%d", &resp); if (resp) { LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE, "transceiver (%s) rejected TRX command " "with response: '%s'\n", phy_instance_name(pinst), buf); rsp_error: if (tcm->critical) { bts_shutdown(pinst->trx->bts, "SIGINT"); /* keep tcm list, so process is stopped */ return -EIO; } } /* remove command from list */ llist_del(&tcm->list); talloc_free(tcm); trx_ctrl_send(l1h); } else