diff options
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gprs_sndcp.c | 36 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_libgtp.c | 22 |
2 files changed, 56 insertions, 2 deletions
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 */ |