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