/** * Dequeues a TCH or FACCH frame, prioritizing the second. * In case if a FACCH frame is found, a TCH frame is being * dropped (i.e. replaced). * * @param queue a transmit queue to take a prim from * @return a FACCH or TCH primitive, otherwise NULL */ static struct trx_ts_prim *sched_prim_dequeue_tch(struct llist_head *queue) { struct trx_ts_prim *facch = NULL; struct trx_ts_prim *tch = NULL; struct trx_ts_prim *i; /* Attempt to find a pair of FACCH and TCH frames */ llist_for_each_entry(i, queue, list) { /* Find one FACCH frame */ if (!facch && PRIM_IS_FACCH(i)) facch = i; /* Find one TCH frame */ if (!tch && PRIM_IS_TCH(i)) tch = i; /* If both are found */ if (facch && tch) break; } /* Prioritize FACCH */ if (facch && tch) { /* We found a pair, dequeue both */ llist_del(&facch->list); llist_del(&tch->list); /* Drop TCH */ talloc_free(tch); /* FACCH replaces TCH */ return facch; } else if (facch) { /* Only FACCH was found */ llist_del(&facch->list); return facch; } else if (tch) { /* Only TCH was found */ llist_del(&tch->list); return tch; } /** * Nothing was found, * e.g. only SACCH frames are in queue */ return NULL; }
/* * We got the channel assigned and can now hand this channel * over to one of our callbacks. */ static int subscr_paging_cb(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param) { struct subscr_request *request; struct gsm_subscriber *subscr = (struct gsm_subscriber *)param; /* There is no request anymore... */ if (llist_empty(&subscr->requests)) return -1; /* * FIXME: What to do with paging requests coming during * this callback? We must be sure to not start paging when * we have an active connection to a subscriber and to make * the subscr_put_channel work as required... */ request = (struct subscr_request *)subscr->requests.next; llist_del(&request->entry); subscr->in_callback = 1; request->cbfn(hooknum, event, msg, data, request->param); subscr->in_callback = 0; subscr_put(subscr); talloc_free(request); return 0; }
/*! \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); }
/* TODO: move subscriber put here... */ void subscr_con_free(struct gsm_subscriber_connection *conn) { if (!conn) return; if (conn->subscr) { subscr_put(conn->subscr); conn->subscr = NULL; } if (conn->ho_lchan) { LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n"); conn->ho_lchan->conn = NULL; } if (conn->lchan) { LOGP(DNM, LOGL_ERROR, "The lchan should have been cleared.\n"); conn->lchan->conn = NULL; } if (conn->secondary_lchan) { LOGP(DNM, LOGL_ERROR, "The secondary_lchan should have been cleared.\n"); conn->secondary_lchan->conn = NULL; } llist_del(&conn->entry); talloc_free(conn); }
/*! \brief Terminate FSM instance with given cause * * This safely terminates the given FSM instance by first iterating * over all children and sending them a termination event. Next, it * calls the FSM descriptors cleanup function (if any), followed by * releasing any memory associated with the FSM instance. * * Finally, the parent FSM instance (if any) is notified using the * parent termination event configured at time of FSM instance start. * * \param[in] fi FSM instance to be terminated * \param[in] cause Cause / reason for termination * \param[in] data Opaque event data to be passed with the parent term event * \param[in] file Calling source file (from osmo_fsm_inst_term macro) * \param[in] line Calling source line (from osmo_fsm_inst_term macro) */ void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause, void *data, const char *file, int line) { struct osmo_fsm_inst *parent; uint32_t parent_term_event = fi->proc.parent_term_event; LOGPFSMSRC(fi, file, line, "Terminating (cause = %s)\n", osmo_fsm_term_cause_name(cause)); _osmo_fsm_inst_term_children(fi, OSMO_FSM_TERM_PARENT, NULL, file, line); /* delete ourselves from the parent */ parent = fi->proc.parent; if (parent) LOGPFSMSRC(fi, file, line, "Removing from parent %s\n", osmo_fsm_inst_name(parent)); llist_del(&fi->proc.child); /* call destructor / clean-up function */ if (fi->fsm->cleanup) fi->fsm->cleanup(fi, cause); LOGPFSMSRC(fi, file, line, "Freeing instance\n"); /* Fetch parent again in case it has changed. */ parent = fi->proc.parent; osmo_fsm_inst_free(fi); /* indicate our termination to the parent */ if (parent && cause != OSMO_FSM_TERM_PARENT) _osmo_fsm_inst_dispatch(parent, parent_term_event, data, file, line); }
static int ipa_client_write_default_cb(struct ipa_client_conn *link) { struct osmo_fd *ofd = link->ofd; struct msgb *msg; struct llist_head *lh; int ret; LOGIPA(link, LOGL_DEBUG, "sending data\n"); if (llist_empty(&link->tx_queue)) { ofd->when &= ~BSC_FD_WRITE; return 0; } lh = link->tx_queue.next; llist_del(lh); msg = llist_entry(lh, struct msgb, list); ret = send(link->ofd->fd, msg->data, msg->len, 0); if (ret < 0) { if (errno == EPIPE || errno == ENOTCONN) { ipa_client_conn_close(link); if (link->updown_cb) link->updown_cb(link, 0); } LOGIPA(link, LOGL_ERROR, "error to send\n"); } msgb_free(msg); return 0; }
void llist_erase(t_vector *vec, int at, void (*destruct)()) { void *strct; strct = llist_del(vec, at); if (strct) destruct(strct); }
/** * Flushes a queue of primitives * * @param list list of prims going to be flushed */ void sched_prim_flush_queue(struct llist_head *list) { struct trx_ts_prim *prim, *prim_next; llist_for_each_entry_safe(prim, prim_next, list, list) { llist_del(&prim->list); talloc_free(prim); }
static struct paging_record *dequeue_pr(struct llist_head *group_q) { struct paging_record *pr; pr = llist_entry(group_q->next, struct paging_record, list); llist_del(&pr->list); return pr; }
static void l1ctl_client_destroy(struct l1ctl_sock_client *lsc) { struct l1ctl_sock_inst *lsi = lsc->l1ctl_sock; if (lsi->close_cb) lsi->close_cb(lsc); osmo_fd_close(&lsc->ofd); llist_del(&lsc->list); talloc_free(lsc); }
/*! \brief Dequeue message buffer from head of queue * \param[in] queue linked list header of queue * \returns message buffer (if any) or NULL if queue empty * * The function will remove the first message buffer from the queue * implemented by \ref llist_head \a queue. */ struct msgb *msgb_dequeue(struct llist_head *queue) { struct llist_head *lh; if (llist_empty(queue)) return NULL; lh = queue->next; llist_del(lh); return llist_entry(lh, struct msgb, list); }
void paging_reset(struct paging_state *ps) { int i; for (i = 0; i < ARRAY_SIZE(ps->paging_queue); i++) { struct llist_head *queue = &ps->paging_queue[i]; struct paging_record *pr, *pr2; llist_for_each_entry_safe(pr, pr2, queue, list) { llist_del(&pr->list); talloc_free(pr); ps->num_paging--; } }
/* evict the 'num_evict' number of oldest entries in the queue */ static void tx_queue_evict(struct mux_subch *sch, int num_evict) { struct subch_txq_entry *tqe; int i; for (i = 0; i < num_evict; i++) { if (llist_empty(&sch->tx_queue)) return; tqe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list); llist_del(&tqe->list); talloc_free(tqe); } }
/*! \brief close a telnet connection */ int telnet_close_client(struct osmo_fd *fd) { struct telnet_connection *conn = (struct telnet_connection*)fd->data; close(fd->fd); osmo_fd_unregister(fd); if (conn->dbg) { log_del_target(conn->dbg); talloc_free(conn->dbg); } llist_del(&conn->entry); talloc_free(conn); return 0; }
struct req_ctx *req_ctx_dequeue(struct llist_head *list) { unsigned long flags; struct req_ctx *rctx; local_irq_save(flags); if (llist_empty(list)) { local_irq_restore(flags); return NULL; } rctx = llist_entry(list->next, struct req_ctx, list); llist_del(&rctx->list); local_irq_restore(flags); return rctx; }
/* return the requested number of bits from the specified subchannel */ static int get_subch_bits(struct subch_mux *mx, int subch, u_int8_t *bits, int num_requested) { struct mux_subch *sch = &mx->subch[subch]; int num_bits = 0; while (num_bits < num_requested) { struct subch_txq_entry *txe; int num_bits_left; int num_bits_thistime; /* make sure we have a valid entry at top of tx queue. * if not, add an idle frame */ if (llist_empty(&sch->tx_queue)) alloc_add_idle_frame(mx, subch); if (llist_empty(&sch->tx_queue)) return -EIO; txe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list); num_bits_left = txe->bit_len - txe->next_bit; if (num_bits_left < num_requested) num_bits_thistime = num_bits_left; else num_bits_thistime = num_requested; /* pull the bits from the txe */ memcpy(bits + num_bits, txe->bits + txe->next_bit, num_bits_thistime); txe->next_bit += num_bits_thistime; /* free the tx_queue entry if it is fully consumed */ if (txe->next_bit >= txe->bit_len) { llist_del(&txe->list); talloc_free(txe); } /* increment global number of bits dequeued */ num_bits += num_bits_thistime; } return num_requested; }
/** * Dequeues a single primitive of required type * from a specified transmit queue. * * @param queue a transmit queue to take a prim from * @param lchan_type required primitive type * @return a primitive or NULL if not found */ struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue, enum trx_lchan_type lchan_type) { struct trx_ts_prim *prim; /* There is nothing to dequeue */ if (llist_empty(queue)) return NULL; /* TCH requires FACCH prioritization, so handle it separately */ if (CHAN_IS_TCH(lchan_type)) return sched_prim_dequeue_tch(queue); llist_for_each_entry(prim, queue, list) { if (prim->chan == lchan_type) { llist_del(&prim->list); return prim; } } return NULL; }
static void subscr_free(struct gsm_subscriber *subscr) { llist_del(&subscr->entry); talloc_free(subscr); }
static int atcmd_done(struct gsmd *g, struct gsmd_atcmd *cmd, const char *buf, u_int8_t channel) { int rc = 0; #if ENABLE_TIMEOUTS remove_channel_timeout(g, channel); #endif if (!cmd) { gsmd_log(GSMD_ERROR, "* Null cmd? *\n"); return -1; } if (!cmd->cb) { gsmd_log(GSMD_NOTICE, "command without cb!!!\n"); } else { cmd->flags = ATCMD_FINAL_CB_FLAG; /* send final result code if there is no information * response in mlbuf */ if (g->mlbuf_len[channel]) { cmd->resp = g->mlbuf[channel]; cmd->resplen = g->mlbuf_len[channel]; cmd->resp[cmd->resplen] = 0; } else { cmd->resp = (char*) buf; cmd->resplen = strlen(buf); } DEBUGP("Calling final cmd->cb() %d <%s>(%d) <%d>\n", g->mlbuf_len[channel],cmd->resp,cmd->resplen,cmd->ret); rc = cmd->cb(cmd, cmd->ctx, cmd->resp); if (rc < 0) { gsmd_log(GSMD_ERROR, "Failed to create response for client\n"); } DEBUGP("Clearing mlbuf\n"); g->mlbuf_len[channel] = 0; g->mlbuf[channel][0] = 0; } /* remove from list of currently executing cmds */ llist_del(&cmd->list); #if ENABLE_TIMEOUTS if (TIMEOUT_ERRORCODE == cmd->ret && STATUS_OK == g->modem_status) check_channel(g,channel); #endif atcmd_free(cmd); /* We're finished with the current command, but if still have pending * command(s) then pop off the first pending */ if (llist_empty(&g->busy_atcmds[channel])) { struct gsmd_atcmd *cur = NULL; u_int32_t initial_delay_secs = 0; if (!llist_empty(&g->pending_atcmds[channel])) { gsmd_log(GSMD_INFO, "cmds pending\n"); cur = llist_entry(g->pending_atcmds[channel].next, struct gsmd_atcmd, list); if (cur) { initial_delay_secs = cur->initial_delay_secs; } else { gsmd_log(GSMD_ERROR, "First pending is null?\n"); } } if (g->pin_status) { if (cur) { if (cur->flags & ATCMD_PIN_SENSITIVE) { gsmd_log(GSMD_INFO, "pin_status %d\n",g->pin_status); if (g->sim_status == GSM0707_CME_SIM_NOT_INSERTED) { gsmd_log(GSMD_INFO, "sim not inserted\n"); /* allow the modem to fail the cmd */ wake_pending_after_delay( g,channel,initial_delay_secs); } else { gsmd_log(GSMD_INFO, "* pin sensitive cmd delayed *\n"); g->pin_sensitive_cmds_waiting = 1; } } else { gsmd_log(GSMD_INFO, "wake pending after %d\n", initial_delay_secs); wake_pending_after_delay(g,channel,initial_delay_secs); } } } else { if (g->pin_sensitive_cmds_waiting) { if (cur && (cur->flags & ATCMD_PIN_SENSITIVE)) { u_int8_t ch_iter = 0; gsmd_log(GSMD_INFO, "chk chnls for pin delayed cmds\n"); for (ch_iter = 0; ch_iter < g->number_channels; ch_iter++) { if (ch_iter == channel) continue; if (!llist_empty(&g->pending_atcmds[ch_iter])) { struct gsmd_atcmd *cur2 = llist_entry(g->pending_atcmds[ch_iter].next, struct gsmd_atcmd, list); if (cur2 && (cur2->flags & ATCMD_PIN_SENSITIVE)) { gsmd_log(GSMD_INFO, "* waking chnl %d *\n", ch_iter); wake_pending_after_delay( g, ch_iter, initial_delay_secs); } } } g->pin_sensitive_cmds_waiting = 0; } } gsmd_log(GSMD_INFO, "wake pending after %d secs\n", initial_delay_secs); wake_pending_after_delay(g, channel,initial_delay_secs); }
/* 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
void rate_ctr_group_free(struct rate_ctr_group *grp) { llist_del(&grp->list); talloc_free(grp); }
struct llist *llist_kill(struct llist *l) { while( ! llist_del(l) ); free(l); return (struct llist *)0; }
int bsc_msc_connect(struct bsc_msc_connection *con) { struct bsc_msc_dest *dest; struct osmo_fd *fd; struct sockaddr_in sin; int on = 1, ret; if (llist_empty(con->dests)) { LOGP(DMSC, LOGL_ERROR, "No MSC(%s) connections configured.\n", con->name); connection_loss(con); return -1; } /* TODO: Why are we not using the libosmocore soecket * abstraction, or libosmo-netif? */ /* move to the next connection */ dest = (struct bsc_msc_dest *) con->dests->next; llist_del(&dest->list); llist_add_tail(&dest->list, con->dests); LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC(%s) at %s:%d\n", con->name, dest->ip, dest->port); con->is_connected = 0; msgb_free(con->pending_msg); con->pending_msg = NULL; fd = &con->write_queue.bfd; fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); fd->priv_nr = 1; if (fd->fd < 0) { perror("Creating TCP socket failed"); return fd->fd; } /* make it non blocking */ setnonblocking(fd); /* set the socket priority */ ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, &dest->dscp, sizeof(dest->dscp)); if (ret != 0) LOGP(DMSC, LOGL_ERROR, "Failed to set DSCP to %d on MSC(%s). %s\n", dest->dscp, con->name, strerror(errno)); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(dest->port); inet_aton(dest->ip, &sin.sin_addr); ret = setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (ret != 0) LOGP(DMSC, LOGL_ERROR, "Failed to set SO_REUSEADDR socket option\n"); ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin)); if (ret == -1 && errno == EINPROGRESS) { LOGP(DMSC, LOGL_ERROR, "MSC(%s) Connection in progress\n", con->name); fd->when = BSC_FD_WRITE; fd->cb = msc_connection_connect; con->timeout_timer.cb = msc_con_timeout; con->timeout_timer.data = con; osmo_timer_schedule(&con->timeout_timer, 20, 0); } else if (ret < 0) { perror("Connection failed"); connection_loss(con); return ret; } else { fd->when = BSC_FD_READ | BSC_FD_EXCEPT; fd->cb = osmo_wqueue_bfd_cb; con->is_connected = 1; if (con->connected) con->connected(con); } ret = osmo_fd_register(fd); if (ret < 0) { perror("Registering the fd failed"); close(fd->fd); return ret; } return ret; }
/*! \brief unregister a FSM from the core * * Once the FSM descriptor is unregistered, active instances can still * use it, but no new instances may be created for it. * * \param[in] fsm Descriptor of Finite State Machine to be removed */ void osmo_fsm_unregister(struct osmo_fsm *fsm) { llist_del(&fsm->list); }