diff --git a/TODO-RELEASE b/TODO-RELEASE index 1815fce..905c234 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -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() \ No newline at end of file diff --git a/gtp/gsn.c b/gtp/gsn.c index c23fb2a..612baf2 100644 --- a/gtp/gsn.c +++ b/gtp/gsn.c @@ -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. */ diff --git a/gtp/gtp.c b/gtp/gtp.c index 9b68315..02cf8a3 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -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 */ diff --git a/include/osmocom/gtp/gsn.h b/include/osmocom/gtp/gsn.h index 936db9b..006fdfd 100644 --- a/include/osmocom/gtp/gsn.h +++ b/include/osmocom/gtp/gsn.h @@ -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)); diff --git a/include/osmocom/gtp/gtp.h b/include/osmocom/gtp/gtp.h index e3c66c9..001a696 100644 --- a/include/osmocom/gtp/gtp.h +++ b/include/osmocom/gtp/gtp.h @@ -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");