aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gprs_bssgp_pcu.cpp82
-rw-r--r--src/gprs_rlcmac.h1
-rw-r--r--src/pcu_main.cpp1
-rw-r--r--src/pcu_vty.c18
4 files changed, 97 insertions, 5 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 374baf63..020df616 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -25,8 +25,13 @@ struct sgsn_instance *sgsn;
void *tall_bsc_ctx;
struct bssgp_bvc_ctx *bctx = NULL;
struct gprs_nsvc *nsvc = NULL;
+static int bvc_sig_reset = 0, bvc_reset = 0, bvc_unblocked = 0;
extern uint16_t spoof_mcc, spoof_mnc;
+struct osmo_timer_list bvc_timer;
+
+static void bvc_timeout(void *_priv);
+
int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
@@ -295,6 +300,11 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp
break;
case BSSGP_PDUT_BVC_RESET_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n");
+ if (!bvc_sig_reset)
+ bvc_sig_reset = 1;
+ else
+ bvc_reset = 1;
+ bvc_timeout(NULL);
break;
case BSSGP_PDUT_PAGING_PS:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_PS\n");
@@ -316,6 +326,8 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n");
+ bvc_unblocked = 1;
+ bvc_timeout(NULL);
break;
case BSSGP_PDUT_SGSN_INVOKE_TRACE:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n");
@@ -362,7 +374,9 @@ 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));
- if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET_ACK)
+ if (!bctx
+ && pdu_type != BSSGP_PDUT_BVC_RESET_ACK
+ && pdu_type != BSSGP_PDUT_BVC_UNBLOCK_ACK)
{
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
"type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci,
@@ -438,14 +452,22 @@ static int nsvc_signal_cb(unsigned int subsys, unsigned int 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);
+ LOGP(DPCU, LOGL_NOTICE, "NS-VC %d is unblocked.\n",
+ nsvc);
+ bvc_sig_reset = 0;
+ bvc_reset = 0;
+ bvc_unblocked = 0;
+ bvc_timeout(NULL);
}
break;
case S_NS_BLOCK:
if (nsvc_unblocked) {
nsvc_unblocked = 0;
+ if (osmo_timer_pending(&bvc_timer))
+ osmo_timer_del(&bvc_timer);
+ bvc_sig_reset = 0;
+ bvc_reset = 0;
+ bvc_unblocked = 0;
LOGP(DPCU, LOGL_NOTICE, "NS-VC is blocked.\n");
}
break;
@@ -454,6 +476,52 @@ static int nsvc_signal_cb(unsigned int subsys, unsigned int signal,
return 0;
}
+int gprs_bssgp_tx_fc_bvc(void)
+{
+ if (!bctx) {
+ LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
+ return -EIO;
+ }
+ /* FIXME: use real values */
+ return bssgp_tx_fc_bvc(bctx, 1, 6553500, 819100, 50000, 50000,
+ NULL, NULL);
+// return bssgp_tx_fc_bvc(bctx, 1, 84000, 25000, 48000, 45000,
+// NULL, NULL);
+}
+
+static void bvc_timeout(void *_priv)
+{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+ if (!bvc_sig_reset) {
+ LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI 0\n");
+ bssgp_tx_bvc_reset(bctx, 0, BSSGP_CAUSE_OML_INTERV);
+ osmo_timer_schedule(&bvc_timer, 1, 0);
+ return;
+ }
+
+ if (!bvc_reset) {
+ LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI %d\n",
+ bctx->bvci);
+ bssgp_tx_bvc_reset(bctx, bctx->bvci, BSSGP_CAUSE_OML_INTERV);
+ osmo_timer_schedule(&bvc_timer, 1, 0);
+ return;
+ }
+
+ if (!bvc_unblocked) {
+ LOGP(DBSSGP, LOGL_INFO, "Sending unblock on BVCI %d\n",
+ bctx->bvci);
+ bssgp_tx_bvc_unblock(bctx);
+ osmo_timer_schedule(&bvc_timer, 1, 0);
+ return;
+ }
+
+ LOGP(DBSSGP, LOGL_DEBUG, "Sending flow control info on BVCI %d\n",
+ bctx->bvci);
+ gprs_bssgp_tx_fc_bvc();
+ osmo_timer_schedule(&bvc_timer, bts->fc_interval, 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,
@@ -501,6 +569,9 @@ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei,
// bssgp_tx_bvc_reset(bctx, bctx->bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC);
+ bvc_timer.cb = bvc_timeout;
+
+
return 0;
}
@@ -509,6 +580,9 @@ void gprs_bssgp_destroy(void)
if (!bssgp_nsi)
return;
+ if (osmo_timer_pending(&bvc_timer))
+ osmo_timer_del(&bvc_timer);
+
osmo_signal_unregister_handler(SS_L_NS, nsvc_signal_cb, NULL);
nsvc = NULL;
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index a5ac7750..e7a68a4f 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -62,6 +62,7 @@ struct gprs_rlcmac_trx {
};
struct gprs_rlcmac_bts {
+ uint8_t fc_interval;
uint8_t cs1;
uint8_t cs2;
uint8_t cs3;
diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp
index 2d7e8ffc..2392152a 100644
--- a/src/pcu_main.cpp
+++ b/src/pcu_main.cpp
@@ -142,6 +142,7 @@ int main(int argc, char *argv[])
if (!gprs_rlcmac_bts)
return -ENOMEM;
gprs_rlcmac_bts->initial_cs = 1;
+ bts->fc_interval = 1;
bts->initial_cs = 1;
bts->cs1 = 1;
bts->t3142 = 20;
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index 39a1b722..8d5b47b1 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -79,6 +79,8 @@ static int config_write_pcu(struct vty *vty)
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
vty_out(vty, "pcu%s", VTY_NEWLINE);
+ vty_out(vty, " flow-control-interval %d%s", bts->fc_interval,
+ VTY_NEWLINE);
if (bts->force_cs)
vty_out(vty, " cs %d%s", bts->initial_cs, VTY_NEWLINE);
if (bts->force_llc_lifetime == 0xffff)
@@ -106,6 +108,19 @@ DEFUN(cfg_pcu,
return CMD_SUCCESS;
}
+DEFUN(cfg_pcu_fc_interval,
+ cfg_pcu_fc_interval_cmd,
+ "flow-control-interval <1..10>",
+ "Interval between sending subsequent Flow Control PDUs\n"
+ "Tiem in seconds\n")
+{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+ bts->fc_interval = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_pcu_cs,
cfg_pcu_cs_cmd,
"cs <1-4>",
@@ -242,6 +257,7 @@ int pcu_vty_init(const struct log_info *cat)
install_node(&pcu_node, config_write_pcu);
install_element(CONFIG_NODE, &cfg_pcu_cmd);
install_default(PCU_NODE);
+ install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd);
install_element(PCU_NODE, &cfg_pcu_cs_cmd);
install_element(PCU_NODE, &cfg_pcu_no_cs_cmd);
install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd);
@@ -249,7 +265,7 @@ int pcu_vty_init(const struct log_info *cat)
install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
install_element(PCU_NODE, &cfg_pcu_alloc_cmd);
install_element(PCU_NODE, &cfg_pcu_two_phase_cmd);
- install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd);
+ install_element(PCU_NODE, &cfg_pcu_fc_interval_cmd);
install_element(PCU_NODE, &ournode_end_cmd);
return 0;