aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Willmann <dwillmann@sysmocom.de>2018-08-31 18:03:16 +0200
committerDaniel Willmann <dwillmann@sysmocom.de>2018-08-31 18:03:16 +0200
commit8e97fccc346d2bf981968f00a003d93baec9a4c7 (patch)
treec264a4dbd9fbc9d7e15b21c3dd0627be295b352f
parent835496d7dd68988dc87257b28c83230be85435d8 (diff)
parentee44b82b967929eaf8867d967a22428972b58d0a (diff)
Merge remote-tracking branch 'origin/master' into daniel/onwaves
-rwxr-xr-xdebian/rules4
-rw-r--r--ggsn/ggsn.c101
-rw-r--r--gtp/gtp.c182
-rw-r--r--gtp/gtp.h12
4 files changed, 192 insertions, 107 deletions
diff --git a/debian/rules b/debian/rules
index bcf1931..5db7886 100755
--- a/debian/rules
+++ b/debian/rules
@@ -17,7 +17,3 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
override_dh_strip:
dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
dh_strip -plibgtp3 --dbg-package=libgtp-dbg
-
-override_dh_autoreconf:
- echo $(VERSION) > .tarball-version
- dh_autoreconf
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 14bf04f..39695b9 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -413,16 +413,19 @@ struct ipcp_hdr {
} __attribute__ ((packed));
/* determine if IPCP contains given option */
-static struct ipcp_option_hdr *ipcp_contains_option(struct ipcp_hdr *ipcp, enum ipcp_options opt)
+static uint8_t *ipcp_contains_option(uint8_t *ipcp, size_t ipcp_len, enum ipcp_options opt, size_t opt_minlen)
{
- uint8_t *cur = ipcp->options;
+ uint8_t *cur_opt = ipcp + sizeof(struct ipcp_hdr);
/* iterate over Options and check if protocol contained */
- while (cur + 2 <= ((uint8_t *)ipcp) + ntohs(ipcp->len)) {
- struct ipcp_option_hdr *cur_opt = (struct ipcp_option_hdr *) cur;
- if (cur_opt->type == opt)
+ while (cur_opt + 2 <= ipcp + ipcp_len) {
+ uint8_t type = cur_opt[0];
+ uint8_t len = cur_opt[1]; /* length value includes 2 bytes type/length */
+ if (len < 2)
+ return NULL;
+ if (type == opt && len >= 2 + opt_minlen)
return cur_opt;
- cur += cur_opt->len;
+ cur_opt += len;
}
return NULL;
}
@@ -460,15 +463,15 @@ enum pco_protocols {
};
/* determine if PCO contains given protocol */
-static uint8_t *pco_contains_proto(struct ul255_t *pco, uint16_t prot)
+static uint8_t *pco_contains_proto(struct ul255_t *pco, size_t offset, uint16_t prot, size_t prot_minlen)
{
- uint8_t *cur = pco->v + 1;
+ uint8_t *cur = pco->v + 1 + offset;
/* iterate over PCO and check if protocol contained */
while (cur + 3 <= pco->v + pco->l) {
uint16_t cur_prot = osmo_load16be(cur);
uint8_t cur_len = cur[2];
- if (cur_prot == prot)
+ if (cur_prot == prot && cur_len >= prot_minlen)
return cur;
cur += cur_len + 3;
}
@@ -500,46 +503,59 @@ static struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
}
/* construct an IPCP PCO response from request*/
-static int build_ipcp_pco(struct apn_ctx *apn, struct pdp_t *pdp, struct msgb *msg)
+static void build_ipcp_pco(struct apn_ctx *apn, struct pdp_t *pdp, struct msgb *msg)
{
const struct in46_addr *dns1 = &apn->v4.cfg.dns[0];
const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
- struct ipcp_hdr *ipcp;
+ uint8_t *ipcp;
+ uint16_t ipcp_len;
uint8_t *len1, *len2, *pco_ipcp;
- uint8_t *start = msg->tail;
unsigned int len_appended;
+ ptrdiff_t consumed;
+ size_t remain, offset = 0;
+
+ /* pco_contains_proto() returns a potentially unaligned pointer into pco_req->v (see OS#3194) */
+ pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
+ while (pco_ipcp) {
+ uint8_t *start = msg->tail;
+
+ ipcp = (pco_ipcp + 3); /* 2=type + 1=len */
+ consumed = (ipcp - &pdp->pco_req.v[0]);
+ remain = sizeof(pdp->pco_req.v) - consumed;
+ ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
+ if (remain < 0 || remain < ipcp_len)
+ return;
+
+ /* Three byte T16L header */
+ msgb_put_u16(msg, 0x8021); /* IPCP */
+ len1 = msgb_put(msg, 1); /* Length of contents: delay */
+
+ msgb_put_u8(msg, 0x02); /* ACK */
+ msgb_put_u8(msg, ipcp[1]); /* ID: Needs to match request */
+ msgb_put_u8(msg, 0x00); /* Length MSB */
+ len2 = msgb_put(msg, 1); /* Length LSB: delay */
+
+ if (dns1->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_PRIMARY_DNS, 4)) {
+ msgb_put_u8(msg, 0x81); /* DNS1 Tag */
+ msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
+ msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
+ }
- if (!(pco_ipcp = pco_contains_proto(&pdp->pco_req, PCO_P_IPCP)))
- return 0;
- ipcp = (struct ipcp_hdr*) (pco_ipcp + 3); /* 2=type + 1=len */
-
- /* Three byte T16L header */
- msgb_put_u16(msg, 0x8021); /* IPCP */
- len1 = msgb_put(msg, 1); /* Length of contents: delay */
-
- msgb_put_u8(msg, 0x02); /* ACK */
- msgb_put_u8(msg, ipcp->id); /* ID: Needs to match request */
- msgb_put_u8(msg, 0x00); /* Length MSB */
- len2 = msgb_put(msg, 1); /* Length LSB: delay */
+ if (dns2->len == 4 && ipcp_contains_option(ipcp, ipcp_len, IPCP_OPT_SECONDARY_DNS, 4)) {
+ msgb_put_u8(msg, 0x83); /* DNS2 Tag */
+ msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
+ msgb_put_u32(msg, ntohl(dns2->v4.s_addr));
+ }
- if (dns1->len == 4 && ipcp_contains_option(ipcp, IPCP_OPT_PRIMARY_DNS)) {
- msgb_put_u8(msg, 0x81); /* DNS1 Tag */
- msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
- msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
- }
+ /* patch in length values */
+ len_appended = msg->tail - start;
+ *len1 = len_appended - 3;
+ *len2 = len_appended - 3;
- if (dns2->len == 4 && ipcp_contains_option(ipcp, IPCP_OPT_SECONDARY_DNS)) {
- msgb_put_u8(msg, 0x83); /* DNS2 Tag */
- msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
- msgb_put_u32(msg, ntohl(dns2->v4.s_addr));
+ offset += 3 + ipcp_len;
+ pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
}
- /* patch in length values */
- len_appended = msg->tail - start;
- *len1 = len_appended - 3;
- *len2 = len_appended - 3;
-
- return 0;
}
/* process one PCO request from a MS/UE, putting together the proper responses */
@@ -555,7 +571,7 @@ static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp)
if (peer_v4)
build_ipcp_pco(apn, pdp, msg);
- if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv6_ADDR)) {
+ if (pco_contains_proto(&pdp->pco_req, 0, PCO_P_DNS_IPv6_ADDR, 0)) {
for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
struct in46_addr *i46a = &apn->v6.cfg.dns[i];
if (i46a->len != 16)
@@ -564,7 +580,7 @@ static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp)
}
}
- if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv4_ADDR)) {
+ if (pco_contains_proto(&pdp->pco_req, 0, PCO_P_DNS_IPv4_ADDR, 0)) {
for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
struct in46_addr *i46a = &apn->v4.cfg.dns[i];
if (i46a->len != 4)
@@ -1111,7 +1127,8 @@ int main(int argc, char **argv)
if (rc < 0)
exit(1);
- g_ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
+ g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
+ OSMO_CTRL_PORT_GGSN, NULL);
if (!g_ctrlh) {
LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
exit(1);
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 42e84a7..1d58088 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -190,6 +190,15 @@ int gtp_set_cb_conf(struct gsn_t *gsn,
return 0;
}
+static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
+ struct pdp_t * pdp, uint8_t recovery)
+{
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ if (gsn->cb_recovery2)
+ gsn->cb_recovery2(peer, pdp, recovery);
+}
+
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
{
@@ -197,6 +206,20 @@ int gtp_set_cb_recovery(struct gsn_t *gsn,
return 0;
}
+/* cb_recovery()
+ * pdp may be NULL if Recovery IE was received from a message independent
+ * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
+ * local setup. In case pdp is known, caller may want to keep that pdp alive to
+ * handle subsequent msg cb as this specific pdp ctx is still valid according to
+ * specs.
+ */
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
+{
+ gsn->cb_recovery2 = cb_recovery2;
+ return 0;
+}
+
int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len))
@@ -977,8 +1000,7 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
if (gsn->cb_conf)
gsn->cb_conf(type, recovery, NULL, cbp);
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, NULL, recovery);
return 0;
}
@@ -1310,6 +1332,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
struct pdp_t pdp_buf;
union gtpie_member *ie[GTPIE_SIZE];
uint8_t recovery;
+ bool recovery_recvd = false;
+ int rc;
uint16_t seq = get_seq(pack);
int hlen = get_hlen(pack);
@@ -1410,8 +1434,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ /* we use recovery futher down after announcing new pdp ctx to user */
+ recovery_recvd = true;
}
/* Selection mode (conditional) */
@@ -1612,6 +1636,9 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Switch to using the old pdp context */
pdp = pdp_old;
+ if (recovery_recvd)
+ emit_cb_recovery(gsn, peer, pdp, recovery);
+
/* Confirm to peer that things were "successful" */
return gtp_create_pdp_resp(gsn, version, pdp,
GTPCAUSE_ACC_REQ);
@@ -1633,13 +1660,16 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Callback function to validata login */
if (gsn->cb_create_context_ind != 0)
- return gsn->cb_create_context_ind(pdp);
+ rc = gsn->cb_create_context_ind(pdp);
else {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"No create_context_ind callback defined\n");
- return gtp_create_pdp_resp(gsn, version, pdp,
+ rc = gtp_create_pdp_resp(gsn, version, pdp,
GTPCAUSE_NOT_SUPPORTED);
}
+ if (recovery_recvd)
+ emit_cb_recovery(gsn, peer, pdp, recovery);
+ return rc;
}
/* Handle Create PDP Context Response */
@@ -1696,8 +1726,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
/* Extract recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
/* Extract protocol configuration options (optional) */
@@ -2106,8 +2135,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
/* Recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
if (version == 0) {
@@ -2267,8 +2295,7 @@ static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
/* Extract recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
/* Check all conditional information elements */
@@ -2337,24 +2364,13 @@ err_out:
return EOF;
}
-/* API: Send Delete PDP Context Request */
+/* API: Deprecated. Send Delete PDP Context Request And free pdp ctx. */
int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
int teardown)
{
- union gtp_packet packet;
- unsigned int length =
- get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
- struct in_addr addr;
struct pdp_t *linked_pdp;
struct pdp_t *secondary_pdp;
int n;
- int count = 0;
-
- if (gsna2in_addr(&addr, &pdp->gsnrc)) {
- gsn->err_address++;
- LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l);
- return EOF;
- }
if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
LOGP(DLGTP, LOGL_ERROR,
@@ -2362,26 +2378,8 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
return EOF;
}
- if (!teardown) {
- for (n = 0; n < PDP_MAXNSAPI; n++)
- if (linked_pdp->secondary_tei[n])
- count++;
- if (count <= 1) {
- LOGP(DLGTP, LOGL_ERROR,
- "Must use teardown for last context: %d\n", count);
- return EOF;
- }
- }
-
- if (pdp->version == 1) {
- if (teardown)
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
- 0xff);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
- }
-
- gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
+ if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF)
+ return EOF;
if (teardown) { /* Remove all contexts */
for (n = 0; n < PDP_MAXNSAPI; n++) {
@@ -2417,6 +2415,54 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
return 0;
}
+/* API: Send Delete PDP Context Request. PDP CTX shall be free'd by user at cb_conf(GTP_DELETE_PDP_RSP) */
+int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
+ int teardown)
+{
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
+ struct in_addr addr;
+ struct pdp_t *linked_pdp;
+ int n;
+ int count = 0;
+
+ if (gsna2in_addr(&addr, &pdp->gsnrc)) {
+ gsn->err_address++;
+ LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l);
+ return EOF;
+ }
+
+ if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "Unknown linked PDP context: %u\n", pdp->teic_own);
+ return EOF;
+ }
+
+ if (!teardown) {
+ for (n = 0; n < PDP_MAXNSAPI; n++)
+ if (linked_pdp->secondary_tei[n])
+ count++;
+ if (count <= 1) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "Must use teardown for last context: %d\n", count);
+ return EOF;
+ }
+ }
+
+ if (pdp->version == 1) {
+ if (teardown)
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
+ 0xff);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
+ }
+
+ gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
+
+ return 0;
+}
+
/* Send Delete PDP Context Response */
int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
@@ -2553,6 +2599,9 @@ int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
if (linked_pdp->secondary_tei[n])
count++;
if (count <= 1) {
+ GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
+ "Ignoring CTX DEL without teardown and count=%d\n",
+ count);
return 0; /* 29.060 7.3.5 Ignore message */
}
}
@@ -2570,19 +2619,32 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
uint8_t cause;
void *cbp = NULL;
uint8_t type = 0;
+ struct pdp_t *pdp = NULL;
int hlen = get_hlen(pack);
/* Remove packet from queue */
if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
return EOF;
+ /* Find the context in question. It may not be available if gtp_delete_context_req
+ * was used and as a result the PDP ctx was already freed */
+ if (pdp_getgtp1(&pdp, get_tei(pack))) {
+ gsn->err_unknownpdp++;
+ GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
+ "Unknown PDP context: %u (expected if gtp_delete_context_req is used)\n",
+ get_tei(pack));
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+
/* 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");
if (gsn->cb_conf)
- gsn->cb_conf(type, EOF, NULL, cbp);
+ gsn->cb_conf(type, EOF, pdp, cbp);
return EOF;
}
@@ -2592,7 +2654,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory information field\n");
if (gsn->cb_conf)
- gsn->cb_conf(type, EOF, NULL, cbp);
+ gsn->cb_conf(type, EOF, pdp, cbp);
return EOF;
}
@@ -2602,13 +2664,13 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Unexpected cause value received: %d\n", cause);
if (gsn->cb_conf)
- gsn->cb_conf(type, cause, NULL, cbp);
+ gsn->cb_conf(type, cause, pdp, cbp);
return EOF;
}
/* Callback function to notify application */
if (gsn->cb_conf)
- gsn->cb_conf(type, cause, NULL, cbp);
+ gsn->cb_conf(type, cause, pdp, cbp);
return 0;
}
@@ -2830,23 +2892,23 @@ int gtp_decaps0(struct gsn_t *gsn)
if ((gsn->mode == GTP_MODE_GGSN) &&
((pheader->type == GTP_CREATE_PDP_RSP) ||
- (pheader->type == GTP_UPDATE_PDP_RSP) ||
- (pheader->type == GTP_DELETE_PDP_RSP))) {
+ (pheader->type == GTP_UPDATE_PDP_RSP))) {
gsn->unexpect++;
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
status,
- "Unexpected GTPv0 Signalling Message\n");
+ "Unexpected GTPv0 Signalling Message '%s'\n",
+ get_value_string(gtp_type_names, pheader->type));
continue; /* Silently discard 29.60: 11.1.4 */
}
if ((gsn->mode == GTP_MODE_SGSN) &&
((pheader->type == GTP_CREATE_PDP_REQ) ||
- (pheader->type == GTP_UPDATE_PDP_REQ) ||
- (pheader->type == GTP_DELETE_PDP_REQ))) {
+ (pheader->type == GTP_UPDATE_PDP_REQ))) {
gsn->unexpect++;
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
status,
- "Unexpected GTPv0 Signalling Message\n");
+ "Unexpected GTPv0 Signalling Message '%s'\n",
+ get_value_string(gtp_type_names, pheader->type));
continue; /* Silently discard 29.60: 11.1.4 */
}
@@ -3007,23 +3069,23 @@ int gtp_decaps1c(struct gsn_t *gsn)
if ((gsn->mode == GTP_MODE_GGSN) &&
((pheader->type == GTP_CREATE_PDP_RSP) ||
- (pheader->type == GTP_UPDATE_PDP_RSP) ||
- (pheader->type == GTP_DELETE_PDP_RSP))) {
+ (pheader->type == GTP_UPDATE_PDP_RSP))) {
gsn->unexpect++;
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
status,
- "Unexpected GTPv1 Signalling Message\n");
+ "Unexpected GTPv1 Signalling Message '%s'\n",
+ get_value_string(gtp_type_names, pheader->type));
continue; /* Silently discard 29.60: 11.1.4 */
}
if ((gsn->mode == GTP_MODE_SGSN) &&
((pheader->type == GTP_CREATE_PDP_REQ) ||
- (pheader->type == GTP_UPDATE_PDP_REQ) ||
- (pheader->type == GTP_DELETE_PDP_REQ))) {
+ (pheader->type == GTP_UPDATE_PDP_REQ))) {
gsn->unexpect++;
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
status,
- "Unexpected GTPv1 Signalling Message\n");
+ "Unexpected GTPv1 Signalling Message '%s'\n",
+ get_value_string(gtp_type_names, pheader->type));
continue; /* Silently discard 29.60: 11.1.4 */
}
diff --git a/gtp/gtp.h b/gtp/gtp.h
index 8f8e293..ed594f1 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -13,6 +13,7 @@
#define _GTP_H
#include <osmocom/core/utils.h>
+#include <osmocom/core/defs.h>
#define GTP_MODE_GGSN 1
#define GTP_MODE_SGSN 2
@@ -270,6 +271,7 @@ struct gsn_t {
int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
/* Counters */
@@ -323,7 +325,10 @@ extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp, struct in_addr *inetaddr);
extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
- void *cbp, int teardown);
+ void *cbp, int teardown)
+ OSMO_DEPRECATED("Use gtp_delete_context_req2() instead, to avoid freeing pdp ctx before reply");
+extern int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp,
+ void *cbp, int teardown);
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
void *pack, unsigned len);
@@ -357,6 +362,11 @@ extern int gtp_set_cb_conf(struct gsn_t *gsn,
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
+ uint8_t recovery))
+ OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer,
+ struct pdp_t * pdp,
uint8_t recovery));
/* Internal functions (not part of the API */