mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-11-02 21:23:23 +00:00
Merge remote-tracking branch 'origin/master' into daniel/onwaves
This commit is contained in:
4
debian/rules
vendored
4
debian/rules
vendored
@@ -17,7 +17,3 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
|||||||
override_dh_strip:
|
override_dh_strip:
|
||||||
dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
|
dh_strip -posmo-ggsn --dbg-package=osmo-ggsn-dbg
|
||||||
dh_strip -plibgtp3 --dbg-package=libgtp-dbg
|
dh_strip -plibgtp3 --dbg-package=libgtp-dbg
|
||||||
|
|
||||||
override_dh_autoreconf:
|
|
||||||
echo $(VERSION) > .tarball-version
|
|
||||||
dh_autoreconf
|
|
||||||
|
|||||||
99
ggsn/ggsn.c
99
ggsn/ggsn.c
@@ -413,16 +413,19 @@ struct ipcp_hdr {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* determine if IPCP contains given option */
|
/* 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 */
|
/* iterate over Options and check if protocol contained */
|
||||||
while (cur + 2 <= ((uint8_t *)ipcp) + ntohs(ipcp->len)) {
|
while (cur_opt + 2 <= ipcp + ipcp_len) {
|
||||||
struct ipcp_option_hdr *cur_opt = (struct ipcp_option_hdr *) cur;
|
uint8_t type = cur_opt[0];
|
||||||
if (cur_opt->type == opt)
|
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;
|
return cur_opt;
|
||||||
cur += cur_opt->len;
|
cur_opt += len;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -460,15 +463,15 @@ enum pco_protocols {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* determine if PCO contains given protocol */
|
/* 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 */
|
/* iterate over PCO and check if protocol contained */
|
||||||
while (cur + 3 <= pco->v + pco->l) {
|
while (cur + 3 <= pco->v + pco->l) {
|
||||||
uint16_t cur_prot = osmo_load16be(cur);
|
uint16_t cur_prot = osmo_load16be(cur);
|
||||||
uint8_t cur_len = cur[2];
|
uint8_t cur_len = cur[2];
|
||||||
if (cur_prot == prot)
|
if (cur_prot == prot && cur_len >= prot_minlen)
|
||||||
return cur;
|
return cur;
|
||||||
cur += cur_len + 3;
|
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*/
|
/* 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 *dns1 = &apn->v4.cfg.dns[0];
|
||||||
const struct in46_addr *dns2 = &apn->v4.cfg.dns[1];
|
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 *len1, *len2, *pco_ipcp;
|
||||||
uint8_t *start = msg->tail;
|
|
||||||
unsigned int len_appended;
|
unsigned int len_appended;
|
||||||
|
ptrdiff_t consumed;
|
||||||
|
size_t remain, offset = 0;
|
||||||
|
|
||||||
if (!(pco_ipcp = pco_contains_proto(&pdp->pco_req, PCO_P_IPCP)))
|
/* pco_contains_proto() returns a potentially unaligned pointer into pco_req->v (see OS#3194) */
|
||||||
return 0;
|
pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
|
||||||
ipcp = (struct ipcp_hdr*) (pco_ipcp + 3); /* 2=type + 1=len */
|
while (pco_ipcp) {
|
||||||
|
uint8_t *start = msg->tail;
|
||||||
|
|
||||||
/* Three byte T16L header */
|
ipcp = (pco_ipcp + 3); /* 2=type + 1=len */
|
||||||
msgb_put_u16(msg, 0x8021); /* IPCP */
|
consumed = (ipcp - &pdp->pco_req.v[0]);
|
||||||
len1 = msgb_put(msg, 1); /* Length of contents: delay */
|
remain = sizeof(pdp->pco_req.v) - consumed;
|
||||||
|
ipcp_len = osmo_load16be(ipcp + 2); /* 1=code + 1=id */
|
||||||
|
if (remain < 0 || remain < ipcp_len)
|
||||||
|
return;
|
||||||
|
|
||||||
msgb_put_u8(msg, 0x02); /* ACK */
|
/* Three byte T16L header */
|
||||||
msgb_put_u8(msg, ipcp->id); /* ID: Needs to match request */
|
msgb_put_u16(msg, 0x8021); /* IPCP */
|
||||||
msgb_put_u8(msg, 0x00); /* Length MSB */
|
len1 = msgb_put(msg, 1); /* Length of contents: delay */
|
||||||
len2 = msgb_put(msg, 1); /* Length LSB: delay */
|
|
||||||
|
|
||||||
if (dns1->len == 4 && ipcp_contains_option(ipcp, IPCP_OPT_PRIMARY_DNS)) {
|
msgb_put_u8(msg, 0x02); /* ACK */
|
||||||
msgb_put_u8(msg, 0x81); /* DNS1 Tag */
|
msgb_put_u8(msg, ipcp[1]); /* ID: Needs to match request */
|
||||||
msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
|
msgb_put_u8(msg, 0x00); /* Length MSB */
|
||||||
msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
|
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 (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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* patch in length values */
|
||||||
|
len_appended = msg->tail - start;
|
||||||
|
*len1 = len_appended - 3;
|
||||||
|
*len2 = len_appended - 3;
|
||||||
|
|
||||||
|
offset += 3 + ipcp_len;
|
||||||
|
pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
/* 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)
|
if (peer_v4)
|
||||||
build_ipcp_pco(apn, pdp, msg);
|
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++) {
|
for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
|
||||||
struct in46_addr *i46a = &apn->v6.cfg.dns[i];
|
struct in46_addr *i46a = &apn->v6.cfg.dns[i];
|
||||||
if (i46a->len != 16)
|
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++) {
|
for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
|
||||||
struct in46_addr *i46a = &apn->v4.cfg.dns[i];
|
struct in46_addr *i46a = &apn->v4.cfg.dns[i];
|
||||||
if (i46a->len != 4)
|
if (i46a->len != 4)
|
||||||
@@ -1111,7 +1127,8 @@ int main(int argc, char **argv)
|
|||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
exit(1);
|
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) {
|
if (!g_ctrlh) {
|
||||||
LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
|
LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
184
gtp/gtp.c
184
gtp/gtp.c
@@ -190,6 +190,15 @@ int gtp_set_cb_conf(struct gsn_t *gsn,
|
|||||||
return 0;
|
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 gtp_set_cb_recovery(struct gsn_t *gsn,
|
||||||
int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
|
int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
|
||||||
{
|
{
|
||||||
@@ -197,6 +206,20 @@ int gtp_set_cb_recovery(struct gsn_t *gsn,
|
|||||||
return 0;
|
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 gtp_set_cb_data_ind(struct gsn_t *gsn,
|
||||||
int (*cb_data_ind) (struct pdp_t * pdp,
|
int (*cb_data_ind) (struct pdp_t * pdp,
|
||||||
void *pack, unsigned len))
|
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)
|
if (gsn->cb_conf)
|
||||||
gsn->cb_conf(type, recovery, NULL, cbp);
|
gsn->cb_conf(type, recovery, NULL, cbp);
|
||||||
|
|
||||||
if (gsn->cb_recovery)
|
emit_cb_recovery(gsn, peer, NULL, recovery);
|
||||||
gsn->cb_recovery(peer, recovery);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1310,6 +1332,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
|
|||||||
struct pdp_t pdp_buf;
|
struct pdp_t pdp_buf;
|
||||||
union gtpie_member *ie[GTPIE_SIZE];
|
union gtpie_member *ie[GTPIE_SIZE];
|
||||||
uint8_t recovery;
|
uint8_t recovery;
|
||||||
|
bool recovery_recvd = false;
|
||||||
|
int rc;
|
||||||
|
|
||||||
uint16_t seq = get_seq(pack);
|
uint16_t seq = get_seq(pack);
|
||||||
int hlen = get_hlen(pack);
|
int hlen = get_hlen(pack);
|
||||||
@@ -1410,8 +1434,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
|
|||||||
|
|
||||||
/* Recovery (optional) */
|
/* Recovery (optional) */
|
||||||
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
||||||
if (gsn->cb_recovery)
|
/* we use recovery futher down after announcing new pdp ctx to user */
|
||||||
gsn->cb_recovery(peer, recovery);
|
recovery_recvd = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Selection mode (conditional) */
|
/* 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 */
|
/* Switch to using the old pdp context */
|
||||||
pdp = pdp_old;
|
pdp = pdp_old;
|
||||||
|
|
||||||
|
if (recovery_recvd)
|
||||||
|
emit_cb_recovery(gsn, peer, pdp, recovery);
|
||||||
|
|
||||||
/* Confirm to peer that things were "successful" */
|
/* Confirm to peer that things were "successful" */
|
||||||
return gtp_create_pdp_resp(gsn, version, pdp,
|
return gtp_create_pdp_resp(gsn, version, pdp,
|
||||||
GTPCAUSE_ACC_REQ);
|
GTPCAUSE_ACC_REQ);
|
||||||
@@ -1633,13 +1660,16 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
|
|||||||
|
|
||||||
/* Callback function to validata login */
|
/* Callback function to validata login */
|
||||||
if (gsn->cb_create_context_ind != 0)
|
if (gsn->cb_create_context_ind != 0)
|
||||||
return gsn->cb_create_context_ind(pdp);
|
rc = gsn->cb_create_context_ind(pdp);
|
||||||
else {
|
else {
|
||||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||||
"No create_context_ind callback defined\n");
|
"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);
|
GTPCAUSE_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
if (recovery_recvd)
|
||||||
|
emit_cb_recovery(gsn, peer, pdp, recovery);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle Create PDP Context Response */
|
/* Handle Create PDP Context Response */
|
||||||
@@ -1696,8 +1726,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
|
|||||||
|
|
||||||
/* Extract recovery (optional) */
|
/* Extract recovery (optional) */
|
||||||
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
||||||
if (gsn->cb_recovery)
|
emit_cb_recovery(gsn, peer, pdp, recovery);
|
||||||
gsn->cb_recovery(peer, recovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract protocol configuration options (optional) */
|
/* Extract protocol configuration options (optional) */
|
||||||
@@ -2106,8 +2135,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
|
|||||||
|
|
||||||
/* Recovery (optional) */
|
/* Recovery (optional) */
|
||||||
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
||||||
if (gsn->cb_recovery)
|
emit_cb_recovery(gsn, peer, pdp, recovery);
|
||||||
gsn->cb_recovery(peer, recovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version == 0) {
|
if (version == 0) {
|
||||||
@@ -2267,8 +2295,7 @@ static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
|
|||||||
|
|
||||||
/* Extract recovery (optional) */
|
/* Extract recovery (optional) */
|
||||||
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
|
||||||
if (gsn->cb_recovery)
|
emit_cb_recovery(gsn, peer, pdp, recovery);
|
||||||
gsn->cb_recovery(peer, recovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check all conditional information elements */
|
/* Check all conditional information elements */
|
||||||
@@ -2337,16 +2364,66 @@ err_out:
|
|||||||
return EOF;
|
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 gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
|
||||||
int teardown)
|
int teardown)
|
||||||
|
{
|
||||||
|
struct pdp_t *linked_pdp;
|
||||||
|
struct pdp_t *secondary_pdp;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
|
||||||
|
LOGP(DLGTP, LOGL_ERROR,
|
||||||
|
"Unknown linked PDP context: %u\n", pdp->teic_own);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
if (teardown) { /* Remove all contexts */
|
||||||
|
for (n = 0; n < PDP_MAXNSAPI; n++) {
|
||||||
|
if (linked_pdp->secondary_tei[n]) {
|
||||||
|
if (pdp_getgtp1
|
||||||
|
(&secondary_pdp,
|
||||||
|
linked_pdp->secondary_tei[n])) {
|
||||||
|
LOGP(DLGTP, LOGL_ERROR,
|
||||||
|
"Unknown secondary PDP context\n");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if (linked_pdp != secondary_pdp) {
|
||||||
|
if (gsn->cb_delete_context)
|
||||||
|
gsn->cb_delete_context
|
||||||
|
(secondary_pdp);
|
||||||
|
pdp_freepdp(secondary_pdp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gsn->cb_delete_context)
|
||||||
|
gsn->cb_delete_context(linked_pdp);
|
||||||
|
pdp_freepdp(linked_pdp);
|
||||||
|
} else {
|
||||||
|
if (gsn->cb_delete_context)
|
||||||
|
gsn->cb_delete_context(pdp);
|
||||||
|
if (pdp == linked_pdp) {
|
||||||
|
linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
|
||||||
|
linked_pdp->nodata = 1;
|
||||||
|
} else
|
||||||
|
pdp_freepdp(pdp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
union gtp_packet packet;
|
||||||
unsigned int length =
|
unsigned int length =
|
||||||
get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
|
get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
struct pdp_t *linked_pdp;
|
struct pdp_t *linked_pdp;
|
||||||
struct pdp_t *secondary_pdp;
|
|
||||||
int n;
|
int n;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
@@ -2383,37 +2460,6 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
|
|||||||
|
|
||||||
gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
|
gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
|
||||||
|
|
||||||
if (teardown) { /* Remove all contexts */
|
|
||||||
for (n = 0; n < PDP_MAXNSAPI; n++) {
|
|
||||||
if (linked_pdp->secondary_tei[n]) {
|
|
||||||
if (pdp_getgtp1
|
|
||||||
(&secondary_pdp,
|
|
||||||
linked_pdp->secondary_tei[n])) {
|
|
||||||
LOGP(DLGTP, LOGL_ERROR,
|
|
||||||
"Unknown secondary PDP context\n");
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
if (linked_pdp != secondary_pdp) {
|
|
||||||
if (gsn->cb_delete_context)
|
|
||||||
gsn->cb_delete_context
|
|
||||||
(secondary_pdp);
|
|
||||||
pdp_freepdp(secondary_pdp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gsn->cb_delete_context)
|
|
||||||
gsn->cb_delete_context(linked_pdp);
|
|
||||||
pdp_freepdp(linked_pdp);
|
|
||||||
} else {
|
|
||||||
if (gsn->cb_delete_context)
|
|
||||||
gsn->cb_delete_context(pdp);
|
|
||||||
if (pdp == linked_pdp) {
|
|
||||||
linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
|
|
||||||
linked_pdp->nodata = 1;
|
|
||||||
} else
|
|
||||||
pdp_freepdp(pdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2553,6 +2599,9 @@ int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
|
|||||||
if (linked_pdp->secondary_tei[n])
|
if (linked_pdp->secondary_tei[n])
|
||||||
count++;
|
count++;
|
||||||
if (count <= 1) {
|
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 */
|
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;
|
uint8_t cause;
|
||||||
void *cbp = NULL;
|
void *cbp = NULL;
|
||||||
uint8_t type = 0;
|
uint8_t type = 0;
|
||||||
|
struct pdp_t *pdp = NULL;
|
||||||
int hlen = get_hlen(pack);
|
int hlen = get_hlen(pack);
|
||||||
|
|
||||||
/* Remove packet from queue */
|
/* Remove packet from queue */
|
||||||
if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
|
if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
|
||||||
return EOF;
|
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 */
|
/* Decode information elements */
|
||||||
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
|
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
|
||||||
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)
|
if (gsn->cb_conf)
|
||||||
gsn->cb_conf(type, EOF, NULL, cbp);
|
gsn->cb_conf(type, EOF, pdp, cbp);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2592,7 +2654,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
|
|||||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||||
"Missing mandatory information field\n");
|
"Missing mandatory information field\n");
|
||||||
if (gsn->cb_conf)
|
if (gsn->cb_conf)
|
||||||
gsn->cb_conf(type, EOF, NULL, cbp);
|
gsn->cb_conf(type, EOF, pdp, cbp);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2602,13 +2664,13 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
|
|||||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||||
"Unexpected cause value received: %d\n", cause);
|
"Unexpected cause value received: %d\n", cause);
|
||||||
if (gsn->cb_conf)
|
if (gsn->cb_conf)
|
||||||
gsn->cb_conf(type, cause, NULL, cbp);
|
gsn->cb_conf(type, cause, pdp, cbp);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback function to notify application */
|
/* Callback function to notify application */
|
||||||
if (gsn->cb_conf)
|
if (gsn->cb_conf)
|
||||||
gsn->cb_conf(type, cause, NULL, cbp);
|
gsn->cb_conf(type, cause, pdp, cbp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2830,23 +2892,23 @@ int gtp_decaps0(struct gsn_t *gsn)
|
|||||||
|
|
||||||
if ((gsn->mode == GTP_MODE_GGSN) &&
|
if ((gsn->mode == GTP_MODE_GGSN) &&
|
||||||
((pheader->type == GTP_CREATE_PDP_RSP) ||
|
((pheader->type == GTP_CREATE_PDP_RSP) ||
|
||||||
(pheader->type == GTP_UPDATE_PDP_RSP) ||
|
(pheader->type == GTP_UPDATE_PDP_RSP))) {
|
||||||
(pheader->type == GTP_DELETE_PDP_RSP))) {
|
|
||||||
gsn->unexpect++;
|
gsn->unexpect++;
|
||||||
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
||||||
status,
|
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 */
|
continue; /* Silently discard 29.60: 11.1.4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gsn->mode == GTP_MODE_SGSN) &&
|
if ((gsn->mode == GTP_MODE_SGSN) &&
|
||||||
((pheader->type == GTP_CREATE_PDP_REQ) ||
|
((pheader->type == GTP_CREATE_PDP_REQ) ||
|
||||||
(pheader->type == GTP_UPDATE_PDP_REQ) ||
|
(pheader->type == GTP_UPDATE_PDP_REQ))) {
|
||||||
(pheader->type == GTP_DELETE_PDP_REQ))) {
|
|
||||||
gsn->unexpect++;
|
gsn->unexpect++;
|
||||||
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
||||||
status,
|
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 */
|
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) &&
|
if ((gsn->mode == GTP_MODE_GGSN) &&
|
||||||
((pheader->type == GTP_CREATE_PDP_RSP) ||
|
((pheader->type == GTP_CREATE_PDP_RSP) ||
|
||||||
(pheader->type == GTP_UPDATE_PDP_RSP) ||
|
(pheader->type == GTP_UPDATE_PDP_RSP))) {
|
||||||
(pheader->type == GTP_DELETE_PDP_RSP))) {
|
|
||||||
gsn->unexpect++;
|
gsn->unexpect++;
|
||||||
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
||||||
status,
|
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 */
|
continue; /* Silently discard 29.60: 11.1.4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gsn->mode == GTP_MODE_SGSN) &&
|
if ((gsn->mode == GTP_MODE_SGSN) &&
|
||||||
((pheader->type == GTP_CREATE_PDP_REQ) ||
|
((pheader->type == GTP_CREATE_PDP_REQ) ||
|
||||||
(pheader->type == GTP_UPDATE_PDP_REQ) ||
|
(pheader->type == GTP_UPDATE_PDP_REQ))) {
|
||||||
(pheader->type == GTP_DELETE_PDP_REQ))) {
|
|
||||||
gsn->unexpect++;
|
gsn->unexpect++;
|
||||||
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
|
||||||
status,
|
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 */
|
continue; /* Silently discard 29.60: 11.1.4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
gtp/gtp.h
12
gtp/gtp.h
@@ -13,6 +13,7 @@
|
|||||||
#define _GTP_H
|
#define _GTP_H
|
||||||
|
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/defs.h>
|
||||||
|
|
||||||
#define GTP_MODE_GGSN 1
|
#define GTP_MODE_GGSN 1
|
||||||
#define GTP_MODE_SGSN 2
|
#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_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_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
|
||||||
int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
|
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 */
|
/* Counters */
|
||||||
|
|
||||||
@@ -323,7 +325,10 @@ extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp,
|
|||||||
void *cbp, struct in_addr *inetaddr);
|
void *cbp, struct in_addr *inetaddr);
|
||||||
|
|
||||||
extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
|
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,
|
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||||
void *pack, unsigned len);
|
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 gtp_set_cb_recovery(struct gsn_t *gsn,
|
||||||
int (*cb) (struct sockaddr_in * peer,
|
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));
|
uint8_t recovery));
|
||||||
|
|
||||||
/* Internal functions (not part of the API */
|
/* Internal functions (not part of the API */
|
||||||
|
|||||||
Reference in New Issue
Block a user