blob: a5e40cdba90b9b786ca980a7c10415819f1941d6 [file] [log] [blame]
Neels Hofmeyr6d804b12017-02-18 22:20:46 +01001/* GSM subscriber details for use in BSC land */
2
3/*
4 * (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
5 *
6 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <talloc.h>
26#include <string.h>
27#include <limits.h>
28
29#include <osmocom/gsm/gsm48.h>
30#include <osmocom/core/logging.h>
31
32#include <openbsc/bsc_subscriber.h>
33#include <openbsc/debug.h>
34
35static struct bsc_subscr *bsc_subscr_alloc(struct llist_head *list)
36{
37 struct bsc_subscr *bsub;
38
39 bsub = talloc_zero(list, struct bsc_subscr);
40 if (!bsub)
41 return NULL;
42
43 llist_add_tail(&bsub->entry, list);
44 bsub->use_count = 1;
45
46 return bsub;
47}
48
49struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list,
50 const char *imsi)
51{
52 struct bsc_subscr *bsub;
53
54 if (!imsi || !*imsi)
55 return NULL;
56
57 llist_for_each_entry(bsub, list, entry) {
58 if (!strcmp(bsub->imsi, imsi))
59 return bsc_subscr_get(bsub);
60 }
61 return NULL;
62}
63
64struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list,
65 uint32_t tmsi)
66{
67 struct bsc_subscr *bsub;
68
69 if (tmsi == GSM_RESERVED_TMSI)
70 return NULL;
71
72 llist_for_each_entry(bsub, list, entry) {
73 if (bsub->tmsi == tmsi)
74 return bsc_subscr_get(bsub);
75 }
76 return NULL;
77}
78
79void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi)
80{
81 if (!bsub)
82 return;
83 strncpy(bsub->imsi, imsi, sizeof(bsub->imsi));
84}
85
86struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct llist_head *list,
87 const char *imsi)
88{
89 struct bsc_subscr *bsub;
90 bsub = bsc_subscr_find_by_imsi(list, imsi);
91 if (bsub)
92 return bsub;
93 bsub = bsc_subscr_alloc(list);
94 bsc_subscr_set_imsi(bsub, imsi);
95 return bsub;
96}
97
98struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct llist_head *list,
99 uint32_t tmsi)
100{
101 struct bsc_subscr *bsub;
102 bsub = bsc_subscr_find_by_tmsi(list, tmsi);
103 if (bsub)
104 return bsub;
105 bsub = bsc_subscr_alloc(list);
106 bsub->tmsi = tmsi;
107 return bsub;
108}
109
110const char *bsc_subscr_name(struct bsc_subscr *bsub)
111{
112 static char buf[32];
113 if (!bsub)
114 return "unknown";
115 if (bsub->imsi[0])
116 snprintf(buf, sizeof(buf), "IMSI:%s", bsub->imsi);
117 else
118 snprintf(buf, sizeof(buf), "TMSI:0x%08x", bsub->tmsi);
119 return buf;
120}
121
122static void bsc_subscr_free(struct bsc_subscr *bsub)
123{
124 llist_del(&bsub->entry);
125 talloc_free(bsub);
126}
127
128struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub,
129 const char *file, int line)
130{
131 OSMO_ASSERT(bsub->use_count < INT_MAX);
132 bsub->use_count++;
133 LOGPSRC(DREF, LOGL_DEBUG, file, line,
134 "BSC subscr %s usage increases to: %d\n",
135 bsc_subscr_name(bsub), bsub->use_count);
136 return bsub;
137}
138
139struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub,
140 const char *file, int line)
141{
142 bsub->use_count--;
143 LOGPSRC(DREF, bsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
144 file, line,
145 "BSC subscr %s usage decreases to: %d\n",
146 bsc_subscr_name(bsub), bsub->use_count);
147 if (bsub->use_count <= 0)
148 bsc_subscr_free(bsub);
149 return NULL;
150}
151
152void log_set_filter_bsc_subscr(struct log_target *target,
153 struct bsc_subscr *bsc_subscr)
154{
155 struct bsc_subscr **fsub = (void*)&target->filter_data[LOG_FLT_BSC_SUBSCR];
156
157 /* free the old data */
158 if (*fsub) {
159 bsc_subscr_put(*fsub);
160 *fsub = NULL;
161 }
162
163 if (bsc_subscr) {
164 target->filter_map |= (1 << LOG_FLT_BSC_SUBSCR);
165 *fsub = bsc_subscr_get(bsc_subscr);
166 } else
167 target->filter_map &= ~(1 << LOG_FLT_BSC_SUBSCR);
168}