blob: 55a895309b16f6e546e55809a1a1223c399b0b07 [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>
27
Philipp Maierbce5f292020-06-18 11:57:17 +020028/*! allocate trunk and add it (if required) to the trunk list.
29 * (called once at startup by VTY).
30 * \param[in] cfg mgcp configuration.
Philipp Maierbce5f292020-06-18 11:57:17 +020031 * \param[in] ttype trunk type.
Philipp Maier080935a2020-07-01 23:08:50 +020032 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +020033 * \returns pointer to allocated trunk, NULL on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020034struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
35{
36 struct mgcp_trunk *trunk;
37
38 trunk = talloc_zero(cfg, struct mgcp_trunk);
39 if (!trunk) {
40 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
41 return NULL;
42 }
43
44 trunk->cfg = cfg;
45 trunk->trunk_type = ttype;
46 trunk->trunk_nr = nr;
47
48 trunk->audio_send_ptime = 1;
49 trunk->audio_send_name = 1;
Philipp Maier869b21c2020-07-03 16:04:16 +020050 trunk->vty_number_endpoints = 32;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020051 trunk->omit_rtcp = 0;
52
53 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
54
Philipp Maierd19de2e2020-06-03 13:55:33 +020055 llist_add_tail(&trunk->entry, &cfg->trunks);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020056
57 mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
58
59 return trunk;
60}
61
Philipp Maierbce5f292020-06-18 11:57:17 +020062/*! allocate endpoints and set default values
63 * (called once at startup by VTY).
64 * \param[in] trunk trunk configuration.
65 * \returns 0 on success, -1 on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020066int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
67{
68 int i;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020069 struct mgcp_endpoint *endp;
Philipp Maier869b21c2020-07-03 16:04:16 +020070 unsigned int number_endpoints;
71 unsigned int first_endpoint_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020072
73 /* This function is called once on startup by the VTY to allocate the
74 * endpoints. The number of endpoints must not change througout the
75 * runtime of the MGW */
76 OSMO_ASSERT(trunk->number_endpoints == 0);
77 OSMO_ASSERT(trunk->endpoints == NULL);
78
Philipp Maier869b21c2020-07-03 16:04:16 +020079 switch (trunk->trunk_type) {
80 case MGCP_TRUNK_VIRTUAL:
81 /* Due to historical reasons the endpoints on the virtual
82 * trunk start counting at 1. */
83 first_endpoint_nr = 1;
84 number_endpoints = trunk->vty_number_endpoints;
85 break;
86 case MGCP_TRUNK_E1:
87 /* The first timeslot on an E1 line is reserved for framing
88 * and alignment and can not be used for audio transport */
89 first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
90 number_endpoints = 31 * MGCP_ENDP_E1_SUBSLOTS;
91 break;
92 default:
93 OSMO_ASSERT(false);
94 }
95
96 /* Make sure the amount of requested endpoints does not execeed
97 * sane limits. The VTY already limits the possible amount,
98 * however miss-initialization of the struct or memory corruption
99 * could still lead to an excessive allocation of endpoints, so
100 * better stop early if that is the case. */
101 OSMO_ASSERT(number_endpoints < 65534);
102
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200103 /* allocate pointer array for the endpoints */
104 trunk->endpoints = _talloc_zero_array(trunk->cfg,
Philipp Maier869b21c2020-07-03 16:04:16 +0200105 sizeof(struct mgcp_endpoint *), number_endpoints, "endpoints");
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200106 if (!trunk->endpoints)
107 return -1;
108
109 /* create endpoints */
Philipp Maier869b21c2020-07-03 16:04:16 +0200110 for (i = 0; i < number_endpoints; i++) {
111 endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200112 if (!endp) {
113 talloc_free(trunk->endpoints);
114 return -1;
115 }
116 trunk->endpoints[i] = endp;
117 }
118
119 /* make the endpoints we just created available to the MGW code */
Philipp Maier869b21c2020-07-03 16:04:16 +0200120 trunk->number_endpoints = number_endpoints;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200121
122 return 0;
123}
124
125/*! get trunk configuration by trunk number (index).
Philipp Maierbce5f292020-06-18 11:57:17 +0200126 * \param[in] cfg mgcp configuration.
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200127 * \param[in] ttype trunk type.
128 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +0200129 * \returns pointer to trunk configuration, NULL on error. */
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200130struct 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 +0200131{
132 struct mgcp_trunk *trunk;
133
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200134 llist_for_each_entry(trunk, &cfg->trunks, entry) {
135 if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
136 return trunk;
137 }
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200138
139 return NULL;
140}
141
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200142/* Made public for unit-testing, do not use from outside this file */
143int e1_trunk_nr_from_epname(const char *epname)
144{
145 unsigned long int trunk_nr;
146 size_t prefix_len;
147 char *str_trunk_nr_end;
148
149 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
150 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
151 return -EINVAL;
152
153 errno = 0;
154 trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
155 if (errno == ERANGE || trunk_nr > 64 || trunk_nr == 0
156 || epname + prefix_len == str_trunk_nr_end
157 || str_trunk_nr_end[0] != '/')
158 return -EINVAL;
159 else
160 return trunk_nr;
161}
162
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200163/*! Find a trunk by the trunk prefix in the endpoint name.
164 * \param[in] epname endpoint name with trunk prefix to look up.
165 * \param[in] cfg that contains the trunks where the endpoint is located.
166 * \returns trunk or NULL if trunk was not found. */
167struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
168{
169 size_t prefix_len;
170 char epname_lc[MGCP_ENDPOINT_MAXLEN];
Vadim Yanitskiyca8639d2020-07-07 14:02:17 +0700171 int trunk_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200172
173 osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
174 epname = epname_lc;
175
176 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
177 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200178 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200179 }
180
Philipp Maier24b8c0c2020-07-02 14:59:16 +0200181 trunk_nr = e1_trunk_nr_from_epname(epname);
182 if (trunk_nr > 0)
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200183 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200184
185 /* Earlier versions of osmo-mgw were accepting endpoint names
186 * without trunk prefix. This is normally not allowed, each MGCP
187 * request should supply an endpoint name with trunk prefix.
188 * However in order to stay compatible with old versions of
189 * osmo-bsc and osmo-msc we still accept endpoint names without
190 * trunk prefix and just assume that the virtual trunk should
191 * be selected. There is even a TTCN3 test for this, see also:
192 * MGCP_Test.TC_crcx_noprefix */
193 if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
194 LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
195 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200196 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200197 }
198
199 LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
200 return NULL;
201}