[GPRS] BSSGP/SGSN: Implement Gb-Interface Paging
We now have a function that generates BSSGP PS and CS paging request. It is called from the libgtp code when we receive a GTP packet from the GGSN for a MM context that is in SUSPEND state. We then issue a PS paging request to the Cell with the BVCI where the last RA update was being performed. TODO: We still don't enqueue the GTP packet (and transmit it on paging complete), and we don't rate-limit the paging requests, i.e. every GTP packet will trigger another paging request. We probably also need some kind of logic that marks the phone as UNREGISTERED if it doesn't respond to paging requests for some time.
This commit is contained in:
parent
bffeff8089
commit
bb35c45a02
|
@ -199,6 +199,33 @@ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len)
|
|||
return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
|
||||
}
|
||||
|
||||
enum bssgp_paging_mode {
|
||||
BSSGP_PAGING_PS,
|
||||
BSSGP_PAGING_CS,
|
||||
};
|
||||
|
||||
enum bssgp_paging_scope {
|
||||
BSSGP_PAGING_BSS_AREA, /* all cells in BSS */
|
||||
BSSGP_PAGING_LOCATION_AREA, /* all cells in LA */
|
||||
BSSGP_PAGING_ROUTEING_AREA, /* all cells in RA */
|
||||
BSSGP_PAGING_BVCI, /* one cell */
|
||||
};
|
||||
|
||||
struct bssgp_paging_info {
|
||||
enum bssgp_paging_mode mode;
|
||||
enum bssgp_paging_scope scope;
|
||||
struct gprs_ra_id raid;
|
||||
uint16_t bvci;
|
||||
const char *imsi;
|
||||
uint32_t *ptmsi;
|
||||
uint16_t drx_params;
|
||||
uint8_t qos[3];
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
/* gprs_bssgp_vty.c */
|
||||
int gprs_bssgp_vty_init(void);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
return sndcp_unitdata_req(msg, &pdp->mm->llme->lle[pdp->sapi], pdp->nsapi, pdp->mm);
|
||||
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, &mm->llme->lle[pdp->sapi],
|
||||
pdp->nsapi, mm);
|
||||
}
|
||||
|
||||
/* Called by SNDCP when it has received/re-assembled a N-PDU */
|
||||
|
|
Loading…
Reference in New Issue