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
commit
ef7f28cc7f
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.gitignore
|
||||
.libs/
|
||||
RLCMACTest
|
||||
libgprs.la
|
||||
pcu
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -31,6 +31,9 @@ enum {
|
|||
DL1IF,
|
||||
DRLCMAC,
|
||||
DRLCMACDATA,
|
||||
DRLCMACDL,
|
||||
DRLCMACUL,
|
||||
DRLCMACSCHED,
|
||||
DBSSGP,
|
||||
DPCU,
|
||||
aDebug_LastEntry
|
||||
|
|
1388
src/gprs_rlcmac.cpp
1388
src/gprs_rlcmac.cpp
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
415
src/gsmL1prim.h
415
src/gsmL1prim.h
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||