2 * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <osmocore/talloc.h>
27 #include <osmocom/logging.h>
28 #include <osmocom/osmocom_data.h>
29 #include <osmocom/networks.h>
33 int gsm_subscr_init(struct osmocom_ms *ms)
35 struct gsm_subscriber *subscr = &ms->subscr;
37 memset(subscr, 0, sizeof(*subscr));
44 INIT_LLIST_HEAD(&subscr->plmn_list);
45 INIT_LLIST_HEAD(&subscr->plmn_na);
50 int gsm_subscr_exit(struct osmocom_ms *ms)
52 struct gsm_subscriber *subscr = &ms->subscr;
53 struct llist_head *lh, *lh2;
56 llist_for_each_safe(lh, lh2, &subscr->plmn_list) {
60 llist_for_each_safe(lh, lh2, &subscr->plmn_na) {
68 /* Attach test card, no sim must be present */
69 int gsm_subscr_testcard(struct osmocom_ms *ms)
71 struct gsm_settings *set = &ms->settings;
72 struct gsm_subscriber *subscr = &ms->subscr;
76 if (subscr->sim_valid) {
77 LOGP(DMM, LOGL_ERROR, "Cannot insert card, until current card "
82 error = gsm_check_imsi(set->test_imsi);
84 LOGP(DMM, LOGL_ERROR, "%s\n", error);
88 /* reset subscriber */
92 sprintf(subscr->sim_name, "test");
93 // TODO: load / save SIM to file system
94 subscr->sim_valid = 1;
95 subscr->ustate = GSM_SIM_U2_NOT_UPDATED;
96 subscr->acc_barr = set->test_barr; /* we may access barred cell */
97 subscr->acc_class = 0xffff; /* we have any access class */
98 subscr->plmn_valid = set->test_rplmn_valid;
99 subscr->plmn_mcc = set->test_rplmn_mcc;
100 subscr->plmn_mnc = set->test_rplmn_mnc;
101 subscr->always_search_hplmn = set->test_always;
102 subscr->t6m_hplmn = 1; /* try to find home network every 6 min */
103 strcpy(subscr->imsi, set->test_imsi);
105 LOGP(DMM, LOGL_INFO, "(ms %s) Inserting test card (IMSI=%s %s,%s)\n",
106 ms->name, subscr->imsi, gsm_imsi_mcc(subscr->imsi),
107 gsm_imsi_mnc(subscr->imsi));
110 msg = gsm48_mmr_msgb_alloc(GSM48_MMR_REG_REQ);
113 gsm48_mmr_downmsg(ms, msg);
119 int gsm_subscr_remove(struct osmocom_ms *ms)
121 struct gsm_subscriber *subscr = &ms->subscr;
124 if (!subscr->sim_valid) {
125 LOGP(DMM, LOGL_ERROR, "Cannot remove card, no card present\n");
130 msg = gsm48_mmr_msgb_alloc(GSM48_MMR_NREG_REQ);
133 gsm48_mmr_downmsg(ms, msg);
138 static const char *subscr_ustate_names[] = {
145 /* change to new U state */
146 void new_sim_ustate(struct gsm_subscriber *subscr, int state)
148 LOGP(DMM, LOGL_INFO, "(ms %s) new state %s -> %s\n", subscr->ms->name,
149 subscr_ustate_names[subscr->ustate],
150 subscr_ustate_names[state]);
152 subscr->ustate = state;
155 /* del forbidden PLMN */
156 int gsm_subscr_del_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
159 struct gsm_sub_plmn_na *na;
161 llist_for_each_entry(na, &subscr->plmn_na, entry) {
162 if (na->mcc == mcc && na->mnc == mnc) {
163 LOGP(DPLMN, LOGL_INFO, "Delete from list of forbidden "
164 "PLMNs (mcc=%s, mnc=%s)\n",
165 gsm_print_mcc(mcc), gsm_print_mnc(mnc));
166 llist_del(&na->entry);
169 update plmn not allowed list on sim
178 /* add forbidden PLMN */
179 int gsm_subscr_add_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
180 uint16_t mnc, uint8_t cause)
182 struct gsm_sub_plmn_na *na;
184 /* don't add Home PLMN */
185 if (subscr->sim_valid && gsm_match_mnc(mcc, mnc, subscr->imsi))
188 LOGP(DPLMN, LOGL_INFO, "Add to list of forbidden PLMNs "
189 "(mcc=%s, mnc=%s)\n", gsm_print_mcc(mcc), gsm_print_mnc(mnc));
190 na = talloc_zero(l23_ctx, struct gsm_sub_plmn_na);
196 llist_add_tail(&na->entry, &subscr->plmn_na);
199 update plmn not allowed list on sim
205 /* search forbidden PLMN */
206 int gsm_subscr_is_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
209 struct gsm_sub_plmn_na *na;
211 llist_for_each_entry(na, &subscr->plmn_na, entry) {
212 if (na->mcc == mcc && na->mnc == mnc)
219 int gsm_subscr_dump_forbidden_plmn(struct osmocom_ms *ms,
220 void (*print)(void *, const char *, ...), void *priv)
222 struct gsm_subscriber *subscr = &ms->subscr;
223 struct gsm_sub_plmn_na *temp;
225 print(priv, "MCC |MNC |cause\n");
226 print(priv, "-------+-------+-------\n");
227 llist_for_each_entry(temp, &subscr->plmn_na, entry)
228 print(priv, "%s |%s%s |#%d\n",
229 gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
230 ((temp->mnc & 0x00f) == 0x00f) ? " ":"", temp->cause);
235 /* dump subscriber */
236 void gsm_subscr_dump(struct gsm_subscriber *subscr,
237 void (*print)(void *, const char *, ...), void *priv)
240 struct gsm_sub_plmn_list *plmn_list;
241 struct gsm_sub_plmn_na *plmn_na;
243 print(priv, "Mobile Subscriber of MS '%s':\n", subscr->ms->name);
245 if (!subscr->sim_valid) {
246 print(priv, " No SIM present.\n");
250 print(priv, " IMSI: %s\n", subscr->imsi);
251 print(priv, " Status: %s IMSI %s", subscr_ustate_names[subscr->ustate],
252 (subscr->imsi_attached) ? "attached" : "detached");
253 if (subscr->tmsi_valid)
254 print(priv, " TSMI %08x", subscr->tmsi);
255 if (subscr->lai_valid)
256 print(priv, " LAI: MCC %s MNC %s LAC 0x%04x (%s, %s)\n",
257 gsm_print_mcc(subscr->lai_mcc),
258 gsm_print_mnc(subscr->lai_mnc), subscr->lai_lac,
259 gsm_get_mcc(subscr->lai_mcc),
260 gsm_get_mnc(subscr->lai_mcc, subscr->lai_mnc));
262 print(priv, " LAI: invalid\n");
263 if (subscr->key_seq != 7) {
264 print(priv, " Key: sequence %d ");
265 for (i = 0; i < sizeof(subscr->key); i++)
266 print(priv, " %02x", subscr->key[i]);
269 if (subscr->plmn_valid)
270 print(priv, " Current PLMN: MCC %s MNC %s (%s, %s)\n",
271 gsm_print_mcc(subscr->plmn_mcc),
272 gsm_print_mnc(subscr->plmn_mnc),
273 gsm_get_mcc(subscr->plmn_mcc),
274 gsm_get_mnc(subscr->plmn_mcc, subscr->plmn_mnc));
275 print(priv, " Access barred cells: %s\n",
276 (subscr->acc_barr) ? "yes" : "no");
277 print(priv, " Access classes:");
278 for (i = 0; i < 16; i++)
279 if ((subscr->acc_class & (1 << i)))
280 print(priv, " C%d", i);
282 if (!llist_empty(&subscr->plmn_list)) {
283 print(priv, " List of preferred PLMNs:\n");
284 print(priv, " MCC |MNC\n");
285 print(priv, " -------+-------\n");
286 llist_for_each_entry(plmn_list, &subscr->plmn_list, entry)
287 print(priv, " %s |%s\n",
288 gsm_print_mcc(plmn_list->mcc),
289 gsm_print_mnc(plmn_list->mnc));
291 if (!llist_empty(&subscr->plmn_na)) {
292 print(priv, " List of forbidden PLMNs:\n");
293 print(priv, " MCC |MNC |cause\n");
294 print(priv, " -------+-------+-------\n");
295 llist_for_each_entry(plmn_na, &subscr->plmn_na, entry)
296 print(priv, " %s |%s%s |#%d\n",
297 gsm_print_mcc(plmn_na->mcc),
298 gsm_print_mnc(plmn_na->mnc),
299 ((plmn_na->mnc & 0x00f) == 0x00f) ? " ":"",
304 char *gsm_check_imsi(const char *imsi)
308 if (!imsi || strlen(imsi) != 15)
309 return "IMSI must have 15 digits!";
311 for (i = 0; i < strlen(imsi); i++) {
312 if (imsi[i] < '0' || imsi[i] > '9')
313 return "IMSI must have digits 0 to 9 only!";