[GPRS] implement GTP->SNDCP->LLC downlink user-data path
This only works for packets that are small enough to not need fragmentation at the SNDCP layer (dns queries, ntp and the like). It requires libgtp built from OpenGGSN dc3744fda045f9fca83de6881176987335a309a8 or later. Plain 0.90 will NOT work. Using this version, I could see bi-directional traffic from various phones going all the way through BTS, OsmoSGSN, OpenGGSN and being routed to and from the real internet. Time to celebrate...
This commit is contained in:
parent
96df60637a
commit
bb1c805718
|
@ -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 */
|
/* 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,
|
int sgsn_rx_sndcp_ud_ind(uint32_t tlli, uint8_t nsapi, struct msgb *msg,
|
||||||
uint32_t npdu_len, uint8_t *npdu);
|
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
|
#endif
|
||||||
|
|
|
@ -86,10 +86,16 @@ struct frag_queue_head {
|
||||||
struct sndcp_entity {
|
struct sndcp_entity {
|
||||||
struct llist_head list;
|
struct llist_head list;
|
||||||
|
|
||||||
|
/* reference to the LLC Entity below this SNDCP entity */
|
||||||
struct gprs_llc_lle *lle;
|
struct gprs_llc_lle *lle;
|
||||||
|
/* The NSAPI we shall use on top of LLC */
|
||||||
uint8_t nsapi;
|
uint8_t nsapi;
|
||||||
|
|
||||||
|
/* NPDU number for the GTP->SNDCP side */
|
||||||
|
uint16_t npdu_nr;
|
||||||
|
/* SNDCP eeceiver state */
|
||||||
enum sndcp_rx_state rx_state;
|
enum sndcp_rx_state rx_state;
|
||||||
|
/* The defragmentation queue */
|
||||||
struct frag_queue_head fqueue;
|
struct frag_queue_head fqueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,6 +172,36 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
|
||||||
return 0;
|
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 */
|
/* 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)
|
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t *hdr, uint8_t len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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");
|
LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
pdp->priv = pctx;
|
||||||
pctx->lib = pdp;
|
pctx->lib = pdp;
|
||||||
pctx->ggsn = ggsn;
|
pctx->ggsn = ggsn;
|
||||||
|
|
||||||
|
@ -354,12 +355,29 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called whenever we recive a DATA packet */
|
/* 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);
|
DEBUGP(DGPRS, "GTP DATA IND from GGSN, length=%u\n", len);
|
||||||
/* FIXME: resolve PDP/MM context, forward to SNDCP layer */
|
/* 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 */
|
/* Called by SNDCP when it has received/re-assembled a N-PDU */
|
||||||
|
|
Loading…
Reference in New Issue