blob: 3639a7b009d167238f5388d2b4a5a0212ad3e4ad [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>
23#include <openbsc/gsm_data.h>
24#include <openbsc/bssap.h>
25#include <openbsc/debug.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
29#include <netinet/in.h>
30#include <arpa/inet.h>
31
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +020032#include <errno.h>
33#include <unistd.h>
34
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +080035int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
36{
37 struct tlv_parsed tp;
38 u_int16_t cic;
39 u_int8_t timeslot;
40 u_int8_t multiplex;
41
42 if (!msg->l3h) {
43 LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
44 return -1;
45 }
46
47 if (msgb_l3len(msg) < 3) {
48 LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
49 return -1;
50 }
51
52 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
53 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
54 LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
55 return -1;
56 }
57
58 cic = ntohs(*(u_int16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
59 timeslot = cic & 0x1f;
60 multiplex = (cic & ~0x1f) >> 5;
61
62 con->msc_timeslot = (32 * multiplex) + timeslot;
63 con->bsc_timeslot = con->msc_timeslot;
64 return 0;
65}
66
67void bsc_mgcp_clear(struct sccp_connections *con)
68{
69 con->msc_timeslot = -1;
70 con->bsc_timeslot = -1;
71}
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +020072
73void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
74{
75 int i;
76
77 for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i)
78 mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
79}
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +020080
Holger Hans Peter Freytherfc9bd232010-04-01 03:55:27 +020081struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
82{
83 struct sccp_connections *sccp;
84
85 llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
86 if (sccp->msc_timeslot == -1)
87 continue;
88 if (mgcp_timeslot_to_endpoint(0, sccp->msc_timeslot) != endpoint)
89 continue;
90
91 return sccp->bsc;
92 }
93
94 LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
95 return NULL;
96}
97
Holger Hans Peter Freyther76c83542010-04-01 06:48:52 +020098/* we need to replace some strings... */
99struct msgb *bsc_mgcp_rewrite(struct msgb *input, const char *ip, int port)
100{
101 static const char *ip_str = "c=IN IP4 ";
102 static const char *aud_str = "m=audio ";
103
104 char buf[128];
105 char *running, *token;
106 struct msgb *output;
107
108 if (msgb_l2len(input) > 4096 - 128) {
109 LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
110 return NULL;
111 }
112
113 output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
114 if (!output) {
115 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
116 return NULL;
117 }
118
119 running = (char *) input->l2h;
120 output->l2h = output->data;
121 for (token = strsep(&running, "\n"); token; token = strsep(&running, "\n")) {
122 int len = strlen(token);
123
124 /* ignore completely empty lines for now */
125 if (len == 0)
126 continue;
127
128 if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
129 output->l3h = msgb_put(output, strlen(ip_str));
130 memcpy(output->l3h, ip_str, strlen(ip_str));
131 output->l3h = msgb_put(output, strlen(ip));
132 memcpy(output->l3h, ip, strlen(ip));
133 output->l3h = msgb_put(output, 2);
134 output->l3h[0] = '\r';
135 output->l3h[1] = '\n';
136 } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
137 int payload;
138 if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
139 LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
140 msgb_free(output);
141 return NULL;
142 }
143
144 snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d\r\n", port, payload);
145 buf[sizeof(buf)-1] = '\0';
146
147 output->l3h = msgb_put(output, strlen(buf));
148 memcpy(output->l3h, buf, strlen(buf));
149 } else {
150 output->l3h = msgb_put(output, len + 1);
151 memcpy(output->l3h, token, len);
152 output->l3h[len] = '\n';
153 }
154 }
155
156 return output;
157}
158
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200159static int mgcp_do_read(struct bsc_fd *fd)
160{
161 struct bsc_nat *nat;
162 struct msgb *msg, *resp;
163 int rc;
164
165 msg = msgb_alloc(4096, "MGCP GW Read");
166 if (!msg) {
167 LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
168 return -1;
169 }
170
171
172 rc = read(fd->fd, msg->data, msg->data_len);
173 if (rc <= 0) {
174 LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
175 msgb_free(msg);
176 return -1;
177 }
178
179 nat = fd->data;
180 msg->l2h = msgb_put(msg, rc);
181 resp = mgcp_handle_message(nat->mgcp_cfg, msg);
182 msgb_free(msg);
183
184 /* we do have a direct answer... e.g. AUEP */
185 if (resp) {
186 if (write_queue_enqueue(&nat->mgcp_queue, resp) != 0) {
187 LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
188 msgb_free(resp);
189 }
190 }
191
192 return 0;
193}
194
195static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
196{
197 int rc;
198
199 rc = write(bfd->fd, msg->data, msg->len);
200
201 if (rc != msg->len) {
202 LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
203 return -1;
204 }
205
206 return rc;
207}
208
209int bsc_mgcp_init(struct bsc_nat *nat)
210{
211 int on;
212 struct sockaddr_in addr;
213
214 if (!nat->mgcp_cfg->call_agent_addr) {
215 LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
216 return -1;
217 }
218
219 nat->mgcp_queue.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
220 if (nat->mgcp_queue.bfd.fd < 0) {
221 LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
222 return -1;
223 }
224
225 on = 1;
226 setsockopt(nat->mgcp_queue.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
227
228 addr.sin_family = AF_INET;
229 addr.sin_port = htons(nat->mgcp_cfg->source_port);
230 inet_aton(nat->mgcp_cfg->source_addr, &addr.sin_addr);
231
232 if (bind(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
233 LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
234 close(nat->mgcp_queue.bfd.fd);
235 nat->mgcp_queue.bfd.fd = -1;
236 return -1;
237 }
238
239 addr.sin_port = htons(2727);
240 inet_aton(nat->mgcp_cfg->call_agent_addr, &addr.sin_addr);
241 if (connect(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
242 LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
243 nat->mgcp_cfg->call_agent_addr, errno);
244 close(nat->mgcp_queue.bfd.fd);
245 nat->mgcp_queue.bfd.fd = -1;
246 return -1;
247 }
248
249 write_queue_init(&nat->mgcp_queue, 10);
250 nat->mgcp_queue.bfd.when = BSC_FD_READ;
251 nat->mgcp_queue.bfd.data = nat;
252 nat->mgcp_queue.read_cb = mgcp_do_read;
253 nat->mgcp_queue.write_cb = mgcp_do_write;
254
255 if (bsc_register_fd(&nat->mgcp_queue.bfd) != 0) {
256 LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
257 close(nat->mgcp_queue.bfd.fd);
258 nat->mgcp_queue.bfd.fd = -1;
259 return -1;
260 }
261
262 return 0;
263}