void subscr_get_channel(struct gsm_subscriber *subscr, int type, gsm_cbfn *cbfn, void *param) { struct subscr_request *request; request = talloc(tall_sub_req_ctx, struct subscr_request); if (!request) { if (cbfn) cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM, NULL, NULL, param); return; } memset(request, 0, sizeof(*request)); request->subscr = subscr_get(subscr); request->channel_type = type; request->cbfn = cbfn; request->param = param; /* * FIXME: We might be able to assign more than one * channel, e.g. voice and SMS submit at the same * time. */ if (!subscr->in_callback && llist_empty(&subscr->requests)) { /* add to the list, send a request */ llist_add_tail(&request->entry, &subscr->requests); subscr_send_paging_request(subscr); } else { /* this will be picked up later, from subscr_put_channel */ llist_add_tail(&request->entry, &subscr->requests); } }
/** * Adds a primitive to the end of transmit queue of a particular * timeslot, whose index is parsed from chan_nr. * * @param trx TRX instance * @param prim to be enqueued primitive * @param chan_nr RSL channel description * @return zero in case of success, otherwise a error number */ int sched_prim_push(struct trx_instance *trx, struct trx_ts_prim *prim, uint8_t chan_nr) { struct trx_ts *ts; uint8_t tn; /* Determine TS index */ tn = chan_nr & 0x7; if (tn > 7) { LOGP(DSCH, LOGL_ERROR, "Incorrect TS index %u\n", tn); return -EINVAL; } /* Check whether required timeslot is allocated and configured */ ts = trx->ts_list[tn]; if (ts == NULL || ts->mf_layout == NULL) { LOGP(DSCH, LOGL_ERROR, "Timeslot %u isn't configured\n", tn); return -EINVAL; } /** * Change talloc context of primitive * from trx to the parent ts */ talloc_steal(ts, prim); /* Add primitive to TS transmit queue */ llist_add_tail(&prim->list, &ts->tx_prims); return 0; }
static int telnet_new_connection(struct osmo_fd *fd, unsigned int what) { struct telnet_connection *connection; struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len); if (new_connection < 0) { LOGP(0, LOGL_ERROR, "telnet accept failed\n"); return new_connection; } connection = talloc_zero(tall_telnet_ctx, struct telnet_connection); connection->priv = fd->data; connection->fd.data = connection; connection->fd.fd = new_connection; connection->fd.when = BSC_FD_READ; connection->fd.cb = client_data; osmo_fd_register(&connection->fd); llist_add_tail(&connection->entry, &active_connections); print_welcome(new_connection); connection->vty = vty_create(new_connection, connection); if (!connection->vty) { LOGP(0, LOGL_ERROR, "couldn't create VTY\n"); close(new_connection); talloc_free(connection); return -1; } return 0; }
/*! \brief register a FSM with the core * * A FSM descriptor needs to be registered with the core before any * instances can be created for it. * * \param[in] fsm Descriptor of Finite State Machine to be registered * \returns 0 on success; negative on error */ int osmo_fsm_register(struct osmo_fsm *fsm) { /* FIXME:check for duplicate name? */ llist_add_tail(&fsm->list, &g_fsms); INIT_LLIST_HEAD(&fsm->instances); return 0; }
void req_ctx_enqueue(struct llist_head *list, struct req_ctx *rctx) { unsigned long flags; /* FIXME: do we need this kind of locking, we're UP! */ local_irq_save(flags); llist_add_tail(&rctx->list, list); local_irq_restore(flags); }
/* register a cipher with the core */ int gprs_cipher_register(struct gprs_cipher_impl *ciph) { if (ciph->algo >= ARRAY_SIZE(selected_ciphers)) return -ERANGE; llist_add_tail(&ciph->list, &gprs_ciphers); /* check if we want to select this implementation over others */ if (!selected_ciphers[ciph->algo] || (selected_ciphers[ciph->algo]->priority > ciph->priority)) selected_ciphers[ciph->algo] = ciph; return 0; }
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan) { struct gsm_subscriber_connection *conn; conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection); if (!conn) return NULL; /* Configure the time and start it so it will be closed */ conn->lchan = lchan; conn->bts = lchan->ts->trx->bts; lchan->conn = conn; llist_add_tail(&conn->entry, &sub_connections); return conn; }
struct gsm_subscriber *subscr_alloc(void) { struct gsm_subscriber *s; s = talloc_zero(tall_subscr_ctx, struct gsm_subscriber); if (!s) return NULL; llist_add_tail(&s->entry, &active_subscribers); s->use_count = 1; s->tmsi = GSM_RESERVED_TMSI; INIT_LLIST_HEAD(&s->requests); return s; }
static struct osmo_config_entry * alloc_entry(struct osmo_config_list *entries, const char *mcc, const char *mnc, const char *option, const char *text) { struct osmo_config_entry *entry = talloc_zero(entries, struct osmo_config_entry); if (!entry) return NULL; entry->mcc = talloc_strdup(entry, mcc); entry->mnc = talloc_strdup(entry, mnc); entry->option = talloc_strdup(entry, option); entry->text = talloc_strdup(entry, text); llist_add_tail(&entry->list, &entries->entry); return entry; }
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr) { struct mgcp_trunk_config *trunk; trunk = talloc_zero(cfg, struct mgcp_trunk_config); if (!trunk) { LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n"); return NULL; } trunk->cfg = cfg; trunk->trunk_type = MGCP_TRUNK_E1; trunk->trunk_nr = nr; trunk->audio_name = talloc_strdup(cfg, "AMR/8000"); trunk->audio_payload = 126; trunk->number_endpoints = 33; llist_add_tail(&trunk->entry, &cfg->trunks); return trunk; }
/* called for the master (listening) socket of the instance, allocates a new client */ static int l1ctl_sock_accept_cb(struct osmo_fd *ofd, unsigned int what) { struct l1ctl_sock_inst *lsi = ofd->data; struct l1ctl_sock_client *lsc; int fd, rc; fd = accept(ofd->fd, NULL, NULL); if (fd < 0) { LOGP(DL1C, LOGL_ERROR, "Failed to accept connection to l2.\n"); return -1; } lsc = talloc_zero(lsi, struct l1ctl_sock_client); if (!lsc) { close(fd); LOGP(DL1C, LOGL_ERROR, "Failed to allocate L1CTL client\n"); return -1; } lsc->l1ctl_sock = lsi; lsc->ofd.fd = fd; lsc->ofd.when = BSC_FD_READ; lsc->ofd.cb = l1ctl_sock_data_cb; lsc->ofd.data = lsc; if (lsi->accept_cb) { rc = lsi->accept_cb(lsc); if (rc < 0) { talloc_free(lsc); close(fd); return rc; } } LOGP(DL1C, LOGL_INFO, "Accepted client (fd=%u) from server (fd=%u)\n", fd, ofd->fd); if (osmo_fd_register(&lsc->ofd) != 0) { LOGP(DL1C, LOGL_ERROR, "Failed to register the l2 connection fd.\n"); talloc_free(lsc); return -1; } llist_add_tail(&lsc->list, &lsi->clients); return 0; }
/* enqueue some data into the tx_queue of a given subchannel */ int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const u_int8_t *data, int len) { struct mux_subch *sch = &mx->subch[s_nr]; int list_len = llist_len(&sch->tx_queue); struct subch_txq_entry *tqe = talloc_zero_size(tall_tqe_ctx, sizeof(*tqe) + len); if (!tqe) return -ENOMEM; tqe->bit_len = len; memcpy(tqe->bits, data, len); if (list_len > 2) tx_queue_evict(sch, list_len-2); llist_add_tail(&tqe->list, &sch->tx_queue); return 0; }
/* add a new ctrl command */ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd, const char *fmt, ...) { struct trx_ctrl_msg *tcm; va_list ap; int l, pending = 0; if (!transceiver_available && !(!strcmp(cmd, "POWEROFF") || !strcmp(cmd, "POWERON"))) { LOGP(DTRX, LOGL_ERROR, "CTRL %s ignored: No clock from " "transceiver, please fix!\n", cmd); return -EIO; } if (!llist_empty(&l1h->trx_ctrl_list)) pending = 1; /* create message */ tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg); if (!tcm) return -ENOMEM; if (fmt && fmt[0]) { l = snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s ", cmd); va_start(ap, fmt); vsnprintf(tcm->cmd + l, sizeof(tcm->cmd) - l - 1, fmt, ap); va_end(ap); } else snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s", cmd); tcm->cmd_len = strlen(cmd); tcm->critical = critical; llist_add_tail(&tcm->list, &l1h->trx_ctrl_list); LOGP(DTRX, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd); /* send message, if no pending message */ if (!pending) trx_ctrl_send(l1h); return 0; }
struct xua_msg *m3ua_xfer_from_data(const struct m3ua_data_hdr *data_hdr, const uint8_t *data, unsigned int data_len) { struct xua_msg *xua = xua_msg_alloc(); struct xua_msg_part *data_part; xua->hdr = XUA_HDR(M3UA_MSGC_XFER, M3UA_XFER_DATA); /* Network Appearance: Optional */ /* Routing Context: Conditional */ /* Protocol Data: Mandatory */ data_part = talloc_zero(xua, struct xua_msg_part); OSMO_ASSERT(data_part); data_part->tag = M3UA_IEI_PROT_DATA; data_part->len = sizeof(*data_hdr) + data_len; data_part->dat = talloc_size(data_part, data_part->len); OSMO_ASSERT(data_part->dat); memcpy(data_part->dat, data_hdr, sizeof(*data_hdr)); memcpy(data_part->dat+sizeof(*data_hdr), data, data_len); llist_add_tail(&data_part->entry, &xua->headers); /* Correlation Id: Optional */ return xua; }
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; }
/* generate paging message for given gsm time */ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt, int *is_empty) { struct llist_head *group_q; int group; int len; *is_empty = 0; ps->bts->load.ccch.pch_total += 1; group = get_pag_subch_nr(ps, gt); if (group < 0) { LOGP(DPAG, LOGL_ERROR, "Paging called for GSM wrong time: FN %d/%d/%d/%d.\n", gt->fn, gt->t1, gt->t2, gt->t3); return -1; } group_q = &ps->paging_queue[group]; /* There is nobody to be paged, send Type1 with two empty ID */ if (llist_empty(group_q)) { //DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n"); len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0); *is_empty = 1; } else { struct paging_record *pr[4]; unsigned int num_pr = 0, imm_ass = 0; time_t now = time(NULL); unsigned int i, num_imsi = 0; ps->bts->load.ccch.pch_used += 1; /* get (if we have) up to four paging records */ for (i = 0; i < ARRAY_SIZE(pr); i++) { if (llist_empty(group_q)) break; pr[i] = dequeue_pr(group_q); /* check for IMM.ASS */ if (pr[i]->type == PAGING_RECORD_IMM_ASS) { imm_ass = 1; break; } num_pr++; /* count how many IMSIs are among them */ if (pr_is_imsi(pr[i])) num_imsi++; } /* if we have an IMMEDIATE ASSIGNMENT */ if (imm_ass) { /* re-add paging records */ for (i = 0; i < num_pr; i++) llist_add(&pr[i]->list, group_q); /* get message and free record */ memcpy(out_buf, pr[num_pr]->u.imm_ass.msg, GSM_MACBLOCK_LEN); pcu_tx_pch_data_cnf(gt->fn, pr[num_pr]->u.imm_ass.msg, GSM_MACBLOCK_LEN); talloc_free(pr[num_pr]); return GSM_MACBLOCK_LEN; } /* make sure the TMSIs are ahead of the IMSIs in the array */ sort_pr_tmsi_imsi(pr, num_pr); if (num_pr == 4 && num_imsi == 0) { /* No IMSI: easy case, can use TYPE 3 */ DEBUGP(DPAG, "Tx PAGING TYPE 3 (4 TMSI)\n"); len = fill_paging_type_3(out_buf, pr[0]->u.paging.identity_lv, pr[0]->u.paging.chan_needed, pr[1]->u.paging.identity_lv, pr[1]->u.paging.chan_needed, pr[2]->u.paging.identity_lv, pr[2]->u.paging.chan_needed, pr[3]->u.paging.identity_lv, pr[3]->u.paging.chan_needed); } else if (num_pr >= 3 && num_imsi <= 1) { /* 3 or 4, of which only up to 1 is IMSI */ DEBUGP(DPAG, "Tx PAGING TYPE 2 (2 TMSI,1 xMSI)\n"); len = fill_paging_type_2(out_buf, pr[0]->u.paging.identity_lv, pr[0]->u.paging.chan_needed, pr[1]->u.paging.identity_lv, pr[1]->u.paging.chan_needed, pr[2]->u.paging.identity_lv); if (num_pr == 4) { /* re-add #4 for next time */ llist_add(&pr[3]->list, group_q); pr[3] = NULL; } } else if (num_pr == 1) { DEBUGP(DPAG, "Tx PAGING TYPE 1 (1 xMSI,1 empty)\n"); len = fill_paging_type_1(out_buf, pr[0]->u.paging.identity_lv, pr[0]->u.paging.chan_needed, NULL, 0); } else { /* 2 (any type) or * 3 or 4, of which only 2 will be sent */ DEBUGP(DPAG, "Tx PAGING TYPE 1 (2 xMSI)\n"); len = fill_paging_type_1(out_buf, pr[0]->u.paging.identity_lv, pr[0]->u.paging.chan_needed, pr[1]->u.paging.identity_lv, pr[1]->u.paging.chan_needed); if (num_pr >= 3) { /* re-add #4 for next time */ llist_add(&pr[2]->list, group_q); pr[2] = NULL; } if (num_pr == 4) { /* re-add #4 for next time */ llist_add(&pr[3]->list, group_q); pr[3] = NULL; } } for (i = 0; i < num_pr; i++) { /* skip those that we might have re-added above */ if (pr[i] == NULL) continue; rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_SENT); /* check if we can expire the paging record, * or if we need to re-queue it */ if (pr[i]->u.paging.expiration_time <= now) { talloc_free(pr[i]); ps->num_paging--; LOGP(DPAG, LOGL_INFO, "Removed paging record, queue_len=%u\n", ps->num_paging); } else llist_add_tail(&pr[i]->list, group_q); } } memset(out_buf+len, 0x2B, GSM_MACBLOCK_LEN-len); return len; }
/*! \brief Enqueue message buffer to tail of a queue * \param[in] queue linked list header of queue * \param[in] msg message buffer to be added to the queue * * The function will append the specified message buffer \a msg to the * queue implemented by \ref llist_head \a queue */ void msgb_enqueue(struct llist_head *queue, struct msgb *msg) { llist_add_tail(&msg->list, queue); }