blob: 0f45a91a5dc788dcfff22a0647e4100fe2dc6369 [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 Freythera7f80182010-03-31 13:02:22 +020098static int mgcp_do_read(struct bsc_fd *fd)
99{
100 struct bsc_nat *nat;
101 struct msgb *msg, *resp;
102 int rc;
103
104 msg = msgb_alloc(4096, "MGCP GW Read");
105 if (!msg) {
106 LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
107 return -1;
108 }
109
110
111 rc = read(fd->fd, msg->data, msg->data_len);
112 if (rc <= 0) {
113 LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
114 msgb_free(msg);
115 return -1;
116 }
117
118 nat = fd->data;
119 msg->l2h = msgb_put(msg, rc);
120 resp = mgcp_handle_message(nat->mgcp_cfg, msg);
121 msgb_free(msg);
122
123 /* we do have a direct answer... e.g. AUEP */
124 if (resp) {
125 if (write_queue_enqueue(&nat->mgcp_queue, resp) != 0) {
126 LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
127 msgb_free(resp);
128 }
129 }
130
131 return 0;
132}
133
134static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
135{
136 int rc;
137
138 rc = write(bfd->fd, msg->data, msg->len);
139
140 if (rc != msg->len) {
141 LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
142 return -1;
143 }
144
145 return rc;
146}
147
148int bsc_mgcp_init(struct bsc_nat *nat)
149{
150 int on;
151 struct sockaddr_in addr;
152
153 if (!nat->mgcp_cfg->call_agent_addr) {
154 LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
155 return -1;
156 }
157
158 nat->mgcp_queue.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
159 if (nat->mgcp_queue.bfd.fd < 0) {
160 LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
161 return -1;
162 }
163
164 on = 1;
165 setsockopt(nat->mgcp_queue.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
166
167 addr.sin_family = AF_INET;
168 addr.sin_port = htons(nat->mgcp_cfg->source_port);
169 inet_aton(nat->mgcp_cfg->source_addr, &addr.sin_addr);
170
171 if (bind(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
172 LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
173 close(nat->mgcp_queue.bfd.fd);
174 nat->mgcp_queue.bfd.fd = -1;
175 return -1;
176 }
177
178 addr.sin_port = htons(2727);
179 inet_aton(nat->mgcp_cfg->call_agent_addr, &addr.sin_addr);
180 if (connect(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
181 LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
182 nat->mgcp_cfg->call_agent_addr, errno);
183 close(nat->mgcp_queue.bfd.fd);
184 nat->mgcp_queue.bfd.fd = -1;
185 return -1;
186 }
187
188 write_queue_init(&nat->mgcp_queue, 10);
189 nat->mgcp_queue.bfd.when = BSC_FD_READ;
190 nat->mgcp_queue.bfd.data = nat;
191 nat->mgcp_queue.read_cb = mgcp_do_read;
192 nat->mgcp_queue.write_cb = mgcp_do_write;
193
194 if (bsc_register_fd(&nat->mgcp_queue.bfd) != 0) {
195 LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
196 close(nat->mgcp_queue.bfd.fd);
197 nat->mgcp_queue.bfd.fd = -1;
198 return -1;
199 }
200
201 return 0;
202}