gtp: Allow setting callback to receive update_context_ind

This will be used by:
* SGSN: Get to know that RNC has gonne down according to GGSN (re-attempt
  Direct Tunnel or go back to tun SGSN<->GGSN).
* GGSN: Maybe find out that Direct Flags are used (should be handled
  internally directly in the rx path probably)

Related: OS#6512
Change-Id: Ic80a9a928c55b6ff85be96014920bb42793cb943
This commit is contained in:
Pau Espin Pedrol
2024-07-24 19:46:43 +02:00
parent 70a1d64e55
commit 0828b2afc3
5 changed files with 75 additions and 27 deletions

View File

@@ -8,3 +8,5 @@
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
libgtp append new field dir_tun_flags in struct pdp_t (older users not using the field should be fine since struct pdp_t is allocated internally)
libgtp ABI break new field cb_create_context_ind in struct gsn_t
libgtp new API gtp_set_cb_update_context_ind(), gtp_update_context_resp()

View File

@@ -497,6 +497,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
/* Initialise call back functions */
(*gsn)->cb_create_context_ind = 0;
(*gsn)->cb_update_context_ind = 0;
(*gsn)->cb_delete_context = 0;
(*gsn)->cb_unsup_ind = 0;
(*gsn)->cb_conf = 0;
@@ -563,6 +564,13 @@ int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
return 0;
}
int gtp_set_cb_update_context_ind(struct gsn_t *gsn,
int (*cb_update_context_ind)(struct pdp_t *pdp))
{
gsn->cb_update_context_ind = cb_update_context_ind;
return 0;
}
int gtp_retrans(struct gsn_t *gsn)
{
/* dummy API, deprecated. */

View File

@@ -1696,10 +1696,11 @@ int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
return 0;
}
/* Send Update PDP Context Response */
static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len,
uint16_t seq, uint64_t tid,
struct pdp_t *pdp, uint8_t cause)
{
@@ -1760,7 +1761,22 @@ static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
}
return gtp_resp(version, gsn, pdp, &packet, length, peer,
fd, get_seq(pack), get_tid(pack));
fd, seq, tid);
}
/* API: Application response to context indication */
int gtp_update_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
{
/* Now send off a reply to the peer */
gtp_update_pdp_resp(gsn, pdp->version, &pdp->sa_peer,
pdp->fd, pdp->seq, pdp->tid, pdp, cause);
if (!gtp_cause_successful(cause))
gtp_freepdp(gsn, pdp);
return 0;
}
/* Handle Update PDP Context Request */
@@ -1768,13 +1784,15 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len)
{
struct pdp_t *pdp;
struct pdp_t *pdp = NULL;
struct pdp_t pdp_backup;
union gtpie_member *ie[GTPIE_SIZE];
uint8_t recovery;
int rc;
uint16_t seq = get_seq(pack);
int hlen = get_hlen(pack);
uint64_t tid = get_tid(pack);
uint64_t imsi;
uint8_t nsapi;
@@ -1792,8 +1810,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
if (0 == version)
return EOF;
else
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, NULL,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, NULL,
GTPCAUSE_INVALID_MESSAGE);
}
@@ -1808,8 +1826,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Unknown PDP context: TID=0x%" PRIx64 "\n",
get_tid(pack));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, NULL,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, NULL,
GTPCAUSE_NON_EXIST);
}
@@ -1821,8 +1839,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, NULL,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, NULL,
GTPCAUSE_MAN_IE_MISSING);
}
@@ -1835,7 +1853,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
"Unknown PDP context: TEI=0x%" PRIx32 "\n",
get_tei(pack));
return gtp_update_pdp_resp(gsn, version, peer,
fd, pack, len, NULL,
fd, seq, tid, NULL,
GTPCAUSE_NON_EXIST);
}
} else {
@@ -1846,7 +1864,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
"Unknown PDP context: IMSI=0x%" PRIx64
" NSAPI=%" PRIu8 "\n", imsi, nsapi);
return gtp_update_pdp_resp(gsn, version, peer,
fd, pack, len, NULL,
fd, seq, tid, NULL,
GTPCAUSE_NON_EXIST);
}
}
@@ -1855,6 +1873,12 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
return EOF;
}
/* Update internal state to be used when user calls gtp_update_context_resp(): */
pdp->seq = seq;
pdp->sa_peer = *peer;
pdp->fd = fd;
pdp->version = version;
/* Make a backup copy in case anything is wrong */
memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
@@ -1865,8 +1889,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
}
@@ -1882,8 +1906,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
@@ -1892,8 +1916,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
}
@@ -1906,8 +1930,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
@@ -1923,8 +1947,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
}
@@ -1951,7 +1975,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq, tid,
pdp, GTPCAUSE_MAN_IE_MISSING);
}
@@ -1963,7 +1987,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq, tid,
pdp, GTPCAUSE_MAN_IE_MISSING);
}
@@ -1976,8 +2000,8 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len, "Missing mandatory information field\n");
memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
len, pdp,
return gtp_update_pdp_resp(gsn, version, peer, fd, seq,
tid, pdp,
GTPCAUSE_MAN_IE_MISSING);
}
@@ -1994,9 +2018,17 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
}
}
/* Callback function to validate login */
if (gsn->cb_update_context_ind != 0)
rc = gsn->cb_update_context_ind(pdp);
else {
/* Confirm to peer that things were "successful" */
rc = gtp_update_pdp_resp(gsn, version, peer, fd, seq, tid, pdp,
GTPCAUSE_ACC_REQ);
}
/* Confirm to peer that things were "successful" */
return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
GTPCAUSE_ACC_REQ);
return rc;
}
/* Handle Update PDP Context Response */

View File

@@ -99,6 +99,7 @@ struct gsn_t {
/* Call back functions */
int (*cb_delete_context) (struct pdp_t *);
int (*cb_create_context_ind) (struct pdp_t *);
int (*cb_update_context_ind)(struct pdp_t *pdp);
int (*cb_unsup_ind) (struct sockaddr_in * peer);
int (*cb_extheader_ind) (struct sockaddr_in * peer);
int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
@@ -134,6 +135,8 @@ extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct
pdp_t *
pdp));
extern int gtp_set_cb_update_context_ind(struct gsn_t *gsn,
int (*cb_update_context_ind)(struct pdp_t *pdp));
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len));

View File

@@ -248,6 +248,9 @@ extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp, struct in_addr *inetaddr);
extern int gtp_update_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
int cause);
extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp, int teardown)
OSMO_DEPRECATED("Use gtp_delete_context_req2() instead, to avoid freeing pdp ctx before reply");