blob: 617993fd4cd7ce7305aff33bcf9204ec2f7776c9 [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 Maierbce5f292020-06-18 11:57:17 +020031/*! allocate trunk and add it (if required) to the trunk list.
32 * (called once at startup by VTY).
33 * \param[in] cfg mgcp configuration.
Philipp Maierbce5f292020-06-18 11:57:17 +020034 * \param[in] ttype trunk type.
Philipp Maier080935a2020-07-01 23:08:50 +020035 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +020036 * \returns pointer to allocated trunk, NULL on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020037struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
38{
39 struct mgcp_trunk *trunk;
40
41 trunk = talloc_zero(cfg, struct mgcp_trunk);
42 if (!trunk) {
43 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
44 return NULL;
45 }
46
47 trunk->cfg = cfg;
48 trunk->trunk_type = ttype;
49 trunk->trunk_nr = nr;
50
51 trunk->audio_send_ptime = 1;
52 trunk->audio_send_name = 1;
Philipp Maier889fe7f2020-07-06 17:44:12 +020053 trunk->v.vty_number_endpoints = 32;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020054 trunk->omit_rtcp = 0;
55
56 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
57
Philipp Maierd19de2e2020-06-03 13:55:33 +020058 llist_add_tail(&trunk->entry, &cfg->trunks);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020059
60 mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
61
62 return trunk;
63}
64
Philipp Maierbce5f292020-06-18 11:57:17 +020065/*! allocate endpoints and set default values
66 * (called once at startup by VTY).
67 * \param[in] trunk trunk configuration.
68 * \returns 0 on success, -1 on failure. */
Philipp Maierc66ab2c2020-06-02 20:55:34 +020069int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
70{
71 int i;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020072 struct mgcp_endpoint *endp;
Philipp Maier869b21c2020-07-03 16:04:16 +020073 unsigned int number_endpoints;
74 unsigned int first_endpoint_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020075
76 /* This function is called once on startup by the VTY to allocate the
77 * endpoints. The number of endpoints must not change througout the
78 * runtime of the MGW */
79 OSMO_ASSERT(trunk->number_endpoints == 0);
80 OSMO_ASSERT(trunk->endpoints == NULL);
81
Philipp Maier869b21c2020-07-03 16:04:16 +020082 switch (trunk->trunk_type) {
83 case MGCP_TRUNK_VIRTUAL:
84 /* Due to historical reasons the endpoints on the virtual
85 * trunk start counting at 1. */
86 first_endpoint_nr = 1;
Philipp Maier889fe7f2020-07-06 17:44:12 +020087 number_endpoints = trunk->v.vty_number_endpoints;
Philipp Maier869b21c2020-07-03 16:04:16 +020088 break;
89 case MGCP_TRUNK_E1:
90 /* The first timeslot on an E1 line is reserved for framing
91 * and alignment and can not be used for audio transport */
92 first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier889fe7f2020-07-06 17:44:12 +020093 number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;
Philipp Maier869b21c2020-07-03 16:04:16 +020094 break;
95 default:
96 OSMO_ASSERT(false);
97 }
98
99 /* Make sure the amount of requested endpoints does not execeed
100 * sane limits. The VTY already limits the possible amount,
101 * however miss-initialization of the struct or memory corruption
102 * could still lead to an excessive allocation of endpoints, so
103 * better stop early if that is the case. */
104 OSMO_ASSERT(number_endpoints < 65534);
105
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200106 /* allocate pointer array for the endpoints */
Philipp Maier7a755be2020-07-07 15:51:06 +0200107 trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
108 number_endpoints);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200109 if (!trunk->endpoints)
110 return -1;
111
112 /* create endpoints */
Philipp Maier869b21c2020-07-03 16:04:16 +0200113 for (i = 0; i < number_endpoints; i++) {
114 endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200115 if (!endp) {
116 talloc_free(trunk->endpoints);
117 return -1;
118 }
119 trunk->endpoints[i] = endp;
120 }
121
122 /* make the endpoints we just created available to the MGW code */
Philipp Maier869b21c2020-07-03 16:04:16 +0200123 trunk->number_endpoints = number_endpoints;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200124
125 return 0;
126}
127
Philipp Maier889fe7f2020-07-06 17:44:12 +0200128/*! Equip trunk with endpoints and resources
129 * (called once at startup by VTY).
130 * \param[in] trunk trunk configuration.
131 * \returns 0 on success, -1 on failure. */
132int mgcp_trunk_equip(struct mgcp_trunk *trunk)
133{
134 unsigned int i;
135
136 /* Allocate endpoints */
137 if(mgcp_trunk_alloc_endpts(trunk) != 0)
138 return -1;
139
140 /* Allocate resources */
141 switch (trunk->trunk_type) {
142 case MGCP_TRUNK_VIRTUAL:
143 /* No additional initaliziation required here, virtual
144 * endpoints will open/close network sockets themselves
145 * on demand. */
146 break;
147 case MGCP_TRUNK_E1:
148 /* The TS initalization happens once on startup for all
149 * timeslots. This only affects the i460 multiplexer. Until
150 * now no E1 resources are claimed yet. This happens on demand
151 * when the related endpoint is actually used */
152 memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));
153 for (i = 0; i < (NUM_E1_TS-1); i++)
154 osmo_i460_ts_init(&trunk->e1.i460_ts[i]);
155 break;
156 default:
157 OSMO_ASSERT(false);
158 }
159
160 return 0;
161}
162
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200163/*! get trunk configuration by trunk number (index).
Philipp Maierbce5f292020-06-18 11:57:17 +0200164 * \param[in] cfg mgcp configuration.
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200165 * \param[in] ttype trunk type.
166 * \param[in] nr trunk number.
Philipp Maierbce5f292020-06-18 11:57:17 +0200167 * \returns pointer to trunk configuration, NULL on error. */
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200168struct 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 +0200169{
170 struct mgcp_trunk *trunk;
171
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200172 llist_for_each_entry(trunk, &cfg->trunks, entry) {
173 if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
174 return trunk;
175 }
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200176
177 return NULL;
178}
179
Philipp Maier7e9ddc92020-06-10 15:22:32 +0200180/* Made public for unit-testing, do not use from outside this file */
181int e1_trunk_nr_from_epname(const char *epname)
182{
183 unsigned long int trunk_nr;
184 size_t prefix_len;
185 char *str_trunk_nr_end;
186
187 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
188 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
189 return -EINVAL;
190
191 errno = 0;
192 trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
193 if (errno == ERANGE || trunk_nr > 64 || trunk_nr == 0
194 || epname + prefix_len == str_trunk_nr_end
195 || str_trunk_nr_end[0] != '/')
196 return -EINVAL;
197 else
198 return trunk_nr;
199}
200
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200201/*! Find a trunk by the trunk prefix in the endpoint name.
202 * \param[in] epname endpoint name with trunk prefix to look up.
203 * \param[in] cfg that contains the trunks where the endpoint is located.
204 * \returns trunk or NULL if trunk was not found. */
205struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
206{
207 size_t prefix_len;
208 char epname_lc[MGCP_ENDPOINT_MAXLEN];
Vadim Yanitskiyca8639d2020-07-07 14:02:17 +0700209 int trunk_nr;
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200210
211 osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
212 epname = epname_lc;
213
214 prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
215 if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200216 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200217 }
218
Philipp Maier24b8c0c2020-07-02 14:59:16 +0200219 trunk_nr = e1_trunk_nr_from_epname(epname);
220 if (trunk_nr > 0)
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200221 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200222
223 /* Earlier versions of osmo-mgw were accepting endpoint names
224 * without trunk prefix. This is normally not allowed, each MGCP
225 * request should supply an endpoint name with trunk prefix.
226 * However in order to stay compatible with old versions of
227 * osmo-bsc and osmo-msc we still accept endpoint names without
228 * trunk prefix and just assume that the virtual trunk should
229 * be selected. There is even a TTCN3 test for this, see also:
230 * MGCP_Test.TC_crcx_noprefix */
231 if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
232 LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
233 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200234 return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200235 }
236
237 LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
238 return NULL;
239}
Philipp Maier889fe7f2020-07-06 17:44:12 +0200240
241/*! Find a trunk (E1) by its associated E1 line number.
242 * \param[in] num e1 line number.
243 * \returns trunk or NULL if trunk was not found. */
244struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)
245{
246 /*! When used on trunks other than E1, the result will always be NULL. */
247 struct mgcp_trunk *trunk;
248
249 llist_for_each_entry(trunk, &cfg->trunks, entry) {
250 if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)
251 return trunk;
252 }
253
254 return NULL;
255}