gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly

libgtp cannot understand its own update pdp request (in gtp v1)
Only require the conditional and mandatory fields for gtpv1 and not
others.
Refer to 3GPP TS 29.060 Ch. 7.3.4
This commit is contained in:
Daniel Willmann 2016-02-04 15:38:12 +01:00 committed by Holger Hans Peter Freyther
parent 05f3ef3eb8
commit d997552d29
1 changed files with 63 additions and 57 deletions

116
gtp/gtp.c
View File

@ -2187,9 +2187,8 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
gsn->err_unknownpdp++; gsn->err_unknownpdp++;
GTP_LOGPKG(LOGL_ERROR, peer, pack, len, GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Unknown PDP context: %u\n", get_tei(pack)); "Unknown PDP context: %u\n", get_tei(pack));
if (gsn->cb_conf) pdp = NULL;
gsn->cb_conf(type, EOF, NULL, cbp); goto err_out;
return EOF;
} }
/* Register that we have received a valid teic from GGSN */ /* Register that we have received a valid teic from GGSN */
@ -2200,23 +2199,12 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
gsn->invalid++; gsn->invalid++;
GTP_LOGPKG(LOGL_ERROR, peer, pack, len, GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Invalid message format\n"); "Invalid message format\n");
if (gsn->cb_conf) goto err_out;
gsn->cb_conf(type, EOF, pdp, cbp);
/* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
pdp_freepdp(pdp); */
return EOF;
} }
/* Extract cause value (mandatory) */ /* Extract cause value (mandatory) */
if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
gsn->missing++; goto err_missing;
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing mandatory information field\n");
if (gsn->cb_conf)
gsn->cb_conf(type, EOF, pdp, cbp);
/* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
pdp_freepdp(pdp); */
return EOF;
} }
/* Extract recovery (optional) */ /* Extract recovery (optional) */
@ -2226,51 +2214,69 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
} }
/* Check all conditional information elements */ /* Check all conditional information elements */
if (GTPCAUSE_ACC_REQ != cause) { /* TODO: This does not handle GGSN-initiated update responses */
if (gsn->cb_conf) if (GTPCAUSE_ACC_REQ == cause) {
gsn->cb_conf(type, cause, pdp, cbp); if (version == 0) {
/* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
pdp_freepdp(pdp); */ &pdp->qos_neg0,
return 0; sizeof(pdp->qos_neg0))) {
} else { goto err_missing;
/* Check for missing conditionary information elements */
if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
gtpie_exist(ie, GTPIE_REORDER, 0) &&
gtpie_exist(ie, GTPIE_FL_DI, 0) &&
gtpie_exist(ie, GTPIE_FL_C, 0) &&
gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
gtpie_exist(ie, GTPIE_EUA, 0) &&
gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
gsn->missing++;
GTP_LOGPKG(LOGL_ERROR, peer, pack,
len,
"Missing conditional information field\n");
if (gsn->cb_conf)
gsn->cb_conf(type, EOF, pdp, cbp);
/* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
pdp_freepdp(pdp); */
return EOF;
} }
/* Update pdp with new values */ if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, goto err_missing;
pdp->qos_neg0, sizeof(pdp->qos_neg0)); }
gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru); if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc); goto err_missing;
gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid); }
gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, }
&pdp->eua.v, sizeof(pdp->eua.v));
gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, if (version == 1) {
&pdp->gsnrc.v, sizeof(pdp->gsnrc.v)); if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, goto err_missing;
&pdp->gsnru.v, sizeof(pdp->gsnru.v)); }
if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
goto err_missing;
}
}
if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
goto err_missing;
}
if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
&pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
goto err_missing;
}
if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
&pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
goto err_missing;
}
if (version == 1) {
if (gtpie_gettlv
(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
&pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
goto err_missing;
}
}
}
if (gsn->cb_conf) if (gsn->cb_conf)
gsn->cb_conf(type, cause, pdp, cbp); gsn->cb_conf(type, cause, pdp, cbp);
return 0; /* Succes */ return 0; /* Succes */
}
err_missing:
gsn->missing++;
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"Missing information field\n");
err_out:
if (gsn->cb_conf)
gsn->cb_conf(type, EOF, pdp, cbp);
return EOF;
} }
/* API: Send Delete PDP Context Request */ /* API: Send Delete PDP Context Request */