diff options
author | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2012-07-12 14:49:15 +0400 |
---|---|---|
committer | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2012-07-12 14:49:15 +0400 |
commit | ef7f28cc7fe67e353821c5f88bc80d5120fec3ca (patch) | |
tree | ca1b24fafa82862b1d5cd38ce1434973033588f0 /src/pcu_l1_if.cpp | |
parent | c7e7f6868b6f24346424dee904f4e76d3f216ff4 (diff) | |
parent | e13fa2d56936d6bed8febcc41508a30e4a1038f0 (diff) |
Merge branch 'jolly_new'
Merge is based on jolly_new branch with two modifications.
1. Modified PCU L1 interface.
pcu_l1_if.cpp - common functions for tx and rx messages on L1 interface.
sysmo_sock.cpp - SYSMO-PCU socket functions.
openbts_sock.cpp - OpenBTS-PCU socket functions.
pcuif_proto.h - L1 interface's primitives.
2. Modified encoding of RLC/MAC Control messages, now we use structures and encode_gsm_rlcmac_downlink() function for encode control blocks (without hand-coding).
Diffstat (limited to 'src/pcu_l1_if.cpp')
-rw-r--r-- | src/pcu_l1_if.cpp | 568 |
1 files changed, 342 insertions, 226 deletions
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 4186e292..fd8b3c34 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -1,6 +1,6 @@ /* pcu_l1_if.cpp * - * Copyright (C) 2012 Ivan Klyuchnikov + * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,63 +17,25 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <gprs_rlcmac.h> -#include <pcu_l1_if.h> -#include <gprs_debug.h> -#include <bitvector.h> -#include <gsmL1prim.h> +#include <errno.h> +#include <assert.h> #include <sys/socket.h> -#include <linux/in.h> +#include <sys/un.h> extern "C" { #include <osmocom/core/talloc.h> -#include <osmocom/core/write_queue.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/timer.h> -#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/core/select.h> +#include <osmocom/core/msgb.h> } -#define MAX_UDP_LENGTH 1500 - -#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) - -struct femtol1_hdl { - struct gsm_time gsm_time; - uint32_t hLayer1; /* handle to the L1 instance in the DSP */ - uint32_t dsp_trace_f; - uint16_t clk_cal; - struct llist_head wlc_list; - - void *priv; /* user reference */ - - struct osmo_timer_list alive_timer; - unsigned int alive_prim_cnt; - - struct osmo_fd read_ofd; /* osmo file descriptors */ - struct osmo_wqueue write_q; - - struct { - uint16_t arfcn; - uint8_t tn; - uint8_t tsc; - uint16_t ta; - } channel_info; - -}; - -struct l1fwd_hdl { - struct sockaddr_storage remote_sa; - socklen_t remote_sa_len; - - struct osmo_wqueue udp_wq; - - struct femtol1_hdl *fl1h; -}; - -struct l1fwd_hdl *l1fh = talloc_zero(NULL, struct l1fwd_hdl); - -struct pcu_l1if_bts pcu_l1if_bts; +#include <gprs_rlcmac.h> +#include <pcu_l1_if.h> +#include <gprs_debug.h> +#include <gprs_bssgp_pcu.h> +#include <pcuif_proto.h> // Variable for storage current FN. int frame_number; @@ -88,244 +50,398 @@ void set_current_fn(int fn) frame_number = fn; } -struct msgb *l1p_msgb_alloc(void) +/* + * PCU messages + */ + +struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr) { - struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim"); + struct msgb *msg; + struct gsm_pcu_if *pcu_prim; - if (msg) - msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t)); + msg = msgb_alloc(sizeof(struct gsm_pcu_if), "pcu_sock_tx"); + if (!msg) + return NULL; + msgb_put(msg, sizeof(struct gsm_pcu_if)); + pcu_prim = (struct gsm_pcu_if *) msg->data; + pcu_prim->msg_type = msg_type; + pcu_prim->bts_nr = bts_nr; return msg; } -// Send RLC/MAC block to OpenBTS. -void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, - uint32_t fn, uint8_t block_nr) +static int pcu_tx_act_req(uint8_t trx, uint8_t ts, uint8_t activate) { - struct msgb *nmsg = l1p_msgb_alloc(); - GsmL1_Prim_t *prim = msgb_l1prim(nmsg); - - prim->id = GsmL1_PrimId_PhDataReq; - prim->u.phDataReq.sapi = GsmL1_Sapi_Pdtch; - memcpy(prim->u.phDataReq.msgUnitParam.u8Buffer, msg->data, msg->len); - prim->u.phDataReq.msgUnitParam.u8Size = msg->len; - osmo_wqueue_enqueue(&l1fh->udp_wq, nmsg); - msgb_free(msg); + struct msgb *msg; + struct gsm_pcu_if *pcu_prim; + struct gsm_pcu_if_act_req *act_req; + + LOGP(DL1IF, LOGL_INFO, "Sending %s request: trx=%d ts=%d\n", + (activate) ? "activate" : "deactivate", trx, ts); + + msg = pcu_msgb_alloc(PCU_IF_MSG_ACT_REQ, 0); + if (!msg) + return -ENOMEM; + pcu_prim = (struct gsm_pcu_if *) msg->data; + act_req = &pcu_prim->u.act_req; + act_req->activate = activate; + act_req->trx_nr = trx; + act_req->ts_nr = ts; + + return pcu_sock_send(msg); } -void pcu_l1if_tx_agch(bitvec * block, int len) +static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, + uint16_t arfcn, uint32_t fn, uint8_t block_nr, uint8_t *data, + uint8_t len) { - struct msgb *msg = l1p_msgb_alloc(); - GsmL1_Prim_t *prim = msgb_l1prim(msg); - - prim->id = GsmL1_PrimId_PhDataReq; - prim->u.phDataReq.sapi = GsmL1_Sapi_Agch; - bitvec_pack(block, prim->u.phDataReq.msgUnitParam.u8Buffer); - prim->u.phDataReq.msgUnitParam.u8Size = len; - osmo_wqueue_enqueue(&l1fh->udp_wq, msg); + struct msgb *msg; + struct gsm_pcu_if *pcu_prim; + struct gsm_pcu_if_data *data_req; + + LOGP(DL1IF, LOGL_DEBUG, "Sending data request: trx=%d ts=%d sapi=%d " + "arfcn=%d fn=%d block=%d data=%s\n", trx, ts, sapi, arfcn, fn, + block_nr, osmo_hexdump(data, len)); + + msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_REQ, 0); + if (!msg) + return -ENOMEM; + pcu_prim = (struct gsm_pcu_if *) msg->data; + data_req = &pcu_prim->u.data_req; + + data_req->sapi = sapi; + data_req->fn = fn; + data_req->arfcn = arfcn; + data_req->trx_nr = trx; + data_req->ts_nr = ts; + data_req->block_nr = block_nr; + memcpy(data_req->data, data, len); + data_req->len = len; + + return pcu_sock_send(msg); } -void pcu_l1if_tx_pch(bitvec * block, int len) +void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, + uint32_t fn, uint8_t block_nr) { - struct msgb *msg = l1p_msgb_alloc(); - GsmL1_Prim_t *prim = msgb_l1prim(msg); - prim->id = GsmL1_PrimId_PhDataReq; - prim->u.phDataReq.sapi = GsmL1_Sapi_Pch; - bitvec_pack(block, prim->u.phDataReq.msgUnitParam.u8Buffer); - prim->u.phDataReq.msgUnitParam.u8Size = len; - osmo_wqueue_enqueue(&l1fh->udp_wq, msg); + pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr, + msg->data, msg->len); + msgb_free(msg); } -int pcu_l1if_rx_pdch(GsmL1_PhDataInd_t *data_ind) +void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, + uint32_t fn, uint8_t block_nr) { - bitvec *block = bitvec_alloc(data_ind->msgUnitParam.u8Size); - bitvec_unpack(block, data_ind->msgUnitParam.u8Buffer); - gprs_rlcmac_rcv_block(block); - bitvec_free(block); - - return 0; + pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, + msg->data, msg->len); + msgb_free(msg); } -static int handle_ph_connect_ind(struct femtol1_hdl *fl1, GsmL1_PhConnectInd_t *connect_ind) +void pcu_l1if_tx_agch(bitvec * block, int plen) { - pcu_l1if_bts.trx[0].arfcn = connect_ind->u16Arfcn; - pcu_l1if_bts.trx[0].ts[connect_ind->u8Tn].enable = 1; - pcu_l1if_bts.trx[0].ts[connect_ind->u8Tn].tsc = connect_ind->u8Tsc; - (l1fh->fl1h)->channel_info.arfcn = connect_ind->u16Arfcn; - (l1fh->fl1h)->channel_info.tn = connect_ind->u8Tn; - (l1fh->fl1h)->channel_info.tsc = connect_ind->u8Tsc; - LOGP(DL1IF, LOGL_NOTICE, "RX: [ PCU <- BTS ] PhConnectInd: ARFCN: %u TN: %u TSC: %u \n", - connect_ind->u16Arfcn, (unsigned)connect_ind->u8Tn, (unsigned)connect_ind->u8Tsc); + uint8_t data[23]; /* prefix PLEN */ + + /* FIXME: why does OpenBTS has no PLEN and no fill in message? */ + bitvec_pack(block, data + 1); + data[0] = (plen << 2) | 0x01; + pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23); +} - return 0; +void pcu_l1if_tx_pch(bitvec * block, int plen, char *imsi) +{ + uint8_t data[23+3]; /* prefix PLEN */ + + /* paging group */ + if (!imsi || strlen(imsi) < 3) + return; + imsi += strlen(imsi) - 3; + data[0] = imsi[0]; + data[1] = imsi[1]; + data[2] = imsi[2]; + + bitvec_pack(block, data + 3+1); + data[3] = (plen << 2) | 0x01; + pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3); } -static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *readytosend_ind) +static void pcu_l1if_tx_bcch(uint8_t *data, int len) { - gprs_rlcmac_rcv_rts_block(0,0, (l1fh->fl1h)->channel_info.arfcn, readytosend_ind->u32Fn, 0); - return 1; + pcu_tx_data_req(0, 0, PCU_IF_SAPI_BCCH, 0, 0, 0, data, len); } -static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind) +static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) { int rc = 0; + + LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d " + "block=%d data=%s\n", data_ind->sapi, + data_ind->arfcn, data_ind->block_nr, + osmo_hexdump(data_ind->data, data_ind->len)); + switch (data_ind->sapi) { - case GsmL1_Sapi_Rach: - break; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - pcu_l1if_rx_pdch(data_ind); - break; - case GsmL1_Sapi_Pbcch: - case GsmL1_Sapi_Pagch: - case GsmL1_Sapi_Ppch: - case GsmL1_Sapi_Pnch: - case GsmL1_Sapi_Ptcch: - case GsmL1_Sapi_Prach: + case PCU_IF_SAPI_PDTCH: + rc = gprs_rlcmac_rcv_block(data_ind->data, data_ind->len, + data_ind->fn); break; default: - LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %u \n", data_ind->sapi); - break; + LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with " + "unsupported sapi %d\n", data_ind->sapi); + rc = -EINVAL; } return rc; } -static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind) +static int pcu_rx_rts_req(struct gsm_pcu_if_rts_req *rts_req) { int rc = 0; - (l1fh->fl1h)->channel_info.ta = ra_ind->measParam.i16BurstTiming; - rc = gprs_rlcmac_rcv_rach(ra_ind->msgUnitParam.u8Buffer[0], ra_ind->u32Fn, ra_ind->measParam.i16BurstTiming); - return rc; -} -/* handle any random indication from the L1 */ -int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg) -{ - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - int rc = 0; + LOGP(DL1IF, LOGL_DEBUG, "RTS request received: trx=%d ts=%d sapi=%d " + "arfcn=%d fn=%d block=%d\n", rts_req->trx_nr, rts_req->ts_nr, + rts_req->sapi, rts_req->arfcn, rts_req->fn, rts_req->block_nr); - switch (l1p->id) { - case GsmL1_PrimId_PhConnectInd: - rc = handle_ph_connect_ind(fl1, &l1p->u.phConnectInd); - break; - case GsmL1_PrimId_PhReadyToSendInd: - rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd); + switch (rts_req->sapi) { + case PCU_IF_SAPI_PDTCH: + gprs_rlcmac_rcv_rts_block(rts_req->trx_nr, rts_req->ts_nr, + rts_req->arfcn, rts_req->fn, rts_req->block_nr); break; - case GsmL1_PrimId_PhDataInd: - rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd); - break; - case GsmL1_PrimId_PhRaInd: - rc = handle_ph_ra_ind(fl1, &l1p->u.phRaInd); + case PCU_IF_SAPI_PTCCH: + /* FIXME */ + { + struct msgb *msg = msgb_alloc(23, "l1_prim"); + memset(msgb_put(msg, 23), 0x2b, 23); + pcu_l1if_tx_ptcch(msg, rts_req->trx_nr, rts_req->ts_nr, + rts_req->arfcn, rts_req->fn, rts_req->block_nr); + } break; default: - break; + LOGP(DL1IF, LOGL_ERROR, "Received PCU RTS request with " + "unsupported sapi %d\n", rts_req->sapi); + rc = -EINVAL; } - /* Special return value '1' means: do not free */ - if (rc != 1) - msgb_free(msg); - return rc; } -/* OpenBTS socket functions */ - -// TODO: We should move this parameters to config file. -#define PCU_L1_IF_PORT 5944 - -/* data has arrived on the udp socket */ -static int udp_read_cb(struct osmo_fd *ofd) +static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind) { - struct msgb *msg = msgb_alloc_headroom(2048, 128, "udp_rx"); - struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data; - struct femtol1_hdl *fl1h = l1fh->fl1h; - int rc; - - if (!msg) - return -ENOMEM; + int rc = 0; - msg->l1h = msg->data; + LOGP(DL1IF, LOGL_INFO, "RACH request received: sapi=%d " + "qta=%d, ra=%d, fn=%d\n", rach_ind->sapi, rach_ind->qta, + rach_ind->ra, rach_ind->fn); - l1fh->remote_sa_len = sizeof(l1fh->remote_sa); - rc = recvfrom(ofd->fd, msg->l1h, msgb_tailroom(msg), 0, - (struct sockaddr *) &l1fh->remote_sa, &l1fh->remote_sa_len); - if (rc < 0) { - perror("read from udp"); - msgb_free(msg); - return rc; - } else if (rc == 0) { - perror("len=0 read from udp"); - msgb_free(msg); - return rc; + switch (rach_ind->sapi) { + case PCU_IF_SAPI_RACH: + rc = gprs_rlcmac_rcv_rach(rach_ind->ra, rach_ind->fn, + rach_ind->qta); + break; + default: + LOGP(DL1IF, LOGL_ERROR, "Received PCU rach request with " + "unsupported sapi %d\n", rach_ind->sapi); + rc = -EINVAL; } - msgb_put(msg, rc); - rc = pcu_l1if_handle_l1prim(fl1h, msg); return rc; } -/* callback when we can write to the UDP socket */ -static int udp_write_cb(struct osmo_fd *ofd, struct msgb *msg) +static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) { - int rc; - struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data; - - //DEBUGP(DGPRS, "UDP: Writing %u bytes for MQ_L1_WRITE queue\n", msgb_l1len(msg)); - - rc = sendto(ofd->fd, msg->l1h, msgb_l1len(msg), 0, - (const struct sockaddr *)&l1fh->remote_sa, l1fh->remote_sa_len); + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + int rc = 0; + int trx, ts, tfi; + struct gprs_rlcmac_tbf *tbf; + int i; + + LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); + + if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) { + LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n"); +bssgp_failed: + /* free all TBF */ + for (trx = 0; trx < 8; trx++) { + bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; + for (ts = 0; ts < 8; ts++) { + for (tfi = 0; tfi < 32; tfi++) { + tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + if (tbf) + tbf_free(tbf); + } + } + } + gprs_bssgp_destroy(); + return 0; + } + LOGP(DL1IF, LOGL_INFO, "BTS available\n"); + LOGP(DL1IF, LOGL_DEBUG, " mcc=%d\n", info_ind->mcc); + LOGP(DL1IF, LOGL_DEBUG, " mnc=%d\n", info_ind->mnc); + LOGP(DL1IF, LOGL_DEBUG, " lac=%d\n", info_ind->lac); + LOGP(DL1IF, LOGL_DEBUG, " rac=%d\n", info_ind->rac); + LOGP(DL1IF, LOGL_DEBUG, " cell_id=%d\n", info_ind->cell_id); + LOGP(DL1IF, LOGL_DEBUG, " nsei=%d\n", info_ind->nsei); + LOGP(DL1IF, LOGL_DEBUG, " nse_timer=%d %d %d %d %d %d %d\n", + info_ind->nse_timer[0], info_ind->nse_timer[1], + info_ind->nse_timer[2], info_ind->nse_timer[3], + info_ind->nse_timer[4], info_ind->nse_timer[5], + info_ind->nse_timer[6]); + LOGP(DL1IF, LOGL_DEBUG, " cell_timer=%d %d %d %d %d %d %d %d %d %d " + "%d\n", + info_ind->cell_timer[0], info_ind->cell_timer[1], + info_ind->cell_timer[2], info_ind->cell_timer[3], + info_ind->cell_timer[4], info_ind->cell_timer[5], + info_ind->cell_timer[6], info_ind->cell_timer[7], + info_ind->cell_timer[8], info_ind->cell_timer[9], + info_ind->cell_timer[10]); + LOGP(DL1IF, LOGL_DEBUG, " repeat_time=%d\n", info_ind->repeat_time); + LOGP(DL1IF, LOGL_DEBUG, " repeat_count=%d\n", info_ind->repeat_count); + LOGP(DL1IF, LOGL_DEBUG, " bvci=%d\n", info_ind->bvci); + LOGP(DL1IF, LOGL_DEBUG, " t3142=%d\n", info_ind->t3142); + LOGP(DL1IF, LOGL_DEBUG, " t3169=%d\n", info_ind->t3169); + LOGP(DL1IF, LOGL_DEBUG, " t3191=%d\n", info_ind->t3191); + LOGP(DL1IF, LOGL_DEBUG, " t3193=%d (ms)\n", info_ind->t3193_10ms * 10); + LOGP(DL1IF, LOGL_DEBUG, " t3195=%d\n", info_ind->t3195); + LOGP(DL1IF, LOGL_DEBUG, " n3101=%d\n", info_ind->n3101); + LOGP(DL1IF, LOGL_DEBUG, " n3103=%d\n", info_ind->n3103); + LOGP(DL1IF, LOGL_DEBUG, " n3105=%d\n", info_ind->n3105); + LOGP(DL1IF, LOGL_DEBUG, " cv_countdown=%d\n", info_ind->cv_countdown); + LOGP(DL1IF, LOGL_DEBUG, " dl_tbf_ext=%d\n", info_ind->dl_tbf_ext); + LOGP(DL1IF, LOGL_DEBUG, " ul_tbf_ext=%d\n", info_ind->ul_tbf_ext); + for (i = 0; i < 4; i++) { + if ((info_ind->flags & (PCU_IF_FLAG_CS1 << i))) + LOGP(DL1IF, LOGL_DEBUG, " Use CS%d\n", i+1); + } + for (i = 0; i < 9; i++) { + if ((info_ind->flags & (PCU_IF_FLAG_MCS1 << i))) + LOGP(DL1IF, LOGL_DEBUG, " Use MCS%d\n", i+1); + } + LOGP(DL1IF, LOGL_DEBUG, " initial_cs=%d\n", info_ind->initial_cs); + LOGP(DL1IF, LOGL_DEBUG, " initial_mcs=%d\n", info_ind->initial_mcs); + LOGP(DL1IF, LOGL_DEBUG, " nsvci=%d\n", info_ind->nsvci[0]); + LOGP(DL1IF, LOGL_DEBUG, " local_port=%d\n", info_ind->local_port[0]); + LOGP(DL1IF, LOGL_DEBUG, " remote_port=%d\n", info_ind->remote_port[0]); + LOGP(DL1IF, LOGL_DEBUG, " remote_ip=%d\n", info_ind->remote_ip[0]); + + rc = gprs_bssgp_create(info_ind->remote_ip[0], info_ind->remote_port[0], + info_ind->nsei, info_ind->nsvci[0], info_ind->bvci, + info_ind->mcc, info_ind->mnc, info_ind->lac, info_ind->rac, + info_ind->cell_id); if (rc < 0) { - LOGP(DPCU, LOGL_ERROR, "error writing to L1 msg_queue: %s\n", - strerror(errno)); - return rc; - } else if (rc < (int)msgb_l1len(msg)) { - LOGP(DPCU, LOGL_ERROR, "short write to L1 msg_queue: " - "%u < %u\n", rc, msgb_l1len(msg)); - return -EIO; + LOGP(DL1IF, LOGL_NOTICE, "SGSN not available\n"); + goto bssgp_failed; } - return 0; + bts->cs1 = !!(info_ind->flags & PCU_IF_FLAG_CS1); + bts->cs2 = !!(info_ind->flags & PCU_IF_FLAG_CS2); + bts->cs3 = !!(info_ind->flags & PCU_IF_FLAG_CS3); + bts->cs4 = !!(info_ind->flags & PCU_IF_FLAG_CS4); + if (!bts->cs1 && !bts->cs2 && !bts->cs3 && !bts->cs4) + bts->cs1 = 1; + if (info_ind->t3142) { /* if timer values are set */ + bts->t3142 = info_ind->t3142; + bts->t3169 = info_ind->t3169; + bts->t3191 = info_ind->t3191; + bts->t3193_msec = info_ind->t3193_10ms * 10; + bts->t3195 = info_ind->t3195; + bts->n3101 = info_ind->n3101; + bts->n3103 = info_ind->n3103; + bts->n3105 = info_ind->n3105; + } + if (info_ind->initial_cs < 1 || info_ind->initial_cs > 4) + bts->initial_cs = 1; + else + bts->initial_cs = info_ind->initial_cs; + + for (trx = 0; trx < 8; trx++) { + bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; + for (ts = 0; ts < 8; ts++) { + if ((info_ind->trx[trx].pdch_mask & (1 << ts))) { + /* FIXME: activate dynamically at RLCMAC */ + if (!bts->trx[trx].pdch[ts].enable) + pcu_tx_act_req(trx, ts, 1); + bts->trx[trx].pdch[ts].enable = 1; + bts->trx[trx].pdch[ts].tsc = + info_ind->trx[trx].tsc[ts]; + LOGP(DL1IF, LOGL_INFO, "PDCH: trx=%d ts=%d\n", + trx, ts); + } else { + if (bts->trx[trx].pdch[ts].enable) + pcu_tx_act_req(trx, ts, 0); + bts->trx[trx].pdch[ts].enable = 0; + /* kick all tbf FIXME: multislot */ + for (tfi = 0; tfi < 32; tfi++) { + tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + if (tbf) + tbf_free(tbf); + } + } + } + } + + return rc; } -int pcu_l1if_open() +static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind) { - //struct l1fwd_hdl *l1fh; - struct femtol1_hdl *fl1h; - int rc; - - memset(&pcu_l1if_bts, 0, sizeof(pcu_l1if_bts)); - - /* allocate new femtol1_handle */ - fl1h = talloc_zero(NULL, struct femtol1_hdl); - INIT_LLIST_HEAD(&fl1h->wlc_list); - - l1fh->fl1h = fl1h; - fl1h->priv = l1fh; - - struct osmo_wqueue * queue = &((l1fh->fl1h)->write_q); - osmo_wqueue_init(queue, 10); - queue->bfd.when |= BSC_FD_READ; - queue->bfd.data = l1fh; - queue->bfd.priv_nr = 0; - - /* Open UDP */ - struct osmo_wqueue *wq = &l1fh->udp_wq; - - osmo_wqueue_init(wq, 10); - wq->write_cb = udp_write_cb; - wq->read_cb = udp_read_cb; - wq->bfd.when |= BSC_FD_READ; - wq->bfd.data = l1fh; - wq->bfd.priv_nr = 0; - rc = osmo_sock_init_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, - IPPROTO_UDP, NULL, PCU_L1_IF_PORT, - OSMO_SOCK_F_BIND); - if (rc < 0) { - perror("sock_init"); - exit(1); + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + int trx, ts, tfi; + struct gprs_rlcmac_tbf *tbf; + uint32_t elapsed; + uint8_t fn13 = time_ind->fn % 13; + + /* omit frame numbers not starting at a MAC block */ + if (fn13 != 0 && fn13 != 4 && fn13 != 8) + return 0; + + LOGP(DL1IF, LOGL_DEBUG, "Time indication received: %d\n", + time_ind->fn % 52); + + set_current_fn(time_ind->fn); + + /* check for poll timeout */ + for (trx = 0; trx < 8; trx++) { + for (ts = 0; ts < 8; ts++) { + for (tfi = 0; tfi < 32; tfi++) { + tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + if (!tbf) + continue; + if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) + continue; + elapsed = (frame_number - tbf->poll_fn) + % 2715648; + if (elapsed >= 20 && elapsed < 200) + gprs_rlcmac_poll_timeout(tbf); + } + } } return 0; } +int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) +{ + int rc = 0; + + switch (msg_type) { + case PCU_IF_MSG_DATA_IND: + rc = pcu_rx_data_ind(&pcu_prim->u.data_ind); + break; + case PCU_IF_MSG_RTS_REQ: + rc = pcu_rx_rts_req(&pcu_prim->u.rts_req); + break; + case PCU_IF_MSG_RACH_IND: + rc = pcu_rx_rach_ind(&pcu_prim->u.rach_ind); + break; + case PCU_IF_MSG_INFO_IND: + rc = pcu_rx_info_ind(&pcu_prim->u.info_ind); + break; + case PCU_IF_MSG_TIME_IND: + rc = pcu_rx_time_ind(&pcu_prim->u.time_ind); + break; + default: + LOGP(DL1IF, LOGL_ERROR, "Received unknwon PCU msg type %d\n", + msg_type); + rc = -EINVAL; + } + + return rc; +} |