From e3a059656f6bf0dd338889b8bd742089e628df70 Mon Sep 17 00:00:00 2001 From: Ivan Kluchnikov Date: Sun, 18 Mar 2012 15:48:51 +0400 Subject: [PATCH] Added L1 interface between PCU and OpenBTS for communication (PCU side). --- gsmL1prim.h | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++ pcu_l1_if.cpp | 95 ++++++++++-- pcu_l1_if.h | 39 ++++- pcu_main.cpp | 93 +++++++++++- 4 files changed, 618 insertions(+), 19 deletions(-) create mode 100644 gsmL1prim.h diff --git a/gsmL1prim.h b/gsmL1prim.h new file mode 100644 index 00000000..f33b2e06 --- /dev/null +++ b/gsmL1prim.h @@ -0,0 +1,410 @@ +/* +* Copyright 2012 Thomas Cooper +* +* This software is distributed under the terms of the GNU Affero Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +*/ + +#ifndef GSML1PRIM_H +#define GSML1PRIM_H + +#include + +typedef enum GsmL1_SubCh_t { +GsmL1_SubCh_NA, +} GsmL1_SubCh_t; + +typedef enum GsmL1_Sapi_t { +GsmL1_Sapi_Fcch, +GsmL1_Sapi_Sch, +GsmL1_Sapi_Sacch, +GsmL1_Sapi_Sdcch, +GsmL1_Sapi_Bcch, +GsmL1_Sapi_Pch, +GsmL1_Sapi_Agch, +GsmL1_Sapi_Cbch, +GsmL1_Sapi_Rach, +GsmL1_Sapi_TchF, +GsmL1_Sapi_FacchF, +GsmL1_Sapi_TchH, +GsmL1_Sapi_FacchH, +GsmL1_Sapi_Nch, +GsmL1_Sapi_Pdtch, +GsmL1_Sapi_Pacch, +GsmL1_Sapi_Pbcch, +GsmL1_Sapi_Pagch, +GsmL1_Sapi_Ppch, +GsmL1_Sapi_Pnch, +GsmL1_Sapi_Ptcch, +GsmL1_Sapi_Prach, +GsmL1_Sapi_Idle, +GsmL1_Sapi_NUM, +} GsmL1_Sapi_t; + +typedef enum GsmL1_Status_t { +GsmL1_Status_Success, +GsmL1_Status_Generic, +GsmL1_Status_NoMemory, +GsmL1_Status_Timeout, +GsmL1_Status_InvalidParam, +GsmL1_Status_Busy, +GsmL1_Status_NoRessource, +GsmL1_Status_Uninitialized, +GsmL1_Status_NullInterface, +GsmL1_Status_NullFctnPtr, +GsmL1_Status_BadCrc, +GsmL1_Status_BadUsf, +GsmL1_Status_InvalidCPS, +GsmL1_Status_UnexpectedBurst, +GsmL1_Status_UnavailCodec, +GsmL1_Status_CriticalError, +GsmL1_Status_OverheatError, +GsmL1_Status_DeviceError, +GsmL1_Status_FacchError, +GsmL1_Status_AlreadyDeactivated, +GsmL1_Status_TxBurstFifoOvrn, +GsmL1_Status_TxBurstFifoUndr, +GsmL1_Status_NotSynchronized, +GsmL1_Status_Unsupported, +GSML1_STATUS_NUM, +} GsmL1_Status_t; + +typedef enum GsmL1_PrimId_t { +GsmL1_PrimId_MphInitReq, +GsmL1_PrimId_MphCloseReq, +GsmL1_PrimId_MphConnectReq, +GsmL1_PrimId_MphDisconnectReq, +GsmL1_PrimId_MphActivateReq, +GsmL1_PrimId_MphDeactivateReq, +GsmL1_PrimId_MphConfigReq, +GsmL1_PrimId_MphMeasureReq, +GsmL1_PrimId_MphInitCnf, +GsmL1_PrimId_MphCloseCnf, +GsmL1_PrimId_MphConnectCnf, +GsmL1_PrimId_MphDisconnectCnf, +GsmL1_PrimId_MphActivateCnf, +GsmL1_PrimId_MphDeactivateCnf, +GsmL1_PrimId_MphConfigCnf, +GsmL1_PrimId_MphMeasureCnf, +GsmL1_PrimId_MphTimeInd, +GsmL1_PrimId_MphSyncInd, +GsmL1_PrimId_PhEmptyFrameReq, +GsmL1_PrimId_PhDataReq, +GsmL1_PrimId_PhConnectInd, +GsmL1_PrimId_PhReadyToSendInd, +GsmL1_PrimId_PhDataInd, +GsmL1_PrimId_PhRaInd, +GsmL1_PrimId_NUM, +} GsmL1_PrimId_t; + +typedef enum GsmL1_Dir_t { +GsmL1_Dir_TxDownlink, +GsmL1_Dir_RxUplink, +} GsmL1_Dir_t; + +typedef enum GsmL1_DevType_t { +GsmL1_DevType_TxdRxu, +} GsmL1_DevType_t; + +typedef enum GsmL1_TchPlType_t { +GsmL1_TchPlType_NA, +GsmL1_TchPlType_Efr, +GsmL1_TchPlType_Fr, +GsmL1_TchPlType_Hr, +GsmL1_TchPlType_Amr, +GsmL1_TchPlType_Amr_SidBad, +GsmL1_TchPlType_Amr_Onset, +GsmL1_TchPlType_Amr_Ratscch, +GsmL1_TchPlType_Amr_SidUpdateInH, +GsmL1_TchPlType_Amr_SidFirstP1, +GsmL1_TchPlType_Amr_SidFirstP2, +GsmL1_TchPlType_Amr_SidFirstInH, +GsmL1_TchPlType_Amr_RatscchMarker, +GsmL1_TchPlType_Amr_RatscchData, +} GsmL1_TchPlType_t; + +typedef enum GsmL1_ConfigParamId_t { +GsmL1_ConfigParamId_SetNbTsc, +GsmL1_ConfigParamId_SetTxPowerLevel, +GsmL1_ConfigParamId_SetLogChParams, +GsmL1_ConfigParamId_SetCipheringParams, +} GsmL1_ConfigParamId_t; + +typedef struct GsmL1_DeviceParam_t { +enum GsmL1_DevType_t devType; +int freqBand; +uint16_t u16Arfcn; +uint16_t u16BcchArfcn; +uint8_t u8NbTsc; +uint8_t u8Ncc; +float fRxPowerLevel; +float fTxPowerLevel; +} GsmL1_DeviceParam_t; + +typedef struct GsmL1_MsgUnitParam_t { +uint8_t u8Buffer[256]; +uint8_t u8Size; +} GsmL1_MsgUnitParam_t; + +typedef struct GsmL1_MeasParam_t { +float fRssi; +float fLinkQuality; +float fBer; +int16_t i16BurstTiming; +} GsmL1_MeasParam_t; + +typedef struct GsmL1_LogChParam_t { +union { +struct { +enum GsmL1_TchPlType_t tchPlType; + +enum { +GsmL1_AmrCmiPhase_NA, +GsmL1_AmrCmiPhase_Odd, +} amrCmiPhase; + +enum { +GsmL1_AmrCodecMode_Unset, +} amrInitCodecMode; + +enum { +GsmL1_AmrCodec_Unset, +GsmL1_AmrCodec_4_75, +GsmL1_AmrCodec_5_15, +GsmL1_AmrCodec_5_9, +GsmL1_AmrCodec_6_7, +GsmL1_AmrCodec_7_4, +GsmL1_AmrCodec_7_95, +GsmL1_AmrCodec_10_2, +GsmL1_AmrCodec_12_2, +} amrActiveCodecSet[8]; +} tch; + +struct { +uint8_t u8Bsic; +uint8_t u8NbrOfAgch; +} rach; + +struct { +uint8_t u8MsPowerLevel; +} sacch; + +struct { +uint8_t u8NbrOfAgch; +} agch; +}; +} GsmL1_LogChParam_t; + +typedef enum GsmL1_LogChComb_t { +GsmL1_LogChComb_0, +GsmL1_LogChComb_I, +GsmL1_LogChComb_II, +GsmL1_LogChComb_IV, +GsmL1_LogChComb_V, +GsmL1_LogChComb_VII, +GsmL1_LogChComb_XIII, +} GsmL1_LogChComb_t; + +enum { +GsmL1_FreqBand_850, +GsmL1_FreqBand_900, +GsmL1_FreqBand_1800, +GsmL1_FreqBand_1900, +}; + +typedef struct GsmL1_MphInitReq_t { +struct GsmL1_DeviceParam_t deviceParam; +} GsmL1_MphInitReq_t; + +typedef struct GsmL1_MphCloseReq_t { +uint32_t hLayer1; +} GsmL1_MphCloseReq_t; + +typedef struct GsmL1_MphConnectReq_t { +uint32_t hLayer1; +uint8_t u8Tn; +enum GsmL1_LogChComb_t logChComb; +} GsmL1_MphConnectReq_t; + +typedef struct GsmL1_MphDisconnectReq_t { +uint32_t hLayer1; +} GsmL1_MphDisconnectReq_t; + +typedef struct GsmL1_MphActivateReq_t { +uint32_t hLayer1; +struct GsmL1_LogChParam_t logChPrm; +uint8_t u8Tn; +enum GsmL1_SubCh_t subCh; +enum GsmL1_Dir_t dir; +enum GsmL1_Sapi_t sapi; +uint32_t hLayer2; +float fBFILevel; +} GsmL1_MphActivateReq_t; + +typedef struct GsmL1_MphDeactivateReq_t { +uint32_t hLayer1; +uint8_t u8Tn; +enum GsmL1_SubCh_t subCh; +enum GsmL1_Dir_t dir; +enum GsmL1_Sapi_t sapi; +} GsmL1_MphDeactivateReq_t; + +typedef struct GsmL1_ConfigParam_t { +struct { +enum GsmL1_Sapi_t sapi; +uint8_t u8Tn; +enum GsmL1_SubCh_t subCh; +enum GsmL1_Dir_t dir; +struct GsmL1_LogChParam_t logChParams; +} setLogChParams; +} GsmL1_ConfigParam_t; + +typedef struct GsmL1_MphConfigReq_t { +uint32_t hLayer1; +enum GsmL1_ConfigParamId_t cfgParamId; +struct GsmL1_ConfigParam_t cfgParams; +} GsmL1_MphConfigReq_t; + +typedef struct GsmL1_MphConfigCnf_t { +enum GsmL1_Status_t status; +enum GsmL1_ConfigParamId_t cfgParamId; +struct GsmL1_ConfigParam_t cfgParams; +} GsmL1_MphConfigCnf_t; + +typedef struct GsmL1_MphMeasureReq_t { +uint32_t hLayer1; +} GsmL1_MphMeasureReq_t; + +typedef struct GsmL1_MphInitCnf_t { +uint32_t hLayer1; +enum GsmL1_Status_t status; +} GsmL1_MphInitCnf_t; + +typedef struct GsmL1_MphCloseCnf_t { +enum GsmL1_Status_t status; +} GsmL1_MphCloseCnf_t; + +typedef struct GsmL1_MphConnectCnf_t { +enum GsmL1_Status_t status; +} GsmL1_MphConnectCnf_t; + +typedef struct GsmL1_MphDisconnectCnf_t { +enum GsmL1_Status_t status; +} GsmL1_MphDisconnectCnf_t; + +typedef struct GsmL1_MphActivateCnf_t { +enum GsmL1_Status_t status; +uint8_t u8Tn; +int sapi; +} GsmL1_MphActivateCnf_t; + +typedef struct GsmL1_MphDeactivateCnf_t { +enum GsmL1_Status_t status; +uint8_t u8Tn; +enum GsmL1_Sapi_t sapi; +} GsmL1_MphDeactivateCnf_t; + +typedef struct GsmL1_MphMeasureCnf_t { +enum GsmL1_Status_t status; +} GsmL1_MphMeasureCnf_t; + +typedef struct GsmL1_MphTimeInd_t { +uint32_t u32Fn; +} GsmL1_MphTimeInd_t; + +typedef struct GsmL1_MphSyncInd_t { +} GsmL1_MphSyncInd_t; + +typedef struct GsmL1_PhEmptyFrameReq_t { +uint32_t hLayer1; +uint8_t u8Tn; +uint32_t u32Fn; +enum GsmL1_Sapi_t sapi; +enum GsmL1_SubCh_t subCh; +uint8_t u8BlockNbr; +} GsmL1_PhEmptyFrameReq_t; + +typedef struct GsmL1_PhDataReq_t { +uint32_t hLayer1; +uint8_t u8Tn; +uint32_t u32Fn; +enum GsmL1_Sapi_t sapi; +enum GsmL1_SubCh_t subCh; +uint8_t u8BlockNbr; +struct GsmL1_MsgUnitParam_t msgUnitParam; +} GsmL1_PhDataReq_t; + +typedef struct GsmL1_PhConnectInd_t { +} GsmL1_PhConnectInd_t; + +typedef struct GsmL1_PhReadyToSendInd_t { +uint32_t hLayer1; +uint8_t u8Tn; +uint32_t u32Fn; +enum GsmL1_Sapi_t sapi; +enum GsmL1_SubCh_t subCh; +uint8_t u8BlockNbr; +uint32_t hLayer2; +} GsmL1_PhReadyToSendInd_t; + +typedef struct GsmL1_PhDataInd_t { +struct GsmL1_MeasParam_t measParam; +struct GsmL1_MsgUnitParam_t msgUnitParam; +enum GsmL1_Sapi_t sapi; +uint32_t hLayer2; +} GsmL1_PhDataInd_t; + +typedef struct GsmL1_PhRaInd_t { +struct GsmL1_MeasParam_t measParam; +struct GsmL1_MsgUnitParam_t msgUnitParam; +uint32_t u32Fn; +uint32_t hLayer2; +} GsmL1_PhRaInd_t; + +typedef struct GsmL1_Prim_t { +union { +struct GsmL1_MphInitReq_t mphInitReq; +struct GsmL1_MphCloseReq_t mphCloseReq; +struct GsmL1_MphConnectReq_t mphConnectReq; +struct GsmL1_MphDisconnectReq_t mphDisconnectReq; +struct GsmL1_MphActivateReq_t mphActivateReq; +struct GsmL1_MphDeactivateReq_t mphDeactivateReq; +struct GsmL1_MphConfigReq_t mphConfigReq; +struct GsmL1_MphMeasureReq_t mphMeasureReq; +struct GsmL1_MphInitCnf_t mphInitCnf; +struct GsmL1_MphCloseCnf_t mphCloseCnf; +struct GsmL1_MphConnectCnf_t mphConnectCnf; +struct GsmL1_MphDisconnectCnf_t mphDisconnectCnf; +struct GsmL1_MphActivateCnf_t mphActivateCnf; +struct GsmL1_MphDeactivateCnf_t mphDeactivateCnf; +struct GsmL1_MphConfigCnf_t mphConfigCnf; +struct GsmL1_MphMeasureCnf_t mphMeasureCnf; +struct GsmL1_MphTimeInd_t mphTimeInd; +struct GsmL1_MphSyncInd_t mphSyncInd; +struct GsmL1_PhEmptyFrameReq_t phEmptyFrameReq; +struct GsmL1_PhDataReq_t phDataReq; +struct GsmL1_PhConnectInd_t phConnectInd; +struct GsmL1_PhReadyToSendInd_t phReadyToSendInd; +struct GsmL1_PhDataInd_t phDataInd; +struct GsmL1_PhRaInd_t phRaInd; +} u; + +enum GsmL1_PrimId_t id; +} GsmL1_Prim_t; diff --git a/pcu_l1_if.cpp b/pcu_l1_if.cpp index 54c5b368..18e8d5be 100644 --- a/pcu_l1_if.cpp +++ b/pcu_l1_if.cpp @@ -26,34 +26,99 @@ #define MAX_UDP_LENGTH 1500 // TODO: We should take ports and IP from config. -UDPSocket pcu_l1if_socket(5070, "127.0.0.1", 5934); UDPSocket pcu_gsmtap_socket(5077, "127.0.0.1", 4729); + +struct msgb *l1p_msgb_alloc(void) +{ + struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim"); + + if (msg) + msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t)); + + return msg; +} + // Send RLC/MAC block to OpenBTS. void pcu_l1if_tx(BitVector * block) { - char buffer[MAX_UDP_LENGTH]; int ofs = 0; - block->pack((unsigned char*)&buffer[ofs]); + struct msgb *msg = l1p_msgb_alloc(); + GsmL1_Prim_t *prim = msgb_l1prim(msg); + + prim->id = GsmL1_PrimId_PhDataReq; + block->pack((unsigned char*)&(prim->u.phDataReq.msgUnitParam.u8Buffer[ofs])); ofs += block->size() >> 3; + prim->u.phDataReq.msgUnitParam.u8Size = ofs; + COUT("Send to OpenBTS: " << *block); - pcu_l1if_socket.write(buffer, ofs); + osmo_wqueue_enqueue(&l1fh->udp_wq, msg); } -// Recieve RLC/MAC block from OpenBTS. -void *pcu_l1if_rx(void *) +int pcu_l1if_rx_pdch(GsmL1_PhDataInd_t *data_ind) { BitVector *block = new BitVector(23*8); - pcu_l1if_socket.nonblocking(); - while (1) { - char buf[MAX_UDP_LENGTH]; - int count = pcu_l1if_socket.read(buf, 3000); - if (count>0) { - block->unpack((const unsigned char*)buf); - COUT("Recieve from OpenBTS (MS): " << *block); - gprs_rlcmac_rcv_block(block); - } + block->unpack((const unsigned char*)data_ind->msgUnitParam.u8Buffer); + COUT("Recieve from OpenBTS (MS): " << *block); + + gprs_rlcmac_rcv_block(block); +} + +static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, + struct msgb *l1p_msg) +{ + int rc = 0; + 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: + break; + default: + //LOGP(DGPRS, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %u \n", data_ind->sapi); + break; } + + 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; + + switch (l1p->id) { + case GsmL1_PrimId_MphTimeInd: + break; + case GsmL1_PrimId_MphSyncInd: + break; + case GsmL1_PrimId_PhConnectInd: + break; + case GsmL1_PrimId_PhReadyToSendInd: + break; + case GsmL1_PrimId_PhDataInd: + rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); + break; + case GsmL1_PrimId_PhRaInd: + break; + default: + break; + } + + /* Special return value '1' means: do not free */ + if (rc != 1) + msgb_free(msg); + + return rc; } void gsmtap_send_llc(uint8_t * data, unsigned len) diff --git a/pcu_l1_if.h b/pcu_l1_if.h index e618cba9..ec56a951 100644 --- a/pcu_l1_if.h +++ b/pcu_l1_if.h @@ -20,11 +20,48 @@ #ifndef PCU_L1_IF_H #define PCU_L1_IF_H + #include +#include +extern "C" { +#include +#include +#include +#include +} + +#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 l1fwd_hdl { + struct sockaddr_storage remote_sa; + socklen_t remote_sa_len; + + struct osmo_wqueue udp_wq; + + struct femtol1_hdl *fl1h; +}; + +extern struct l1fwd_hdl *l1fh; void pcu_l1if_tx(BitVector * block); -void *pcu_l1if_rx(void *); +int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1h, struct msgb *msg); void gsmtap_send_llc(uint8_t * data, unsigned len); diff --git a/pcu_main.cpp b/pcu_main.cpp index 939e1140..d4b3938b 100644 --- a/pcu_main.cpp +++ b/pcu_main.cpp @@ -26,7 +26,9 @@ #define SGSN_IP "127.0.0.1" #define SGSN_PORT 23000 #define NSVCI 4 +#define PCU_L1_IF_PORT 5944 +struct l1fwd_hdl *l1fh = talloc_zero(NULL, struct l1fwd_hdl); int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, uint16_t bvci) { @@ -46,16 +48,100 @@ int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, return rc; } +/* data has arrived on the udp socket */ +static int udp_read_cb(struct osmo_fd *ofd) +{ + 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; + + msg->l1h = msg->data; + + 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; + } + 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) +{ + 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); + if (rc < 0) { + LOGP(DGPRS, LOGL_ERROR, "error writing to L1 msg_queue: %s\n", + strerror(errno)); + return rc; + } else if (rc < msgb_l1len(msg)) { + LOGP(DGPRS, LOGL_ERROR, "short write to L1 msg_queue: " + "%u < %u\n", rc, msgb_l1len(msg)); + return -EIO; + } + + return 0; +} + +int pcu_l1if_open() +{ + //struct l1fwd_hdl *l1fh; + struct femtol1_hdl *fl1h; + int rc; + + /* allocate new femtol1_handle */ + fl1h = talloc_zero(NULL, struct femtol1_hdl); + INIT_LLIST_HEAD(&fl1h->wlc_list); + + l1fh->fl1h = fl1h; + fl1h->priv = l1fh; + + /* 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); + } +} + int main(int argc, char *argv[]) { uint16_t nsvci = NSVCI; struct gprs_ns_inst *sgsn_nsi; struct gprs_nsvc *nsvc; - // Socket for reading BitVectors (RLC/MAC Frames) from OpenBTS application. - Thread pcu_l1if; - pcu_l1if.start(pcu_l1if_rx, NULL); osmo_init_logging(&log_info); + pcu_l1if_open(); + sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); bssgp_nsi = sgsn_nsi; @@ -92,3 +178,4 @@ int main(int argc, char *argv[]) i++; } } +