blob: 1436ebd35b7737c53da8012257a831ee7ae39373 [file] [log] [blame]
Holger Hans Peter Freyther07fc0972012-10-24 21:52:16 +02001/**
2 * This file contains helper routines for MGCP Gateway handling.
3 *
4 * The first thing to remember is that each BSC has its own namespace/range
5 * of endpoints. Whenever a BSSMAP ASSIGNMENT REQUEST is received this code
6 * will be called to select an endpoint on the BSC. The mapping from original
7 * multiplex/timeslot to BSC multiplex'/timeslot' will be stored.
8 *
9 * The second part is to take messages on the public MGCP GW interface
10 * and forward them to the right BSC. This requires the MSC to first
11 * assign the timeslot. This assumption has been true so far. We are using
12 * the policy_cb of the MGCP protocol code to decide if the request should
13 * be immediately answered or delayed. An extension "Z: noanswer" is used
14 * to request the BSC to not respond. This is saving some bytes of bandwidth
15 * and as we are using TCP to forward the message we know it will arrive.
16 * The mgcp_do_read method reads these messages and hands them to the protocol
17 * parsing code which will call the mentioned policy_cb. The bsc_mgcp_forward
18 * method is used on the way back from the BSC to the network.
19 *
20 * The third part is to patch messages forwarded to the BSC. This includes
21 * the endpoint number, the ports to be used inside the SDP file and maybe
22 * some other bits.
23 *
24 */
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080025/*
Holger Hans Peter Freyther07fc0972012-10-24 21:52:16 +020026 * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
27 * (C) 2010-2012 by On-Waves
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080028 * All Rights Reserved
29 *
30 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +010031 * it under the terms of the GNU Affero General Public License as published by
32 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080033 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010038 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080039 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010040 * You should have received a copy of the GNU Affero General Public License
41 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080042 *
43 */
44
45#include <openbsc/bsc_nat.h>
Holger Hans Peter Freytherc2b31ed2010-07-31 05:17:17 +080046#include <openbsc/bsc_nat_sccp.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080047#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080048#include <openbsc/debug.h>
Holger Hans Peter Freyther19c530c2010-10-13 23:52:01 +020049#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +020050#include <openbsc/mgcp.h>
51#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080052
Harald Welted5db12c2010-08-03 15:11:51 +020053#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +080054
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010055#include <osmocom/core/talloc.h>
Harald Welted36ff762011-03-23 18:26:56 +010056#include <osmocom/gsm/gsm0808.h>
57#include <osmocom/gsm/protocol/gsm_08_08.h>
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +020058
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080059#include <netinet/in.h>
60#include <arpa/inet.h>
61
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +020062#include <errno.h>
63#include <unistd.h>
64
Holger Hans Peter Freyther77956aa2012-11-05 13:52:53 +010065static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output)
66{
67 if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) {
68 LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
69 msgb_free(output);
70 }
71}
72
Holger Hans Peter Freyther9ec030d2011-02-27 11:04:27 +010073int bsc_mgcp_nr_multiplexes(int max_endpoints)
74{
75 int div = max_endpoints / 32;
76
77 if ((max_endpoints % 32) != 0)
78 div += 1;
79
80 return div;
81}
82
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010083static int bsc_init_endps_if_needed(struct bsc_connection *con)
84{
Holger Hans Peter Freyther9ec030d2011-02-27 11:04:27 +010085 int multiplexes;
86
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010087 /* we have done that */
88 if (con->_endpoint_status)
89 return 0;
90
91 /* we have no config... */
92 if (!con->cfg)
93 return -1;
94
Holger Hans Peter Freyther9ec030d2011-02-27 11:04:27 +010095 multiplexes = bsc_mgcp_nr_multiplexes(con->cfg->max_endpoints);
96 con->number_multiplexes = multiplexes;
97 con->max_endpoints = con->cfg->max_endpoints;
98 con->_endpoint_status = talloc_zero_array(con, char, 32 * multiplexes + 1);
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010099 return con->_endpoint_status == NULL;
100}
101
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800102static int bsc_assign_endpoint(struct bsc_connection *bsc, struct sccp_connections *con)
103{
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +0100104 int multiplex;
105 int timeslot;
Holger Hans Peter Freyther9ec030d2011-02-27 11:04:27 +0100106 const int number_endpoints = bsc->max_endpoints;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800107 int i;
108
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +0100109 mgcp_endpoint_to_timeslot(bsc->last_endpoint, &multiplex, &timeslot);
110 timeslot += 1;
111
112 for (i = 0; i < number_endpoints; ++i) {
113 int endpoint;
114
115 /* Wrap around timeslots */
116 if (timeslot == 0)
117 timeslot = 1;
118
119 if (timeslot == 0x1f) {
120 timeslot = 1;
121 multiplex += 1;
122 }
123
124 /* Wrap around the multiplex */
125 if (multiplex >= bsc->number_multiplexes)
126 multiplex = 0;
127
128 endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800129
Holger Hans Peter Freyther9ec030d2011-02-27 11:04:27 +0100130 /* Now check if we are allowed to assign this one */
131 if (endpoint >= bsc->max_endpoints) {
132 multiplex = 0;
133 timeslot = 1;
134 endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot);
135 }
136
137
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100138 if (bsc->_endpoint_status[endpoint] == 0) {
139 bsc->_endpoint_status[endpoint] = 1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800140 con->bsc_endp = endpoint;
141 bsc->last_endpoint = endpoint;
142 return 0;
143 }
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +0100144
145 timeslot += 1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800146 }
147
148 return -1;
149}
150
151static uint16_t create_cic(int endpoint)
152{
153 int timeslot, multiplex;
154
155 mgcp_endpoint_to_timeslot(endpoint, &multiplex, &timeslot);
156 return (multiplex << 5) | (timeslot & 0x1f);
157}
158
159int bsc_mgcp_assign_patch(struct sccp_connections *con, struct msgb *msg)
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800160{
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800161 struct sccp_connections *mcon;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800162 struct tlv_parsed tp;
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +0800163 uint16_t cic;
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +0800164 uint8_t timeslot;
165 uint8_t multiplex;
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +0100166 unsigned int endp;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800167
168 if (!msg->l3h) {
169 LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
170 return -1;
171 }
172
173 if (msgb_l3len(msg) < 3) {
174 LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
175 return -1;
176 }
177
178 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
179 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
180 LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
181 return -1;
182 }
183
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +0800184 cic = ntohs(*(uint16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800185 timeslot = cic & 0x1f;
186 multiplex = (cic & ~0x1f) >> 5;
187
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800188
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800189 endp = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800190
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100191 if (endp >= con->bsc->nat->mgcp_cfg->trunk.number_endpoints) {
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +0100192 LOGP(DNAT, LOGL_ERROR,
193 "MSC attempted to assign bad endpoint 0x%x\n",
194 endp);
195 return -1;
196 }
197
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800198 /* find stale connections using that endpoint */
199 llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800200 if (mcon->msc_endp == endp) {
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800201 LOGP(DNAT, LOGL_ERROR,
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800202 "Endpoint %d was assigned to 0x%x and now 0x%x\n",
203 endp,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800204 sccp_src_ref_to_int(&mcon->patched_ref),
205 sccp_src_ref_to_int(&con->patched_ref));
206 bsc_mgcp_dlcx(mcon);
207 }
208 }
209
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800210 con->msc_endp = endp;
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100211 if (bsc_init_endps_if_needed(con->bsc) != 0)
212 return -1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800213 if (bsc_assign_endpoint(con->bsc, con) != 0)
214 return -1;
215
216 /*
217 * now patch the message for the new CIC...
218 * still assumed to be one multiplex only
219 */
220 cic = htons(create_cic(con->bsc_endp));
221 memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE),
222 &cic, sizeof(cic));
223
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800224 return 0;
225}
226
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800227static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200228{
229 if (nat->bsc_endpoints[i].transaction_id) {
230 talloc_free(nat->bsc_endpoints[i].transaction_id);
231 nat->bsc_endpoints[i].transaction_id = NULL;
232 }
233
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800234 nat->bsc_endpoints[i].transaction_state = 0;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200235 nat->bsc_endpoints[i].bsc = NULL;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200236}
237
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200238void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
239{
240 int i;
241
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100242 for (i = 1; i < nat->mgcp_cfg->trunk.number_endpoints; ++i){
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200243 bsc_mgcp_free_endpoint(nat, i);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100244 mgcp_free_endp(&nat->mgcp_cfg->trunk.endpoints[i]);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800245 }
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200246}
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200247
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800248/* send a MDCX where we do not want a response */
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800249static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp)
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800250{
251 char buf[2096];
252 int len;
253
254 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherf42f45b2010-04-22 13:06:24 +0800255 "MDCX 23 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800256 "Z: noanswer\r\n"
257 "\r\n"
258 "c=IN IP4 %s\r\n"
259 "m=audio %d RTP/AVP 255\r\n",
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800260 port,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800261 bsc->nat->mgcp_cfg->source_addr,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800262 endp->bts_end.local_port);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800263 if (len < 0) {
Holger Hans Peter Freyther74568912012-09-14 15:51:43 +0200264 LOGP(DMGCP, LOGL_ERROR, "snprintf for MDCX failed.\n");
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800265 return;
266 }
Holger Hans Peter Freytherd38aa452010-08-30 11:58:49 +0800267
Holger Hans Peter Freyther6de9d0b2012-10-30 16:32:19 +0100268 bsc_write_mgcp(bsc, (uint8_t *) buf, len);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800269}
270
271static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
272{
273 char buf[2096];
274 int len;
275
276 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherbf812fa2010-08-30 12:01:36 +0800277 "DLCX 26 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800278 "Z: noanswer\r\n", endpoint);
279 if (len < 0) {
280 LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
281 return;
282 }
283
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +0800284 bsc_write_mgcp(bsc, (uint8_t *) buf, len);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800285}
286
287void bsc_mgcp_init(struct sccp_connections *con)
288{
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800289 con->msc_endp = -1;
290 con->bsc_endp = -1;
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800291}
292
293void bsc_mgcp_dlcx(struct sccp_connections *con)
294{
295 /* send a DLCX down the stream */
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100296 if (con->bsc_endp != -1 && con->bsc->_endpoint_status) {
297 if (con->bsc->_endpoint_status[con->bsc_endp] != 1)
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800298 LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp);
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100299 con->bsc->_endpoint_status[con->bsc_endp] = 0;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800300 bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp);
301 bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800302 }
303
304 bsc_mgcp_init(con);
305}
306
307
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800308struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200309{
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800310 struct sccp_connections *con = NULL;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200311 struct sccp_connections *sccp;
312
313 llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800314 if (sccp->msc_endp == -1)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200315 continue;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800316 if (sccp->msc_endp != endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200317 continue;
318
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800319 con = sccp;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200320 }
321
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800322 if (con)
323 return con;
Holger Hans Peter Freythereb52e892010-04-18 02:14:45 +0800324
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200325 LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
326 return NULL;
327}
328
Holger Hans Peter Freythercb3c2c92012-10-24 21:53:07 +0200329static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int state, const char *transaction_id)
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200330{
331 struct bsc_nat *nat;
332 struct bsc_endpoint *bsc_endp;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800333 struct sccp_connections *sccp;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200334 struct mgcp_endpoint *mgcp_endp;
335 struct msgb *bsc_msg;
336
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100337 nat = tcfg->cfg->data;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200338 bsc_endp = &nat->bsc_endpoints[endpoint];
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100339 mgcp_endp = &nat->mgcp_cfg->trunk.endpoints[endpoint];
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200340
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800341 if (bsc_endp->transaction_id) {
342 LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
343 endpoint, bsc_endp->transaction_id);
344 talloc_free(bsc_endp->transaction_id);
345 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800346 bsc_endp->transaction_state = 0;
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800347 }
348 bsc_endp->bsc = NULL;
349
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800350 sccp = bsc_mgcp_find_con(nat, endpoint);
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200351
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800352 if (!sccp) {
Holger Hans Peter Freyther3d194d92010-04-24 21:02:01 +0800353 LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state);
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200354
355 switch (state) {
356 case MGCP_ENDP_CRCX:
357 return MGCP_POLICY_REJECT;
358 break;
359 case MGCP_ENDP_DLCX:
360 return MGCP_POLICY_CONT;
361 break;
362 case MGCP_ENDP_MDCX:
363 return MGCP_POLICY_CONT;
364 break;
365 default:
366 LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
367 return MGCP_POLICY_CONT;
368 break;
369 }
370 }
371
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200372 /* we need to generate a new and patched message */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800373 bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, sccp->bsc_endp,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800374 nat->mgcp_cfg->source_addr, mgcp_endp->bts_end.local_port);
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200375 if (!bsc_msg) {
376 LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
377 return MGCP_POLICY_CONT;
378 }
379
380
Holger Hans Peter Freytherb3e0a032010-04-04 18:11:49 +0200381 bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800382 bsc_endp->transaction_state = state;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800383 bsc_endp->bsc = sccp->bsc;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200384
385 /* we need to update some bits */
386 if (state == MGCP_ENDP_CRCX) {
387 struct sockaddr_in sock;
388 socklen_t len = sizeof(sock);
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800389 if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
Holger Hans Peter Freyther92febd32010-04-06 11:17:07 +0200390 LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
391 errno, strerror(errno));
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200392 } else {
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800393 mgcp_endp->bts_end.addr = sock.sin_addr;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200394 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200395
Holger Hans Peter Freythere66cac32010-08-05 01:50:44 +0800396 /* send the message and a fake MDCX to force sending of a dummy packet */
Holger Hans Peter Freyther368a0a72011-01-07 16:54:46 +0100397 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800398 bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800399 return MGCP_POLICY_DEFER;
400 } else if (state == MGCP_ENDP_DLCX) {
401 /* we will free the endpoint now and send a DLCX to the BSC */
Holger Hans Peter Freyther3a347f02010-05-01 10:31:53 +0800402 msgb_free(bsc_msg);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800403 bsc_mgcp_dlcx(sccp);
404 return MGCP_POLICY_CONT;
405 } else {
Holger Hans Peter Freyther368a0a72011-01-07 16:54:46 +0100406 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800407 return MGCP_POLICY_DEFER;
408 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200409}
410
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200411/*
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800412 * We do have a failure, free data downstream..
413 */
414static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp,
415 struct bsc_connection *bsc)
416{
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800417 LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n",
418 ENDPOINT_NUMBER(endp), bsc_endp->transaction_state);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800419
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800420 /* if a CRCX failed... send a DLCX down the stream */
421 if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) {
422 struct sccp_connections *con;
423 con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp));
424 if (!con) {
425 LOGP(DMGCP, LOGL_ERROR,
426 "No SCCP connection for endp 0x%x\n",
427 ENDPOINT_NUMBER(endp));
428 } else {
429 if (con->bsc == bsc) {
Holger Hans Peter Freyther8574dcf2010-08-29 22:39:07 +0800430 bsc_mgcp_send_dlcx(bsc, con->bsc_endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800431 } else {
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800432 LOGP(DMGCP, LOGL_ERROR,
433 "Endpoint belongs to a different BSC\n");
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800434 }
435 }
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800436 }
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800437
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800438 bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp));
439 mgcp_free_endp(endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800440}
441
442/*
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200443 * We have received a msg from the BSC. We will see if we know
444 * this transaction and if it belongs to the BSC. Then we will
445 * need to patch the content to point to the local network and we
446 * need to update the I: that was assigned by the BSS.
447 */
448void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
449{
450 struct msgb *output;
451 struct bsc_endpoint *bsc_endp = NULL;
452 struct mgcp_endpoint *endp = NULL;
Holger Hans Peter Freytherd2dd6e82010-04-06 11:06:11 +0200453 int i, code;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200454 char transaction_id[60];
455
456 /* Some assumption that our buffer is big enough.. and null terminate */
457 if (msgb_l2len(msg) > 2000) {
458 LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n");
459 return;
460 }
461
462 msg->l2h[msgb_l2len(msg)] = '\0';
463
464 if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) {
465 LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n");
466 return;
467 }
468
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100469 for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) {
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200470 if (bsc->nat->bsc_endpoints[i].bsc != bsc)
471 continue;
Holger Hans Peter Freyther3f7c7d02010-04-05 18:00:05 +0200472 /* no one listening? a bug? */
473 if (!bsc->nat->bsc_endpoints[i].transaction_id)
474 continue;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200475 if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
476 continue;
477
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100478 endp = &bsc->nat->mgcp_cfg->trunk.endpoints[i];
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200479 bsc_endp = &bsc->nat->bsc_endpoints[i];
480 break;
481 }
482
483 if (!bsc_endp) {
Holger Hans Peter Freytherb9ac37d2010-04-05 17:58:52 +0200484 LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n",
485 transaction_id, (const char *) msg->l2h);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200486 return;
487 }
488
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800489 endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800490 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800491 free_chan_downstream(endp, bsc_endp, bsc);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800492 return;
493 }
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200494
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200495 /* free some stuff */
496 talloc_free(bsc_endp->transaction_id);
497 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800498 bsc_endp->transaction_state = 0;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200499
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200500 /*
501 * rewrite the information. In case the endpoint was deleted
502 * there should be nothing for us to rewrite so putting endp->rtp_port
503 * with the value of 0 should be no problem.
504 */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800505 output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800506 bsc->nat->mgcp_cfg->source_addr, endp->net_end.local_port);
Holger Hans Peter Freyther5cc94fb2010-04-05 22:56:49 +0200507
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200508 if (!output) {
509 LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
510 return;
511 }
512
Holger Hans Peter Freyther77956aa2012-11-05 13:52:53 +0100513 mgcp_queue_for_call_agent(bsc->nat, output);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200514}
515
516int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
517{
518 /* we want to parse two strings */
519 return sscanf(str, "%3d %59s\n", code, transaction) != 2;
520}
521
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800522uint32_t bsc_mgcp_extract_ci(const char *str)
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200523{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800524 unsigned int ci;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200525 char *res = strstr(str, "I: ");
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800526 if (!res) {
527 LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200528 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800529 }
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200530
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800531 if (sscanf(res, "I: %u", &ci) != 1) {
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800532 LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200533 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800534 }
535
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200536 return ci;
537}
538
Holger Hans Peter Freyther9592c452012-01-17 15:58:48 +0100539/**
540 * Create a new MGCPCommand based on the input and endpoint from a message
541 */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800542static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
543 int endp, int len, int cr)
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200544{
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800545 int slen;
546 int ret;
547 char buf[40];
548
549 buf[0] = buf[39] = '\0';
550 ret = sscanf(tok, "%*s %s", buf);
Holger Hans Peter Freyther9592c452012-01-17 15:58:48 +0100551 if (ret != 1) {
552 LOGP(DMGCP, LOGL_ERROR,
553 "Failed to find Endpoint in: %s\n", tok);
554 return;
555 }
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800556
557 slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s",
558 op, buf, endp, cr ? "\r\n" : "\n");
559 output->l3h = msgb_put(output, slen);
560}
561
562/* we need to replace some strings... */
563struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint, const char *ip, int port)
564{
Holger Hans Peter Freyther3dfe8a12012-11-07 11:36:58 +0100565 static const char crcx_str[] = "CRCX ";
566 static const char dlcx_str[] = "DLCX ";
567 static const char mdcx_str[] = "MDCX ";
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800568
Holger Hans Peter Freyther3dfe8a12012-11-07 11:36:58 +0100569 static const char ip_str[] = "c=IN IP4 ";
570 static const char aud_str[] = "m=audio ";
571 static const char fmt_str[] = "a=fmtp:";
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200572
573 char buf[128];
574 char *running, *token;
575 struct msgb *output;
576
Holger Hans Peter Freythere2f34d52012-11-06 13:16:26 +0100577 /* keep state to add the a=fmtp line */
578 int found_fmtp = 0;
579 int payload = -1;
580 int cr = 1;
581
582 if (length > 4096 - 256) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200583 LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
584 return NULL;
585 }
586
587 output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
588 if (!output) {
589 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
590 return NULL;
591 }
592
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200593 running = input;
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200594 output->l2h = output->data;
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800595 output->l3h = output->l2h;
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200596 for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200597 int len = strlen(token);
Holger Hans Peter Freythere2f34d52012-11-06 13:16:26 +0100598 cr = len > 0 && token[len - 1] == '\r';
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200599
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800600 if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) {
601 patch_mgcp(output, "CRCX", token, endpoint, len, cr);
602 } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) {
603 patch_mgcp(output, "DLCX", token, endpoint, len, cr);
604 } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) {
605 patch_mgcp(output, "MDCX", token, endpoint, len, cr);
606 } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200607 output->l3h = msgb_put(output, strlen(ip_str));
608 memcpy(output->l3h, ip_str, strlen(ip_str));
609 output->l3h = msgb_put(output, strlen(ip));
610 memcpy(output->l3h, ip, strlen(ip));
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200611
612 if (cr) {
613 output->l3h = msgb_put(output, 2);
614 output->l3h[0] = '\r';
615 output->l3h[1] = '\n';
616 } else {
617 output->l3h = msgb_put(output, 1);
618 output->l3h[0] = '\n';
619 }
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200620 } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200621 if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
622 LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
623 msgb_free(output);
624 return NULL;
625 }
626
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200627 snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d%s",
628 port, payload, cr ? "\r\n" : "\n");
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200629 buf[sizeof(buf)-1] = '\0';
630
631 output->l3h = msgb_put(output, strlen(buf));
632 memcpy(output->l3h, buf, strlen(buf));
Holger Hans Peter Freythere2f34d52012-11-06 13:16:26 +0100633 } else if (strncmp(fmt_str, token, (sizeof fmt_str) - 1) == 0) {
634 found_fmtp = 1;
635 goto copy;
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200636 } else {
Holger Hans Peter Freythere2f34d52012-11-06 13:16:26 +0100637copy:
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200638 output->l3h = msgb_put(output, len + 1);
639 memcpy(output->l3h, token, len);
640 output->l3h[len] = '\n';
641 }
642 }
643
Holger Hans Peter Freythere2f34d52012-11-06 13:16:26 +0100644 /*
645 * the above code made sure that we have 128 bytes lefts. So we can
646 * safely append another line.
647 */
648 if (!found_fmtp && payload != -1) {
649 snprintf(buf, sizeof(buf) - 1, "a=fmtp:%d mode-set=2%s",
650 payload, cr ? "\r\n" : "\n");
651 buf[sizeof(buf) - 1] = '\0';
652 output->l3h = msgb_put(output, strlen(buf));
653 memcpy(output->l3h, buf, strlen(buf));
654 }
655
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200656 return output;
657}
658
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200659static int mgcp_do_read(struct osmo_fd *fd)
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200660{
661 struct bsc_nat *nat;
662 struct msgb *msg, *resp;
663 int rc;
664
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200665 nat = fd->data;
666
667 rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1);
668 if (rc <= 0) {
669 LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
670 return -1;
671 }
672
673 nat->mgcp_msg[rc] = '\0';
674 nat->mgcp_length = rc;
675
676 msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read");
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200677 if (!msg) {
678 LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
679 return -1;
680 }
681
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200682 msg->l2h = msgb_put(msg, rc);
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200683 memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200684 resp = mgcp_handle_message(nat->mgcp_cfg, msg);
685 msgb_free(msg);
686
687 /* we do have a direct answer... e.g. AUEP */
Holger Hans Peter Freyther77956aa2012-11-05 13:52:53 +0100688 if (resp)
689 mgcp_queue_for_call_agent(nat, resp);
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200690
691 return 0;
692}
693
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200694static int mgcp_do_write(struct osmo_fd *bfd, struct msgb *msg)
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200695{
696 int rc;
697
698 rc = write(bfd->fd, msg->data, msg->len);
699
700 if (rc != msg->len) {
701 LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
702 return -1;
703 }
704
705 return rc;
706}
707
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800708int bsc_mgcp_nat_init(struct bsc_nat *nat)
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200709{
710 int on;
711 struct sockaddr_in addr;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800712 struct mgcp_config *cfg = nat->mgcp_cfg;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200713
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800714 if (!cfg->call_agent_addr) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200715 LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
716 return -1;
717 }
718
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800719 if (cfg->bts_ip) {
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200720 LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
721 return -1;
722 }
723
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800724 cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
725 if (cfg->gw_fd.bfd.fd < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200726 LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
727 return -1;
728 }
729
730 on = 1;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800731 setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200732
733 addr.sin_family = AF_INET;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800734 addr.sin_port = htons(cfg->source_port);
735 inet_aton(cfg->source_addr, &addr.sin_addr);
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200736
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800737 if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freytherd000c272011-03-29 17:12:07 +0200738 LOGP(DMGCP, LOGL_ERROR, "Failed to bind on %s:%d errno: %d\n",
739 cfg->source_addr, cfg->source_port, errno);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800740 close(cfg->gw_fd.bfd.fd);
741 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200742 return -1;
743 }
744
745 addr.sin_port = htons(2727);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800746 inet_aton(cfg->call_agent_addr, &addr.sin_addr);
747 if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200748 LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800749 cfg->call_agent_addr, errno);
750 close(cfg->gw_fd.bfd.fd);
751 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200752 return -1;
753 }
754
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200755 osmo_wqueue_init(&cfg->gw_fd, 10);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800756 cfg->gw_fd.bfd.when = BSC_FD_READ;
757 cfg->gw_fd.bfd.data = nat;
758 cfg->gw_fd.read_cb = mgcp_do_read;
759 cfg->gw_fd.write_cb = mgcp_do_write;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200760
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200761 if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200762 LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800763 close(cfg->gw_fd.bfd.fd);
764 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200765 return -1;
766 }
767
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200768 /* some more MGCP config handling */
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800769 cfg->data = nat;
770 cfg->policy_cb = bsc_mgcp_policy_cb;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100771 cfg->trunk.force_realloc = 1;
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000772
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800773 if (cfg->bts_ip)
774 talloc_free(cfg->bts_ip);
775 cfg->bts_ip = "";
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000776
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200777 nat->bsc_endpoints = talloc_zero_array(nat,
778 struct bsc_endpoint,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100779 cfg->trunk.number_endpoints + 1);
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800780 if (!nat->bsc_endpoints) {
781 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800782 close(cfg->gw_fd.bfd.fd);
783 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800784 return -1;
785 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200786
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +0800787 if (mgcp_reset_transcoder(cfg) < 0) {
788 LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n");
789 talloc_free(nat->bsc_endpoints);
790 nat->bsc_endpoints = NULL;
791 close(cfg->gw_fd.bfd.fd);
792 cfg->gw_fd.bfd.fd = -1;
793 return -1;
794 }
795
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200796 return 0;
797}
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200798
799void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
800{
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800801 struct rate_ctr *ctr = NULL;
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200802 int i;
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800803
804 if (bsc->cfg)
805 ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS];
806
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100807 for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) {
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200808 struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i];
809
810 if (bsc_endp->bsc != bsc)
811 continue;
812
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800813 if (ctr)
814 rate_ctr_inc(ctr);
815
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800816 bsc_mgcp_free_endpoint(bsc->nat, i);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100817 mgcp_free_endp(&bsc->nat->mgcp_cfg->trunk.endpoints[i]);
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200818 }
819}