aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_ns.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-05-11 06:20:54 +0200
committerHarald Welte <laforge@gnumonks.org>2010-05-11 06:33:17 +0200
commit99e3248192caa1348a28e4a5eda3db745960fd31 (patch)
tree1af1841de62d6863677eba43a3c823b971c2ab53 /openbsc/src/gprs/gprs_ns.c
parent6b72cdf85423f9aca68bce15084e8a1b30b3db55 (diff)
[gprs] NS: Add signals in the event of BLOCK/UNBLOCK/RESET
The signals will be sent upon reception of NS-BLOCK/UNBLOCK/RESET PDUs We also export functions to generate/send BLOCK/UNBLOCK and RESET.
Diffstat (limited to 'openbsc/src/gprs/gprs_ns.c')
-rw-r--r--openbsc/src/gprs/gprs_ns.c77
1 files changed, 73 insertions, 4 deletions
diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c
index be3d1d93a..3fa2c0169 100644
--- a/openbsc/src/gprs/gprs_ns.c
+++ b/openbsc/src/gprs/gprs_ns.c
@@ -57,6 +57,7 @@
#include <osmocore/talloc.h>
#include <osmocore/select.h>
#include <openbsc/debug.h>
+#include <openbsc/signal.h>
#include <openbsc/gprs_ns.h>
#include <openbsc/gprs_bssgp.h>
@@ -128,6 +129,17 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci)
return nsvc;
}
+static void ns_dispatch_signal(struct nsvc *nsvc, unsigned int signal,
+ uint8_t cause)
+{
+ struct ns_signal_data nssd;
+
+ nssd.nsvc = nsvc;
+ nssd.cause = cause;
+
+ dispatch_signal(SS_NS, signal, &nssd);
+}
+
/* Section 10.3.2, Table 13 */
static const struct value_string ns_cause_str[] = {
{ NS_CAUSE_TRANSIT_FAIL, "Transit network failure" },
@@ -183,7 +195,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type)
return gprs_ns_tx(nsvc, msg);
}
-static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause)
+int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause)
{
struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
struct gprs_ns_hdr *nsh;
@@ -204,6 +216,32 @@ static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause)
}
+int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause)
+{
+ struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+ struct gprs_ns_hdr *nsh;
+ uint16_t nsvci = htons(nsvc->nsvci);
+
+ if (!msg)
+ return -ENOMEM;
+
+ /* be conservative and mark it as blocked even now! */
+ nsvc->state |= NSE_S_BLOCKED;
+
+ nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh));
+ nsh->pdu_type = NS_PDUT_BLOCK;
+
+ msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
+ msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
+
+ return gprs_ns_tx(nsvc, msg);
+}
+
+int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc)
+{
+ return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK);
+}
+
#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */
static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = {
@@ -393,9 +431,41 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg)
/* start the test procedure */
nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE);
+ /* inform interested parties about the fact that this NSVC
+ * has received RESET */
+ ns_dispatch_signal(nsvc, S_NS_RESET, cause);
+
return gprs_ns_tx_reset_ack(nsvc);
}
+static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+ struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
+ struct tlv_parsed tp;
+ uint8_t *cause;
+ int rc;
+
+ DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei);
+
+ nsvc->state |= NSE_S_BLOCKED;
+
+ rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0);
+
+ if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) ||
+ !TLVP_PRESENT(&tp, NS_IE_VCI)) {
+ /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */
+ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n");
+ return -EINVAL;
+ }
+
+ cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE);
+ //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI);
+
+ ns_dispatch_signal(nsvc, S_NS_BLOCK, cause);
+
+ return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK);
+}
+
/* main entry point, here incoming NS frames enter */
int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
struct sockaddr_in *saddr)
@@ -467,6 +537,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
/* Section 7.2: unblocking procedure */
DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei);
nsvc->state &= ~NSE_S_BLOCKED;
+ ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0);
rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
break;
case NS_PDUT_UNBLOCK_ACK:
@@ -477,9 +548,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
nsvc->state = NSE_S_ALIVE;
break;
case NS_PDUT_BLOCK:
- DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei);
- nsvc->state |= NSE_S_BLOCKED;
- rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
+ rc = gprs_ns_rx_block(nsvc, msg);
break;
case NS_PDUT_BLOCK_ACK:
DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei);