/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB) */ static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3) { uint16_t arfcn; uint8_t tsc, tn; uint8_t mf_task_id = p3 & 0xff; uint8_t mf_task_flags = p3 >> 8; putchart('T'); /* before sending first of the four bursts, copy data to API ram */ if (burst_id == 0) { uint16_t *info_ptr = dsp_api.ndb->a_cu; struct msgb *msg; const uint8_t *data; /* distinguish between DCCH and ACCH */ if (mf_task_flags & MF_F_SACCH) { msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_SACCH]); data = msg ? msg->l3h : pu_get_meas_frame(); } else { msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]); data = msg ? msg->l3h : pu_get_idle_frame(); } /* Fill data block Header */ info_ptr[0] = (1 << B_BLUD); // 1st word: Set B_BLU bit. info_ptr[1] = 0; // 2nd word: cleared. info_ptr[2] = 0; // 3rd word: cleared. /* Copy the actual data after the header */ dsp_memcpy_to_api(&info_ptr[3], data, 23, 0); if (msg) msgb_free(msg); } rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn); l1s_tx_apc_helper(arfcn); if (p1 == 0) /* DUL_DSP_TASK, one normal burst */ dsp_load_tch_param(&l1s.next_time, SIG_ONLY_MODE, INVALID_CHANNEL, 0, 0, 0, tn); else if (p1 == 2) /* DUL_DSP_TASK, four normal bursts */ dsp_load_tch_param(&l1s.next_time, SIG_ONLY_MODE, SDCCH_4, 0, 0, 0, tn); dsp_load_tx_task( dsp_task_iq_swap(DUL_DSP_TASK, arfcn, 1), burst_id, tsc ); l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3); return 0; }
/* Callback from select layer if we can write to the socket */ static int gsmtap_fd_cb(struct bsc_fd *fd, unsigned int flags) { struct msgb *msg; int rc; if (!(flags & BSC_FD_WRITE)) return 0; msg = msgb_dequeue(&gsmtap_txqueue); if (!msg) { /* no more messages in the queue, disable READ cb */ gsmtap_bfd.when = 0; return 0; } rc = write(gsmtap_bfd.fd, msg->data, msg->len); if (rc < 0) { perror("writing msgb to gsmtap fd"); msgb_free(msg); return rc; } if (rc != msg->len) { perror("short write to gsmtap fd"); msgb_free(msg); return -EIO; } msgb_free(msg); return 0; }
int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what) { struct write_queue *queue; queue = container_of(fd, struct write_queue, bfd); if (what & BSC_FD_READ) queue->read_cb(fd); if (what & BSC_FD_EXCEPT) queue->except_cb(fd); if (what & BSC_FD_WRITE) { struct msgb *msg; fd->when &= ~BSC_FD_WRITE; msg = msgb_dequeue(&queue->msg_queue); if (!msg) return -1; --queue->current_length; queue->write_cb(fd, msg); msgb_free(msg); if (!llist_empty(&queue->msg_queue)) fd->when |= BSC_FD_WRITE; } return 0; }
/*! \brief Select loop function for write queue handling * \param[in] fd osmocom file descriptor * \param[in] what bit-mask of events that have happened * * This function is provided so that it can be registered with the * select loop abstraction code (\ref osmo_fd::cb). */ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_wqueue *queue; queue = container_of(fd, struct osmo_wqueue, bfd); if (what & BSC_FD_READ) queue->read_cb(fd); if (what & BSC_FD_EXCEPT) queue->except_cb(fd); if (what & BSC_FD_WRITE) { struct msgb *msg; fd->when &= ~BSC_FD_WRITE; /* the queue might have been emptied */ if (!llist_empty(&queue->msg_queue)) { --queue->current_length; msg = msgb_dequeue(&queue->msg_queue); queue->write_cb(fd, msg); msgb_free(msg); if (!llist_empty(&queue->msg_queue)) fd->when |= BSC_FD_WRITE; } } return 0; }
/*! \brief Clear a \ref osmo_wqueue * \param[in] queue Write queue to be cleared * * This function will clear (remove/release) all messages in it. */ void osmo_wqueue_clear(struct osmo_wqueue *queue) { while (!llist_empty(&queue->msg_queue)) { struct msgb *msg = msgb_dequeue(&queue->msg_queue); msgb_free(msg); } queue->current_length = 0; queue->bfd.when &= ~BSC_FD_WRITE; }
/* flush all pending msgb */ void l1a_txq_msgb_flush(struct llist_head *queue) { struct msgb *msg; unsigned long flags; local_firq_save(flags); while ((msg = msgb_dequeue(queue))) msgb_free(msg); local_irq_restore(flags); }
size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link) { size_t deleted = 0; while (!llist_empty(&link->tx_queue)) { struct msgb *msg = msgb_dequeue(&link->tx_queue); msgb_free(msg); deleted += 1; } link->ofd->when &= ~BSC_FD_WRITE; return deleted; }
static int pcu_sock_write(struct osmo_fd *bfd) { struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data; int rc; while (!llist_empty(&state->upqueue)) { struct msgb *msg, *msg2; struct gsm_pcu_if *pcu_prim; /* peek at the beginning of the queue */ msg = llist_entry(state->upqueue.next, struct msgb, list); pcu_prim = (struct gsm_pcu_if *)msg->data; bfd->when &= ~BSC_FD_WRITE; /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */ if (!msgb_length(msg)) { LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO " "bytes!\n", pcu_prim->msg_type); goto dontsend; } /* try to send it over the socket */ rc = write(bfd->fd, msgb_data(msg), msgb_length(msg)); if (rc == 0) goto close; if (rc < 0) { if (errno == EAGAIN) { bfd->when |= BSC_FD_WRITE; break; } goto close; } dontsend: /* _after_ we send it, we can deueue */ msg2 = msgb_dequeue(&state->upqueue); assert(msg == msg2); msgb_free(msg); } return 0; close: pcu_sock_close(state, 1); return -1; }
/*! \brief Select loop function for write queue handling * \param[in] fd osmocom file descriptor * \param[in] what bit-mask of events that have happened * * This function is provided so that it can be registered with the * select loop abstraction code (\ref osmo_fd::cb). */ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_wqueue *queue; int rc; queue = container_of(fd, struct osmo_wqueue, bfd); if (what & BSC_FD_READ) { rc = queue->read_cb(fd); if (rc == -EBADF) goto err_badfd; } if (what & BSC_FD_EXCEPT) { rc = queue->except_cb(fd); if (rc == -EBADF) goto err_badfd; } if (what & BSC_FD_WRITE) { struct msgb *msg; fd->when &= ~BSC_FD_WRITE; /* the queue might have been emptied */ if (!llist_empty(&queue->msg_queue)) { --queue->current_length; msg = msgb_dequeue(&queue->msg_queue); rc = queue->write_cb(fd, msg); msgb_free(msg); if (rc == -EBADF) goto err_badfd; if (!llist_empty(&queue->msg_queue)) fd->when |= BSC_FD_WRITE; } } err_badfd: /* Return value is not checked in osmo_select_main() */ return 0; }
static void ipa_server_conn_write(struct ipa_server_conn *conn) { struct msgb *msg; int ret; LOGIPA(conn, LOGL_DEBUG, "sending data\n"); msg = msgb_dequeue(&conn->tx_queue); if (!msg) { conn->ofd.when &= ~BSC_FD_WRITE; return; } ret = send(conn->ofd.fd, msg->data, msg->len, 0); if (ret < 0) { LOGIPA(conn, LOGL_ERROR, "error to send\n"); } msgb_free(msg); }
/* write from tx_queue to RTP/RTCP socket */ static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss) { struct msgb *msg; int written; msg = msgb_dequeue(&rss->tx_queue); if (!msg) { rss->bfd.when &= ~BSC_FD_WRITE; return 0; } written = write(rss->bfd.fd, msg->data, msg->len); if (written < msg->len) { LOGP(DMIB, LOGL_ERROR, "short write"); msgb_free(msg); return -EIO; } msgb_free(msg); return 0; }
static struct msgb *tx_dequeue_msgb(struct lapdm_entity *le) { struct lapdm_datalink *dl; int last = le->last_tx_dequeue; int i = last, n = ARRAY_SIZE(le->datalink); struct msgb *msg = NULL; /* round-robin dequeue */ do { /* next */ i = (i + 1) % n; dl = &le->datalink[i]; if ((msg = msgb_dequeue(&dl->dl.tx_queue))) break; } while (i != last); if (msg) { /* Set last dequeue position */ le->last_tx_dequeue = i; } return msg; }
static void pcu_sock_close(struct pcu_sock_state *state, int lost) { struct osmo_fd *bfd = &state->conn_bfd; struct gprs_rlcmac_bts *bts = bts_main_data(); uint8_t trx, ts; LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n", (lost) ? "LOST" : "closed"); close(bfd->fd); bfd->fd = -1; osmo_fd_unregister(bfd); /* flush the queue */ while (!llist_empty(&state->upqueue)) { struct msgb *msg = msgb_dequeue(&state->upqueue); msgb_free(msg); } /* disable all slots, kick all TBFs */ for (trx = 0; trx < 8; trx++) { #ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { l1if_close_pdch(bts->trx[trx].fl1h); bts->trx[trx].fl1h = NULL; } #endif for (ts = 0; ts < 8; ts++) bts->trx[trx].pdch[ts].disable(); /* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c for the reset. */ gprs_rlcmac_tbf::free_all(&bts->trx[trx]); } gprs_bssgp_destroy(); exit(0); }