mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
				synced 2025-11-03 21:53:25 +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
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										61
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								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,35 +503,45 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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 */
 | 
							/* Three byte T16L header */
 | 
				
			||||||
		msgb_put_u16(msg, 0x8021);	/* IPCP */
 | 
							msgb_put_u16(msg, 0x8021);	/* IPCP */
 | 
				
			||||||
		len1 = msgb_put(msg, 1);	/* Length of contents: delay */
 | 
							len1 = msgb_put(msg, 1);	/* Length of contents: delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msgb_put_u8(msg, 0x02);		/* ACK */
 | 
							msgb_put_u8(msg, 0x02);		/* ACK */
 | 
				
			||||||
	msgb_put_u8(msg, ipcp->id);	/* ID: Needs to match request */
 | 
							msgb_put_u8(msg, ipcp[1]);	/* ID: Needs to match request */
 | 
				
			||||||
		msgb_put_u8(msg, 0x00);		/* Length MSB */
 | 
							msgb_put_u8(msg, 0x00);		/* Length MSB */
 | 
				
			||||||
		len2 = msgb_put(msg, 1);	/* Length LSB: delay */
 | 
							len2 = msgb_put(msg, 1);	/* Length LSB: delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dns1->len == 4 && ipcp_contains_option(ipcp, IPCP_OPT_PRIMARY_DNS)) {
 | 
							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, 0x81);		/* DNS1 Tag */
 | 
				
			||||||
			msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
 | 
								msgb_put_u8(msg, 2 + dns1->len);/* DNS1 Length, incl. TL */
 | 
				
			||||||
			msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
 | 
								msgb_put_u32(msg, ntohl(dns1->v4.s_addr));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dns2->len == 4 && ipcp_contains_option(ipcp, IPCP_OPT_SECONDARY_DNS)) {
 | 
							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, 0x83);		/* DNS2 Tag */
 | 
				
			||||||
			msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
 | 
								msgb_put_u8(msg, 2 + dns2->len);/* DNS2 Length, incl. TL */
 | 
				
			||||||
			msgb_put_u32(msg, ntohl(dns2->v4.s_addr));
 | 
								msgb_put_u32(msg, ntohl(dns2->v4.s_addr));
 | 
				
			||||||
@@ -539,7 +552,10 @@ static int build_ipcp_pco(struct apn_ctx *apn, struct pdp_t *pdp, struct msgb *m
 | 
				
			|||||||
		*len1 = len_appended - 3;
 | 
							*len1 = len_appended - 3;
 | 
				
			||||||
		*len2 = len_appended - 3;
 | 
							*len2 = len_appended - 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
							offset += 3 + ipcp_len;
 | 
				
			||||||
 | 
							pco_ipcp = pco_contains_proto(&pdp->pco_req, offset, PCO_P_IPCP, sizeof(struct ipcp_hdr));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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 */
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								gtp/gtp.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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,6 +325,9 @@ 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)
 | 
				
			||||||
 | 
							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);
 | 
									   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,
 | 
				
			||||||
@@ -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