diff options
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gprs_bssgp.c | 63 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_libgtp.c | 40 |
2 files changed, 97 insertions, 6 deletions
diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index c7c49d4bd..f27e3a7e8 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -787,3 +787,66 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) return gprs_ns_sendmsg(bssgp_nsi, msg); } + +/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ +int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, + struct bssgp_paging_info *pinfo) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t drx_params = htons(pinfo->drx_params); + uint8_t mi[10]; + int imsi_len = gsm48_generate_mid_from_imsi(mi, pinfo->imsi); + uint8_t ra[6]; + + if (imsi_len < 2) + return -EINVAL; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + if (pinfo->mode == BSSGP_PAGING_PS) + bgph->pdu_type = BSSGP_PDUT_PAGING_PS; + else + bgph->pdu_type = BSSGP_PDUT_PAGING_CS; + /* IMSI */ + msgb_tvlv_put(msg, BSSGP_IE_IMSI, imsi_len-2, mi+2); + /* DRX Parameters */ + msgb_tvlv_put(msg, BSSGP_IE_DRX_PARAMS, 2, + (uint8_t *) &drx_params); + /* Scope */ + switch (pinfo->scope) { + case BSSGP_PAGING_BSS_AREA: + { + uint8_t null = 0; + msgb_tvlv_put(msg, BSSGP_IE_BSS_AREA_ID, 1, &null); + } + break; + case BSSGP_PAGING_LOCATION_AREA: + gsm48_construct_ra(ra, &pinfo->raid); + msgb_tvlv_put(msg, BSSGP_IE_LOCATION_AREA, 4, ra); + break; + case BSSGP_PAGING_ROUTEING_AREA: + gsm48_construct_ra(ra, &pinfo->raid); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + break; + case BSSGP_PAGING_BVCI: + { + uint16_t bvci = htons(pinfo->bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *)&bvci); + } + break; + } + /* QoS profile mandatory for PS */ + if (pinfo->mode == BSSGP_PAGING_PS) + msgb_tvlv_put(msg, BSSGP_IE_QOS_PROFILE, 3, pinfo->qos); + + /* Optional (P-)TMSI */ + if (pinfo->ptmsi) { + uint32_t ptmsi = htonl(*pinfo->ptmsi); + msgb_tvlv_put(msg, BSSGP_IE_TMSI, 4, (uint8_t *) &ptmsi); + } + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index 6de3c3d1f..a1d233a9a 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -357,27 +357,55 @@ static int cb_extheader_ind(struct sockaddr_in *peer) /* Called whenever we recive a DATA packet */ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len) { + struct bssgp_paging_info pinfo; struct sgsn_pdp_ctx *pdp; - struct msgb *msg = msgb_alloc_headroom(len+128, 128, "GTP->SNDCP"); + struct sgsn_mm_ctx *mm; + struct msgb *msg; uint8_t *ud; + int rc; DEBUGP(DGPRS, "GTP DATA IND from GGSN, length=%u\n", len); - /* FIXME: resolve PDP/MM context, forward to SNDCP layer */ pdp = lib->priv; if (!pdp) { DEBUGP(DGPRS, "GTP DATA IND from GGSN for unknown PDP\n"); return -EIO; } + mm = pdp->mm; + msg = msgb_alloc_headroom(len+128, 128, "GTP->SNDCP"); 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; + msgb_tlli(msg) = mm->tlli; + msgb_bvci(msg) = mm->bvci; + msgb_nsei(msg) = mm->nsei; + + switch (mm->mm_state) { + case GMM_REGISTERED_SUSPENDED: + /* initiate PS PAGING procedure */ + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.mode = BSSGP_PAGING_PS; + pinfo.scope = BSSGP_PAGING_BVCI; + pinfo.bvci = mm->bvci; + pinfo.imsi = mm->imsi; + pinfo.ptmsi = mm->p_tmsi; + pinfo.drx_params = mm->drx_parms; + pinfo.qos[0] = 0; // FIXME + rc = gprs_bssgp_tx_paging(mm->nsei, 0, &pinfo); + /* FIXME: queue the packet we received from GTP */ + break; + case GMM_REGISTERED_NORMAL: + break; + default: + LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state " + "%u\n", mm->tlli, mm->mm_state); + msgb_free(msg); + return -1; + } - return sndcp_unitdata_req(msg, &pdp->mm->llme->lle[pdp->sapi], pdp->nsapi, pdp->mm); + return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi], + pdp->nsapi, mm); } /* Called by SNDCP when it has received/re-assembled a N-PDU */ |