blob: cb6360bfa449274c1ba8bafd4ad39c39a3496b3d [file] [log] [blame]
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +08001/*
2 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2010 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <openbsc/bsc_nat.h>
Holger Hans Peter Freytherc2b31ed2010-07-31 05:17:17 +080023#include <openbsc/bsc_nat_sccp.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080024#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080025#include <openbsc/debug.h>
Holger Hans Peter Freyther19c530c2010-10-13 23:52:01 +020026#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +020027#include <openbsc/mgcp.h>
28#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080029
Harald Welted5db12c2010-08-03 15:11:51 +020030#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +080031
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +020032#include <osmocore/talloc.h>
Holger Hans Peter Freyther13959482010-06-15 18:50:57 +080033#include <osmocore/gsm0808.h>
Holger Hans Peter Freyther69d801e2010-06-15 20:13:33 +080034#include <osmocore/protocol/gsm_08_08.h>
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +020035
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080036#include <netinet/in.h>
37#include <arpa/inet.h>
38
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +020039#include <errno.h>
40#include <unistd.h>
41
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080042static int bsc_assign_endpoint(struct bsc_connection *bsc, struct sccp_connections *con)
43{
44 const int number_endpoints = ARRAY_SIZE(bsc->endpoint_status);
45 int i;
46
47 for (i = 1; i < number_endpoints; ++i) {
48 int endpoint = (bsc->last_endpoint + i) % number_endpoints;
49 if (endpoint == 0)
50 endpoint = 1;
51
52 if (bsc->endpoint_status[endpoint] == 0) {
53 bsc->endpoint_status[endpoint] = 1;
54 con->bsc_endp = endpoint;
55 bsc->last_endpoint = endpoint;
56 return 0;
57 }
58 }
59
60 return -1;
61}
62
63static uint16_t create_cic(int endpoint)
64{
65 int timeslot, multiplex;
66
67 mgcp_endpoint_to_timeslot(endpoint, &multiplex, &timeslot);
68 return (multiplex << 5) | (timeslot & 0x1f);
69}
70
71int bsc_mgcp_assign_patch(struct sccp_connections *con, struct msgb *msg)
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080072{
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +080073 struct sccp_connections *mcon;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080074 struct tlv_parsed tp;
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +080075 uint16_t cic;
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +080076 uint8_t timeslot;
77 uint8_t multiplex;
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +010078 unsigned int endp;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080079
80 if (!msg->l3h) {
81 LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
82 return -1;
83 }
84
85 if (msgb_l3len(msg) < 3) {
86 LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
87 return -1;
88 }
89
90 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
91 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
92 LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
93 return -1;
94 }
95
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +080096 cic = ntohs(*(uint16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080097 timeslot = cic & 0x1f;
98 multiplex = (cic & ~0x1f) >> 5;
99
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800100
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800101 endp = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800102
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +0100103 if (endp >= con->bsc->nat->mgcp_cfg->number_endpoints) {
104 LOGP(DNAT, LOGL_ERROR,
105 "MSC attempted to assign bad endpoint 0x%x\n",
106 endp);
107 return -1;
108 }
109
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800110 /* find stale connections using that endpoint */
111 llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800112 if (mcon->msc_endp == endp) {
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800113 LOGP(DNAT, LOGL_ERROR,
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800114 "Endpoint %d was assigned to 0x%x and now 0x%x\n",
115 endp,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800116 sccp_src_ref_to_int(&mcon->patched_ref),
117 sccp_src_ref_to_int(&con->patched_ref));
118 bsc_mgcp_dlcx(mcon);
119 }
120 }
121
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800122 con->msc_endp = endp;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800123 if (bsc_assign_endpoint(con->bsc, con) != 0)
124 return -1;
125
126 /*
127 * now patch the message for the new CIC...
128 * still assumed to be one multiplex only
129 */
130 cic = htons(create_cic(con->bsc_endp));
131 memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE),
132 &cic, sizeof(cic));
133
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800134 return 0;
135}
136
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800137static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200138{
139 if (nat->bsc_endpoints[i].transaction_id) {
140 talloc_free(nat->bsc_endpoints[i].transaction_id);
141 nat->bsc_endpoints[i].transaction_id = NULL;
142 }
143
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800144 nat->bsc_endpoints[i].transaction_state = 0;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200145 nat->bsc_endpoints[i].bsc = NULL;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200146}
147
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200148void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
149{
150 int i;
151
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800152 for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i){
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200153 bsc_mgcp_free_endpoint(nat, i);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800154 mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
155 }
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200156}
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200157
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800158/* send a MDCX where we do not want a response */
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800159static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp)
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800160{
161 char buf[2096];
162 int len;
163
164 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherf42f45b2010-04-22 13:06:24 +0800165 "MDCX 23 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800166 "Z: noanswer\r\n"
167 "\r\n"
168 "c=IN IP4 %s\r\n"
169 "m=audio %d RTP/AVP 255\r\n",
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800170 port,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800171 bsc->nat->mgcp_cfg->source_addr,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800172 endp->bts_end.local_port);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800173 if (len < 0) {
174 LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
175 return;
176 }
Holger Hans Peter Freytherd38aa452010-08-30 11:58:49 +0800177
178 #warning "The MDCX is not send to the BSC. It should"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800179}
180
181static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
182{
183 char buf[2096];
184 int len;
185
186 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherbf812fa2010-08-30 12:01:36 +0800187 "DLCX 26 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800188 "Z: noanswer\r\n", endpoint);
189 if (len < 0) {
190 LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
191 return;
192 }
193
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +0800194 bsc_write_mgcp(bsc, (uint8_t *) buf, len);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800195}
196
197void bsc_mgcp_init(struct sccp_connections *con)
198{
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800199 con->msc_endp = -1;
200 con->bsc_endp = -1;
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800201}
202
203void bsc_mgcp_dlcx(struct sccp_connections *con)
204{
205 /* send a DLCX down the stream */
Holger Hans Peter Freyther39cd32e2010-08-28 18:11:07 +0800206 if (con->bsc_endp != -1) {
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800207 if (con->bsc->endpoint_status[con->bsc_endp] != 1)
208 LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp);
209 con->bsc->endpoint_status[con->bsc_endp] = 0;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800210 bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp);
211 bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800212 }
213
214 bsc_mgcp_init(con);
215}
216
217
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800218struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200219{
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800220 struct sccp_connections *con = NULL;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200221 struct sccp_connections *sccp;
222
223 llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800224 if (sccp->msc_endp == -1)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200225 continue;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800226 if (sccp->msc_endp != endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200227 continue;
228
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800229 con = sccp;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200230 }
231
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800232 if (con)
233 return con;
Holger Hans Peter Freythereb52e892010-04-18 02:14:45 +0800234
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200235 LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
236 return NULL;
237}
238
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200239int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const char *transaction_id)
240{
241 struct bsc_nat *nat;
242 struct bsc_endpoint *bsc_endp;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800243 struct sccp_connections *sccp;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200244 struct mgcp_endpoint *mgcp_endp;
245 struct msgb *bsc_msg;
246
247 nat = cfg->data;
248 bsc_endp = &nat->bsc_endpoints[endpoint];
249 mgcp_endp = &nat->mgcp_cfg->endpoints[endpoint];
250
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800251 if (bsc_endp->transaction_id) {
252 LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
253 endpoint, bsc_endp->transaction_id);
254 talloc_free(bsc_endp->transaction_id);
255 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800256 bsc_endp->transaction_state = 0;
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800257 }
258 bsc_endp->bsc = NULL;
259
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800260 sccp = bsc_mgcp_find_con(nat, endpoint);
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200261
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800262 if (!sccp) {
Holger Hans Peter Freyther3d194d92010-04-24 21:02:01 +0800263 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 +0200264
265 switch (state) {
266 case MGCP_ENDP_CRCX:
267 return MGCP_POLICY_REJECT;
268 break;
269 case MGCP_ENDP_DLCX:
270 return MGCP_POLICY_CONT;
271 break;
272 case MGCP_ENDP_MDCX:
273 return MGCP_POLICY_CONT;
274 break;
275 default:
276 LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
277 return MGCP_POLICY_CONT;
278 break;
279 }
280 }
281
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200282 /* we need to generate a new and patched message */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800283 bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, sccp->bsc_endp,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800284 nat->mgcp_cfg->source_addr, mgcp_endp->bts_end.local_port);
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200285 if (!bsc_msg) {
286 LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
287 return MGCP_POLICY_CONT;
288 }
289
290
Holger Hans Peter Freytherb3e0a032010-04-04 18:11:49 +0200291 bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800292 bsc_endp->transaction_state = state;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800293 bsc_endp->bsc = sccp->bsc;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200294
295 /* we need to update some bits */
296 if (state == MGCP_ENDP_CRCX) {
297 struct sockaddr_in sock;
298 socklen_t len = sizeof(sock);
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800299 if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
Holger Hans Peter Freyther92febd32010-04-06 11:17:07 +0200300 LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
301 errno, strerror(errno));
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200302 } else {
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800303 mgcp_endp->bts_end.addr = sock.sin_addr;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200304 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200305
Holger Hans Peter Freythere66cac32010-08-05 01:50:44 +0800306 /* send the message and a fake MDCX to force sending of a dummy packet */
Holger Hans Peter Freyther19c530c2010-10-13 23:52:01 +0200307 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP);
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800308 bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800309 return MGCP_POLICY_DEFER;
310 } else if (state == MGCP_ENDP_DLCX) {
311 /* we will free the endpoint now and send a DLCX to the BSC */
Holger Hans Peter Freyther3a347f02010-05-01 10:31:53 +0800312 msgb_free(bsc_msg);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800313 bsc_mgcp_dlcx(sccp);
314 return MGCP_POLICY_CONT;
315 } else {
Holger Hans Peter Freyther19c530c2010-10-13 23:52:01 +0200316 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800317 return MGCP_POLICY_DEFER;
318 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200319}
320
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200321/*
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800322 * We do have a failure, free data downstream..
323 */
324static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp,
325 struct bsc_connection *bsc)
326{
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800327 LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n",
328 ENDPOINT_NUMBER(endp), bsc_endp->transaction_state);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800329
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800330 /* if a CRCX failed... send a DLCX down the stream */
331 if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) {
332 struct sccp_connections *con;
333 con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp));
334 if (!con) {
335 LOGP(DMGCP, LOGL_ERROR,
336 "No SCCP connection for endp 0x%x\n",
337 ENDPOINT_NUMBER(endp));
338 } else {
339 if (con->bsc == bsc) {
Holger Hans Peter Freyther8574dcf2010-08-29 22:39:07 +0800340 bsc_mgcp_send_dlcx(bsc, con->bsc_endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800341 } else {
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800342 LOGP(DMGCP, LOGL_ERROR,
343 "Endpoint belongs to a different BSC\n");
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800344 }
345 }
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800346 }
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800347
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800348 bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp));
349 mgcp_free_endp(endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800350}
351
352/*
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200353 * We have received a msg from the BSC. We will see if we know
354 * this transaction and if it belongs to the BSC. Then we will
355 * need to patch the content to point to the local network and we
356 * need to update the I: that was assigned by the BSS.
357 */
358void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
359{
360 struct msgb *output;
361 struct bsc_endpoint *bsc_endp = NULL;
362 struct mgcp_endpoint *endp = NULL;
Holger Hans Peter Freytherd2dd6e82010-04-06 11:06:11 +0200363 int i, code;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200364 char transaction_id[60];
365
366 /* Some assumption that our buffer is big enough.. and null terminate */
367 if (msgb_l2len(msg) > 2000) {
368 LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n");
369 return;
370 }
371
372 msg->l2h[msgb_l2len(msg)] = '\0';
373
374 if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) {
375 LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n");
376 return;
377 }
378
379 for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
380 if (bsc->nat->bsc_endpoints[i].bsc != bsc)
381 continue;
Holger Hans Peter Freyther3f7c7d02010-04-05 18:00:05 +0200382 /* no one listening? a bug? */
383 if (!bsc->nat->bsc_endpoints[i].transaction_id)
384 continue;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200385 if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
386 continue;
387
388 endp = &bsc->nat->mgcp_cfg->endpoints[i];
389 bsc_endp = &bsc->nat->bsc_endpoints[i];
390 break;
391 }
392
393 if (!bsc_endp) {
Holger Hans Peter Freytherb9ac37d2010-04-05 17:58:52 +0200394 LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n",
395 transaction_id, (const char *) msg->l2h);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200396 return;
397 }
398
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800399 endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800400 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800401 free_chan_downstream(endp, bsc_endp, bsc);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800402 return;
403 }
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200404
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200405 /* free some stuff */
406 talloc_free(bsc_endp->transaction_id);
407 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800408 bsc_endp->transaction_state = 0;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200409
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200410 /*
411 * rewrite the information. In case the endpoint was deleted
412 * there should be nothing for us to rewrite so putting endp->rtp_port
413 * with the value of 0 should be no problem.
414 */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800415 output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800416 bsc->nat->mgcp_cfg->source_addr, endp->net_end.local_port);
Holger Hans Peter Freyther5cc94fb2010-04-05 22:56:49 +0200417
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200418 if (!output) {
419 LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
420 return;
421 }
422
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800423 if (write_queue_enqueue(&bsc->nat->mgcp_cfg->gw_fd, output) != 0) {
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200424 LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
425 msgb_free(output);
426 }
427}
428
429int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
430{
431 /* we want to parse two strings */
432 return sscanf(str, "%3d %59s\n", code, transaction) != 2;
433}
434
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800435uint32_t bsc_mgcp_extract_ci(const char *str)
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200436{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800437 unsigned int ci;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200438 char *res = strstr(str, "I: ");
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800439 if (!res) {
440 LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200441 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800442 }
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200443
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800444 if (sscanf(res, "I: %u", &ci) != 1) {
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800445 LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200446 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800447 }
448
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200449 return ci;
450}
451
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800452static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
453 int endp, int len, int cr)
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200454{
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800455 int slen;
456 int ret;
457 char buf[40];
458
459 buf[0] = buf[39] = '\0';
460 ret = sscanf(tok, "%*s %s", buf);
461
462 slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s",
463 op, buf, endp, cr ? "\r\n" : "\n");
464 output->l3h = msgb_put(output, slen);
465}
466
467/* we need to replace some strings... */
468struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint, const char *ip, int port)
469{
470 static const char *crcx_str = "CRCX ";
471 static const char *dlcx_str = "DLCX ";
472 static const char *mdcx_str = "MDCX ";
473
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200474 static const char *ip_str = "c=IN IP4 ";
475 static const char *aud_str = "m=audio ";
476
477 char buf[128];
478 char *running, *token;
479 struct msgb *output;
480
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200481 if (length > 4096 - 128) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200482 LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
483 return NULL;
484 }
485
486 output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
487 if (!output) {
488 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
489 return NULL;
490 }
491
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200492 running = input;
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200493 output->l2h = output->data;
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800494 output->l3h = output->l2h;
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200495 for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200496 int len = strlen(token);
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200497 int cr = len > 0 && token[len - 1] == '\r';
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200498
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800499 if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) {
500 patch_mgcp(output, "CRCX", token, endpoint, len, cr);
501 } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) {
502 patch_mgcp(output, "DLCX", token, endpoint, len, cr);
503 } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) {
504 patch_mgcp(output, "MDCX", token, endpoint, len, cr);
505 } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200506 output->l3h = msgb_put(output, strlen(ip_str));
507 memcpy(output->l3h, ip_str, strlen(ip_str));
508 output->l3h = msgb_put(output, strlen(ip));
509 memcpy(output->l3h, ip, strlen(ip));
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200510
511 if (cr) {
512 output->l3h = msgb_put(output, 2);
513 output->l3h[0] = '\r';
514 output->l3h[1] = '\n';
515 } else {
516 output->l3h = msgb_put(output, 1);
517 output->l3h[0] = '\n';
518 }
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200519 } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
520 int payload;
521 if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
522 LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
523 msgb_free(output);
524 return NULL;
525 }
526
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200527 snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d%s",
528 port, payload, cr ? "\r\n" : "\n");
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200529 buf[sizeof(buf)-1] = '\0';
530
531 output->l3h = msgb_put(output, strlen(buf));
532 memcpy(output->l3h, buf, strlen(buf));
533 } else {
534 output->l3h = msgb_put(output, len + 1);
535 memcpy(output->l3h, token, len);
536 output->l3h[len] = '\n';
537 }
538 }
539
540 return output;
541}
542
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200543static int mgcp_do_read(struct bsc_fd *fd)
544{
545 struct bsc_nat *nat;
546 struct msgb *msg, *resp;
547 int rc;
548
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200549 nat = fd->data;
550
551 rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1);
552 if (rc <= 0) {
553 LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
554 return -1;
555 }
556
557 nat->mgcp_msg[rc] = '\0';
558 nat->mgcp_length = rc;
559
560 msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read");
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200561 if (!msg) {
562 LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
563 return -1;
564 }
565
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200566 msg->l2h = msgb_put(msg, rc);
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200567 memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200568 resp = mgcp_handle_message(nat->mgcp_cfg, msg);
569 msgb_free(msg);
570
571 /* we do have a direct answer... e.g. AUEP */
572 if (resp) {
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800573 if (write_queue_enqueue(&nat->mgcp_cfg->gw_fd, resp) != 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200574 LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
575 msgb_free(resp);
576 }
577 }
578
579 return 0;
580}
581
582static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
583{
584 int rc;
585
586 rc = write(bfd->fd, msg->data, msg->len);
587
588 if (rc != msg->len) {
589 LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
590 return -1;
591 }
592
593 return rc;
594}
595
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800596int bsc_mgcp_nat_init(struct bsc_nat *nat)
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200597{
598 int on;
599 struct sockaddr_in addr;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800600 struct mgcp_config *cfg = nat->mgcp_cfg;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200601
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800602 if (!cfg->call_agent_addr) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200603 LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
604 return -1;
605 }
606
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800607 if (cfg->bts_ip) {
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200608 LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
609 return -1;
610 }
611
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800612 cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
613 if (cfg->gw_fd.bfd.fd < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200614 LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
615 return -1;
616 }
617
618 on = 1;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800619 setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200620
621 addr.sin_family = AF_INET;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800622 addr.sin_port = htons(cfg->source_port);
623 inet_aton(cfg->source_addr, &addr.sin_addr);
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200624
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800625 if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200626 LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800627 close(cfg->gw_fd.bfd.fd);
628 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200629 return -1;
630 }
631
632 addr.sin_port = htons(2727);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800633 inet_aton(cfg->call_agent_addr, &addr.sin_addr);
634 if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200635 LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800636 cfg->call_agent_addr, errno);
637 close(cfg->gw_fd.bfd.fd);
638 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200639 return -1;
640 }
641
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800642 write_queue_init(&cfg->gw_fd, 10);
643 cfg->gw_fd.bfd.when = BSC_FD_READ;
644 cfg->gw_fd.bfd.data = nat;
645 cfg->gw_fd.read_cb = mgcp_do_read;
646 cfg->gw_fd.write_cb = mgcp_do_write;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200647
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800648 if (bsc_register_fd(&cfg->gw_fd.bfd) != 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200649 LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800650 close(cfg->gw_fd.bfd.fd);
651 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200652 return -1;
653 }
654
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200655 /* some more MGCP config handling */
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800656 cfg->data = nat;
657 cfg->policy_cb = bsc_mgcp_policy_cb;
658 cfg->force_realloc = 1;
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000659
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800660 if (cfg->bts_ip)
661 talloc_free(cfg->bts_ip);
662 cfg->bts_ip = "";
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000663
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200664 nat->bsc_endpoints = talloc_zero_array(nat,
665 struct bsc_endpoint,
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800666 cfg->number_endpoints + 1);
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800667 if (!nat->bsc_endpoints) {
668 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800669 close(cfg->gw_fd.bfd.fd);
670 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800671 return -1;
672 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200673
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +0800674 if (mgcp_reset_transcoder(cfg) < 0) {
675 LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n");
676 talloc_free(nat->bsc_endpoints);
677 nat->bsc_endpoints = NULL;
678 close(cfg->gw_fd.bfd.fd);
679 cfg->gw_fd.bfd.fd = -1;
680 return -1;
681 }
682
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200683 return 0;
684}
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200685
686void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
687{
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800688 struct rate_ctr *ctr = NULL;
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200689 int i;
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800690
691 if (bsc->cfg)
692 ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS];
693
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200694 for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
695 struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i];
696
697 if (bsc_endp->bsc != bsc)
698 continue;
699
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800700 if (ctr)
701 rate_ctr_inc(ctr);
702
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800703 bsc_mgcp_free_endpoint(bsc->nat, i);
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200704 mgcp_free_endp(&bsc->nat->mgcp_cfg->endpoints[i]);
705 }
706}