Statefull reset and unblock BVCs and sending flow control messages

The flow control interval can be set via VTY.
This commit is contained in:
Andreas Eversberg 2012-09-23 06:41:21 +02:00
parent 4b39dd1c00
commit cd8a83a42c
4 changed files with 97 additions and 5 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;