blob: 4df5621ed5aa596bc0893738c9a4e7bc10bd958b [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
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +08009 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080018 *
19 */
20
21#include <openbsc/bsc_nat.h>
Holger Hans Peter Freytherc2b31ed2010-07-31 05:17:17 +080022#include <openbsc/bsc_nat_sccp.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080023#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080024#include <openbsc/debug.h>
Holger Hans Peter Freyther19c530c2010-10-13 23:52:01 +020025#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +020026#include <openbsc/mgcp.h>
27#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080028
Harald Welted5db12c2010-08-03 15:11:51 +020029#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +080030
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +020031#include <osmocore/talloc.h>
Holger Hans Peter Freyther13959482010-06-15 18:50:57 +080032#include <osmocore/gsm0808.h>
Holger Hans Peter Freyther69d801e2010-06-15 20:13:33 +080033#include <osmocore/protocol/gsm_08_08.h>
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +020034
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080035#include <netinet/in.h>
36#include <arpa/inet.h>
37
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +020038#include <errno.h>
39#include <unistd.h>
40
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010041static int bsc_init_endps_if_needed(struct bsc_connection *con)
42{
43 /* we have done that */
44 if (con->_endpoint_status)
45 return 0;
46
47 /* we have no config... */
48 if (!con->cfg)
49 return -1;
50
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +010051 con->number_multiplexes = con->cfg->number_multiplexes;
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010052 con->_endpoint_status = talloc_zero_array(con, char,
53 (32 * con->cfg->number_multiplexes) + 1);
54 return con->_endpoint_status == NULL;
55}
56
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080057static int bsc_assign_endpoint(struct bsc_connection *bsc, struct sccp_connections *con)
58{
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +010059 int multiplex;
60 int timeslot;
61 const int number_endpoints = 32 * bsc->number_multiplexes;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080062 int i;
63
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +010064 mgcp_endpoint_to_timeslot(bsc->last_endpoint, &multiplex, &timeslot);
65 timeslot += 1;
66
67 for (i = 0; i < number_endpoints; ++i) {
68 int endpoint;
69
70 /* Wrap around timeslots */
71 if (timeslot == 0)
72 timeslot = 1;
73
74 if (timeslot == 0x1f) {
75 timeslot = 1;
76 multiplex += 1;
77 }
78
79 /* Wrap around the multiplex */
80 if (multiplex >= bsc->number_multiplexes)
81 multiplex = 0;
82
83 endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080084
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +010085 if (bsc->_endpoint_status[endpoint] == 0) {
86 bsc->_endpoint_status[endpoint] = 1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080087 con->bsc_endp = endpoint;
88 bsc->last_endpoint = endpoint;
89 return 0;
90 }
Holger Hans Peter Freythera9e93312011-02-26 11:38:00 +010091
92 timeslot += 1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +080093 }
94
95 return -1;
96}
97
98static uint16_t create_cic(int endpoint)
99{
100 int timeslot, multiplex;
101
102 mgcp_endpoint_to_timeslot(endpoint, &multiplex, &timeslot);
103 return (multiplex << 5) | (timeslot & 0x1f);
104}
105
106int bsc_mgcp_assign_patch(struct sccp_connections *con, struct msgb *msg)
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800107{
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800108 struct sccp_connections *mcon;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800109 struct tlv_parsed tp;
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +0800110 uint16_t cic;
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +0800111 uint8_t timeslot;
112 uint8_t multiplex;
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +0100113 unsigned int endp;
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800114
115 if (!msg->l3h) {
116 LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
117 return -1;
118 }
119
120 if (msgb_l3len(msg) < 3) {
121 LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
122 return -1;
123 }
124
125 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
126 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
127 LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
128 return -1;
129 }
130
Holger Hans Peter Freythere2c15202010-07-23 19:09:21 +0800131 cic = ntohs(*(uint16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800132 timeslot = cic & 0x1f;
133 multiplex = (cic & ~0x1f) >> 5;
134
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800135
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800136 endp = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800137
Holger Hans Peter Freyther14069772010-11-04 17:14:41 +0100138 if (endp >= con->bsc->nat->mgcp_cfg->number_endpoints) {
139 LOGP(DNAT, LOGL_ERROR,
140 "MSC attempted to assign bad endpoint 0x%x\n",
141 endp);
142 return -1;
143 }
144
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800145 /* find stale connections using that endpoint */
146 llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800147 if (mcon->msc_endp == endp) {
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800148 LOGP(DNAT, LOGL_ERROR,
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800149 "Endpoint %d was assigned to 0x%x and now 0x%x\n",
150 endp,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800151 sccp_src_ref_to_int(&mcon->patched_ref),
152 sccp_src_ref_to_int(&con->patched_ref));
153 bsc_mgcp_dlcx(mcon);
154 }
155 }
156
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800157 con->msc_endp = endp;
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100158 if (bsc_init_endps_if_needed(con->bsc) != 0)
159 return -1;
Holger Hans Peter Freyther45fd07d2010-08-28 18:22:14 +0800160 if (bsc_assign_endpoint(con->bsc, con) != 0)
161 return -1;
162
163 /*
164 * now patch the message for the new CIC...
165 * still assumed to be one multiplex only
166 */
167 cic = htons(create_cic(con->bsc_endp));
168 memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE),
169 &cic, sizeof(cic));
170
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800171 return 0;
172}
173
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800174static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200175{
176 if (nat->bsc_endpoints[i].transaction_id) {
177 talloc_free(nat->bsc_endpoints[i].transaction_id);
178 nat->bsc_endpoints[i].transaction_id = NULL;
179 }
180
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800181 nat->bsc_endpoints[i].transaction_state = 0;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200182 nat->bsc_endpoints[i].bsc = NULL;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200183}
184
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200185void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
186{
187 int i;
188
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800189 for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i){
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200190 bsc_mgcp_free_endpoint(nat, i);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800191 mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
192 }
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200193}
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200194
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800195/* send a MDCX where we do not want a response */
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800196static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp)
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800197{
198 char buf[2096];
199 int len;
200
201 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherf42f45b2010-04-22 13:06:24 +0800202 "MDCX 23 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800203 "Z: noanswer\r\n"
204 "\r\n"
205 "c=IN IP4 %s\r\n"
206 "m=audio %d RTP/AVP 255\r\n",
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800207 port,
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800208 bsc->nat->mgcp_cfg->source_addr,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800209 endp->bts_end.local_port);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800210 if (len < 0) {
211 LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
212 return;
213 }
Holger Hans Peter Freytherd38aa452010-08-30 11:58:49 +0800214
215 #warning "The MDCX is not send to the BSC. It should"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800216}
217
218static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
219{
220 char buf[2096];
221 int len;
222
223 len = snprintf(buf, sizeof(buf),
Holger Hans Peter Freytherbf812fa2010-08-30 12:01:36 +0800224 "DLCX 26 %x@mgw MGCP 1.0\r\n"
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800225 "Z: noanswer\r\n", endpoint);
226 if (len < 0) {
227 LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
228 return;
229 }
230
Holger Hans Peter Freytherdbd16fe2010-07-23 19:08:55 +0800231 bsc_write_mgcp(bsc, (uint8_t *) buf, len);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800232}
233
234void bsc_mgcp_init(struct sccp_connections *con)
235{
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800236 con->msc_endp = -1;
237 con->bsc_endp = -1;
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800238}
239
240void bsc_mgcp_dlcx(struct sccp_connections *con)
241{
242 /* send a DLCX down the stream */
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100243 if (con->bsc_endp != -1 && con->bsc->_endpoint_status) {
244 if (con->bsc->_endpoint_status[con->bsc_endp] != 1)
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800245 LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp);
Holger Hans Peter Freythered500e32011-02-25 17:09:07 +0100246 con->bsc->_endpoint_status[con->bsc_endp] = 0;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800247 bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp);
248 bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800249 }
250
251 bsc_mgcp_init(con);
252}
253
254
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800255struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200256{
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800257 struct sccp_connections *con = NULL;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200258 struct sccp_connections *sccp;
259
260 llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800261 if (sccp->msc_endp == -1)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200262 continue;
Holger Hans Peter Freytherf4b34392010-08-28 16:08:39 +0800263 if (sccp->msc_endp != endpoint)
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200264 continue;
265
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800266 con = sccp;
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200267 }
268
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800269 if (con)
270 return con;
Holger Hans Peter Freythereb52e892010-04-18 02:14:45 +0800271
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +0200272 LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
273 return NULL;
274}
275
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200276int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const char *transaction_id)
277{
278 struct bsc_nat *nat;
279 struct bsc_endpoint *bsc_endp;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800280 struct sccp_connections *sccp;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200281 struct mgcp_endpoint *mgcp_endp;
282 struct msgb *bsc_msg;
283
284 nat = cfg->data;
285 bsc_endp = &nat->bsc_endpoints[endpoint];
286 mgcp_endp = &nat->mgcp_cfg->endpoints[endpoint];
287
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800288 if (bsc_endp->transaction_id) {
289 LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
290 endpoint, bsc_endp->transaction_id);
291 talloc_free(bsc_endp->transaction_id);
292 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800293 bsc_endp->transaction_state = 0;
Holger Hans Peter Freytherfef76122010-04-24 21:05:18 +0800294 }
295 bsc_endp->bsc = NULL;
296
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800297 sccp = bsc_mgcp_find_con(nat, endpoint);
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200298
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800299 if (!sccp) {
Holger Hans Peter Freyther3d194d92010-04-24 21:02:01 +0800300 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 +0200301
302 switch (state) {
303 case MGCP_ENDP_CRCX:
304 return MGCP_POLICY_REJECT;
305 break;
306 case MGCP_ENDP_DLCX:
307 return MGCP_POLICY_CONT;
308 break;
309 case MGCP_ENDP_MDCX:
310 return MGCP_POLICY_CONT;
311 break;
312 default:
313 LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
314 return MGCP_POLICY_CONT;
315 break;
316 }
317 }
318
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200319 /* we need to generate a new and patched message */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800320 bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, sccp->bsc_endp,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800321 nat->mgcp_cfg->source_addr, mgcp_endp->bts_end.local_port);
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200322 if (!bsc_msg) {
323 LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
324 return MGCP_POLICY_CONT;
325 }
326
327
Holger Hans Peter Freytherb3e0a032010-04-04 18:11:49 +0200328 bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800329 bsc_endp->transaction_state = state;
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800330 bsc_endp->bsc = sccp->bsc;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200331
332 /* we need to update some bits */
333 if (state == MGCP_ENDP_CRCX) {
334 struct sockaddr_in sock;
335 socklen_t len = sizeof(sock);
Holger Hans Peter Freyther08a1b162010-04-18 02:26:16 +0800336 if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
Holger Hans Peter Freyther92febd32010-04-06 11:17:07 +0200337 LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
338 errno, strerror(errno));
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200339 } else {
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800340 mgcp_endp->bts_end.addr = sock.sin_addr;
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200341 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200342
Holger Hans Peter Freythere66cac32010-08-05 01:50:44 +0800343 /* send the message and a fake MDCX to force sending of a dummy packet */
Holger Hans Peter Freyther368a0a72011-01-07 16:54:46 +0100344 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
Holger Hans Peter Freyther601180f2010-08-29 23:40:33 +0800345 bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800346 return MGCP_POLICY_DEFER;
347 } else if (state == MGCP_ENDP_DLCX) {
348 /* we will free the endpoint now and send a DLCX to the BSC */
Holger Hans Peter Freyther3a347f02010-05-01 10:31:53 +0800349 msgb_free(bsc_msg);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800350 bsc_mgcp_dlcx(sccp);
351 return MGCP_POLICY_CONT;
352 } else {
Holger Hans Peter Freyther368a0a72011-01-07 16:54:46 +0100353 bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800354 return MGCP_POLICY_DEFER;
355 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200356}
357
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200358/*
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800359 * We do have a failure, free data downstream..
360 */
361static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp,
362 struct bsc_connection *bsc)
363{
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800364 LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n",
365 ENDPOINT_NUMBER(endp), bsc_endp->transaction_state);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800366
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800367 /* if a CRCX failed... send a DLCX down the stream */
368 if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) {
369 struct sccp_connections *con;
370 con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp));
371 if (!con) {
372 LOGP(DMGCP, LOGL_ERROR,
373 "No SCCP connection for endp 0x%x\n",
374 ENDPOINT_NUMBER(endp));
375 } else {
376 if (con->bsc == bsc) {
Holger Hans Peter Freyther8574dcf2010-08-29 22:39:07 +0800377 bsc_mgcp_send_dlcx(bsc, con->bsc_endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800378 } else {
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800379 LOGP(DMGCP, LOGL_ERROR,
380 "Endpoint belongs to a different BSC\n");
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800381 }
382 }
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800383 }
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800384
Holger Hans Peter Freytherc021fbe2010-08-28 16:46:27 +0800385 bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp));
386 mgcp_free_endp(endp);
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800387}
388
389/*
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200390 * We have received a msg from the BSC. We will see if we know
391 * this transaction and if it belongs to the BSC. Then we will
392 * need to patch the content to point to the local network and we
393 * need to update the I: that was assigned by the BSS.
394 */
395void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
396{
397 struct msgb *output;
398 struct bsc_endpoint *bsc_endp = NULL;
399 struct mgcp_endpoint *endp = NULL;
Holger Hans Peter Freytherd2dd6e82010-04-06 11:06:11 +0200400 int i, code;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200401 char transaction_id[60];
402
403 /* Some assumption that our buffer is big enough.. and null terminate */
404 if (msgb_l2len(msg) > 2000) {
405 LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n");
406 return;
407 }
408
409 msg->l2h[msgb_l2len(msg)] = '\0';
410
411 if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) {
412 LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n");
413 return;
414 }
415
416 for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
417 if (bsc->nat->bsc_endpoints[i].bsc != bsc)
418 continue;
Holger Hans Peter Freyther3f7c7d02010-04-05 18:00:05 +0200419 /* no one listening? a bug? */
420 if (!bsc->nat->bsc_endpoints[i].transaction_id)
421 continue;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200422 if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
423 continue;
424
425 endp = &bsc->nat->mgcp_cfg->endpoints[i];
426 bsc_endp = &bsc->nat->bsc_endpoints[i];
427 break;
428 }
429
430 if (!bsc_endp) {
Holger Hans Peter Freytherb9ac37d2010-04-05 17:58:52 +0200431 LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n",
432 transaction_id, (const char *) msg->l2h);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200433 return;
434 }
435
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800436 endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800437 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther7d476012010-08-06 19:16:34 +0800438 free_chan_downstream(endp, bsc_endp, bsc);
Holger Hans Peter Freytherb84b5f62010-08-06 08:34:46 +0800439 return;
440 }
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200441
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200442 /* free some stuff */
443 talloc_free(bsc_endp->transaction_id);
444 bsc_endp->transaction_id = NULL;
Holger Hans Peter Freyther5b2726e2010-08-06 09:05:05 +0800445 bsc_endp->transaction_state = 0;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200446
Holger Hans Peter Freytherdd16b422010-04-07 09:53:54 +0200447 /*
448 * rewrite the information. In case the endpoint was deleted
449 * there should be nothing for us to rewrite so putting endp->rtp_port
450 * with the value of 0 should be no problem.
451 */
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800452 output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1,
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800453 bsc->nat->mgcp_cfg->source_addr, endp->net_end.local_port);
Holger Hans Peter Freyther5cc94fb2010-04-05 22:56:49 +0200454
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200455 if (!output) {
456 LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
457 return;
458 }
459
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800460 if (write_queue_enqueue(&bsc->nat->mgcp_cfg->gw_fd, output) != 0) {
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200461 LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
462 msgb_free(output);
463 }
464}
465
466int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
467{
468 /* we want to parse two strings */
469 return sscanf(str, "%3d %59s\n", code, transaction) != 2;
470}
471
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800472uint32_t bsc_mgcp_extract_ci(const char *str)
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200473{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800474 unsigned int ci;
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200475 char *res = strstr(str, "I: ");
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800476 if (!res) {
477 LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200478 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800479 }
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200480
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800481 if (sscanf(res, "I: %u", &ci) != 1) {
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800482 LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str);
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200483 return CI_UNUSED;
Holger Hans Peter Freyther9c31cfc2010-08-06 08:19:05 +0800484 }
485
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200486 return ci;
487}
488
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800489static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
490 int endp, int len, int cr)
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200491{
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800492 int slen;
493 int ret;
494 char buf[40];
495
496 buf[0] = buf[39] = '\0';
497 ret = sscanf(tok, "%*s %s", buf);
498
499 slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s",
500 op, buf, endp, cr ? "\r\n" : "\n");
501 output->l3h = msgb_put(output, slen);
502}
503
504/* we need to replace some strings... */
505struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint, const char *ip, int port)
506{
507 static const char *crcx_str = "CRCX ";
508 static const char *dlcx_str = "DLCX ";
509 static const char *mdcx_str = "MDCX ";
510
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200511 static const char *ip_str = "c=IN IP4 ";
512 static const char *aud_str = "m=audio ";
513
514 char buf[128];
515 char *running, *token;
516 struct msgb *output;
517
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200518 if (length > 4096 - 128) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200519 LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
520 return NULL;
521 }
522
523 output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
524 if (!output) {
525 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
526 return NULL;
527 }
528
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200529 running = input;
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200530 output->l2h = output->data;
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800531 output->l3h = output->l2h;
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200532 for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200533 int len = strlen(token);
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200534 int cr = len > 0 && token[len - 1] == '\r';
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200535
Holger Hans Peter Freytherf7c86c52010-08-30 13:44:32 +0800536 if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) {
537 patch_mgcp(output, "CRCX", token, endpoint, len, cr);
538 } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) {
539 patch_mgcp(output, "DLCX", token, endpoint, len, cr);
540 } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) {
541 patch_mgcp(output, "MDCX", token, endpoint, len, cr);
542 } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200543 output->l3h = msgb_put(output, strlen(ip_str));
544 memcpy(output->l3h, ip_str, strlen(ip_str));
545 output->l3h = msgb_put(output, strlen(ip));
546 memcpy(output->l3h, ip, strlen(ip));
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200547
548 if (cr) {
549 output->l3h = msgb_put(output, 2);
550 output->l3h[0] = '\r';
551 output->l3h[1] = '\n';
552 } else {
553 output->l3h = msgb_put(output, 1);
554 output->l3h[0] = '\n';
555 }
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200556 } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
557 int payload;
558 if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
559 LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
560 msgb_free(output);
561 return NULL;
562 }
563
Holger Hans Peter Freyther9e5300a2010-04-04 19:34:44 +0200564 snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d%s",
565 port, payload, cr ? "\r\n" : "\n");
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +0200566 buf[sizeof(buf)-1] = '\0';
567
568 output->l3h = msgb_put(output, strlen(buf));
569 memcpy(output->l3h, buf, strlen(buf));
570 } else {
571 output->l3h = msgb_put(output, len + 1);
572 memcpy(output->l3h, token, len);
573 output->l3h[len] = '\n';
574 }
575 }
576
577 return output;
578}
579
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200580static int mgcp_do_read(struct bsc_fd *fd)
581{
582 struct bsc_nat *nat;
583 struct msgb *msg, *resp;
584 int rc;
585
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200586 nat = fd->data;
587
588 rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1);
589 if (rc <= 0) {
590 LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
591 return -1;
592 }
593
594 nat->mgcp_msg[rc] = '\0';
595 nat->mgcp_length = rc;
596
597 msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read");
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200598 if (!msg) {
599 LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
600 return -1;
601 }
602
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200603 msg->l2h = msgb_put(msg, rc);
Holger Hans Peter Freyther8d200652010-04-04 18:09:10 +0200604 memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200605 resp = mgcp_handle_message(nat->mgcp_cfg, msg);
606 msgb_free(msg);
607
608 /* we do have a direct answer... e.g. AUEP */
609 if (resp) {
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800610 if (write_queue_enqueue(&nat->mgcp_cfg->gw_fd, resp) != 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200611 LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
612 msgb_free(resp);
613 }
614 }
615
616 return 0;
617}
618
619static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
620{
621 int rc;
622
623 rc = write(bfd->fd, msg->data, msg->len);
624
625 if (rc != msg->len) {
626 LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
627 return -1;
628 }
629
630 return rc;
631}
632
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800633int bsc_mgcp_nat_init(struct bsc_nat *nat)
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200634{
635 int on;
636 struct sockaddr_in addr;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800637 struct mgcp_config *cfg = nat->mgcp_cfg;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200638
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800639 if (!cfg->call_agent_addr) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200640 LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
641 return -1;
642 }
643
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800644 if (cfg->bts_ip) {
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200645 LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
646 return -1;
647 }
648
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800649 cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
650 if (cfg->gw_fd.bfd.fd < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200651 LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
652 return -1;
653 }
654
655 on = 1;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800656 setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200657
658 addr.sin_family = AF_INET;
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800659 addr.sin_port = htons(cfg->source_port);
660 inet_aton(cfg->source_addr, &addr.sin_addr);
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200661
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800662 if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200663 LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800664 close(cfg->gw_fd.bfd.fd);
665 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200666 return -1;
667 }
668
669 addr.sin_port = htons(2727);
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800670 inet_aton(cfg->call_agent_addr, &addr.sin_addr);
671 if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200672 LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800673 cfg->call_agent_addr, errno);
674 close(cfg->gw_fd.bfd.fd);
675 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200676 return -1;
677 }
678
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800679 write_queue_init(&cfg->gw_fd, 10);
680 cfg->gw_fd.bfd.when = BSC_FD_READ;
681 cfg->gw_fd.bfd.data = nat;
682 cfg->gw_fd.read_cb = mgcp_do_read;
683 cfg->gw_fd.write_cb = mgcp_do_write;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200684
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800685 if (bsc_register_fd(&cfg->gw_fd.bfd) != 0) {
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200686 LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800687 close(cfg->gw_fd.bfd.fd);
688 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200689 return -1;
690 }
691
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200692 /* some more MGCP config handling */
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800693 cfg->data = nat;
694 cfg->policy_cb = bsc_mgcp_policy_cb;
695 cfg->force_realloc = 1;
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000696
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800697 if (cfg->bts_ip)
698 talloc_free(cfg->bts_ip);
699 cfg->bts_ip = "";
Holger Hans Peter Freytherd5e6c232010-08-05 10:08:36 +0000700
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200701 nat->bsc_endpoints = talloc_zero_array(nat,
702 struct bsc_endpoint,
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800703 cfg->number_endpoints + 1);
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800704 if (!nat->bsc_endpoints) {
705 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n");
Holger Hans Peter Freyther249d69a2010-09-18 21:13:54 +0800706 close(cfg->gw_fd.bfd.fd);
707 cfg->gw_fd.bfd.fd = -1;
Holger Hans Peter Freyther3c792142010-09-19 04:34:04 +0800708 return -1;
709 }
Holger Hans Peter Freythera0df82d2010-04-01 08:21:33 +0200710
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +0800711 if (mgcp_reset_transcoder(cfg) < 0) {
712 LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n");
713 talloc_free(nat->bsc_endpoints);
714 nat->bsc_endpoints = NULL;
715 close(cfg->gw_fd.bfd.fd);
716 cfg->gw_fd.bfd.fd = -1;
717 return -1;
718 }
719
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200720 return 0;
721}
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200722
723void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
724{
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800725 struct rate_ctr *ctr = NULL;
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200726 int i;
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800727
728 if (bsc->cfg)
729 ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS];
730
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200731 for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
732 struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i];
733
734 if (bsc_endp->bsc != bsc)
735 continue;
736
Holger Hans Peter Freyther8330c1c2010-06-17 18:29:42 +0800737 if (ctr)
738 rate_ctr_inc(ctr);
739
Holger Hans Peter Freyther7b7eef62010-04-22 12:08:17 +0800740 bsc_mgcp_free_endpoint(bsc->nat, i);
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200741 mgcp_free_endp(&bsc->nat->mgcp_cfg->endpoints[i]);
742 }
743}