blob: 5120e168ec59e09706da388924df4f674ea72575 [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/* Manage identity of neighboring BSS cells for inter-MSC handover. */
2/*
3 * (C) 2018-2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: AGPL-3.0+
7 *
8 * Author: Neels Hofmeyr
9 * Author: Stefan Sperling <ssperling@sysmocom.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Affero General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Affero General Public License for more details.
20 *
21 * You should have received a copy of the GNU Affero General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25#include <errno.h>
26
27#include <osmocom/core/linuxlist.h>
28#include <osmocom/core/utils.h>
29#include <osmocom/gsm/gsm0808.h>
30#include <osmocom/sigtran/osmo_ss7.h>
31#include <osmocom/sigtran/sccp_helpers.h>
32
33#include <osmocom/msc/neighbor_ident.h>
34#include <osmocom/msc/gsm_data.h>
35#include <osmocom/msc/sccp_ran.h>
36#include <osmocom/msc/cell_id_list.h>
37
38/* XXX greater than or equal to IPA_STRING_MAX (libosmocore) and MAX_PC_STR_LEN (libosmo-sccp). */
39#define NEIGHBOR_IDENT_ADDR_STRING_MAX 64
40
41static struct gsm_network *gsmnet;
42
43void neighbor_ident_init(struct gsm_network *net)
44{
45 gsmnet = net;
46 INIT_LLIST_HEAD(&gsmnet->neighbor_ident_list);
47}
48
49int msc_ipa_name_from_str(struct msc_ipa_name *min, const char *name)
50{
51 int rc = osmo_strlcpy(min->buf, name, sizeof(min->buf));
52 if (rc >= sizeof(min->buf)) {
53 min->len = 0;
54 return -1;
55 }
56 min->len = rc;
57 return 0;
58}
59
60int msc_ipa_name_cmp(const struct msc_ipa_name *a, const struct msc_ipa_name *b)
61{
62 size_t cmp_len;
63 int rc;
64 if (a == b)
65 return 0;
66 if (!a || !b)
67 return a ? 1 : -1;
68 cmp_len = OSMO_MIN(sizeof(a->buf), OSMO_MIN(a->len, b->len));
69 if (!cmp_len)
70 rc = 0;
71 else
72 rc = memcmp(a->buf, b->buf, cmp_len);
73 if (rc)
74 return rc;
75 if (a->len < b->len)
76 return -1;
77 if (a->len > b->len)
78 return 1;
79 return 0;
80}
81
82const char *neighbor_ident_addr_name(const struct neighbor_ident_addr *nia)
83{
84 static char buf[128];
85 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
86
87 OSMO_STRBUF_PRINTF(sb, "%s-", osmo_rat_type_name(nia->ran_type));
88
89 switch (nia->type) {
90 case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER:
91 OSMO_STRBUF_PRINTF(sb, "localRAN-%s", nia->local_ran_peer_pc_str);
92 break;
93 case MSC_NEIGHBOR_TYPE_REMOTE_MSC:
94 OSMO_STRBUF_PRINTF(sb, "remoteMSC-");
95 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_escape_str_buf2, nia->remote_msc_ipa_name.buf,
96 nia->remote_msc_ipa_name.len);
97 break;
98 default:
99 return NULL;
100 }
101
102 return buf;
103}
104
105const struct neighbor_ident_entry *neighbor_ident_add(struct llist_head *ni_list,
106 const struct neighbor_ident_addr *nia,
107 const struct gsm0808_cell_id *cid)
108{
109 struct neighbor_ident_entry *nie;
110
111 if (!ni_list)
112 return NULL;
113
114 nie = (struct neighbor_ident_entry*)neighbor_ident_find_by_addr(ni_list, nia);
115 if (!nie) {
116 nie = talloc_zero(gsmnet, struct neighbor_ident_entry);
117 OSMO_ASSERT(nie);
118 *nie = (struct neighbor_ident_entry){
119 .addr = *nia,
120 };
121 INIT_LLIST_HEAD(&nie->cell_ids);
122 llist_add_tail(&nie->entry, ni_list);
123 }
124
125 cell_id_list_add_cell(nie, &nie->cell_ids, cid);
126 return nie;
127}
128
129const struct neighbor_ident_entry *neighbor_ident_find_by_cell(const struct llist_head *ni_list,
130 enum osmo_rat_type ran_type,
131 const struct gsm0808_cell_id *cell_id)
132{
133 struct neighbor_ident_entry *e;
134 llist_for_each_entry(e, ni_list, entry) {
135 if (ran_type != OSMO_RAT_UNKNOWN) {
136 if (e->addr.ran_type != ran_type)
137 continue;
138 }
139
140 if (!cell_id_list_find(&e->cell_ids, cell_id, 0, false))
141 continue;
142 return e;
143 }
144 return NULL;
145}
146
147const struct neighbor_ident_entry *neighbor_ident_find_by_addr(const struct llist_head *ni_list,
148 const struct neighbor_ident_addr *nia)
149{
150 struct neighbor_ident_entry *e;
151
152 llist_for_each_entry(e, ni_list, entry) {
153 if (nia->ran_type != OSMO_RAT_UNKNOWN
154 && e->addr.ran_type != nia->ran_type)
155 continue;
156
157 if (e->addr.type != nia->type)
158 continue;
159
160 switch (e->addr.type) {
161 case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER:
162 if (strcmp(e->addr.local_ran_peer_pc_str, nia->local_ran_peer_pc_str))
163 continue;
164 break;
165 case MSC_NEIGHBOR_TYPE_REMOTE_MSC:
166 if (msc_ipa_name_cmp(&e->addr.remote_msc_ipa_name, &nia->remote_msc_ipa_name))
167 continue;
168 break;
169 default:
170 continue;
171 }
172
173 return e;
174 }
175
176 return NULL;
177}
178
179void neighbor_ident_del(const struct neighbor_ident_entry *nie)
180{
181 struct neighbor_ident_entry *e = (struct neighbor_ident_entry*)nie;
182 llist_del(&e->entry);
183 talloc_free(e);
184}
185
186void neighbor_ident_clear(struct llist_head *ni_list)
187{
188 struct neighbor_ident_entry *nie;
189 while ((nie = llist_first_entry_or_null(ni_list, struct neighbor_ident_entry, entry)))
190 neighbor_ident_del(nie);
191}