aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/sgsn.h2
-rw-r--r--openbsc/src/gprs/gprs_sndcp.c36
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c22
3 files changed, 58 insertions, 2 deletions
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
index b7825685b..cc24f9781 100644
--- a/openbsc/include/openbsc/sgsn.h
+++ b/openbsc/include/openbsc/sgsn.h
@@ -57,5 +57,7 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
/* Called by SNDCP when it has received/re-assembled a N-PDU */
int sgsn_rx_sndcp_ud_ind(uint32_t tlli, uint8_t nsapi, struct msgb *msg,
uint32_t npdu_len, uint8_t *npdu);
+int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+ void *mmcontext);
#endif
diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
index 0a94251fe..600802511 100644
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -86,10 +86,16 @@ struct frag_queue_head {
struct sndcp_entity {
struct llist_head list;
+ /* reference to the LLC Entity below this SNDCP entity */
struct gprs_llc_lle *lle;
+ /* The NSAPI we shall use on top of LLC */
uint8_t nsapi;
+ /* NPDU number for the GTP->SNDCP side */
+ uint16_t npdu_nr;
+ /* SNDCP eeceiver state */
enum sndcp_rx_state rx_state;
+ /* The defragmentation queue */
struct frag_queue_head fqueue;
};
@@ -166,6 +172,36 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
return 0;
}
+int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+ void *mmcontext)
+{
+ struct sndcp_entity *sne;
+ struct sndcp_common_hdr *sch;
+ struct sndcp_udata_hdr *suh;
+
+ /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
+
+ sne = sndcp_entity_by_lle(lle, nsapi);
+ if (!sne) {
+ LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
+ return -EIO;
+ }
+
+ /* prepend the user-data header */
+ suh = (struct sndcp_udata_hdr *) msgb_push(msg, sizeof(*suh));
+ suh->npdu_low = sne->npdu_nr & 0xff;
+ suh->npdu_high = (sne->npdu_nr >> 8) & 0xf;
+ sne->npdu_nr = (sne->npdu_nr + 1) % 0xfff;
+
+ /* prepend common SNDCP header */
+ sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch));
+ sch->first = 1;
+ sch->type = 1;
+ sch->nsapi = nsapi;
+
+ return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext);
+}
+
/* Section 5.1.2.17 LL-UNITDATA.ind */
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t *hdr, uint8_t len)
{
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index 37ffd8985..6de3c3d1f 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -113,6 +113,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n");
return NULL;
}
+ pdp->priv = pctx;
pctx->lib = pdp;
pctx->ggsn = ggsn;
@@ -354,12 +355,29 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
}
/* Called whenever we recive a DATA packet */
-static int cb_data_ind(struct pdp_t *pdp, void *packet, unsigned int len)
+static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
{
+ struct sgsn_pdp_ctx *pdp;
+ struct msgb *msg = msgb_alloc_headroom(len+128, 128, "GTP->SNDCP");
+ uint8_t *ud;
+
DEBUGP(DGPRS, "GTP DATA IND from GGSN, length=%u\n", len);
/* FIXME: resolve PDP/MM context, forward to SNDCP layer */
- return 0;
+ pdp = lib->priv;
+ if (!pdp) {
+ DEBUGP(DGPRS, "GTP DATA IND from GGSN for unknown PDP\n");
+ return -EIO;
+ }
+
+ ud = msgb_put(msg, len);
+ memcpy(ud, packet, len);
+
+ msgb_tlli(msg) = pdp->mm->tlli;
+ msgb_bvci(msg) = pdp->mm->bvci;
+ msgb_nsei(msg) = pdp->mm->nsei;
+
+ return sndcp_unitdata_req(msg, &pdp->mm->llme->lle[pdp->sapi], pdp->nsapi, pdp->mm);
}
/* Called by SNDCP when it has received/re-assembled a N-PDU */