blob: 27663b490c3faaf6c7421df26311f0020fe6cfec [file] [log] [blame]
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001/* Trunk handling */
2
3/*
4 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2009-2012 by On-Waves
6 * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
Philipp Maier993ea6b2020-08-04 18:26:50 +020024#include <osmocom/mgcp/mgcp.h>
25#include <osmocom/mgcp/mgcp_protocol.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020026#include <osmocom/mgcp/mgcp_endp.h>
27#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maier889fe7f2020-07-06 17:44:12 +020028#include <osmocom/mgcp/mgcp_e1.h>
29#include <osmocom/abis/e1_input.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020030
Philipp Maierbd060c32021-07-09 10:24:33 +020031const struct value_string mgcp_trunk_type_strs[] = {
32 { MGCP_TRUNK_VIRTUAL, "virtual" },
33 { MGCP_TRUNK_E1, "e1" },
34 { 0, NULL }
35};
36
Philipp Maierbce5f292020-06-18 11:57:17 +020037/*! allocate trunk and add it (if required) to the trunk list.
38 * (called once at startup by VTY).
39 * \param[in] cfg mgcp configuration.
Philipp Maierbce5f292020-06-18 11:57:17 +020040 * \param[in] ttype trunk type.
Philipp Maier080935a2020-07-01 23:08:50 +020041 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +020042 * \returns pointer to allocated trunk, NULL on failure. */
Philipp Maierd70eef62021-07-19 13:53:28 +020043struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
Philipp Maierc66ab2c2020-06-02 20:55:34 +020044{
45 struct mgcp_trunk *trunk;
46
47 trunk = talloc_zero(cfg, struct mgcp_trunk);
48 if (!trunk) {
49 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
50 return NULL;
51 }
52
53 trunk->cfg = cfg;
54 trunk->trunk_type = ttype;
55 trunk->trunk_nr = nr;
56
57 trunk->audio_send_ptime = 1;
58 trunk->audio_send_name = 1;
Philipp Maierae6858b2020-09-07 12:07:40 +020059 trunk->v.vty_number_endpoints = 512;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020060 trunk->omit_rtcp = 0;
61
62 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
63
Philipp Maierd19de2e2020-06-03 13:55:33 +020064 llist_add_tail(&trunk->entry, &cfg->trunks);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020065
Philipp Maiera065e632021-07-09 13:22:42 +020066 mgcp_ratectr_trunk_alloc(trunk);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020067
68 return trunk;
69}
70
Philipp Maierbce5f292020-06-18 11:57:17 +020071/*! allocate endpoints and set default values
72 * (called once at startup by VTY).
73 * \param[in] trunk trunk configuration.
74 * \returns 0 on success, -1 on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020075int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
76{
77 int i;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020078 struct mgcp_endpoint *endp;
Philipp Maier869b21c2020-07-03 16:04:16 +020079 unsigned int number_endpoints;
80 unsigned int first_endpoint_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020081
82 /* This function is called once on startup by the VTY to allocate the
83 * endpoints. The number of endpoints must not change througout the
84 * runtime of the MGW */
85 OSMO_ASSERT(trunk->number_endpoints == 0);
86 OSMO_ASSERT(trunk->endpoints == NULL);
87
Philipp Maier869b21c2020-07-03 16:04:16 +020088 switch (trunk->trunk_type) {
89 case MGCP_TRUNK_VIRTUAL:
90 /* Due to historical reasons the endpoints on the virtual
91 * trunk start counting at 1. */
92 first_endpoint_nr = 1;
Philipp Maier889fe7f2020-07-06 17:44:12 +020093 number_endpoints = trunk->v.vty_number_endpoints;
Philipp Maier869b21c2020-07-03 16:04:16 +020094 break;
95 case MGCP_TRUNK_E1:
96 /* The first timeslot on an E1 line is reserved for framing
97 * and alignment and can not be used for audio transport */
98 first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier889fe7f2020-07-06 17:44:12 +020099 number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier869b21c2020-07-03 16:04:16 +0200100 break;
101 default:
102 OSMO_ASSERT(false);
103 }
104
105 /* Make sure the amount of requested endpoints does not execeed
106 * sane limits. The VTY already limits the possible amount,
107 * however miss-initialization of the struct or memory corruption
108 * could still lead to an excessive allocation of endpoints, so
109 * better stop early if that is the case. */
110 OSMO_ASSERT(number_endpoints < 65534);
111
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200112 /* allocate pointer array for the endpoints */
Philipp Maier7a755be2020-07-07 15:51:06 +0200113 trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
114 number_endpoints);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200115 if (!trunk->endpoints)
116 return -1;
117
118 /* create endpoints */
Philipp Maier869b21c2020-07-03 16:04:16 +0200119 for (i = 0; i < number_endpoints; i++) {
120 endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200121 if (!endp) {
122 talloc_free(trunk->endpoints);
123 return -1;
124 }
125 trunk->endpoints[i] = endp;
126 }
127
128 /* make the endpoints we just created available to the MGW code */
Philipp Maier869b21c2020-07-03 16:04:16 +0200129 trunk->number_endpoints = number_endpoints;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200130
131 return 0;
132}
133
Philipp Maier889fe7f2020-07-06 17:44:12 +0200134/*! Equip trunk with endpoints and resources
135 * (called once at startup by VTY).
136 * \param[in] trunk trunk configuration.
137 * \returns 0 on success, -1 on failure. */
138int mgcp_trunk_equip(struct mgcp_trunk *trunk)
139{
140 unsigned int i;
141
142 /* Allocate endpoints */
143 if(mgcp_trunk_alloc_endpts(trunk) != 0)
144 return -1;
145
146 /* Allocate resources */
147 switch (trunk->trunk_type) {
148 case MGCP_TRUNK_VIRTUAL:
149 /* No additional initaliziation required here, virtual
150 * endpoints will open/close network sockets themselves
151 * on demand. */
152 break;
153 case MGCP_TRUNK_E1:
154 /* The TS initalization happens once on startup for all
155 * timeslots. This only affects the i460 multiplexer. Until
156 * now no E1 resources are claimed yet. This happens on demand
157 * when the related endpoint is actually used */
158 memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));
159 for (i = 0; i < (NUM_E1_TS-1); i++)
160 osmo_i460_ts_init(&trunk->e1.i460_ts[i]);
161 break;
162 default:
163 OSMO_ASSERT(false);
164 }
165
166 return 0;
167}
168
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200169/*! get trunk configuration by trunk number (index).
Philipp Maierbce5f292020-06-18 11:57:17 +0200170 * \param[in] cfg mgcp configuration.
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200171 * \param[in] ttype trunk type.
172 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +0200173 * \returns pointer to trunk configuration, NULL on error. */
Philipp Maierd70eef62021-07-19 13:53:28 +0200174struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200175{
176 struct mgcp_trunk *trunk;
177
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200178 llist_for_each_entry(trunk, &cfg->trunks, entry) {
179 if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
180 return trunk;
181 }
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200182
183 return NULL;
184}
185
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200186/* Made public for unit-testing, do not use from outside this file */
Philipp Maierd70eef62021-07-19 13:53:28 +0200187int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname)
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200188{
Philipp Maierd70eef62021-07-19 13:53:28 +0200189 unsigned long trunk_nr_temp;
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200190 size_t prefix_len;
191 char *str_trunk_nr_end;
192
193 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
194 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
195 return -EINVAL;
196
197 errno = 0;
Philipp Maierd70eef62021-07-19 13:53:28 +0200198 trunk_nr_temp = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
199 if (errno == ERANGE || trunk_nr_temp > 64
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200200 || epname + prefix_len == str_trunk_nr_end
201 || str_trunk_nr_end[0] != '/')
202 return -EINVAL;
Philipp Maierd70eef62021-07-19 13:53:28 +0200203 else {
204 *trunk_nr = (unsigned int)trunk_nr_temp;
205 return 0;
206 }
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200207}
208
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200209/*! Find a trunk by the trunk prefix in the endpoint name.
210 * \param[in] epname endpoint name with trunk prefix to look up.
211 * \param[in] cfg that contains the trunks where the endpoint is located.
212 * \returns trunk or NULL if trunk was not found. */
213struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
214{
215 size_t prefix_len;
216 char epname_lc[MGCP_ENDPOINT_MAXLEN];
Philipp Maierd70eef62021-07-19 13:53:28 +0200217 unsigned int trunk_nr;
218 int rc;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200219
220 osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
221 epname = epname_lc;
222
223 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
224 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200225 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200226 }
227
Philipp Maierd70eef62021-07-19 13:53:28 +0200228 rc = e1_trunk_nr_from_epname(&trunk_nr, epname);
229 if (rc == 0)
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200230 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200231
232 /* Earlier versions of osmo-mgw were accepting endpoint names
233 * without trunk prefix. This is normally not allowed, each MGCP
234 * request should supply an endpoint name with trunk prefix.
235 * However in order to stay compatible with old versions of
236 * osmo-bsc and osmo-msc we still accept endpoint names without
237 * trunk prefix and just assume that the virtual trunk should
238 * be selected. There is even a TTCN3 test for this, see also:
239 * MGCP_Test.TC_crcx_noprefix */
240 if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
241 LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
242 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200243 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200244 }
245
246 LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
247 return NULL;
248}
Philipp Maier889fe7f2020-07-06 17:44:12 +0200249
250/*! Find a trunk (E1) by its associated E1 line number.
251 * \param[in] num e1 line number.
252 * \returns trunk or NULL if trunk was not found. */
253struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)
254{
255 /*! When used on trunks other than E1, the result will always be NULL. */
256 struct mgcp_trunk *trunk;
257
258 llist_for_each_entry(trunk, &cfg->trunks, entry) {
259 if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)
260 return trunk;
261 }
262
263 return NULL;
264}