blob: 77146fc766665e6b30b497fad417b177c0a5d27a [file] [log] [blame]
Pau Espin Pedrol05190c32023-01-05 20:13:13 +01001/* PDP context functionality */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <stdint.h>
23
24#include <osmocom/core/linuxlist.h>
25#include <osmocom/core/talloc.h>
26#include <osmocom/core/timer.h>
27#include <osmocom/core/rate_ctr.h>
28#include <osmocom/core/stats.h>
29
30#include <osmocom/sgsn/pdpctx.h>
31#include <osmocom/sgsn/gprs_sgsn.h>
32#include <osmocom/sgsn/sgsn.h>
33#include <osmocom/sgsn/debug.h>
34#include <osmocom/sgsn/signal.h>
35#include <osmocom/sgsn/gtp_ggsn.h>
36#include <osmocom/sgsn/gprs_llc_xid.h>
37#include <osmocom/sgsn/gprs_sndcp.h>
38#include <osmocom/sgsn/gprs_llc.h>
39#include <osmocom/sgsn/gprs_sm.h>
40#include <osmocom/sgsn/gtp.h>
41
Pau Espin Pedrol05190c32023-01-05 20:13:13 +010042static const struct rate_ctr_desc pdpctx_ctr_description[] = {
43 { "udata:packets:in", "User Data Messages ( In)" },
44 { "udata:packets:out", "User Data Messages (Out)" },
45 { "udata:bytes:in", "User Data Bytes ( In)" },
46 { "udata:bytes:out", "User Data Bytes (Out)" },
47};
48
49static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
50 .group_name_prefix = "sgsn:pdpctx",
51 .group_description = "SGSN PDP Context Statistics",
52 .num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
53 .ctr_desc = pdpctx_ctr_description,
54 .class_id = OSMO_STATS_CLASS_SUBSCRIBER,
55};
56
57/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
58struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
59 struct sgsn_ggsn_ctx *ggsn,
60 uint8_t nsapi)
61{
62 struct sgsn_pdp_ctx *pdp;
63
64 pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
65 if (pdp)
66 return NULL;
67
Pau Espin Pedrol15a52d92023-01-05 20:26:31 +010068 pdp = talloc_zero(sgsn, struct sgsn_pdp_ctx);
Pau Espin Pedrol05190c32023-01-05 20:13:13 +010069 if (!pdp)
70 return NULL;
71
72 pdp->mm = mm;
73 pdp->ggsn = ggsn;
74 pdp->nsapi = nsapi;
75 pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
76 if (!pdp->ctrg) {
77 LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
78 talloc_free(pdp);
79 return NULL;
80 }
81 llist_add(&pdp->list, &mm->pdp_list);
82 sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
Pau Espin Pedrol15a52d92023-01-05 20:26:31 +010083 llist_add(&pdp->g_list, &sgsn->pdp_list);
Pau Espin Pedrol05190c32023-01-05 20:13:13 +010084
85 return pdp;
86}
87
88/*
89 * This function will not trigger any GSM DEACT PDP ACK messages, so you
90 * probably want to call sgsn_delete_pdp_ctx() instead if the connection
91 * isn't detached already.
92 */
93void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
94{
95 struct sgsn_signal_data sig_data;
96
97 OSMO_ASSERT(pdp->mm != NULL);
98
99 /* There might still be pending callbacks in libgtp. So the parts of
100 * this object relevant to GTP need to remain intact in this case. */
101
102 LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
103
104 if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
105 /* Force the deactivation of the SNDCP layer */
106 if (pdp->mm->gb.llme)
107 sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
108 }
109
110 memset(&sig_data, 0, sizeof(sig_data));
111 sig_data.pdp = pdp;
112 osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
113
114 /* Detach from MM context */
115 pdp_ctx_detach_mm_ctx(pdp);
116 if (pdp->ggsn)
117 sgsn_delete_pdp_ctx(pdp);
118}
119
120/*
121 * Don't call this function directly unless you know what you are doing.
122 * In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
123 * implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
124 */
125void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
126{
127 struct sgsn_signal_data sig_data;
128
129 memset(&sig_data, 0, sizeof(sig_data));
130 sig_data.pdp = pdp;
131 osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
132
133 if (osmo_timer_pending(&pdp->timer)) {
134 LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
135 osmo_timer_del(&pdp->timer);
136 }
137
138 rate_ctr_group_free(pdp->ctrg);
139 if (pdp->mm)
140 llist_del(&pdp->list);
141 if (pdp->ggsn)
142 sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
143 llist_del(&pdp->g_list);
144
145 /* _if_ we still have a library handle, at least set it to NULL
146 * to avoid any dereferences of the now-deleted PDP context from
147 * sgsn_libgtp:cb_data_ind() */
148 if (pdp->lib) {
149 struct pdp_t *lib = pdp->lib;
150 LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
151 "has a libgtp handle attached to it, this shouldn't "
152 "happen!\n");
153 osmo_generate_backtrace();
154 lib->priv = NULL;
155 }
156
157 talloc_free(pdp);
158}