aboutsummaryrefslogtreecommitdiffstats
path: root/gtp
diff options
context:
space:
mode:
Diffstat (limited to 'gtp')
-rw-r--r--gtp/gtp.c39
-rw-r--r--gtp/pdp.c19
-rw-r--r--gtp/pdp.h1
3 files changed, 53 insertions, 6 deletions
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_resp(struct gsn_t *gsn, int version,
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(&pdp, 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(&pdp, 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, &teid_gn)) {
+ gsn->missing++;
+ GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
+ "Missing mandatory information field\n");
+ return EOF;
+ }
+
+ if (pdp_getgtp1_peer_d(&pdp, 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 <string.h>
#include <inttypes.h>
#include "pdp.h"
+#include "gtp.h"
#include "lookupa.h"
/* ***********************************************************
@@ -202,6 +203,24 @@ int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
}
}
+/* 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 = &pdpa[i];
+ if (candidate->inuse && candidate->teid_gn == teid_gn &&
+ candidate->gsnru.l == sizeof(peer->sin_addr) &&
+ !memcmp(&peer->sin_addr, candidate->gsnru.v, sizeof(peer->sin_addr))) {
+ *pdp = &pdpa[i];
+ return 0;
+ }
+ }
+ return EOF;
+}
+
int pdp_tidhash(uint64_t tid)
{
return (lookup(&tid, 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_getpdp(struct pdp_t **pdp);
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);