[MERGED] openggsn[master]: libgtp: Delete PDP context on receiving GTPv1 Error Indication
Harald Welte has submitted this change and it was merged. Change subject: libgtp: Delete PDP context on receiving GTPv1 Error Indication .. libgtp: Delete PDP context on receiving GTPv1 Error Indication When a peer GSN receives a GPDU for an unknown PDP context, it sends a GTP Error Indication. This Error Indication should be used to delete the offending PDP context locally. In GTPv1, the Error Indication contains some mandatory IEs using which we can look up the PDP context and delete it. The existing code only dealt with GTPv0 Error Indications which lack those IEs and use the TEI in the header instead. Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9 Closes: OS#2426 --- M gtp/gtp.c M gtp/pdp.c M gtp/pdp.h 3 files changed, 53 insertions(+), 6 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/gtp/gtp.c b/gtp/gtp.c index a4e8e2b..012aa79 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -2581,17 +2581,44 @@ int gtp_error_ind_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len) { + union gtpie_member *ie[GTPIE_SIZE]; struct pdp_t *pdp; /* Find the context in question */ - if (pdp_tidget(, be64toh(((union gtp_packet *)pack)->gtp0.h.tid))) { - gsn->err_unknownpdp++; - GTP_LOGPKG(LOGL_ERROR, peer, pack, len, - "Unknown PDP context\n"); - return EOF; + if (version == 0) { + if (pdp_tidget(, be64toh(((union gtp_packet *)pack)->gtp0.h.tid))) { + gsn->err_unknownpdp++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Unknown PDP context\n"); + return EOF; + } + } else if (version == 1) { + /* we have to look-up based on the *peer* TEID */ + int hlen = get_hlen(pack); + uint32_t teid_gn; + + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Invalid message format\n"); + return EOF; + } + + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, _gn)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Missing mandatory information field\n"); + return EOF; + } + + if (pdp_getgtp1_peer_d(, peer, teid_gn)) { + gsn->err_unknownpdp++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unknown PDP context\n"); + return EOF; + } } - gsn->err_unknownpdp++; /* TODO: Change counter */ GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Received Error Indication\n"); diff --git a/gtp/pdp.c b/gtp/pdp.c index f297af9..c576a4e 100644 --- a/gtp/pdp.c +++ b/gtp/pdp.c @@ -28,6 +28,7 @@ #include #include #include "pdp.h" +#include "gtp.h" #include "lookupa.h" /* *** @@ -202,6 +203,24 @@ } } +/* get a PDP based on the *peer* address + TEI-Data. Used for matching inbound Error Ind */ +int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn) +{ + unsigned int i; + + /* this is O(n) but we don't have (nor want) another hash... */ + for (i = 0; i < PDP_MAX; i++) { + struct pdp_t *candidate = [i]; + if (candidate->inuse && candidate->teid_gn == teid_gn && + candidate->gsnru.l == sizeof(peer->sin_addr) && + !memcmp(>sin_addr, candidate->gsnru.v, sizeof(peer->sin_addr))) { + *pdp = [i]; + return 0; + } + } + return EOF; +} + int pdp_tidhash(uint64_t tid) { return (lookup(, sizeof(tid), 0) % PDP_MAX); diff --git a/gtp/pdp.h b/gtp/pdp.h index 217b1d6..432f1df 100644 --- a/gtp/pdp.h +++ b/gtp/pdp.h @@ -232,6 +232,7 @@ int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl); int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei); +int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn); int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); -- To view, visit https://gerrit.osmocom.org/3503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9 Gerrit-PatchSet: 1 Gerrit-Project: openggsn Gerrit-Branch: master Gerrit-Owner: Harald WelteGerrit-Reviewer: Harald
openggsn[master]: libgtp: Delete PDP context on receiving GTPv1 Error Indication
Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/3503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9 Gerrit-PatchSet: 1 Gerrit-Project: openggsn Gerrit-Branch: master Gerrit-Owner: Harald WelteGerrit-Reviewer: Harald Welte Gerrit-Reviewer: Jenkins Builder Gerrit-HasComments: No
[PATCH] openggsn[master]: libgtp: Delete PDP context on receiving GTPv1 Error Indication
Review at https://gerrit.osmocom.org/3503 libgtp: Delete PDP context on receiving GTPv1 Error Indication When a peer GSN receives a GPDU for an unknown PDP context, it sends a GTP Error Indication. This Error Indication should be used to delete the offending PDP context locally. In GTPv1, the Error Indication contains some mandatory IEs using which we can look up the PDP context and delete it. The existing code only dealt with GTPv0 Error Indications which lack those IEs and use the TEI in the header instead. Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9 Closes: OS#2426 --- M gtp/gtp.c M gtp/pdp.c M gtp/pdp.h 3 files changed, 53 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openggsn refs/changes/03/3503/1 diff --git a/gtp/gtp.c b/gtp/gtp.c index a4e8e2b..012aa79 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -2581,17 +2581,44 @@ int gtp_error_ind_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len) { + union gtpie_member *ie[GTPIE_SIZE]; struct pdp_t *pdp; /* Find the context in question */ - if (pdp_tidget(, be64toh(((union gtp_packet *)pack)->gtp0.h.tid))) { - gsn->err_unknownpdp++; - GTP_LOGPKG(LOGL_ERROR, peer, pack, len, - "Unknown PDP context\n"); - return EOF; + if (version == 0) { + if (pdp_tidget(, be64toh(((union gtp_packet *)pack)->gtp0.h.tid))) { + gsn->err_unknownpdp++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Unknown PDP context\n"); + return EOF; + } + } else if (version == 1) { + /* we have to look-up based on the *peer* TEID */ + int hlen = get_hlen(pack); + uint32_t teid_gn; + + /* Decode information elements */ + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { + gsn->invalid++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Invalid message format\n"); + return EOF; + } + + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, _gn)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Missing mandatory information field\n"); + return EOF; + } + + if (pdp_getgtp1_peer_d(, peer, teid_gn)) { + gsn->err_unknownpdp++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unknown PDP context\n"); + return EOF; + } } - gsn->err_unknownpdp++; /* TODO: Change counter */ GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Received Error Indication\n"); diff --git a/gtp/pdp.c b/gtp/pdp.c index f297af9..c576a4e 100644 --- a/gtp/pdp.c +++ b/gtp/pdp.c @@ -28,6 +28,7 @@ #include #include #include "pdp.h" +#include "gtp.h" #include "lookupa.h" /* *** @@ -202,6 +203,24 @@ } } +/* get a PDP based on the *peer* address + TEI-Data. Used for matching inbound Error Ind */ +int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn) +{ + unsigned int i; + + /* this is O(n) but we don't have (nor want) another hash... */ + for (i = 0; i < PDP_MAX; i++) { + struct pdp_t *candidate = [i]; + if (candidate->inuse && candidate->teid_gn == teid_gn && + candidate->gsnru.l == sizeof(peer->sin_addr) && + !memcmp(>sin_addr, candidate->gsnru.v, sizeof(peer->sin_addr))) { + *pdp = [i]; + return 0; + } + } + return EOF; +} + int pdp_tidhash(uint64_t tid) { return (lookup(, sizeof(tid), 0) % PDP_MAX); diff --git a/gtp/pdp.h b/gtp/pdp.h index 217b1d6..432f1df 100644 --- a/gtp/pdp.h +++ b/gtp/pdp.h @@ -232,6 +232,7 @@ int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl); int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei); +int pdp_getgtp1_peer_d(struct pdp_t **pdp, const struct sockaddr_in *peer, uint32_t teid_gn); int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); -- To view, visit https://gerrit.osmocom.org/3503 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3e843f9ef1d6fd7868cc992e083c0891d16b6da9 Gerrit-PatchSet: 1 Gerrit-Project: openggsn Gerrit-Branch: master Gerrit-Owner: Harald Welte