blob: dfedc4bd0faaa927c2ae16b658a4860a65acc6d1 [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
24#include <osmocom/mgcp/mgcp_internal.h>
25#include <osmocom/mgcp/mgcp_endp.h>
26#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maier889fe7f2020-07-06 17:44:12 +020027#include <osmocom/mgcp/mgcp_e1.h>
28#include <osmocom/abis/e1_input.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020029
Philipp Maierbce5f292020-06-18 11:57:17 +020030/*! allocate trunk and add it (if required) to the trunk list.
31 * (called once at startup by VTY).
32 * \param[in] cfg mgcp configuration.
Philipp Maierbce5f292020-06-18 11:57:17 +020033 * \param[in] ttype trunk type.
Philipp Maier080935a2020-07-01 23:08:50 +020034 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +020035 * \returns pointer to allocated trunk, NULL on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020036struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
37{
38 struct mgcp_trunk *trunk;
39
40 trunk = talloc_zero(cfg, struct mgcp_trunk);
41 if (!trunk) {
42 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
43 return NULL;
44 }
45
46 trunk->cfg = cfg;
47 trunk->trunk_type = ttype;
48 trunk->trunk_nr = nr;
49
50 trunk->audio_send_ptime = 1;
51 trunk->audio_send_name = 1;
Philipp Maier889fe7f2020-07-06 17:44:12 +020052 trunk->v.vty_number_endpoints = 32;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020053 trunk->omit_rtcp = 0;
54
55 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
56
Philipp Maierd19de2e2020-06-03 13:55:33 +020057 llist_add_tail(&trunk->entry, &cfg->trunks);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020058
59 mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
60
61 return trunk;
62}
63
Philipp Maierbce5f292020-06-18 11:57:17 +020064/*! allocate endpoints and set default values
65 * (called once at startup by VTY).
66 * \param[in] trunk trunk configuration.
67 * \returns 0 on success, -1 on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020068int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
69{
70 int i;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020071 struct mgcp_endpoint *endp;
Philipp Maier869b21c2020-07-03 16:04:16 +020072 unsigned int number_endpoints;
73 unsigned int first_endpoint_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020074
75 /* This function is called once on startup by the VTY to allocate the
76 * endpoints. The number of endpoints must not change througout the
77 * runtime of the MGW */
78 OSMO_ASSERT(trunk->number_endpoints == 0);
79 OSMO_ASSERT(trunk->endpoints == NULL);
80
Philipp Maier869b21c2020-07-03 16:04:16 +020081 switch (trunk->trunk_type) {
82 case MGCP_TRUNK_VIRTUAL:
83 /* Due to historical reasons the endpoints on the virtual
84 * trunk start counting at 1. */
85 first_endpoint_nr = 1;
Philipp Maier889fe7f2020-07-06 17:44:12 +020086 number_endpoints = trunk->v.vty_number_endpoints;
Philipp Maier869b21c2020-07-03 16:04:16 +020087 break;
88 case MGCP_TRUNK_E1:
89 /* The first timeslot on an E1 line is reserved for framing
90 * and alignment and can not be used for audio transport */
91 first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier889fe7f2020-07-06 17:44:12 +020092 number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier869b21c2020-07-03 16:04:16 +020093 break;
94 default:
95 OSMO_ASSERT(false);
96 }
97
98 /* Make sure the amount of requested endpoints does not execeed
99 * sane limits. The VTY already limits the possible amount,
100 * however miss-initialization of the struct or memory corruption
101 * could still lead to an excessive allocation of endpoints, so
102 * better stop early if that is the case. */
103 OSMO_ASSERT(number_endpoints < 65534);
104
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200105 /* allocate pointer array for the endpoints */
Philipp Maier7a755be2020-07-07 15:51:06 +0200106 trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
107 number_endpoints);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200108 if (!trunk->endpoints)
109 return -1;
110
111 /* create endpoints */
Philipp Maier869b21c2020-07-03 16:04:16 +0200112 for (i = 0; i < number_endpoints; i++) {
113 endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200114 if (!endp) {
115 talloc_free(trunk->endpoints);
116 return -1;
117 }
118 trunk->endpoints[i] = endp;
119 }
120
121 /* make the endpoints we just created available to the MGW code */
Philipp Maier869b21c2020-07-03 16:04:16 +0200122 trunk->number_endpoints = number_endpoints;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200123
124 return 0;
125}
126
Philipp Maier889fe7f2020-07-06 17:44:12 +0200127/*! Equip trunk with endpoints and resources
128 * (called once at startup by VTY).
129 * \param[in] trunk trunk configuration.
130 * \returns 0 on success, -1 on failure. */
131int mgcp_trunk_equip(struct mgcp_trunk *trunk)
132{
133 unsigned int i;
134
135 /* Allocate endpoints */
136 if(mgcp_trunk_alloc_endpts(trunk) != 0)
137 return -1;
138
139 /* Allocate resources */
140 switch (trunk->trunk_type) {
141 case MGCP_TRUNK_VIRTUAL:
142 /* No additional initaliziation required here, virtual
143 * endpoints will open/close network sockets themselves
144 * on demand. */
145 break;
146 case MGCP_TRUNK_E1:
147 /* The TS initalization happens once on startup for all
148 * timeslots. This only affects the i460 multiplexer. Until
149 * now no E1 resources are claimed yet. This happens on demand
150 * when the related endpoint is actually used */
151 memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));
152 for (i = 0; i < (NUM_E1_TS-1); i++)
153 osmo_i460_ts_init(&trunk->e1.i460_ts[i]);
154 break;
155 default:
156 OSMO_ASSERT(false);
157 }
158
159 return 0;
160}
161
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200162/*! get trunk configuration by trunk number (index).
Philipp Maierbce5f292020-06-18 11:57:17 +0200163 * \param[in] cfg mgcp configuration.
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200164 * \param[in] ttype trunk type.
165 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +0200166 * \returns pointer to trunk configuration, NULL on error. */
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200167struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200168{
169 struct mgcp_trunk *trunk;
170
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200171 llist_for_each_entry(trunk, &cfg->trunks, entry) {
172 if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
173 return trunk;
174 }
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200175
176 return NULL;
177}
178
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200179/* Made public for unit-testing, do not use from outside this file */
180int e1_trunk_nr_from_epname(const char *epname)
181{
182 unsigned long int trunk_nr;
183 size_t prefix_len;
184 char *str_trunk_nr_end;
185
186 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
187 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
188 return -EINVAL;
189
190 errno = 0;
191 trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
192 if (errno == ERANGE || trunk_nr > 64 || trunk_nr == 0
193 || epname + prefix_len == str_trunk_nr_end
194 || str_trunk_nr_end[0] != '/')
195 return -EINVAL;
196 else
197 return trunk_nr;
198}
199
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200200/*! Find a trunk by the trunk prefix in the endpoint name.
201 * \param[in] epname endpoint name with trunk prefix to look up.
202 * \param[in] cfg that contains the trunks where the endpoint is located.
203 * \returns trunk or NULL if trunk was not found. */
204struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
205{
206 size_t prefix_len;
207 char epname_lc[MGCP_ENDPOINT_MAXLEN];
Vadim Yanitskiyca8639d2020-07-07 14:02:17 +0700208 int trunk_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200209
210 osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
211 epname = epname_lc;
212
213 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
214 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200215 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200216 }
217
Philipp Maier24b8c0c2020-07-02 14:59:16 +0200218 trunk_nr = e1_trunk_nr_from_epname(epname);
219 if (trunk_nr > 0)
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200220 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200221
222 /* Earlier versions of osmo-mgw were accepting endpoint names
223 * without trunk prefix. This is normally not allowed, each MGCP
224 * request should supply an endpoint name with trunk prefix.
225 * However in order to stay compatible with old versions of
226 * osmo-bsc and osmo-msc we still accept endpoint names without
227 * trunk prefix and just assume that the virtual trunk should
228 * be selected. There is even a TTCN3 test for this, see also:
229 * MGCP_Test.TC_crcx_noprefix */
230 if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
231 LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
232 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200233 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200234 }
235
236 LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
237 return NULL;
238}
Philipp Maier889fe7f2020-07-06 17:44:12 +0200239
240/*! Find a trunk (E1) by its associated E1 line number.
241 * \param[in] num e1 line number.
242 * \returns trunk or NULL if trunk was not found. */
243struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)
244{
245 /*! When used on trunks other than E1, the result will always be NULL. */
246 struct mgcp_trunk *trunk;
247
248 llist_for_each_entry(trunk, &cfg->trunks, entry) {
249 if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)
250 return trunk;
251 }
252
253 return NULL;
254}