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).
zecke/hacks/quick-exit
Ivan Kluchnikov 2012-07-12 14:49:15 +04:00
commit ef7f28cc7f
20 changed files with 3632 additions and 2415 deletions

View File

@ -24,7 +24,7 @@ dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.9)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.3)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.5.2)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.5.1.4)
AC_MSG_CHECKING([whether to enable sysmocom-bts hardware support])
AC_ARG_ENABLE(sysmocom-bts,

6
src/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.gitignore
.libs/
RLCMACTest
libgprs.la
pcu

View File

@ -18,12 +18,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# FIXME: This has to go!!
OPENBSC_DIR = $(top_srcdir)/../openbsc/openbsc
OPENGGSN_DIR = $(top_srcdir)/../openggsn
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(OPENBSC_DIR)/include
AM_CXXFLAGS = -Wall -ldl -pthread -lgtp
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -Wall -ldl -pthread
noinst_LTLIBRARIES = libgprs.la
@ -33,15 +29,18 @@ libgprs_la_SOURCES = \
gsm_rlcmac.cpp \
gprs_bssgp_pcu.cpp \
gprs_rlcmac.cpp \
gprs_rlcmac_data.cpp \
gprs_rlcmac_sched.cpp \
gsm_timer.cpp \
bitvector.cpp
bitvector.cpp \
pcu_l1_if.cpp
if ENABLE_SYSMOBTS
libgprs_la_SOURCES += \
sysmo_l1_if.cpp
sysmo_sock.cpp
else
libgprs_la_SOURCES += \
pcu_l1_if.cpp
openbts_sock.cpp
endif
noinst_PROGRAMS = \
@ -54,6 +53,7 @@ noinst_HEADERS = \
gsm_rlcmac.h \
gprs_bssgp_pcu.h \
gprs_rlcmac.h \
pcuif_proto.h \
pcu_l1_if.h \
gsm_timer.h \
bitvector.h

View File

@ -23,19 +23,24 @@
struct sgsn_instance *sgsn;
void *tall_bsc_ctx;
struct bssgp_bvc_ctx *bctx = btsctx_alloc(BVCI, NSEI);
struct bssgp_bvc_ctx *bctx = NULL;
struct gprs_nsvc *nsvc = NULL;
extern uint16_t spoof_mcc, spoof_mnc;
int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
int i = 0;
uint8_t trx, ts;
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
int tfi;
uint32_t tlli;
int i, j;
uint8_t trx, ts;
uint8_t *data;
uint16_t len;
struct gprs_rlcmac_tbf *tbf;
tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, ntohl(budh->tlli));
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
tlli = ntohl(budh->tlli);
if (!tbf)
{
@ -44,31 +49,88 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
/* LLC_PDU is mandatory IE */
if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU))
{
LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tbf->tlli);
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}
tbf_dl_establish(tbf);
uint8_t *llc_pdu = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
uint16_t llc_pdu_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
tbf_dl_data_transfer(tbf, llc_pdu, llc_pdu_len);
}
int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, struct tlv_parsed *tp)
{
uint8_t *ptmsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_TMSI);
uint16_t ptmsi_len = TLVP_LEN(tp, BSSGP_IE_TMSI);
LOGP(DBSSGP, LOGL_NOTICE, " P-TMSI = ");
for (int i = 0; i < ptmsi_len; i++)
data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
if (len > sizeof(tbf->llc_frame))
{
LOGPC(DBSSGP, LOGL_NOTICE, "%02x", ptmsi[i]);
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP TLLI=0x%08x Rx UL-UD IE_LLC_PDU too large\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg);
}
LOGPC(DBSSGP, LOGL_NOTICE, "\n");
gprs_rlcmac_paging_request(ptmsi, ptmsi_len);
/* read IMSI. if no IMSI exists, use first paging block (any paging),
* because during attachment the IMSI might not be known, so the MS
* will listen to all paging blocks. */
char imsi[16] = "000";
if (TLVP_PRESENT(tp, BSSGP_IE_IMSI))
{
uint8_t imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
uint8_t *bcd_imsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_IMSI);
if ((bcd_imsi[0] & 0x08))
imsi_len = imsi_len * 2 - 1;
else
imsi_len = (imsi_len - 1) * 2;
for (i = 0, j = 0; j < imsi_len && j < 16; j++)
{
if (!(j & 1)) {
imsi[j] = (bcd_imsi[i] >> 4) + '0';
i++;
} else
imsi[j] = (bcd_imsi[i] & 0xf) + '0';
}
imsi[j] = '\0';
}
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len);
/* check for existing TBF */
if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli);
if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) {
LOGP(DRLCMAC, LOGL_DEBUG, "TBF in WAIT RELEASE state "
"(T3193), so reuse TBF\n");
memcpy(tbf->llc_frame, data, len);
tbf->llc_length = len;
memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset
rlc states */
gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL);
} else {
/* the TBF exists, so we must write it in the queue */
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
memcpy(msgb_put(llc_msg, len), data, len);
msgb_enqueue(&tbf->llc_queue, llc_msg);
}
} else {
// Create new TBF
tfi = tfi_alloc(&trx, &ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
tbf = tbf_alloc(tfi, trx, ts);
tbf->direction = GPRS_RLCMAC_DL_TBF;
tbf->tlli = tlli;
tbf->tlli_valid = 1;
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
/* new TBF, so put first frame */
memcpy(tbf->llc_frame, data, len);
tbf->llc_length = len;
/* trigger downlink assignment and set state to ASSIGN.
* we don't use old_downlink, so the possible uplink is used
* to trigger downlink assignment. if there is no uplink,
* AGCH is used. */
gprs_rlcmac_trigger_downlink_assignment(tbf, 0, imsi);
}
return 0;
}
/* Receive a BSSGP PDU from a BSS on a PTP BVCI */
@ -90,26 +152,26 @@ int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_
switch (pdu_type) {
case BSSGP_PDUT_DL_UNITDATA:
LOGP(DBSSGP, LOGL_NOTICE, "RX: [SGSN->PCU] BSSGP_PDUT_DL_UNITDATA\n");
LOGP(DBSSGP, LOGL_DEBUG, "RX: [SGSN->PCU] BSSGP_PDUT_DL_UNITDATA\n");
gprs_bssgp_pcu_rx_dl_ud(msg, tp);
break;
case BSSGP_PDUT_PAGING_PS:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_PS\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_PS\n");
break;
case BSSGP_PDUT_PAGING_CS:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_CS\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n");
break;
case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RA_CAPA_UPDATE_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RA_CAPA_UPDATE_ACK\n");
break;
case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLOW_CONTROL_BVC_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLOW_CONTROL_BVC_ACK\n");
break;
case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLOW_CONTROL_MS_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLOW_CONTROL_MS_ACK\n");
break;
default:
DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x unknown\n", bctx->bvci, pdu_type);
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u PDU type 0x%02x unknown\n", bctx->bvci, pdu_type);
rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
break;
}
@ -128,41 +190,40 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp
/* FIXME: send NM_STATUS.ind to NM */
break;
case BSSGP_PDUT_SUSPEND_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n");
break;
case BSSGP_PDUT_SUSPEND_NACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_NACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_NACK\n");
break;
case BSSGP_PDUT_BVC_RESET_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_BVC_RESET_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n");
break;
case BSSGP_PDUT_PAGING_PS:
LOGP(DBSSGP, LOGL_NOTICE, "RX: [SGSN->PCU] BSSGP_PDUT_PAGING_PS\n");
gprs_bssgp_pcu_rx_paging_ps(msg, tp);
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_PS\n");
break;
case BSSGP_PDUT_PAGING_CS:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_CS\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n");
break;
case BSSGP_PDUT_RESUME_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RESUME_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_ACK\n");
break;
case BSSGP_PDUT_RESUME_NACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RESUME_NACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_NACK\n");
break;
case BSSGP_PDUT_FLUSH_LL:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLUSH_LL\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLUSH_LL\n");
break;
case BSSGP_PDUT_BVC_BLOCK_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n");
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n");
break;
case BSSGP_PDUT_SGSN_INVOKE_TRACE:
LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n");
break;
default:
DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type);
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type);
rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
break;
}
@ -178,6 +239,13 @@ int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
uint16_t ns_bvci = msgb_bvci(msg);
int data_len;
int rc = 0;
struct bssgp_bvc_ctx *bctx;
if (pdu_type == BSSGP_PDUT_STATUS) {
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u received STATUS\n",
msgb_nsei(msg), ns_bvci);
return 0;
}
/* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
@ -196,12 +264,6 @@ int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
/* look-up or create the BTS context for this BVC */
bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg));
/* Only a RESET PDU can create a new BVC context */
if (!bctx)
{
bctx = btsctx_alloc(ns_bvci, msgb_nsei(msg));
}
if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET_ACK)
{
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
@ -219,17 +281,17 @@ int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
if (ns_bvci == BVCI_SIGNALLING)
{
LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_SIGNALLING gprs_bssgp_rx_sign\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_SIGNALLING gprs_bssgp_rx_sign\n");
rc = gprs_bssgp_pcu_rx_sign(msg, &tp, bctx);
}
else if (ns_bvci == BVCI_PTM)
{
LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_PTM bssgp_tx_status\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_PTM bssgp_tx_status\n");
rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
}
else
{
LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_PTP gprs_bssgp_rx_ptp\n");
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_PTP gprs_bssgp_rx_ptp\n");
rc = gprs_bssgp_pcu_rx_ptp(msg, &tp, bctx);
}
return rc;
@ -239,3 +301,128 @@ int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
return 0;
}
static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, uint16_t bvci)
{
int rc = 0;
switch (event) {
case GPRS_NS_EVT_UNIT_DATA:
/* hand the message into the BSSGP implementation */
rc = gprs_bssgp_pcu_rcvmsg(msg);
break;
default:
LOGP(DPCU, LOGL_NOTICE, "RLCMAC: Unknown event %u from NS\n", event);
if (msg)
talloc_free(msg);
rc = -EIO;
break;
}
return rc;
}
static int nsvc_unblocked = 0;
static int nsvc_signal_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct ns_signal_data *nssd;
if (subsys != SS_L_NS)
return -EINVAL;
nssd = (struct ns_signal_data *)signal_data;
if (nssd->nsvc != nsvc) {
LOGP(DPCU, LOGL_ERROR, "Signal received of unknown NSVC\n");
return -EINVAL;
}
switch (signal) {
case S_NS_UNBLOCK:
if (!nsvc_unblocked) {
nsvc_unblocked = 1;
LOGP(DPCU, LOGL_NOTICE, "NS-VC is unblocked.\n");
bssgp_tx_bvc_reset(bctx, bctx->bvci,
BSSGP_CAUSE_PROTO_ERR_UNSPEC);
}
break;
case S_NS_BLOCK:
if (nsvc_unblocked) {
nsvc_unblocked = 0;
LOGP(DPCU, LOGL_NOTICE, "NS-VC is blocked.\n");
}
break;
}
return 0;
}
/* create BSSGP/NS layer instances */
int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei,
uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac,
uint16_t rac, uint16_t cell_id)
{
struct sockaddr_in dest;
if (bctx)
return 0; /* if already created, must return 0: no error */
bssgp_nsi = gprs_ns_instantiate(&sgsn_ns_cb, NULL);
if (!bssgp_nsi) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n");
return -EINVAL;
}
gprs_ns_nsip_listen(bssgp_nsi);
dest.sin_family = AF_INET;
dest.sin_port = htons(sgsn_port);
dest.sin_addr.s_addr = htonl(sgsn_ip);
nsvc = gprs_ns_nsip_connect(bssgp_nsi, &dest, nsei, nsvci);
if (!nsvc) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NSVCt\n");
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
return -EINVAL;
}
bctx = btsctx_alloc(bvci, nsei);
if (!bctx) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create BSSGP context\n");
nsvc = NULL;
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
return -EINVAL;
}
bctx->ra_id.mcc = spoof_mcc ? : mcc;
bctx->ra_id.mnc = spoof_mnc ? : mnc;
bctx->ra_id.lac = lac;
bctx->ra_id.rac = rac;
bctx->cell_id = cell_id;
osmo_signal_register_handler(SS_L_NS, nsvc_signal_cb, NULL);
// bssgp_tx_bvc_reset(bctx, bctx->bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC);
return 0;
}
void gprs_bssgp_destroy(void)
{
if (!bssgp_nsi)
return;
osmo_signal_unregister_handler(SS_L_NS, nsvc_signal_cb, NULL);
nsvc = NULL;
/* FIXME: move this to libgb: btsctx_free() */
llist_del(&bctx->list);
talloc_free(bctx);
bctx = NULL;
/* FIXME: blocking... */
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
}

View File

@ -39,23 +39,10 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei);
}
#include <gprs_debug.h>
#define BVCI 7
#define NSEI 3
#define QOS_PROFILE 0
#define BSSGP_HDR_LEN 53
#define NS_HDR_LEN 4
#define MAX_LEN_PDU 60
#define IE_LLC_PDU 14
#define BLOCK_DATA_LEN 20
#define BLOCK_LEN 23
#define CELL_ID 0
#define MNC 1
#define MCC 001
#define PCU_LAC 1
#define PCU_RAC 0
extern struct bssgp_bvc_ctx *bctx;
@ -67,4 +54,10 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp
int gprs_bssgp_pcu_rcvmsg(struct msgb *msg);
int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei,
uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac,
uint16_t rac, uint16_t cell_id);
void gprs_bssgp_destroy(void);
#endif // GPRS_BSSGP_PCU_H

View File

@ -33,12 +33,15 @@
/* default categories */
static const struct log_info_cat default_categories[] = {
{"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_NOTICE, 1},
{"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_NOTICE, 1},
{"DRLCMAC", "\033[1;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACDATA", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_NOTICE, 1},
{"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_NOTICE , 1},
{"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}
{"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0},
{"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_INFO, 1},
{"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_INFO, 1},
{"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1},
{"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1},
{"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1},
{"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1},
{"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO , 1},
{"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1},
};
enum {

View File

@ -31,6 +31,9 @@ enum {
DL1IF,
DRLCMAC,
DRLCMACDATA,
DRLCMACDL,
DRLCMACUL,
DRLCMACSCHED,
DBSSGP,
DPCU,
aDebug_LastEntry

File diff suppressed because it is too large Load Diff

View File

@ -29,24 +29,93 @@ extern "C" {
#include <osmocom/core/timer.h>
}
#define LLC_MAX_LEN 1543
#define UL_RLC_DATA_BLOCK_LEN 23
/* This special feature will delay assignment of downlink TBF by one second,
* in case there is already a TBF.
* This is usefull to debug downlink establishment during packet idle mode.
*/
//#define DEBUG_DL_ASS_IDLE
enum gprs_rlcmac_tbf_stage {
TBF_ESTABLISH,
TBF_DATA_TRANSFER,
TBF_RELEASE
/*
* PDCH instanc
*/
struct gprs_rlcmac_tbf;
struct gprs_rlcmac_pdch {
uint8_t enable; /* TS is enabled */
uint8_t tsc; /* TSC of this slot */
uint8_t next_ul_tfi; /* next uplink TBF/TFI to schedule (0..31) */
uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */
struct gprs_rlcmac_tbf *tbf[32]; /* array of TBF pointers, by TFI */
uint32_t last_rts_fn; /* store last frame number of RTS */
};
struct gprs_rlcmac_trx {
uint16_t arfcn;
struct gprs_rlcmac_pdch pdch[8];
};
struct gprs_rlcmac_bts {
uint8_t cs1;
uint8_t cs2;
uint8_t cs3;
uint8_t cs4;
uint8_t initial_cs;
uint8_t t3142;
uint8_t t3169;
uint8_t t3191;
uint16_t t3193_msec;
uint8_t t3195;
uint8_t n3101;
uint8_t n3103;
uint8_t n3105;
struct gprs_rlcmac_trx trx[8];
};
extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
/*
* TBF instance
*/
#define LLC_MAX_LEN 1543
#define RLC_MAX_SNS 128 /* GPRS, must be power of 2 */
#define RLC_MAX_WS 64 /* max window size */
#define RLC_MAX_LEN 54 /* CS-4 including spare bits */
#define Tassign_agch 0,500000/* wait for assignment, before transmitting DL */
#define Tassign_pacch 0,100000/* wait for assignment, before transmitting DL */
enum gprs_rlcmac_tbf_state {
WAIT_ESTABLISH,
CCCH_ESTABLISH,
PACCH_ESTABLISH,
FINISH_ESTABLISH,
WAIT_DATA_TRANSFER,
DATA_TRANSFER,
FINISH_DATA_TRANSFER,
RELEASE
GPRS_RLCMAC_NULL = 0, /* new created TBF */
GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */
GPRS_RLCMAC_FLOW, /* RLC/MAC flow, ressource needed */
GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */
GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */
GPRS_RLCMAC_RELEASING, /* releasing, wait to free TBI/USF */
};
enum gprs_rlcmac_tbf_poll_state {
GPRS_RLCMAC_POLL_NONE = 0,
GPRS_RLCMAC_POLL_SCHED, /* a polling was scheduled */
};
enum gprs_rlcmac_tbf_dl_ass_state {
GPRS_RLCMAC_DL_ASS_NONE = 0,
GPRS_RLCMAC_DL_ASS_SEND_ASS, /* send downlink assignment on next RTS */
GPRS_RLCMAC_DL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_ul_ass_state {
GPRS_RLCMAC_UL_ASS_NONE = 0,
GPRS_RLCMAC_UL_ASS_SEND_ASS, /* send uplink assignment on next RTS */
GPRS_RLCMAC_UL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_ul_ack_state {
GPRS_RLCMAC_UL_ACK_NONE = 0,
GPRS_RLCMAC_UL_ACK_SEND_ACK, /* send acknowledge on next RTS */
GPRS_RLCMAC_UL_ACK_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_direction {
@ -54,30 +123,57 @@ enum gprs_rlcmac_tbf_direction {
GPRS_RLCMAC_UL_TBF
};
struct tbf_llc_pdu {
struct llist_head list;
uint8_t num;
uint8_t data[LLC_MAX_LEN];
uint16_t len;
};
struct gprs_rlcmac_tbf {
struct llist_head list;
enum gprs_rlcmac_tbf_state state;
enum gprs_rlcmac_tbf_stage stage;
enum gprs_rlcmac_tbf_direction direction;
struct gprs_rlcmac_tbf *next_tbf;
uint8_t tfi;
uint32_t tlli;
struct llist_head llc_pdus;
struct tbf_llc_pdu llc_pdu;
uint8_t llc_pdu_list_len;
uint8_t rlc_data[LLC_MAX_LEN];
uint16_t data_index;
uint8_t bsn;
uint8_t tlli_valid;
uint8_t trx, ts, tsc;
struct gprs_rlcmac_pdch *pdch;
uint16_t arfcn, ta;
uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t llc_index; /* current write/read position of frame */
uint16_t llc_length; /* len of current DL LLC_frame, 0 == no frame */
llist_head llc_queue; /* queued LLC DL data */
enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state;
enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state;
enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state;
enum gprs_rlcmac_tbf_poll_state poll_state;
uint32_t poll_fn;
uint16_t ws; /* window size */
uint16_t sns; /* sequence number space */
/* Please note that all variables here will be reset when changing
* from WAIT RELEASE back to FLOW state (re-use of TBF).
* All states that need reset must be in this struct, so this is why
* variables are in both (dl and ul) structs and not outside union.
*/
union {
struct {
uint16_t bsn; /* block sequence number */
uint16_t v_s; /* send state */
uint16_t v_a; /* ack state */
char v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
int32_t tx_counter; /* count all transmitted blocks */
uint8_t n3105; /* N3105 counter */
} dl;
struct {
uint16_t bsn; /* block sequence number */
uint16_t v_r; /* receive state */
uint16_t v_q; /* receive window state */
char v_n[RLC_MAX_SNS/2]; /* receive state array */
int32_t rx_counter; /* count all received blocks */
uint8_t n3103; /* N3103 counter */
uint8_t usf; /* USF */
} ul;
} dir;
uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */
uint8_t rlc_block_len[RLC_MAX_SNS/2]; /* block len of history */
struct osmo_timer_list timer;
unsigned int T; /* Txxxx number */
@ -88,6 +184,30 @@ struct gprs_rlcmac_tbf {
unsigned int num_fT_exp; /* number of consecutive fT expirations */
};
extern struct llist_head gprs_rlcmac_tbfs;
int tfi_alloc(uint8_t *_trx, uint8_t *_ts);
struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts);
struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction);
struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction);
struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn);
int find_free_usf(uint8_t trx, uint8_t ts);
void tbf_free(struct gprs_rlcmac_tbf *tbf);
void tbf_new_state(struct gprs_rlcmac_tbf *tbf,
enum gprs_rlcmac_tbf_state state);
void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
unsigned int seconds, unsigned int microseconds);
void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf);
/* TS 44.060 Section 10.4.7 Table 10.4.7.1: Payload Type field */
enum gprs_rlcmac_block_type {
GPRS_RLCMAC_DATA_BLOCK = 0x0,
@ -96,64 +216,56 @@ enum gprs_rlcmac_block_type {
GPRS_RLCMAC_RESERVED = 0x3
};
extern struct llist_head gprs_rlcmac_tbfs;
int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn);
int select_pdch(uint8_t *_trx, uint8_t *_ts);
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
uint32_t poll_fn);
int tfi_alloc();
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi,
uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc,
uint8_t poll);
static struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, gprs_rlcmac_tbf_direction dir);
void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn,
uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll);
static struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, gprs_rlcmac_tbf_direction dir);
void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *tbf,
uint8_t final);
static void tbf_free(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
static struct tbf_llc_pdu *tbf_llc_pdu_by_num(struct llist_head llc_pdus, uint8_t num);
void tbf_timer_cb(void *_tbf);
int tbf_add_llc_pdu(struct gprs_rlcmac_tbf *tbf, uint8_t *data, uint16_t llc_pdu_len);
struct gprs_rlcmac_tbf *tbf_alloc(gprs_rlcmac_tbf_direction dir, uint32_t tlli = 0);
int tbf_ul_establish(struct gprs_rlcmac_tbf *tbf, uint8_t ra, uint32_t Fn, uint16_t qta);
int tbf_dl_establish(struct gprs_rlcmac_tbf *tbf);
int tbf_ul_data_transfer(struct gprs_rlcmac_tbf *tbf, RlcMacUplinkDataBlock_t * ul_data_block);
int tbf_dl_data_transfer(struct gprs_rlcmac_tbf *tbf, uint8_t *llc_pdu = NULL, uint16_t llc_pdu_len = 0);
int tbf_ul_release(struct gprs_rlcmac_tbf *tbf);
int tbf_dl_release(struct gprs_rlcmac_tbf *tbf);
static void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, unsigned int seconds);
static void tbf_gsm_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int fT, int frames);
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi, uint32_t tlli = 0);
void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, uint8_t ti, uint8_t bsn);
void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block);
int gprs_rlcmac_rcv_data_block(bitvec *rlc_block);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block);
void gprs_rlcmac_rcv_block(bitvec *rlc_block);
void gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
int gprs_rlcmac_tx_llc_pdus(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn);
void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf);
struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf);
void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
uint8_t old_downlink, char *imsi);
int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t ssn, uint8_t *rbb);
int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len);
struct msgb *gprs_rlcmac_send_data_block_acknowledged(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
uint32_t fn);
int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
void gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len);
#endif // GPRS_RLCMAC_H

1409
src/gprs_rlcmac_data.cpp Normal file

File diff suppressed because it is too large Load Diff

184
src/gprs_rlcmac_sched.cpp Normal file
View File

@ -0,0 +1,184 @@
/* PDCH scheduler
*
* 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
* as published by the Free Software Foundation; either version 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <gprs_bssgp_pcu.h>
#include <gprs_rlcmac.h>
#include <pcu_l1_if.h>
extern struct llist_head block_queue;
static uint8_t rlcmac_dl_idle[23] = {
0x47, /* control without optional header octets, no polling, USF=111 */
0x94, /* dummy downlink control message, paging mode 00 */
0x2b, /* no persistance level, 7 bits spare pattern */
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b
};
int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_tbf *tbf;
uint8_t usf = 0x7;
struct msgb *msg = NULL;
uint32_t poll_fn;
uint8_t i, tfi;
if (trx >= 8 || ts >= 8)
return -EINVAL;
pdch = &bts->trx[trx].pdch[ts];
if (!pdch->enable) {
LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: "
"TRX=%d TS=%d\n", trx, ts);
return -EIO;
}
/* store last frame number of RTS */
pdch->last_rts_fn = fn;
/* check uplink ressource for polling */
poll_fn = fn + 4;
if ((block_nr % 3) == 2)
poll_fn ++;
poll_fn = poll_fn % 2715648;
for (tfi = 0; tfi < 32; tfi++) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* no polling */
if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
continue;
/* polling for next uplink block */
if (tbf->poll_fn == poll_fn)
break;
}
/* found uplink where a block is polled */
if (tfi < 32) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling free USF for "
"polling at FN=%d of TFI=%d\n", trx, ts, fn, block_nr,
poll_fn, tfi);
/* use free USF */
/* else, we search for uplink ressource */
} else {
/* select uplink ressource */
for (i = 0, tfi = pdch->next_ul_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* no UL TBF, go next */
if (tbf->direction != GPRS_RLCMAC_UL_TBF)
continue;
/* no UL ressources needed, go next */
/* we don't need to give ressources in FINISHED state,
* because we have received all blocks and only poll
* for packet control ack. */
if (tbf->state != GPRS_RLCMAC_FLOW)
continue;
/* use this USF */
usf = tbf->dir.ul.usf;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "
"TRX=%d TS=%d FN=%d block_nr=%d scheduling "
"USF=%d for required uplink ressource of "
"TBF=%d\n", trx, ts, fn, block_nr, usf, tfi);
/* next TBF to handle ressource is the next one */
pdch->next_ul_tfi = (tfi + 1) & 31;
break;
}
}
/* Prio 1: select control message */
for (tfi = 0; tfi < 32; tfi++) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* schedule PACKET DOWNLINK ASSIGNMENT */
if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS)
msg = gprs_rlcmac_send_packet_downlink_assignment(tbf,
fn);
else
/* schedule PACKET UPLINK ASSIGNMENT */
if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS)
msg = gprs_rlcmac_send_packet_uplink_assignment(tbf,
fn);
else
/* schedule PACKET UPLINK ACK */
if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK)
msg = gprs_rlcmac_send_uplink_ack(tbf, fn);
if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
"message at RTS for TBF=%d\n", tfi);
break;
}
}
/* Prio 2: select data message for downlink */
if (!msg) {
/* select downlink ressource */
for (i = 0, tfi = pdch->next_dl_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* no DL TBF, go next */
if (tbf->direction != GPRS_RLCMAC_DL_TBF)
continue;
/* no DL ressources needed, go next */
if (tbf->state != GPRS_RLCMAC_FLOW
&& tbf->state != GPRS_RLCMAC_FINISHED)
continue;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data "
"message at RTS for TBF=%d\n", tfi);
/* next TBF to handle ressource is the next one */
pdch->next_dl_tfi = (tfi + 1) & 31;
/* generate DL data block */
msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn);
break;
}
}
/* Prio 3: send dummy contol message */
if (!msg) {
msg = msgb_alloc(23, "rlcmac_dl_idle");
if (!msg)
return -ENOMEM;
memcpy(msgb_put(msg, 23), rlcmac_dl_idle, 23);
}
/* msg is now available */
/* set USF */
msg->data[0] = (msg->data[0] & 0xf8) | usf;
// printf("len=%d, date=%s\n", msg->len, osmo_hexdump(msg->data, msg->len));
/* send PDTCH/PACCH to L1 */
pcu_l1if_tx_pdtch(msg, trx, ts, arfcn, fn, block_nr);
return 0;
}

View File

@ -1,415 +0,0 @@
/*
* Copyright 2012 Thomas Cooper <tacooper@vt.edu>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GSML1PRIM_H
#define GSML1PRIM_H
#include <stdint.h>
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 {
uint8_t u8Tn;
uint8_t u8Tsc;
uint16_t u16Arfcn;
} 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;
#endif

183
src/openbts_sock.cpp Normal file
View File

@ -0,0 +1,183 @@
/* openbts_sock.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/