blob: c4b66d65f269d329a9792d3ac8e2be357008b23d [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 */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020022#include <osmocom/sgsn/gprs_utils.h>
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020023
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
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020033/* TODO: Move this to libosmocore/msgb.c */
34int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
35 size_t old_size, size_t new_size)
36{
37 int rc;
38 uint8_t *rest = area + old_size;
39 int rest_len = msg->len - old_size - (area - msg->data);
40 int delta_size = (int)new_size - (int)old_size;
41
42 if (delta_size == 0)
43 return 0;
44
45 if (delta_size > 0) {
46 rc = msgb_trim(msg, msg->len + delta_size);
47 if (rc < 0)
48 return rc;
49 }
50
51 memmove(area + new_size, area + old_size, rest_len);
52
53 if (msg->l1h >= rest)
54 msg->l1h += delta_size;
55 if (msg->l2h >= rest)
56 msg->l2h += delta_size;
57 if (msg->l3h >= rest)
58 msg->l3h += delta_size;
59 if (msg->l4h >= rest)
60 msg->l4h += delta_size;
61
62 if (delta_size < 0)
63 msgb_trim(msg, msg->len + delta_size);
64
65 return 0;
66}
67
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +020068int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020069{
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +020070 uint8_t *last_len_field;
71 int len;
72
73 /* Can we even write the length field to the output? */
74 if (max_len == 0)
75 return -1;
76
77 /* Remember where we need to put the length once we know it */
78 last_len_field = apn_enc;
79 len = 1;
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020080 apn_enc += 1;
81
82 while (str[0]) {
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +020083 if (len >= max_len)
84 return -1;
85
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020086 if (str[0] == '.') {
87 *last_len_field = (apn_enc - last_len_field) - 1;
88 last_len_field = apn_enc;
89 } else {
90 *apn_enc = str[0];
91 }
92 apn_enc += 1;
93 str += 1;
94 len += 1;
Holger Hans Peter Freyther7127b022014-08-04 11:52:52 +020095 }
96
97 *last_len_field = (apn_enc - last_len_field) - 1;
98
99 return len;
100}
101
Jacob Erlbeck79af67d2015-01-19 08:27:34 +0100102/* GSM 04.08, 10.5.7.3 GPRS Timer */
103int gprs_tmr_to_secs(uint8_t tmr)
104{
105 switch (tmr & GPRS_TMR_UNIT_MASK) {
106 case GPRS_TMR_2SECONDS:
107 return 2 * (tmr & GPRS_TMR_FACT_MASK);
108 default:
109 case GPRS_TMR_MINUTE:
110 return 60 * (tmr & GPRS_TMR_FACT_MASK);
111 case GPRS_TMR_6MINUTE:
112 return 360 * (tmr & GPRS_TMR_FACT_MASK);
113 case GPRS_TMR_DEACTIVATED:
114 return -1;
115 }
116}
117
118/* This functions returns a tmr value such that
119 * - f is monotonic
120 * - f(s) <= s
121 * - f(s) == s if a tmr exists with s = gprs_tmr_to_secs(tmr)
122 * - the best possible resolution is used
123 * where
124 * f(s) = gprs_tmr_to_secs(gprs_secs_to_tmr_floor(s))
125 */
126uint8_t gprs_secs_to_tmr_floor(int secs)
127{
128 if (secs < 0)
129 return GPRS_TMR_DEACTIVATED;
130 if (secs < 2 * 32)
131 return GPRS_TMR_2SECONDS | (secs / 2);
132 if (secs < 60 * 2)
133 /* Ensure monotonicity */
134 return GPRS_TMR_2SECONDS | GPRS_TMR_FACT_MASK;
135 if (secs < 60 * 32)
136 return GPRS_TMR_MINUTE | (secs / 60);
137 if (secs < 360 * 6)
138 /* Ensure monotonicity */
139 return GPRS_TMR_MINUTE | GPRS_TMR_FACT_MASK;
140 if (secs < 360 * 32)
141 return GPRS_TMR_6MINUTE | (secs / 360);
142
143 return GPRS_TMR_6MINUTE | GPRS_TMR_FACT_MASK;
144}
145
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200146/* GSM 04.08, 10.5.1.4 */
147int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len)
148{
149 if (value_len != GSM48_TMSI_LEN)
150 return 0;
151
152 if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_TMSI)
153 return 0;
154
155 return 1;
156}
157
158/* GSM 04.08, 10.5.1.4 */
159int gprs_is_mi_imsi(const uint8_t *value, size_t value_len)
160{
161 if (value_len == 0)
162 return 0;
163
164 if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI)
165 return 0;
166
167 return 1;
168}
169
170int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi)
171{
172 uint32_t tmsi_be;
173
174 if (!gprs_is_mi_tmsi(value, value_len))
175 return 0;
176
177 memcpy(&tmsi_be, value + 1, sizeof(tmsi_be));
178
179 *tmsi = ntohl(tmsi_be);
180 return 1;
181}
182
Jacob Erlbeck49389172014-10-02 16:14:47 +0200183void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi)
184{
185 uint32_t tmsi_be;
186
187 memcpy(&tmsi_be, value, sizeof(tmsi_be));
188
189 *tmsi = ntohl(tmsi_be);
190}
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100191
Jacob Erlbecke7bcdc32016-01-04 18:43:34 +0100192int gprs_ra_id_equals(const struct gprs_ra_id *id1,
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100193 const struct gprs_ra_id *id2)
Jacob Erlbecke7bcdc32016-01-04 18:43:34 +0100194{
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100195 return (id1->mcc == id2->mcc
196 && !osmo_mnc_cmp(id1->mnc, id1->mnc_3_digits,
197 id2->mnc, id2->mnc_3_digits)
198 && id1->lac == id2->lac && id1->rac == id2->rac);
Jacob Erlbecke7bcdc32016-01-04 18:43:34 +0100199}