<p>laforge <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/15386">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Split out GPRS SM layer into its own file<br><br>Change-Id: Ie61d22e7868af6de73cdf9c731f07130b282599d<br>---<br>M include/osmocom/sgsn/Makefile.am<br>M include/osmocom/sgsn/gprs_gmm.h<br>A include/osmocom/sgsn/gprs_sm.h<br>M src/sgsn/Makefile.am<br>M src/sgsn/gprs_gb.c<br>M src/sgsn/gprs_gmm.c<br>M src/sgsn/gprs_ranap.c<br>M src/sgsn/gprs_sgsn.c<br>A src/sgsn/gprs_sm.c<br>M src/sgsn/sgsn_libgtp.c<br>M tests/sgsn/Makefile.am<br>11 files changed, 780 insertions(+), 709 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am</span><br><span>index 9ddc2bc..3fdb6b3 100644</span><br><span>--- a/include/osmocom/sgsn/Makefile.am</span><br><span>+++ b/include/osmocom/sgsn/Makefile.am</span><br><span>@@ -14,6 +14,7 @@</span><br><span>     gprs_llc_xid.h \</span><br><span>     gprs_ranap.h \</span><br><span>       gprs_sgsn.h \</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_sm.h \</span><br><span>  gprs_sndcp_comp.h \</span><br><span>  gprs_sndcp_dcomp.h \</span><br><span>         gprs_sndcp.h \</span><br><span>diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h</span><br><span>index 982cd93..e2b17d2 100644</span><br><span>--- a/include/osmocom/sgsn/gprs_gmm.h</span><br><span>+++ b/include/osmocom/sgsn/gprs_gmm.h</span><br><span>@@ -6,21 +6,16 @@</span><br><span> </span><br><span> #include <stdbool.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(0, 100%, 40%);">-                         uint8_t cause, uint8_t pco_len, uint8_t *pco_v);</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);</span><br><span> int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,</span><br><span>                                    const struct osmo_auth_vector *vec,</span><br><span>                                  uint8_t key_seq, bool force_standby);</span><br><span> </span><br><span> int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,</span><br><span>                     bool drop_cipherable);</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                          struct gprs_llc_llme *llme);</span><br><span> int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,</span><br><span>                     struct gprs_llc_llme *llme, bool drop_cipherable);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_gmm_sendmsg(struct msgb *msg, int command,</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct sgsn_mm_ctx *mm, bool encryptable);</span><br><span> int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);</span><br><span> int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,</span><br><span>                                  struct gprs_llc_llme *llme);</span><br><span>@@ -47,7 +42,6 @@</span><br><span> void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx);</span><br><span> void extract_subscr_hlr(struct sgsn_mm_ctx *ctx);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm);</span><br><span> #endif /* _GPRS_GMM_H */</span><br><span>diff --git a/include/osmocom/sgsn/gprs_sm.h b/include/osmocom/sgsn/gprs_sm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..55c95b8</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/sgsn/gprs_sm.h</span><br><span>@@ -0,0 +1,15 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sgsn.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint8_t cause, uint8_t pco_len, uint8_t *pco_v);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                           struct gprs_llc_llme *llme);</span><br><span>diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am</span><br><span>index 4402c9c..8bc1abb 100644</span><br><span>--- a/src/sgsn/Makefile.am</span><br><span>+++ b/src/sgsn/Makefile.am</span><br><span>@@ -48,6 +48,7 @@</span><br><span>     gprs_mm_state_iu_fsm.c \</span><br><span>     gprs_ranap.c \</span><br><span>       gprs_sgsn.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_sm.c \</span><br><span>  gprs_sndcp.c \</span><br><span>       gprs_sndcp_comp.c \</span><br><span>  gprs_sndcp_dcomp.c \</span><br><span>diff --git a/src/sgsn/gprs_gb.c b/src/sgsn/gprs_gb.c</span><br><span>index 65342cf..2d9c25a 100644</span><br><span>--- a/src/sgsn/gprs_gb.c</span><br><span>+++ b/src/sgsn/gprs_gb.c</span><br><span>@@ -31,6 +31,7 @@</span><br><span> #include <osmocom/sgsn/gprs_mm_state_gb_fsm.h></span><br><span> #include <osmocom/sgsn/gprs_sgsn.h></span><br><span> #include <osmocom/sgsn/gprs_gmm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sm.h></span><br><span> #include <osmocom/sgsn/debug.h></span><br><span> </span><br><span> /* Main entry point for incoming 04.08 GPRS messages from Gb */</span><br><span>diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c</span><br><span>index 3317a09..afae369 100644</span><br><span>--- a/src/sgsn/gprs_gmm.c</span><br><span>+++ b/src/sgsn/gprs_gmm.c</span><br><span>@@ -29,7 +29,6 @@</span><br><span> #include <stdbool.h></span><br><span> #include <netinet/in.h></span><br><span> #include <arpa/inet.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <netdb.h></span><br><span> </span><br><span> #include "bscconfig.h"</span><br><span> </span><br><span>@@ -42,7 +41,6 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/tdef.h></span><br><span> #include <osmocom/crypt/auth.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/apn.h></span><br><span> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h></span><br><span> </span><br><span> #include <osmocom/gprs/gprs_bssgp.h></span><br><span>@@ -66,9 +64,6 @@</span><br><span> </span><br><span> #define PTMSI_ALLOC</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */</span><br><span style="color: hsl(0, 100%, 40%);">-#define T339X_MAX_RETRANS 4</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> extern struct sgsn_instance *sgsn;</span><br><span> extern void *tall_sgsn_ctx;</span><br><span> </span><br><span>@@ -91,20 +86,6 @@</span><br><span>      },</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const struct tlv_definition gsm48_sm_att_tlvdef = {</span><br><span style="color: hsl(0, 100%, 40%);">-  .def = {</span><br><span style="color: hsl(0, 100%, 40%);">-                [GSM48_IE_GSM_APN]              = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-          [GSM48_IE_GSM_PROTO_CONF_OPT]   = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-          [GSM48_IE_GSM_PDP_ADDR]         = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-          [GSM48_IE_GSM_AA_TMR]           = { TLV_TYPE_TV, 1 },</span><br><span style="color: hsl(0, 100%, 40%);">-           [GSM48_IE_GSM_NAME_FULL]        = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-          [GSM48_IE_GSM_NAME_SHORT]       = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-          [GSM48_IE_GSM_TIMEZONE]         = { TLV_TYPE_FIXED, 1 },</span><br><span style="color: hsl(0, 100%, 40%);">-                [GSM48_IE_GSM_UTC_AND_TZ]       = { TLV_TYPE_FIXED, 7 },</span><br><span style="color: hsl(0, 100%, 40%);">-                [GSM48_IE_GSM_LSA_ID]           = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(0, 100%, 40%);">-  },</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Our implementation, should be kept in SGSN */</span><br><span> </span><br><span> static void mmctx_timer_cb(void *_mm);</span><br><span>@@ -146,7 +127,7 @@</span><br><span> /* Send a message through the underlying layer.</span><br><span>  * For param encryptable, see 3GPP TS 24.008 § 4.7.1.2 and</span><br><span>  * gsm48_hdr_gmm_cipherable(). Pass false for not cipherable messages. */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_gmm_sendmsg(struct msgb *msg, int command,</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_gmm_sendmsg(struct msgb *msg, int command,</span><br><span>                              struct sgsn_mm_ctx *mm, bool encryptable)</span><br><span> {</span><br><span>  if (mm) {</span><br><span>@@ -199,7 +180,7 @@</span><br><span> }</span><br><span> </span><br><span> /* Store BVCI/NSEI in MM context */</span><br><span style="color: hsl(0, 100%, 40%);">-static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)</span><br><span style="color: hsl(120, 100%, 40%);">+void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)</span><br><span> {</span><br><span>        msgb_tlli(msg) = mm->gb.tlli;</span><br><span>     msgb_bvci(msg) = mm->gb.bvci;</span><br><span>@@ -228,7 +209,7 @@</span><br><span> </span><br><span> /* Chapter 9.4.18 */</span><br><span> static int _tx_status(struct msgb *msg, uint8_t cause,</span><br><span style="color: hsl(0, 100%, 40%);">-                  struct sgsn_mm_ctx *mmctx, int sm)</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct sgsn_mm_ctx *mmctx)</span><br><span> {</span><br><span>        struct gsm48_hdr *gh;</span><br><span> </span><br><span>@@ -238,13 +219,8 @@</span><br><span>             get_value_string(gsm48_gmm_cause_names, cause));</span><br><span> </span><br><span>         gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (sm) {</span><br><span style="color: hsl(0, 100%, 40%);">-               gh->proto_discr = GSM48_PDISC_SM_GPRS;</span><br><span style="color: hsl(0, 100%, 40%);">-               gh->msg_type = GSM48_MT_GSM_STATUS;</span><br><span style="color: hsl(0, 100%, 40%);">-  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                gh->proto_discr = GSM48_PDISC_MM_GPRS;</span><br><span style="color: hsl(0, 100%, 40%);">-               gh->msg_type = GSM48_MT_GMM_STATUS;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(120, 100%, 40%);">+     gh->proto_discr = GSM48_PDISC_MM_GPRS;</span><br><span style="color: hsl(120, 100%, 40%);">+     gh->msg_type = GSM48_MT_GMM_STATUS;</span><br><span>       gh->data[0] = cause;</span><br><span> </span><br><span>  return gsm48_gmm_sendmsg(msg, 0, mmctx, true);</span><br><span>@@ -255,15 +231,7 @@</span><br><span>        struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 GMM STATUS");</span><br><span> </span><br><span>      mmctx2msgid(msg, mmctx);</span><br><span style="color: hsl(0, 100%, 40%);">-        return _tx_status(msg, cause, mmctx, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_tx_sm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SM STATUS");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      mmctx2msgid(msg, mmctx);</span><br><span style="color: hsl(0, 100%, 40%);">-        return _tx_status(msg, cause, mmctx, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+      return _tx_status(msg, cause, mmctx);</span><br><span> }</span><br><span> </span><br><span> static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,</span><br><span>@@ -306,29 +274,6 @@</span><br><span>     return _tx_detach_req(msg, detach_type, cause, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct gsm48_qos default_qos = {</span><br><span style="color: hsl(0, 100%, 40%);">-   .delay_class = 4,       /* best effort */</span><br><span style="color: hsl(0, 100%, 40%);">-       .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,</span><br><span style="color: hsl(0, 100%, 40%);">-  .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps,</span><br><span style="color: hsl(0, 100%, 40%);">-      .preced_class = GSM48_QOS_PC_NORMAL,</span><br><span style="color: hsl(0, 100%, 40%);">-    .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT,</span><br><span style="color: hsl(0, 100%, 40%);">-   .traf_class = GSM48_QOS_TC_INTERACTIVE,</span><br><span style="color: hsl(0, 100%, 40%);">- .deliv_order = GSM48_QOS_DO_UNORDERED,</span><br><span style="color: hsl(0, 100%, 40%);">-  .deliv_err_sdu = GSM48_QOS_ERRSDU_YES,</span><br><span style="color: hsl(0, 100%, 40%);">-  .max_sdu_size = GSM48_QOS_MAXSDU_1520,</span><br><span style="color: hsl(0, 100%, 40%);">-  .max_bitrate_up = GSM48_QOS_MBRATE_63k,</span><br><span style="color: hsl(0, 100%, 40%);">- .max_bitrate_down = GSM48_QOS_MBRATE_63k,</span><br><span style="color: hsl(0, 100%, 40%);">-       .resid_ber = GSM48_QOS_RBER_5e_2,</span><br><span style="color: hsl(0, 100%, 40%);">-       .sdu_err_ratio = GSM48_QOS_SERR_1e_2,</span><br><span style="color: hsl(0, 100%, 40%);">-   .handling_prio = 3,</span><br><span style="color: hsl(0, 100%, 40%);">-     .xfer_delay = 0x10,     /* 200ms */</span><br><span style="color: hsl(0, 100%, 40%);">-     .guar_bitrate_up = GSM48_QOS_MBRATE_0k,</span><br><span style="color: hsl(0, 100%, 40%);">- .guar_bitrate_down = GSM48_QOS_MBRATE_0k,</span><br><span style="color: hsl(0, 100%, 40%);">-       .sig_ind = 0,   /* not optimised for signalling */</span><br><span style="color: hsl(0, 100%, 40%);">-      .max_bitrate_down_ext = 0,      /* use octet 9 */</span><br><span style="color: hsl(0, 100%, 40%);">-       .guar_bitrate_down_ext = 0,     /* use octet 13 */</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Chapter 9.4.2: Attach accept */</span><br><span> int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)</span><br><span> {</span><br><span>@@ -2155,645 +2100,6 @@</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* GPRS SESSION MANAGEMENT */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void pdpctx_timer_cb(void *_mm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void pdpctx_timer_rearm(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned long seconds;</span><br><span style="color: hsl(0, 100%, 40%);">-  if (osmo_timer_pending(&pdp->timer))</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPDPCTXP(LOGL_ERROR, pdp, "Scheduling PDP timer %u while old "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "timer %u pending\n", T, pdp->T);</span><br><span style="color: hsl(0, 100%, 40%);">-  seconds = osmo_tdef_get(sgsn->cfg.T_defs, T, OSMO_TDEF_S, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-       osmo_timer_schedule(&pdp->timer, seconds, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void pdpctx_timer_start(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  if (osmo_timer_pending(&pdp->timer))</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPDPCTXP(LOGL_ERROR, pdp, "Starting PDP timer %u while old "</span><br><span style="color: hsl(0, 100%, 40%);">-                        "timer %u pending\n", T, pdp->T);</span><br><span style="color: hsl(0, 100%, 40%);">-  pdp->T = T;</span><br><span style="color: hsl(0, 100%, 40%);">-  pdp->num_T_exp = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo_timer_setup(&pdp->timer, pdpctx_timer_cb, pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-     pdpctx_timer_rearm(pdp, pdp->T);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void pdpctx_timer_stop(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (pdp->T != T)</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPDPCTXP(LOGL_ERROR, pdp, "Stopping PDP timer %u but "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "%u is running\n", T, pdp->T);</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_timer_del(&pdp->timer);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Detach from MM context */</span><br><span style="color: hsl(0, 100%, 40%);">-    llist_del(&pdp->list);</span><br><span style="color: hsl(0, 100%, 40%);">-   pdp->mm = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* stop timer 3395 */</span><br><span style="color: hsl(0, 100%, 40%);">-   pdpctx_timer_stop(pdp, 3395);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">-static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t v[6];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   v[0] = PDP_TYPE_ORG_IETF;</span><br><span style="color: hsl(0, 100%, 40%);">-       v[1] = PDP_TYPE_N_IETF_IPv4;</span><br><span style="color: hsl(0, 100%, 40%);">-    *(uint32_t *)(v+2) = htonl(ipaddr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void msgb_put_pdp_addr_ppp(struct msgb *msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t v[2];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   v[0] = PDP_TYPE_ORG_ETSI;</span><br><span style="color: hsl(0, 100%, 40%);">-       v[1] = PDP_TYPE_N_ETSI_PPP;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.2: Activate PDP Context Accept */</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP ACC");</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gsm48_hdr *gh;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(0, 100%, 40%);">-       rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- mmctx2msgid(msg, pdp->mm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(0, 100%, 40%);">-   gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(0, 100%, 40%);">- gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* Negotiated LLC SAPI */</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_v_put(msg, pdp->sapi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* FIXME: copy QoS parameters from original request */</span><br><span style="color: hsl(0, 100%, 40%);">-  //msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* Radio priority 10.5.7.2 */</span><br><span style="color: hsl(0, 100%, 40%);">-   msgb_v_put(msg, pdp->lib->radio_pri);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* PDP address */</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Highest 4 bits of first byte need to be set to 1, otherwise</span><br><span style="color: hsl(0, 100%, 40%);">-   * the IE is identical with the 04.08 PDP Address IE */</span><br><span style="color: hsl(0, 100%, 40%);">- pdp->lib->eua.v[0] &= ~0xf0;</span><br><span style="color: hsl(0, 100%, 40%);">-  msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,</span><br><span style="color: hsl(0, 100%, 40%);">-                     pdp->lib->eua.l, pdp->lib->eua.v);</span><br><span style="color: hsl(0, 100%, 40%);">-     pdp->lib->eua.v[0] |= 0xf0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Optional: Protocol configuration options (FIXME: why 'req') */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (pdp->lib->pco_req.l)</span><br><span style="color: hsl(0, 100%, 40%);">-          msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,</span><br><span style="color: hsl(0, 100%, 40%);">-                       pdp->lib->pco_req.l, pdp->lib->pco_req.v);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* Optional: Packet Flow Identifier */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.3: Activate PDP Context reject */</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(0, 100%, 40%);">-                      uint8_t cause, uint8_t pco_len, uint8_t *pco_v)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP REJ");</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gsm48_hdr *gh;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              get_value_string(gsm48_gsm_cause_names, cause));</span><br><span style="color: hsl(0, 100%, 40%);">-      rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- mmctx2msgid(msg, mm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(0, 100%, 40%);">-   gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(0, 100%, 40%);">- gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     msgb_v_put(msg, cause);</span><br><span style="color: hsl(0, 100%, 40%);">- if (pco_len && pco_v)</span><br><span style="color: hsl(0, 100%, 40%);">-           msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */</span><br><span style="color: hsl(0, 100%, 40%);">-static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    uint8_t sm_cause, bool teardown)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET REQ");</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsm48_hdr *gh;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t tear_down_ind = (0x9 << 4) | (!!teardown);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");</span><br><span style="color: hsl(0, 100%, 40%);">-       rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   mmctx2msgid(msg, mm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(0, 100%, 40%);">-   gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(0, 100%, 40%);">- gh->msg_type = GSM48_MT_GSM_DEACT_PDP_REQ;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   msgb_v_put(msg, sm_cause);</span><br><span style="color: hsl(0, 100%, 40%);">-      msgb_v_put(msg, tear_down_ind);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  pdpctx_timer_start(pdp, 3395);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, sm_cause, teardown);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */</span><br><span style="color: hsl(0, 100%, 40%);">-static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET ACC");</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsm48_hdr *gh;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(0, 100%, 40%);">-       rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    mmctx2msgid(msg, mm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(0, 100%, 40%);">-   gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(0, 100%, 40%);">- gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   return _gsm48_tx_gsm_deact_pdp_acc(pdp->mm, pdp->ti);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int activate_ggsn(struct sgsn_mm_ctx *mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-         struct sgsn_ggsn_ctx *ggsn, const uint8_t transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-               const uint8_t req_nsapi, const uint8_t req_llc_sapi,</span><br><span style="color: hsl(0, 100%, 40%);">-            struct tlv_parsed *tp, int destroy_ggsn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGMMCTXP(LOGL_DEBUG, mmctx, "Using GGSN %u\n", ggsn->id);</span><br><span style="color: hsl(0, 100%, 40%);">- ggsn->gsn = sgsn->gsn;</span><br><span style="color: hsl(0, 100%, 40%);">-    pdp = sgsn_create_pdp_ctx(ggsn, mmctx, req_nsapi, tp);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!pdp)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* Store SAPI and Transaction Identifier */</span><br><span style="color: hsl(0, 100%, 40%);">-     pdp->sapi = req_llc_sapi;</span><br><span style="color: hsl(0, 100%, 40%);">-    pdp->ti = transaction_id;</span><br><span style="color: hsl(0, 100%, 40%);">-    pdp->destroy_ggsn = destroy_ggsn;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *hostent)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct sgsn_ggsn_ctx *ggsn;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct sgsn_ggsn_lookup *lookup = arg;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct in_addr *addr = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    char buf[INET_ADDRSTRLEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* The context is gone while we made a request */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!lookup->mmctx) {</span><br><span style="color: hsl(0, 100%, 40%);">-                talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-               talloc_free(lookup);</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (status != ARES_SUCCESS) {</span><br><span style="color: hsl(0, 100%, 40%);">-           struct sgsn_mm_ctx *mmctx = lookup->mmctx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGMMCTXP(LOGL_ERROR, mmctx, "DNS query failed.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Need to try with three digits now */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (lookup->state == SGSN_GGSN_2DIGIT) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     char *hostname;</span><br><span style="color: hsl(0, 100%, 40%);">-                 int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 lookup->state = SGSN_GGSN_3DIGIT;</span><br><span style="color: hsl(0, 100%, 40%);">-                    hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   lookup->apn_str, 1);</span><br><span style="color: hsl(0, 100%, 40%);">-                 LOGMMCTXP(LOGL_DEBUG, mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                            "Going to query %s\n", hostname);</span><br><span style="color: hsl(0, 100%, 40%);">-                     rc = sgsn_ares_query(sgsn, hostname,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    ggsn_lookup_cb, lookup);</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (rc != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't start GGSN\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                            goto reject_due_failure;</span><br><span style="color: hsl(0, 100%, 40%);">-                        }</span><br><span style="color: hsl(0, 100%, 40%);">-                       return;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't resolve GGSN\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          goto reject_due_failure;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (hostent->h_length != sizeof(struct in_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGMMCTXP(LOGL_ERROR, lookup->mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "Wrong addr size(%zu)\n", sizeof(struct in_addr));</span><br><span style="color: hsl(0, 100%, 40%);">-            goto reject_due_failure;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Get the first addr from the list */</span><br><span style="color: hsl(0, 100%, 40%);">-  addr = (struct in_addr *) hostent->h_addr_list[0];</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!addr) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "No host address.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                goto reject_due_failure;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ggsn) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          goto reject_due_failure;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       ggsn->remote_addr = *addr;</span><br><span style="color: hsl(0, 100%, 40%);">-   LOGMMCTXP(LOGL_NOTICE, lookup->mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                  "Selected %s as GGSN.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             inet_ntop(AF_INET, addr, buf, sizeof(buf)));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* forget about the ggsn look-up */</span><br><span style="color: hsl(0, 100%, 40%);">-     lookup->mmctx->ggsn_lookup = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        activate_ggsn(lookup->mmctx, ggsn, lookup->ti, lookup->nsapi,</span><br><span style="color: hsl(0, 100%, 40%);">-                  lookup->sapi, &lookup->tp, 1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* Now free it */</span><br><span style="color: hsl(0, 100%, 40%);">-       talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-       talloc_free(lookup);</span><br><span style="color: hsl(0, 100%, 40%);">-    return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-reject_due_failure:</span><br><span style="color: hsl(0, 100%, 40%);">-      gsm48_tx_gsm_act_pdp_rej(lookup->mmctx, lookup->ti,</span><br><span style="color: hsl(0, 100%, 40%);">-                               GMM_CAUSE_NET_FAIL, 0, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   lookup->mmctx->ggsn_lookup = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-       talloc_free(lookup);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *delete)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t req_qos_len, req_pdpa_len;</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t *req_qos, *req_pdpa;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct tlv_parsed tp;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct sgsn_ggsn_ctx *ggsn;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(0, 100%, 40%);">-       enum gsm48_gsm_cause gsm_cause;</span><br><span style="color: hsl(0, 100%, 40%);">- char apn_str[GSM_APN_LENGTH] = { 0, };</span><br><span style="color: hsl(0, 100%, 40%);">-  char *hostname;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_llc_lle *lle;</span><br><span style="color: hsl(0, 100%, 40%);">-       char buf[INET_ADDRSTRLEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      LOGMMCTXP(LOGL_INFO, mmctx, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",</span><br><span style="color: hsl(0, 100%, 40%);">-              act_req->req_llc_sapi, act_req->req_nsapi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* FIXME: length checks! */</span><br><span style="color: hsl(0, 100%, 40%);">-     req_qos_len = act_req->data[0];</span><br><span style="color: hsl(0, 100%, 40%);">-      req_qos = act_req->data + 1; /* 10.5.6.5 */</span><br><span style="color: hsl(0, 100%, 40%);">-  req_pdpa_len = act_req->data[1 + req_qos_len];</span><br><span style="color: hsl(0, 100%, 40%);">-       req_pdpa = act_req->data + 1 + req_qos_len + 1;      /* 10.5.6.4 */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  switch (req_pdpa[0] & 0xf) {</span><br><span style="color: hsl(0, 100%, 40%);">-        case 0x0:</span><br><span style="color: hsl(0, 100%, 40%);">-               DEBUGPC(DMM, "ETSI ");</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case 0x1:</span><br><span style="color: hsl(0, 100%, 40%);">-               DEBUGPC(DMM, "IETF ");</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case 0xf:</span><br><span style="color: hsl(0, 100%, 40%);">-               DEBUGPC(DMM, "Empty ");</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       switch (req_pdpa[1]) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case 0x21:</span><br><span style="color: hsl(0, 100%, 40%);">-              DEBUGPC(DMM, "IPv4 ");</span><br><span style="color: hsl(0, 100%, 40%);">-                if (req_pdpa_len >= 6) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     struct in_addr ia;</span><br><span style="color: hsl(0, 100%, 40%);">-                      ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));</span><br><span style="color: hsl(0, 100%, 40%);">-                        DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case 0x57:</span><br><span style="color: hsl(0, 100%, 40%);">-              DEBUGPC(DMM, "IPv6 ");</span><br><span style="color: hsl(0, 100%, 40%);">-                if (req_pdpa_len >= 18) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    /* FIXME: print IPv6 address */</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                DEBUGPC(DMM, "0x%02x ", req_pdpa[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-         break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGPC(DMM, LOGL_INFO, "\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* Check if NSAPI is out of range (TS 04.65 / 7.2) */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Send reject with GSM_CAUSE_INV_MAND_INFO */</span><br><span style="color: hsl(0, 100%, 40%);">-          return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          GSM_CAUSE_INV_MAND_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                0, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Optional: Access Point Name, Protocol Config Options */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (req_pdpa + req_pdpa_len < msg->data + msg->len)</span><br><span style="color: hsl(0, 100%, 40%);">-            tlv_parse(&tp, &gsm48_sm_att_tlvdef, req_pdpa + req_pdpa_len,</span><br><span style="color: hsl(0, 100%, 40%);">-                     (msg->data + msg->len) - (req_pdpa + req_pdpa_len), 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-      else</span><br><span style="color: hsl(0, 100%, 40%);">-            memset(&tp, 0, sizeof(tp));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* put the non-TLV elements in the TLV parser structure to</span><br><span style="color: hsl(0, 100%, 40%);">-       * pass them on to the SGSN / GTP code */</span><br><span style="color: hsl(0, 100%, 40%);">-       tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len;</span><br><span style="color: hsl(0, 100%, 40%);">-   tp.lv[OSMO_IE_GSM_REQ_QOS].val = req_qos;</span><br><span style="color: hsl(0, 100%, 40%);">-       tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;</span><br><span style="color: hsl(0, 100%, 40%);">-     tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Check if NSAPI is already in use */</span><br><span style="color: hsl(0, 100%, 40%);">-  pdp = sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (pdp) {</span><br><span style="color: hsl(0, 100%, 40%);">-              /* We already have a PDP context for this TLLI + NSAPI tuple */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (pdp->sapi == act_req->req_llc_sapi &&</span><br><span style="color: hsl(0, 100%, 40%);">-             pdp->ti == transaction_id) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* This apparently is a re-transmission of a PDP CTX</span><br><span style="color: hsl(0, 100%, 40%);">-                     * ACT REQ (our ACT ACK must have got dropped) */</span><br><span style="color: hsl(0, 100%, 40%);">-                       rc = gsm48_tx_gsm_act_pdp_acc(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                          return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             /* Also re-transmit the SNDCP XID message */</span><br><span style="color: hsl(0, 100%, 40%);">-                            lle = &pdp->mm->gb.llme->lle[pdp->sapi];</span><br><span style="color: hsl(0, 100%, 40%);">-                                rc = sndcp_sn_xid_req(lle,pdp->nsapi);</span><br><span style="color: hsl(0, 100%, 40%);">-                               if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                                  return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-                      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Send reject with GSM_CAUSE_NSAPI_IN_USE */</span><br><span style="color: hsl(0, 100%, 40%);">-           return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          GSM_CAUSE_NSAPI_IN_USE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                         0, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (mmctx->ggsn_lookup) {</span><br><span style="color: hsl(0, 100%, 40%);">-            if (mmctx->ggsn_lookup->sapi == act_req->req_llc_sapi &&</span><br><span style="color: hsl(0, 100%, 40%);">-                       mmctx->ggsn_lookup->ti == transaction_id) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOGMMCTXP(LOGL_NOTICE, mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                           "Re-transmission while doing look-up. Ignoring.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                  return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Only increment counter for a real activation, after we checked</span><br><span style="color: hsl(0, 100%, 40%);">-        * for re-transmissions */</span><br><span style="color: hsl(0, 100%, 40%);">-      rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Determine GGSN based on APN and subscription options */</span><br><span style="color: hsl(0, 100%, 40%);">-      ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (ggsn)</span><br><span style="color: hsl(0, 100%, 40%);">-               return activate_ggsn(mmctx, ggsn, transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                               act_req->req_nsapi, act_req->req_llc_sapi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                &tp, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (strlen(apn_str) == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-               goto no_context;</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!sgsn->cfg.dynamic_lookup)</span><br><span style="color: hsl(0, 100%, 40%);">-               goto no_context;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* schedule a dynamic look-up */</span><br><span style="color: hsl(0, 100%, 40%);">-        mmctx->ggsn_lookup = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_lookup);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!mmctx->ggsn_lookup)</span><br><span style="color: hsl(0, 100%, 40%);">-             goto no_context;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        mmctx->ggsn_lookup->state = SGSN_GGSN_2DIGIT;</span><br><span style="color: hsl(0, 100%, 40%);">-     mmctx->ggsn_lookup->mmctx = mmctx;</span><br><span style="color: hsl(0, 100%, 40%);">-        strcpy(mmctx->ggsn_lookup->apn_str, apn_str);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     mmctx->ggsn_lookup->orig_msg = msg;</span><br><span style="color: hsl(0, 100%, 40%);">-       mmctx->ggsn_lookup->tp = tp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      mmctx->ggsn_lookup->ti = transaction_id;</span><br><span style="color: hsl(0, 100%, 40%);">-  mmctx->ggsn_lookup->nsapi = act_req->req_nsapi;</span><br><span style="color: hsl(0, 100%, 40%);">-        mmctx->ggsn_lookup->sapi = act_req->req_llc_sapi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                           mmctx->ggsn_lookup->apn_str, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGMMCTXP(LOGL_DEBUG, mmctx, "Going to query %s\n", hostname);</span><br><span style="color: hsl(0, 100%, 40%);">-        rc = sgsn_ares_query(sgsn, hostname,</span><br><span style="color: hsl(0, 100%, 40%);">-                            ggsn_lookup_cb, mmctx->ggsn_lookup);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGMMCTXP(LOGL_ERROR, mmctx, "Failed to start ares query.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                goto no_context;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       *delete = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-no_context:</span><br><span style="color: hsl(0, 100%, 40%);">-    LOGMMCTXP(LOGL_ERROR, mmctx, "No GGSN context found!\n");</span><br><span style="color: hsl(0, 100%, 40%);">-     return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  gsm_cause, 0, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.1: Activate PDP Context Request */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                              struct msgb *_msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- bool delete = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct msgb *msg;</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /*</span><br><span style="color: hsl(0, 100%, 40%);">-       * This is painful. We might not have a static GGSN</span><br><span style="color: hsl(0, 100%, 40%);">-      * configuration and then would need to copy the msg</span><br><span style="color: hsl(0, 100%, 40%);">-     * and re-do most of this routine (or call it again</span><br><span style="color: hsl(0, 100%, 40%);">-      * and make sure it only goes through the dynamic</span><br><span style="color: hsl(0, 100%, 40%);">-        * resolving. The question is what to optimize for</span><br><span style="color: hsl(0, 100%, 40%);">-       * and the dynamic resolution will be the right thing</span><br><span style="color: hsl(0, 100%, 40%);">-    * in the long run.</span><br><span style="color: hsl(0, 100%, 40%);">-      */</span><br><span style="color: hsl(0, 100%, 40%);">-     msg = bssgp_msgb_copy(_msg, __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-             struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-            uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGMMCTXP(LOGL_ERROR, mmctx, "-> ACTIVATE PDP CONTEXT REQ failed copy.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Send reject with GSM_CAUSE_INV_MAND_INFO */</span><br><span style="color: hsl(0, 100%, 40%);">-          return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          GSM_CAUSE_NET_FAIL,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             0, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = do_act_pdp_req(mmctx, msg, &delete);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (delete)</span><br><span style="color: hsl(0, 100%, 40%);">-             msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            get_value_string(gsm48_gsm_cause_names, gh->data[0]));</span><br><span style="color: hsl(0, 100%, 40%);">-       rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!pdp) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Request for "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "non-existing PDP Context (IMSI=%s, TI=%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        mm->imsi, transaction_id);</span><br><span style="color: hsl(0, 100%, 40%);">-           return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(0, 100%, 40%);">-       rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!pdp) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Accept for "</span><br><span style="color: hsl(0, 100%, 40%);">-                       "non-existing PDP Context (IMSI=%s, TI=%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        mm->imsi, transaction_id);</span><br><span style="color: hsl(0, 100%, 40%);">-           return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       /* stop timer 3395 */</span><br><span style="color: hsl(0, 100%, 40%);">-   pdpctx_timer_stop(pdp, 3395);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (pdp->ggsn)</span><br><span style="color: hsl(0, 100%, 40%);">-               return sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-        /* GTP side already detached, freeing */</span><br><span style="color: hsl(0, 100%, 40%);">-        sgsn_pdp_ctx_free(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsm48_hdr *gh = msgb_l3(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS SM STATUS (cause: %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               get_value_string(gsm48_gsm_cause_names, gh->data[0]));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void pdpctx_timer_cb(void *_pdp)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct sgsn_pdp_ctx *pdp = _pdp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        pdp->num_T_exp++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    switch (pdp->T) {</span><br><span style="color: hsl(0, 100%, 40%);">-    case 3395:      /* waiting for PDP CTX DEACT ACK */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (pdp->num_T_exp > T339X_MAX_RETRANS) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 LOGPDPCTXP(LOGL_NOTICE, pdp, "T3395 expired > %d times\n", T339X_MAX_RETRANS);</span><br><span style="color: hsl(0, 100%, 40%);">-                     pdp->state = PDP_STATE_INACTIVE;</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (pdp->ggsn)</span><br><span style="color: hsl(0, 100%, 40%);">-                               sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-                       else</span><br><span style="color: hsl(0, 100%, 40%);">-                            sgsn_pdp_ctx_free(pdp);</span><br><span style="color: hsl(0, 100%, 40%);">-                 break;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-               _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, GSM_CAUSE_NET_FAIL, true);</span><br><span style="color: hsl(0, 100%, 40%);">-          pdpctx_timer_rearm(pdp, 3395);</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGPDPCTXP(LOGL_ERROR, pdp, "timer expired in unknown mode %u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     pdp->T);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* GPRS Session Management */</span><br><span style="color: hsl(0, 100%, 40%);">-int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                    struct gprs_llc_llme *llme)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* MMCTX can be NULL when called */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!mmctx) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGGBIUP(llme, msg, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            /* 6.1.3.6 */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (gh->msg_type == GSM48_MT_GSM_STATUS)</span><br><span style="color: hsl(0, 100%, 40%);">-                     return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               return gsm0408_gprs_force_reattach_oldmsg(msg, llme);</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       switch (gh->msg_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case GSM48_MT_GSM_ACT_PDP_REQ:</span><br><span style="color: hsl(0, 100%, 40%);">-          rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case GSM48_MT_GSM_DEACT_PDP_REQ:</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case GSM48_MT_GSM_DEACT_PDP_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = gsm48_rx_gsm_deact_pdp_ack(mmctx, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case GSM48_MT_GSM_STATUS:</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = gsm48_rx_gsm_status(mmctx, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-           break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case GSM48_MT_GSM_REQ_PDP_ACT_REJ:</span><br><span style="color: hsl(0, 100%, 40%);">-      case GSM48_MT_GSM_ACT_AA_PDP_REQ:</span><br><span style="color: hsl(0, 100%, 40%);">-       case GSM48_MT_GSM_DEACT_AA_PDP_REQ:</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGMMCTXP(LOGL_NOTICE, mmctx, "Unimplemented GSM 04.08 GSM msg type 0x%02x: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));</span><br><span style="color: hsl(0, 100%, 40%);">-         rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGMMCTXP(LOGL_NOTICE, mmctx, "Unknown GSM 04.08 GSM msg type 0x%02x: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));</span><br><span style="color: hsl(0, 100%, 40%);">-         rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,</span><br><span>                                     struct gprs_llc_llme *llme)</span><br><span> {</span><br><span>diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c</span><br><span>index 027b666..27b9641 100644</span><br><span>--- a/src/sgsn/gprs_ranap.c</span><br><span>+++ b/src/sgsn/gprs_ranap.c</span><br><span>@@ -32,6 +32,7 @@</span><br><span> #include <osmocom/ranap/ranap_common.h></span><br><span> </span><br><span> #include <osmocom/sgsn/gprs_gmm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sm.h></span><br><span> #include <osmocom/sgsn/debug.h></span><br><span> #include <osmocom/sgsn/sgsn.h></span><br><span> #include <osmocom/sgsn/gprs_ranap.h></span><br><span>diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/gprs_sgsn.c</span><br><span>index 1c23d06..189f7bb 100644</span><br><span>--- a/src/sgsn/gprs_sgsn.c</span><br><span>+++ b/src/sgsn/gprs_sgsn.c</span><br><span>@@ -39,6 +39,7 @@</span><br><span> #include <osmocom/sgsn/gprs_sgsn.h></span><br><span> #include <osmocom/sgsn/sgsn.h></span><br><span> #include <osmocom/sgsn/gprs_gmm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sm.h></span><br><span> #include <osmocom/sgsn/gprs_utils.h></span><br><span> #include <osmocom/sgsn/signal.h></span><br><span> #include <osmocom/sgsn/gprs_gmm_attach.h></span><br><span>diff --git a/src/sgsn/gprs_sm.c b/src/sgsn/gprs_sm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8cf5c5d</span><br><span>--- /dev/null</span><br><span>+++ b/src/sgsn/gprs_sm.c</span><br><span>@@ -0,0 +1,749 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Section "9.5 GPRS Session Management Messages"</span><br><span style="color: hsl(120, 100%, 40%);">+ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2010 by On-Waves</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <netdb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "bscconfig.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/apn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_gmm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/sgsn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_llc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sndcp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_ranap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern void *tall_sgsn_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */</span><br><span style="color: hsl(120, 100%, 40%);">+#define T339X_MAX_RETRANS 4</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct tlv_definition gsm48_sm_att_tlvdef = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .def = {</span><br><span style="color: hsl(120, 100%, 40%);">+              [GSM48_IE_GSM_APN]              = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [GSM48_IE_GSM_PROTO_CONF_OPT]   = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [GSM48_IE_GSM_PDP_ADDR]         = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [GSM48_IE_GSM_AA_TMR]           = { TLV_TYPE_TV, 1 },</span><br><span style="color: hsl(120, 100%, 40%);">+         [GSM48_IE_GSM_NAME_FULL]        = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [GSM48_IE_GSM_NAME_SHORT]       = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [GSM48_IE_GSM_TIMEZONE]         = { TLV_TYPE_FIXED, 1 },</span><br><span style="color: hsl(120, 100%, 40%);">+              [GSM48_IE_GSM_UTC_AND_TZ]       = { TLV_TYPE_FIXED, 7 },</span><br><span style="color: hsl(120, 100%, 40%);">+              [GSM48_IE_GSM_LSA_ID]           = { TLV_TYPE_TLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm48_qos default_qos = {</span><br><span style="color: hsl(120, 100%, 40%);">+     .delay_class = 4,       /* best effort */</span><br><span style="color: hsl(120, 100%, 40%);">+     .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,</span><br><span style="color: hsl(120, 100%, 40%);">+        .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps,</span><br><span style="color: hsl(120, 100%, 40%);">+    .preced_class = GSM48_QOS_PC_NORMAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT,</span><br><span style="color: hsl(120, 100%, 40%);">+ .traf_class = GSM48_QOS_TC_INTERACTIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+       .deliv_order = GSM48_QOS_DO_UNORDERED,</span><br><span style="color: hsl(120, 100%, 40%);">+        .deliv_err_sdu = GSM48_QOS_ERRSDU_YES,</span><br><span style="color: hsl(120, 100%, 40%);">+        .max_sdu_size = GSM48_QOS_MAXSDU_1520,</span><br><span style="color: hsl(120, 100%, 40%);">+        .max_bitrate_up = GSM48_QOS_MBRATE_63k,</span><br><span style="color: hsl(120, 100%, 40%);">+       .max_bitrate_down = GSM48_QOS_MBRATE_63k,</span><br><span style="color: hsl(120, 100%, 40%);">+     .resid_ber = GSM48_QOS_RBER_5e_2,</span><br><span style="color: hsl(120, 100%, 40%);">+     .sdu_err_ratio = GSM48_QOS_SERR_1e_2,</span><br><span style="color: hsl(120, 100%, 40%);">+ .handling_prio = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+   .xfer_delay = 0x10,     /* 200ms */</span><br><span style="color: hsl(120, 100%, 40%);">+   .guar_bitrate_up = GSM48_QOS_MBRATE_0k,</span><br><span style="color: hsl(120, 100%, 40%);">+       .guar_bitrate_down = GSM48_QOS_MBRATE_0k,</span><br><span style="color: hsl(120, 100%, 40%);">+     .sig_ind = 0,   /* not optimised for signalling */</span><br><span style="color: hsl(120, 100%, 40%);">+    .max_bitrate_down_ext = 0,      /* use octet 9 */</span><br><span style="color: hsl(120, 100%, 40%);">+     .guar_bitrate_down_ext = 0,     /* use octet 13 */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* GPRS SESSION MANAGEMENT */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void pdpctx_timer_cb(void *_mm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void pdpctx_timer_rearm(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned long seconds;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_timer_pending(&pdp->timer))</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPDPCTXP(LOGL_ERROR, pdp, "Scheduling PDP timer %u while old "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "timer %u pending\n", T, pdp->T);</span><br><span style="color: hsl(120, 100%, 40%);">+        seconds = osmo_tdef_get(sgsn->cfg.T_defs, T, OSMO_TDEF_S, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_timer_schedule(&pdp->timer, seconds, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void pdpctx_timer_start(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_timer_pending(&pdp->timer))</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPDPCTXP(LOGL_ERROR, pdp, "Starting PDP timer %u while old "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "timer %u pending\n", T, pdp->T);</span><br><span style="color: hsl(120, 100%, 40%);">+        pdp->T = T;</span><br><span style="color: hsl(120, 100%, 40%);">+        pdp->num_T_exp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_timer_setup(&pdp->timer, pdpctx_timer_cb, pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+   pdpctx_timer_rearm(pdp, pdp->T);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void pdpctx_timer_stop(struct sgsn_pdp_ctx *pdp, unsigned int T)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (pdp->T != T)</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPDPCTXP(LOGL_ERROR, pdp, "Stopping PDP timer %u but "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "%u is running\n", T, pdp->T);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_timer_del(&pdp->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Detach from MM context */</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_del(&pdp->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->mm = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* stop timer 3395 */</span><br><span style="color: hsl(120, 100%, 40%);">+ pdpctx_timer_stop(pdp, 3395);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t v[6];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       v[0] = PDP_TYPE_ORG_IETF;</span><br><span style="color: hsl(120, 100%, 40%);">+     v[1] = PDP_TYPE_N_IETF_IPv4;</span><br><span style="color: hsl(120, 100%, 40%);">+  *(uint32_t *)(v+2) = htonl(ipaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_pdp_addr_ppp(struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t v[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       v[0] = PDP_TYPE_ORG_ETSI;</span><br><span style="color: hsl(120, 100%, 40%);">+     v[1] = PDP_TYPE_N_ETSI_PPP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Chapter 9.4.18 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int _tx_status(struct msgb *msg, uint8_t cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct sgsn_mm_ctx *mmctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* MMCTX might be NULL! */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           get_value_string(gsm48_gmm_cause_names, cause));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     gh->proto_discr = GSM48_PDISC_SM_GPRS;</span><br><span style="color: hsl(120, 100%, 40%);">+     gh->msg_type = GSM48_MT_GSM_STATUS;</span><br><span style="color: hsl(120, 100%, 40%);">+        gh->data[0] = cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return gsm48_gmm_sendmsg(msg, 0, mmctx, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm48_tx_sm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SM STATUS");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  mmctx2msgid(msg, mmctx);</span><br><span style="color: hsl(120, 100%, 40%);">+      return _tx_status(msg, cause, mmctx);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.2: Activate PDP Context Accept */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP ACC");</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     mmctx2msgid(msg, pdp->mm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(120, 100%, 40%);">+ gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(120, 100%, 40%);">+       gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Negotiated LLC SAPI */</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_v_put(msg, pdp->sapi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* FIXME: copy QoS parameters from original request */</span><br><span style="color: hsl(120, 100%, 40%);">+        //msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Radio priority 10.5.7.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_v_put(msg, pdp->lib->radio_pri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* PDP address */</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Highest 4 bits of first byte need to be set to 1, otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+         * the IE is identical with the 04.08 PDP Address IE */</span><br><span style="color: hsl(120, 100%, 40%);">+       pdp->lib->eua.v[0] &= ~0xf0;</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,</span><br><span style="color: hsl(120, 100%, 40%);">+                   pdp->lib->eua.l, pdp->lib->eua.v);</span><br><span style="color: hsl(120, 100%, 40%);">+   pdp->lib->eua.v[0] |= 0xf0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Optional: Protocol configuration options (FIXME: why 'req') */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (pdp->lib->pco_req.l)</span><br><span style="color: hsl(120, 100%, 40%);">+                msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,</span><br><span style="color: hsl(120, 100%, 40%);">+                             pdp->lib->pco_req.l, pdp->lib->pco_req.v);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Optional: Packet Flow Identifier */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.3: Activate PDP Context reject */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(120, 100%, 40%);">+                            uint8_t cause, uint8_t pco_len, uint8_t *pco_v)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP REJ");</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            get_value_string(gsm48_gsm_cause_names, cause));</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     mmctx2msgid(msg, mm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(120, 100%, 40%);">+ gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(120, 100%, 40%);">+       gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_v_put(msg, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (pco_len && pco_v)</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */</span><br><span style="color: hsl(120, 100%, 40%);">+static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  uint8_t sm_cause, bool teardown)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET REQ");</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t tear_down_ind = (0x9 << 4) | (!!teardown);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       mmctx2msgid(msg, mm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(120, 100%, 40%);">+ gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(120, 100%, 40%);">+       gh->msg_type = GSM48_MT_GSM_DEACT_PDP_REQ;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_v_put(msg, sm_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_v_put(msg, tear_down_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  pdpctx_timer_start(pdp, 3395);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, sm_cause, teardown);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */</span><br><span style="color: hsl(120, 100%, 40%);">+static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET ACC");</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t transaction_id = tid ^ 0x8; /* flip */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        mmctx2msgid(msg, mm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));</span><br><span style="color: hsl(120, 100%, 40%);">+ gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);</span><br><span style="color: hsl(120, 100%, 40%);">+       gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return gsm48_gmm_sendmsg(msg, 0, mm, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return _gsm48_tx_gsm_deact_pdp_acc(pdp->mm, pdp->ti);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int activate_ggsn(struct sgsn_mm_ctx *mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+         struct sgsn_ggsn_ctx *ggsn, const uint8_t transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+             const uint8_t req_nsapi, const uint8_t req_llc_sapi,</span><br><span style="color: hsl(120, 100%, 40%);">+          struct tlv_parsed *tp, int destroy_ggsn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGMMCTXP(LOGL_DEBUG, mmctx, "Using GGSN %u\n", ggsn->id);</span><br><span style="color: hsl(120, 100%, 40%);">+       ggsn->gsn = sgsn->gsn;</span><br><span style="color: hsl(120, 100%, 40%);">+  pdp = sgsn_create_pdp_ctx(ggsn, mmctx, req_nsapi, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!pdp)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Store SAPI and Transaction Identifier */</span><br><span style="color: hsl(120, 100%, 40%);">+   pdp->sapi = req_llc_sapi;</span><br><span style="color: hsl(120, 100%, 40%);">+  pdp->ti = transaction_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  pdp->destroy_ggsn = destroy_ggsn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *hostent)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sgsn_ggsn_ctx *ggsn;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sgsn_ggsn_lookup *lookup = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct in_addr *addr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  char buf[INET_ADDRSTRLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* The context is gone while we made a request */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!lookup->mmctx) {</span><br><span style="color: hsl(120, 100%, 40%);">+              talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+             talloc_free(lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (status != ARES_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct sgsn_mm_ctx *mmctx = lookup->mmctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGMMCTXP(LOGL_ERROR, mmctx, "DNS query failed.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Need to try with three digits now */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (lookup->state == SGSN_GGSN_2DIGIT) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   char *hostname;</span><br><span style="color: hsl(120, 100%, 40%);">+                       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     lookup->state = SGSN_GGSN_3DIGIT;</span><br><span style="color: hsl(120, 100%, 40%);">+                  hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 lookup->apn_str, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGMMCTXP(LOGL_DEBUG, mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                          "Going to query %s\n", hostname);</span><br><span style="color: hsl(120, 100%, 40%);">+                   rc = sgsn_ares_query(sgsn, hostname,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ggsn_lookup_cb, lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't start GGSN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                          goto reject_due_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't resolve GGSN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                goto reject_due_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (hostent->h_length != sizeof(struct in_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGMMCTXP(LOGL_ERROR, lookup->mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Wrong addr size(%zu)\n", sizeof(struct in_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          goto reject_due_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Get the first addr from the list */</span><br><span style="color: hsl(120, 100%, 40%);">+        addr = (struct in_addr *) hostent->h_addr_list[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!addr) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "No host address.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              goto reject_due_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ggsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                goto reject_due_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ggsn->remote_addr = *addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGMMCTXP(LOGL_NOTICE, lookup->mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                "Selected %s as GGSN.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           inet_ntop(AF_INET, addr, buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* forget about the ggsn look-up */</span><br><span style="color: hsl(120, 100%, 40%);">+   lookup->mmctx->ggsn_lookup = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    activate_ggsn(lookup->mmctx, ggsn, lookup->ti, lookup->nsapi,</span><br><span style="color: hsl(120, 100%, 40%);">+                        lookup->sapi, &lookup->tp, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Now free it */</span><br><span style="color: hsl(120, 100%, 40%);">+     talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     talloc_free(lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+  return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+reject_due_failure:</span><br><span style="color: hsl(120, 100%, 40%);">+        gsm48_tx_gsm_act_pdp_rej(lookup->mmctx, lookup->ti,</span><br><span style="color: hsl(120, 100%, 40%);">+                             GMM_CAUSE_NET_FAIL, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ lookup->mmctx->ggsn_lookup = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(lookup->orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     talloc_free(lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *delete)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t req_qos_len, req_pdpa_len;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t *req_qos, *req_pdpa;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_ggsn_ctx *ggsn;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+     enum gsm48_gsm_cause gsm_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+       char apn_str[GSM_APN_LENGTH] = { 0, };</span><br><span style="color: hsl(120, 100%, 40%);">+        char *hostname;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_llc_lle *lle;</span><br><span style="color: hsl(120, 100%, 40%);">+     char buf[INET_ADDRSTRLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGMMCTXP(LOGL_INFO, mmctx, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",</span><br><span style="color: hsl(120, 100%, 40%);">+            act_req->req_llc_sapi, act_req->req_nsapi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FIXME: length checks! */</span><br><span style="color: hsl(120, 100%, 40%);">+   req_qos_len = act_req->data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    req_qos = act_req->data + 1; /* 10.5.6.5 */</span><br><span style="color: hsl(120, 100%, 40%);">+        req_pdpa_len = act_req->data[1 + req_qos_len];</span><br><span style="color: hsl(120, 100%, 40%);">+     req_pdpa = act_req->data + 1 + req_qos_len + 1;      /* 10.5.6.4 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (req_pdpa[0] & 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case 0x0:</span><br><span style="color: hsl(120, 100%, 40%);">+             DEBUGPC(DMM, "ETSI ");</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 0x1:</span><br><span style="color: hsl(120, 100%, 40%);">+             DEBUGPC(DMM, "IETF ");</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 0xf:</span><br><span style="color: hsl(120, 100%, 40%);">+             DEBUGPC(DMM, "Empty ");</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (req_pdpa[1]) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case 0x21:</span><br><span style="color: hsl(120, 100%, 40%);">+            DEBUGPC(DMM, "IPv4 ");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (req_pdpa_len >= 6) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct in_addr ia;</span><br><span style="color: hsl(120, 100%, 40%);">+                    ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));</span><br><span style="color: hsl(120, 100%, 40%);">+                      DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 0x57:</span><br><span style="color: hsl(120, 100%, 40%);">+            DEBUGPC(DMM, "IPv6 ");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (req_pdpa_len >= 18) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* FIXME: print IPv6 address */</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEBUGPC(DMM, "0x%02x ", req_pdpa[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGPC(DMM, LOGL_INFO, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Check if NSAPI is out of range (TS 04.65 / 7.2) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Send reject with GSM_CAUSE_INV_MAND_INFO */</span><br><span style="color: hsl(120, 100%, 40%);">+                return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                GSM_CAUSE_INV_MAND_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Optional: Access Point Name, Protocol Config Options */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (req_pdpa + req_pdpa_len < msg->data + msg->len)</span><br><span style="color: hsl(120, 100%, 40%);">+          tlv_parse(&tp, &gsm48_sm_att_tlvdef, req_pdpa + req_pdpa_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                   (msg->data + msg->len) - (req_pdpa + req_pdpa_len), 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    else</span><br><span style="color: hsl(120, 100%, 40%);">+          memset(&tp, 0, sizeof(tp));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* put the non-TLV elements in the TLV parser structure to</span><br><span style="color: hsl(120, 100%, 40%);">+     * pass them on to the SGSN / GTP code */</span><br><span style="color: hsl(120, 100%, 40%);">+     tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ tp.lv[OSMO_IE_GSM_REQ_QOS].val = req_qos;</span><br><span style="color: hsl(120, 100%, 40%);">+     tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;</span><br><span style="color: hsl(120, 100%, 40%);">+   tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check if NSAPI is already in use */</span><br><span style="color: hsl(120, 100%, 40%);">+        pdp = sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (pdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* We already have a PDP context for this TLLI + NSAPI tuple */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (pdp->sapi == act_req->req_llc_sapi &&</span><br><span style="color: hsl(120, 100%, 40%);">+                   pdp->ti == transaction_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* This apparently is a re-transmission of a PDP CTX</span><br><span style="color: hsl(120, 100%, 40%);">+                   * ACT REQ (our ACT ACK must have got dropped) */</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = gsm48_tx_gsm_act_pdp_acc(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* Also re-transmit the SNDCP XID message */</span><br><span style="color: hsl(120, 100%, 40%);">+                          lle = &pdp->mm->gb.llme->lle[pdp->sapi];</span><br><span style="color: hsl(120, 100%, 40%);">+                              rc = sndcp_sn_xid_req(lle,pdp->nsapi);</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Send reject with GSM_CAUSE_NSAPI_IN_USE */</span><br><span style="color: hsl(120, 100%, 40%);">+         return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                GSM_CAUSE_NSAPI_IN_USE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (mmctx->ggsn_lookup) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (mmctx->ggsn_lookup->sapi == act_req->req_llc_sapi &&</span><br><span style="color: hsl(120, 100%, 40%);">+                     mmctx->ggsn_lookup->ti == transaction_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGMMCTXP(LOGL_NOTICE, mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                         "Re-transmission while doing look-up. Ignoring.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Only increment counter for a real activation, after we checked</span><br><span style="color: hsl(120, 100%, 40%);">+      * for re-transmissions */</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Determine GGSN based on APN and subscription options */</span><br><span style="color: hsl(120, 100%, 40%);">+    ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ggsn)</span><br><span style="color: hsl(120, 100%, 40%);">+             return activate_ggsn(mmctx, ggsn, transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             act_req->req_nsapi, act_req->req_llc_sapi,</span><br><span style="color: hsl(120, 100%, 40%);">+                              &tp, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (strlen(apn_str) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto no_context;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!sgsn->cfg.dynamic_lookup)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto no_context;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* schedule a dynamic look-up */</span><br><span style="color: hsl(120, 100%, 40%);">+      mmctx->ggsn_lookup = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!mmctx->ggsn_lookup)</span><br><span style="color: hsl(120, 100%, 40%);">+           goto no_context;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    mmctx->ggsn_lookup->state = SGSN_GGSN_2DIGIT;</span><br><span style="color: hsl(120, 100%, 40%);">+   mmctx->ggsn_lookup->mmctx = mmctx;</span><br><span style="color: hsl(120, 100%, 40%);">+      strcpy(mmctx->ggsn_lookup->apn_str, apn_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mmctx->ggsn_lookup->orig_msg = msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     mmctx->ggsn_lookup->tp = tp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  mmctx->ggsn_lookup->ti = transaction_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        mmctx->ggsn_lookup->nsapi = act_req->req_nsapi;</span><br><span style="color: hsl(120, 100%, 40%);">+      mmctx->ggsn_lookup->sapi = act_req->req_llc_sapi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                         mmctx->ggsn_lookup->apn_str, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGMMCTXP(LOGL_DEBUG, mmctx, "Going to query %s\n", hostname);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = sgsn_ares_query(sgsn, hostname,</span><br><span style="color: hsl(120, 100%, 40%);">+                          ggsn_lookup_cb, mmctx->ggsn_lookup);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGMMCTXP(LOGL_ERROR, mmctx, "Failed to start ares query.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              goto no_context;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     *delete = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+no_context:</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGMMCTXP(LOGL_ERROR, mmctx, "No GGSN context found!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gsm_cause, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.1: Activate PDP Context Request */</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    struct msgb *_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     bool delete = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * This is painful. We might not have a static GGSN</span><br><span style="color: hsl(120, 100%, 40%);">+    * configuration and then would need to copy the msg</span><br><span style="color: hsl(120, 100%, 40%);">+   * and re-do most of this routine (or call it again</span><br><span style="color: hsl(120, 100%, 40%);">+    * and make sure it only goes through the dynamic</span><br><span style="color: hsl(120, 100%, 40%);">+      * resolving. The question is what to optimize for</span><br><span style="color: hsl(120, 100%, 40%);">+     * and the dynamic resolution will be the right thing</span><br><span style="color: hsl(120, 100%, 40%);">+  * in the long run.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = bssgp_msgb_copy(_msg, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGMMCTXP(LOGL_ERROR, mmctx, "-> ACTIVATE PDP CONTEXT REQ failed copy.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Send reject with GSM_CAUSE_INV_MAND_INFO */</span><br><span style="color: hsl(120, 100%, 40%);">+                return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                GSM_CAUSE_NET_FAIL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = do_act_pdp_req(mmctx, msg, &delete);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (delete)</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          get_value_string(gsm48_gsm_cause_names, gh->data[0]));</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!pdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Request for "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "non-existing PDP Context (IMSI=%s, TI=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      mm->imsi, transaction_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t transaction_id = gsm48_hdr_trans_id(gh);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_pdp_ctx *pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!pdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Accept for "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "non-existing PDP Context (IMSI=%s, TI=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      mm->imsi, transaction_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* stop timer 3395 */</span><br><span style="color: hsl(120, 100%, 40%);">+ pdpctx_timer_stop(pdp, 3395);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdp->ggsn)</span><br><span style="color: hsl(120, 100%, 40%);">+             return sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* GTP side already detached, freeing */</span><br><span style="color: hsl(120, 100%, 40%);">+      sgsn_pdp_ctx_free(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm48_hdr *gh = msgb_l3(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS SM STATUS (cause: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             get_value_string(gsm48_gsm_cause_names, gh->data[0]));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void pdpctx_timer_cb(void *_pdp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct sgsn_pdp_ctx *pdp = _pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pdp->num_T_exp++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (pdp->T) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case 3395:      /* waiting for PDP CTX DEACT ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (pdp->num_T_exp > T339X_MAX_RETRANS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPDPCTXP(LOGL_NOTICE, pdp, "T3395 expired > %d times\n", T339X_MAX_RETRANS);</span><br><span style="color: hsl(120, 100%, 40%);">+                   pdp->state = PDP_STATE_INACTIVE;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (pdp->ggsn)</span><br><span style="color: hsl(120, 100%, 40%);">+                             sgsn_delete_pdp_ctx(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+                     else</span><br><span style="color: hsl(120, 100%, 40%);">+                          sgsn_pdp_ctx_free(pdp);</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, GSM_CAUSE_NET_FAIL, true);</span><br><span style="color: hsl(120, 100%, 40%);">+                pdpctx_timer_rearm(pdp, 3395);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPDPCTXP(LOGL_ERROR, pdp, "timer expired in unknown mode %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   pdp->T);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* GPRS Session Management */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct gprs_llc_llme *llme)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* MMCTX can be NULL when called */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mmctx) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGGBIUP(llme, msg, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          /* 6.1.3.6 */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gh->msg_type == GSM48_MT_GSM_STATUS)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return gsm0408_gprs_force_reattach_oldmsg(msg, llme);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (gh->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case GSM48_MT_GSM_ACT_PDP_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_MT_GSM_DEACT_PDP_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_MT_GSM_DEACT_PDP_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = gsm48_rx_gsm_deact_pdp_ack(mmctx, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_MT_GSM_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = gsm48_rx_gsm_status(mmctx, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_MT_GSM_REQ_PDP_ACT_REJ:</span><br><span style="color: hsl(120, 100%, 40%);">+    case GSM48_MT_GSM_ACT_AA_PDP_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+     case GSM48_MT_GSM_DEACT_AA_PDP_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGMMCTXP(LOGL_NOTICE, mmctx, "Unimplemented GSM 04.08 GSM msg type 0x%02x: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGMMCTXP(LOGL_NOTICE, mmctx, "Unknown GSM 04.08 GSM msg type 0x%02x: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c</span><br><span>index f6d7a69..c5bc5b8 100644</span><br><span>--- a/src/sgsn/sgsn_libgtp.c</span><br><span>+++ b/src/sgsn/sgsn_libgtp.c</span><br><span>@@ -48,6 +48,7 @@</span><br><span> #include <osmocom/sgsn/gprs_llc.h></span><br><span> #include <osmocom/sgsn/gprs_sgsn.h></span><br><span> #include <osmocom/sgsn/gprs_gmm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gprs_sm.h></span><br><span> #include <osmocom/sgsn/gprs_subscriber.h></span><br><span> #include <osmocom/sgsn/gprs_sndcp.h></span><br><span> #include <osmocom/sgsn/gprs_ranap.h></span><br><span>diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am</span><br><span>index 9afe0f7..bdcd9b4 100644</span><br><span>--- a/tests/sgsn/Makefile.am</span><br><span>+++ b/tests/sgsn/Makefile.am</span><br><span>@@ -59,6 +59,7 @@</span><br><span>         $(top_builddir)/src/sgsn/gprs_llc_xid.o \</span><br><span>    $(top_builddir)/src/sgsn/gprs_sndcp_xid.o \</span><br><span>         $(top_builddir)/src/sgsn/slhc.o \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(top_builddir)/src/sgsn/gprs_sm.o \</span><br><span>         $(top_builddir)/src/sgsn/gprs_sndcp_comp.o \</span><br><span>         $(top_builddir)/src/sgsn/gprs_sndcp_pcomp.o \</span><br><span>         $(top_builddir)/src/sgsn/v42bis.o \</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/15386">change 15386</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sgsn/+/15386"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie61d22e7868af6de73cdf9c731f07130b282599d </div>
<div style="display:none"> Gerrit-Change-Number: 15386 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>