blob: 9b3dad5d208489baf32f38cab6d0a91e2c4daa14 [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/*
Vadim Yanitskiy999a5932023-05-18 17:22:26 +07002 * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01003 * All Rights Reserved
4 *
5 * SPDX-License-Identifier: AGPL-3.0+
6 *
7 * Author: Neels Hofmeyr
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <osmocom/msc/gsm_data.h>
24#include <osmocom/msc/paging.h>
25#include <osmocom/msc/vlr.h>
26#include <osmocom/msc/ran_peer.h>
27#include <osmocom/msc/sgs_iface.h>
28#include <osmocom/msc/signal.h>
29#include <osmocom/msc/msc_a.h>
30#include <osmocom/msc/transaction.h>
31
32#define LOG_PAGING(vsub, paging_request, level, fmt, args ...) \
33 LOGP(DPAG, level, "Paging: %s%s%s: " fmt, \
34 vlr_subscr_name(vsub), paging_request ? " for " : "", paging_request ? (paging_request)->label : "", ## args)
35
36#define VSUB_USE_PAGING "Paging"
37
38const struct value_string paging_cause_names[] = {
39 { PAGING_CAUSE_CALL_CONVERSATIONAL, "CALL_CONVERSATIONAL" },
40 { PAGING_CAUSE_CALL_STREAMING, "CALL_STREAMING" },
41 { PAGING_CAUSE_CALL_INTERACTIVE, "CALL_INTERACTIVE" },
42 { PAGING_CAUSE_CALL_BACKGROUND, "CALL_BACKGROUND" },
43 { PAGING_CAUSE_SIGNALLING_LOW_PRIO, "SIGNALLING_LOW_PRIO" },
44 { PAGING_CAUSE_SIGNALLING_HIGH_PRIO, "SIGNALLING_HIGH_PRIO" },
45 { PAGING_CAUSE_UNSPECIFIED, "UNSPECIFIED" },
46 {}
47};
48
49static void paging_response_timer_cb(void *data)
50{
51 struct vlr_subscr *vsub = data;
Philipp Maier002fb012019-09-24 09:26:47 +020052
53 if (vsub->cs.attached_via_ran == OSMO_RAT_EUTRAN_SGS)
54 sgs_iface_tx_serv_abrt(vsub);
55
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010056 paging_expired(vsub);
57}
58
59/* Execute a paging on the currently active RAN. Returns the number of
60 * delivered paging requests or -EINVAL in case of failure. */
61static int msc_paging_request(struct paging_request *pr, struct vlr_subscr *vsub)
62{
63 struct gsm_network *net = vsub->vlr->user_ctx;
64
65 /* The subscriber was last seen in subscr->lac. Find out which
66 * BSCs/RNCs are responsible and send them a paging request via open
67 * SCCP connections (if any). */
68 switch (vsub->cs.attached_via_ran) {
69 case OSMO_RAT_GERAN_A:
70 return ran_peers_down_paging(net->a.sri, CELL_IDENT_LAC, vsub, pr->cause);
71 case OSMO_RAT_UTRAN_IU:
72 return ran_peers_down_paging(net->iu.sri, CELL_IDENT_LAC, vsub, pr->cause);
73 case OSMO_RAT_EUTRAN_SGS:
74 return sgs_iface_tx_paging(vsub, sgs_serv_ind_from_paging_cause(pr->cause));
75 default:
Vadim Yanitskiy01926fc2019-06-15 23:05:56 +070076 LOG_PAGING(vsub, pr, LOGL_ERROR, "Cannot page, subscriber not attached\n");
Vadim Yanitskiy08553e02019-06-15 23:04:19 +070077 return -EINVAL;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010078 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010079}
80
81struct paging_request *paging_request_start(struct vlr_subscr *vsub, enum paging_cause cause,
82 paging_cb_t paging_cb, struct gsm_trans *trans,
83 const char *label)
84{
85 int rc;
86 struct paging_request *pr;
Alexander Couzensae167fc2020-09-25 05:25:16 +020087 int paging_response_timer;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010088
Vadim Yanitskiya12ac822019-06-15 23:01:42 +070089 pr = talloc(vsub, struct paging_request);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010090 OSMO_ASSERT(pr);
91 *pr = (struct paging_request){
92 .label = label,
93 .cause = cause,
94 .paging_cb = paging_cb,
95 .trans = trans,
96 };
97
98 if (vsub->cs.is_paging) {
99 LOG_PAGING(vsub, pr, LOGL_DEBUG, "Already paging, not starting another request\n");
100 } else {
101 LOG_PAGING(vsub, pr, LOGL_DEBUG, "Starting paging\n");
102
103 rc = msc_paging_request(pr, vsub);
104 if (rc <= 0) {
105 LOG_PAGING(vsub, pr, LOGL_ERROR, "Starting paging failed (rc=%d)\n", rc);
106 talloc_free(pr);
107 return NULL;
108 }
109
110 /* reduced on the first paging callback */
111 vlr_subscr_get(vsub, VSUB_USE_PAGING);
112 vsub->cs.is_paging = true;
Alexander Couzensae167fc2020-09-25 05:25:16 +0200113 paging_response_timer = osmo_tdef_get(msc_ran_infra[vsub->cs.attached_via_ran].tdefs, -4, OSMO_TDEF_S, 10);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100114 osmo_timer_setup(&vsub->cs.paging_response_timer, paging_response_timer_cb, vsub);
Alexander Couzensae167fc2020-09-25 05:25:16 +0200115 osmo_timer_schedule(&vsub->cs.paging_response_timer, paging_response_timer, 0);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100116 }
117
118 llist_add_tail(&pr->entry, &vsub->cs.requests);
119
120 return pr;
121}
122
Neels Hofmeyr2fd69e12024-03-26 00:50:04 +0100123/* Two subscribers (e.g. an old TMSI and a new TMSI) turn out to have the same identity, so in order to discard one of
124 * them, transfer any pending Paging requests to the vsub that will survive. */
125void paging_request_join_vsub(struct vlr_subscr *keep_vsub, struct vlr_subscr *discarding_vsub)
126{
127 struct paging_request *pr;
128
129 if (!discarding_vsub->cs.is_paging)
130 return;
131
132 /* transfer all Paging Response callbacks */
133 while ((pr = llist_first_entry_or_null(&discarding_vsub->cs.requests, struct paging_request, entry))) {
134 llist_del(&pr->entry);
135 talloc_steal(keep_vsub, pr);
136 llist_add_tail(&pr->entry, &keep_vsub->cs.requests);
137 }
138
139 /* make sure a Paging use count is present on keep_vsub, if needed */
140 if (!keep_vsub->cs.is_paging && !llist_empty(&keep_vsub->cs.requests)) {
141 vlr_subscr_get(keep_vsub, VSUB_USE_PAGING);
142 keep_vsub->cs.is_paging = true;
143 }
144
145 /* Already made sure at the top of this function that discarding_vsub->cs.is_paging == true */
146 discarding_vsub->cs.is_paging = false;
147 osmo_timer_del(&discarding_vsub->cs.paging_response_timer);
148 vlr_subscr_put(discarding_vsub, VSUB_USE_PAGING);
149}
150
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100151void paging_request_remove(struct paging_request *pr)
152{
153 struct gsm_trans *trans = pr->trans;
154 struct vlr_subscr *vsub = trans ? trans->vsub : NULL;
155 LOG_PAGING(vsub, pr, LOGL_DEBUG, "Removing Paging Request\n");
156
157 if (pr->trans && pr->trans->paging_request == pr)
158 pr->trans->paging_request = NULL;
159
160 llist_del(&pr->entry);
161 talloc_free(pr);
162}
163
164static void paging_concludes(struct vlr_subscr *vsub, struct msc_a *msc_a)
165{
166 struct paging_request *pr, *pr_next;
167 struct paging_signal_data sig_data;
168
Neels Hofmeyrebf55f42020-03-09 21:01:56 +0100169 if (!vsub) {
170 /* A Paging Response has no subscriber. (Related: OS#4449) */
171 return;
172 }
173
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100174 osmo_timer_del(&vsub->cs.paging_response_timer);
175
176 llist_for_each_entry_safe(pr, pr_next, &vsub->cs.requests, entry) {
177 struct gsm_trans *trans = pr->trans;
178 paging_cb_t paging_cb = pr->paging_cb;
179
180 LOG_PAGING(vsub, pr, LOGL_DEBUG, "Paging Response action (%s)%s\n",
181 msc_a ? "success" : "expired",
182 paging_cb ? "" : " (no action defined)");
183
184 /* Remove the paging request before the paging_cb could deallocate e.g. the trans */
185 paging_request_remove(pr);
186 pr = NULL;
187
188 if (paging_cb)
189 paging_cb(msc_a, trans);
190 }
191
192 /* Inform parts of the system we don't know */
193 sig_data = (struct paging_signal_data){
194 .vsub = vsub,
195 .msc_a = msc_a,
196 };
197 osmo_signal_dispatch(SS_PAGING, msc_a ? S_PAGING_SUCCEEDED : S_PAGING_EXPIRED, &sig_data);
198
199 /* balanced with the moment we start paging */
200 if (vsub->cs.is_paging) {
201 vsub->cs.is_paging = false;
202 vlr_subscr_put(vsub, VSUB_USE_PAGING);
203 }
204
205 /* Handling of the paging requests has usually added transactions, which keep the msc_a connection active. If
206 * there are none, then this probably marks release of the connection. */
207 if (msc_a)
208 msc_a_put(msc_a, MSC_A_USE_PAGING_RESPONSE);
209}
210
211void paging_response(struct msc_a *msc_a)
212{
213 paging_concludes(msc_a_vsub(msc_a), msc_a);
214}
215
216void paging_expired(struct vlr_subscr *vsub)
217{
218 paging_concludes(vsub, NULL);
219}