blob: 91a09d2db2fa0ebd76f463e2e48153683dc56f62 [file] [log] [blame]
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +02001/* GPRS utility functions */
2
3/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2010-2014 by On-Waves
5 * (C) 2013 by Holger Hans Peter Freyther
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22#include <openbsc/gprs_utils.h>
23
24#include <osmocom/core/msgb.h>
25#include <osmocom/gprs/gprs_ns.h>
26
Harald Welte53373bc2016-04-20 17:11:43 +020027#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020028#include <osmocom/gsm/protocol/gsm_04_08.h>
Jacob Erlbecke7bcdc32016-01-04 18:43:34 +010029#include <osmocom/gsm/gsm48.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020030
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020031#include <string.h>
32
33/* FIXME: this needs to go to libosmocore/msgb.c */
34struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name)
35{
36 struct libgb_msgb_cb *old_cb, *new_cb;
37 struct msgb *new_msg;
38
39 new_msg = msgb_alloc(msg->data_len, name);
40 if (!new_msg)
41 return NULL;
42
43 /* copy data */
44 memcpy(new_msg->_data, msg->_data, new_msg->data_len);
45
46 /* copy header */
47 new_msg->len = msg->len;
48 new_msg->data += msg->data - msg->_data;
49 new_msg->head += msg->head - msg->_data;
50 new_msg->tail += msg->tail - msg->_data;
51
Jacob Erlbeck7e31f842014-09-22 18:50:08 +020052 if (msg->l1h)
53 new_msg->l1h = new_msg->_data + (msg->l1h - msg->_data);
54 if (msg->l2h)
55 new_msg->l2h = new_msg->_data + (msg->l2h - msg->_data);
56 if (msg->l3h)
57 new_msg->l3h = new_msg->_data + (msg->l3h - msg->_data);
58 if (msg->l4h)
59 new_msg->l4h = new_msg->_data + (msg->l4h - msg->_data);
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020060
61 /* copy GB specific data */
62 old_cb = LIBGB_MSGB_CB(msg);
63 new_cb = LIBGB_MSGB_CB(new_msg);
64
Jacob Erlbeck7e31f842014-09-22 18:50:08 +020065 if (old_cb->bssgph)
66 new_cb->bssgph = new_msg->_data + (old_cb->bssgph - msg->_data);
67 if (old_cb->llch)
68 new_cb->llch = new_msg->_data + (old_cb->llch - msg->_data);
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020069
70 /* bssgp_cell_id is a pointer into the old msgb, so we need to make
71 * it a pointer into the new msgb */
Jacob Erlbeck7e31f842014-09-22 18:50:08 +020072 if (old_cb->bssgp_cell_id)
73 new_cb->bssgp_cell_id = new_msg->_data +
74 (old_cb->bssgp_cell_id - msg->_data);
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020075 new_cb->nsei = old_cb->nsei;
76 new_cb->bvci = old_cb->bvci;
77 new_cb->tlli = old_cb->tlli;
78
79 return new_msg;
80}
81
82/* TODO: Move this to libosmocore/msgb.c */
83int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
84 size_t old_size, size_t new_size)
85{
86 int rc;
87 uint8_t *rest = area + old_size;
88 int rest_len = msg->len - old_size - (area - msg->data);
89 int delta_size = (int)new_size - (int)old_size;
90
91 if (delta_size == 0)
92 return 0;
93
94 if (delta_size > 0) {
95 rc = msgb_trim(msg, msg->len + delta_size);
96 if (rc < 0)
97 return rc;
98 }
99
100 memmove(area + new_size, area + old_size, rest_len);
101
102 if (msg->l1h >= rest)
103 msg->l1h += delta_size;
104 if (msg->l2h >= rest)
105 msg->l2h += delta_size;
106 if (msg->l3h >= rest)
107 msg->l3h += delta_size;
108 if (msg->l4h >= rest)
109 msg->l4h += delta_size;
110
111 if (delta_size < 0)
112 msgb_trim(msg, msg->len + delta_size);
113
114 return 0;
115}
116
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200117int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +0200118{
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200119 uint8_t *last_len_field;
120 int len;
121
122 /* Can we even write the length field to the output? */
123 if (max_len == 0)
124 return -1;
125
126 /* Remember where we need to put the length once we know it */
127 last_len_field = apn_enc;
128 len = 1;
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +0200129 apn_enc += 1;
130
131 while (str[0]) {
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200132 if (len >= max_len)
133 return -1;
134
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +0200135 if (str[0] == '.') {
136 *last_len_field = (apn_enc - last_len_field) - 1;
137 last_len_field = apn_enc;
138 } else {
139 *apn_enc = str[0];
140 }
141 apn_enc += 1;
142 str += 1;
143 len += 1;
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +0200144 }
145
146 *last_len_field = (apn_enc - last_len_field) - 1;
147
148 return len;
149}
150
Jacob Erlbeck79af67d2015-01-19 08:27:34 +0100151/* GSM 04.08, 10.5.7.3 GPRS Timer */
152int gprs_tmr_to_secs(uint8_t tmr)
153{
154 switch (tmr & GPRS_TMR_UNIT_MASK) {
155 case GPRS_TMR_2SECONDS:
156 return 2 * (tmr & GPRS_TMR_FACT_MASK);
157 default:
158 case GPRS_TMR_MINUTE:
159 return 60 * (tmr & GPRS_TMR_FACT_MASK);
160 case GPRS_TMR_6MINUTE:
161 return 360 * (tmr & GPRS_TMR_FACT_MASK);
162 case GPRS_TMR_DEACTIVATED:
163 return -1;
164 }
165}
166
167/* This functions returns a tmr value such that
168 * - f is monotonic
169 * - f(s) <= s
170 * - f(s) == s if a tmr exists with s = gprs_tmr_to_secs(tmr)
171 * - the best possible resolution is used
172 * where
173 * f(s) = gprs_tmr_to_secs(gprs_secs_to_tmr_floor(s))
174 */
175uint8_t gprs_secs_to_tmr_floor(int secs)
176{
177 if (secs < 0)
178 return GPRS_TMR_DEACTIVATED;
179 if (secs < 2 * 32)
180 return GPRS_TMR_2SECONDS | (secs / 2);
181 if (secs < 60 * 2)
182 /* Ensure monotonicity */
183 return GPRS_TMR_2SECONDS | GPRS_TMR_FACT_MASK;
184 if (secs < 60 * 32)
185 return GPRS_TMR_MINUTE | (secs / 60);
186 if (secs < 360 * 6)
187 /* Ensure monotonicity */
188 return GPRS_TMR_MINUTE | GPRS_TMR_FACT_MASK;
189 if (secs < 360 * 32)
190 return GPRS_TMR_6MINUTE | (secs / 360);
191
192 return GPRS_TMR_6MINUTE | GPRS_TMR_FACT_MASK;
193}
194
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200195/* GSM 04.08, 10.5.1.4 */
196int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len)
197{
198 if (value_len != GSM48_TMSI_LEN)
199 return 0;
200
201 if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_TMSI)
202 return 0;
203
204 return 1;
205}
206
207/* GSM 04.08, 10.5.1.4 */
208int gprs_is_mi_imsi(const uint8_t *value, size_t value_len)
209{
210 if (value_len == 0)
211 return 0;
212
213 if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI)
214 return 0;
215
216 return 1;
217}
218
219int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi)
220{
221 uint32_t tmsi_be;
222
223 if (!gprs_is_mi_tmsi(value, value_len))
224 return 0;
225
226 memcpy(&tmsi_be, value + 1, sizeof(tmsi_be));
227
228 *tmsi = ntohl(tmsi_be);
229 return 1;
230}
231
Jacob Erlbeck49389172014-10-02 16:14:47 +0200232void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi)
233{
234 uint32_t tmsi_be;
235
236 memcpy(&tmsi_be, value, sizeof(tmsi_be));
237
238 *tmsi = ntohl(tmsi_be);
239}
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100240
Jacob Erlbecke7bcdc32016-01-04 18:43:34 +0100241int gprs_ra_id_equals(const struct gprs_ra_id *id1,
242 const struct gprs_ra_id *id2)
243{
244 return (id1->mcc == id2->mcc && id1->mnc == id2->mnc &&
245 id1->lac == id2->lac && id1->rac == id2->rac);
246}