blob: e86390e2ef24dd623f13581ae583ac87be684d83 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* Use the UniPorte library to allocate endpoints */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010 by On-Waves
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <mgcp_ss7.h>
24#include <mgcp/mgcp.h>
25#include <mgcp/mgcp_internal.h>
26
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080027#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080028
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080029#include <osmocore/select.h>
30#include <osmocore/talloc.h>
31#include <osmocore/timer.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080032
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080033#include <osmocom/vty/command.h>
34#include <osmocom/vty/vty.h>
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +080035#include <osmocom/vty/telnet_interface.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080036
37/* uniporte includes */
38#ifndef NO_UNIPORTE
39#include <UniPorte.h>
40#include <BusMastHostApi.h>
41#include <MtnSa.h>
42#include <SystemLayer.h>
43#include <PredefMobs.h>
44#endif
45
46#include <errno.h>
47#include <limits.h>
48#include <string.h>
49#include <unistd.h>
50#include <signal.h>
51#include <netdb.h>
52
53#ifndef _GNU_SOURCE
54#define _GNU_SOURCE
55#endif
56#include <getopt.h>
57
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080058static struct log_target *stderr_target;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080059static char *config_file = "mgcp_mgw.cfg";
60static int exit_on_failure = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080061
62#define TO_MGW_PORT(no) (no-1)
63#define FROM_MGW_PORT(no) (no+1)
64
Holger Hans Peter Freytherf41617b2010-08-04 07:08:33 +080065static struct mgcp_config *g_cfg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080066static struct mgcp_ss7 *s_ss7;
67
68struct mgcp_ss7_endpoint {
69 unsigned int port;
70 int block;
71};
72
73static void mgcp_ss7_endp_free(struct mgcp_ss7* ss7, int endp);
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +080074static void mgcp_ss7_do_exec(struct mgcp_ss7 *mgcp, uint8_t type, uint32_t port, uint32_t param);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080075static void mgcp_mgw_vty_init();
76
77static void check_exit(int status)
78{
79 if (exit_on_failure && status == 21) {
80 LOGP(DMGCP, LOGL_ERROR, "Failure detected with the MGW. Exiting.\n");
81 exit(-1);
82 }
83}
84
85#ifndef NO_UNIPORTE
86static void Force_Poll( int milliseconds )
87{
88 int timeout = 0;
89 unsigned long startTime;
90
91 startTime = SysLyrGetTime();
92
93 /* Loop until the specified number of milliseconds
94 * have elapsed.
95 */
96 do {
97 MtnSaPoll();
98 SysLyrSleep( 20 );
99 } while ((SysLyrGetTime()-startTime)<(unsigned long)milliseconds);
100 return;
101}
102
103static char eventName[Event_TELEMETRY_DATA + 1][128] = {
104 { "Event_NOT_READY" },
105 { "Event_READY" },
106 { "Event_ANSWER" },
107 { "Event_OUTGOING_CALL" },
108 { "Event_ABORT" },
109 { "Event_CONNECT" },
110 { "Event_DISCONNECT" },
111 { "Event_MANAGED_OBJECT_GET_COMPLETE" },
112 { "Event_MANAGED_OBJECT_GET_AND_CLEAR_COMPLETE" },
113 { "Event_MANAGED_OBJECT_SET_COMPLETE" },
114 { "Event_MANAGED_OBJECT_TRAP" },
115 { "Event_PREDEF_MOB_SET_COMPLETE" },
116 { "Event_PREDEF_MOB_GET_COMPLETE" },
117 { "Event_USER_MOB_DEFINE_COMPLETE" },
118 { "Event_USER_MOB_SET_COMPLETE" },
119 { "Event_USER_MOB_GET_COMPLETE" },
120 { "Event_RECEIVE_DATA" },
121 { "Event_SEND_COMPLETE" },
122 { "Event_TDM_CONNECT_COMPLETE" },
123 { "Event_LOG" },
124 { "Event_DEVICE_IN_CONTACT" },
125 { "Event_DEVICE_MANAGED" },
126 { "Event_DEVICE_OUT_OF_CONTACT" },
127 { "Event_TELEMETRY_DATA" } };
128
129static char stateName[PortState_END_OF_ENUM][128] = {
130 { "PortState_IDLE" },
131 { "PortState_SIGNALING" },
132 { "PortState_INITIATING" },
133 { "PortState_LINK" },
134 { "PortState_TRAINING" },
135 { "PortState_EC_NEGOTIATING" },
136 { "PortState_DATA" },
137 { "PortState_RESYNCING" },
138 { "PortState_FAX" },
139 { "PortState_COMMAND_ESCAPE" },
140 { "PortState_TERMINATING" },
141 { "PortState_VOICE" },
142 { "PortState_PORT_RESET" },
143 { "PortState_DSP_RESET" },
144 { "PortState_ALLOCATED" },
145 { "PortState_OUT_OF_SERVICE" },
146 { "PortState_RECONFIGURE" },
147 { "PortState_ON_HOLD" } };
148static int uniporte_events(unsigned long port, EventTypeT event,
149 void *event_data, unsigned long event_data_length ) {
150 char text[128];
151 ManObjectInfoPtr info;
152 DataReceiveInfoPtr dataInfo;
153 int i;
154 ToneDetectionPtr tones;
155
156
157 /* Don't print output when we receive data or complete
158 * sending data. That would be too verbose.
159 */
160 if (event==Event_DEVICE_MANAGED) {
161 MtnSaSetManObject(0, ChannelType_ETHERNET, ManObj_C_MOE_COMM_LOSS_RESET_DELAY ,
162 10, 0);
163 }
164 else if (event==Event_MANAGED_OBJECT_TRAP ) {
165 info = (ManObjectInfoPtr)event_data;
166 if (info->trapId == Trap_PORT_STATE_CHANGE) {
167 sprintf(text, "Port #%ld, Change to state %s", port, stateName[info->value]);
168 puts(text);
169
170 /* update the mgcp state */
171 int mgcp_endp = FROM_MGW_PORT(port);
172 if (s_ss7->mgw_end[mgcp_endp].block != 1)
173 fprintf(stderr, "State change on a non blocked port. ERROR.\n");
174 s_ss7->mgw_end[mgcp_endp].block = 0;
175 }
176 }
177 else if ( event == Event_MANAGED_OBJECT_SET_COMPLETE ) {
178 info = (ManObjectInfoPtr)event_data;
179
180 sprintf(text, "Object %d value %d status %d", info->object, info->value,
181 info->status );
182 puts(text);
183 check_exit(info->status);
184 }
185 else if ( ( event == Event_USER_MOB_SET_COMPLETE ) ||
186 ( event == Event_USER_MOB_DEFINE_COMPLETE ) )
187 {
188 info = (ManObjectInfoPtr)event_data;
189
190 sprintf( text, "Mob ID %d status %d", info->MOBId, info->status );
191 puts(text);
192 check_exit(info->status);
193 }
194 else if ( event == Event_USER_MOB_GET_COMPLETE )
195 {
196 info = (ManObjectInfoPtr)event_data;
197
198 sprintf( text, "Mob ID %d status %d", info->MOBId, info->status );
199 puts(text);
200 check_exit(info->status);
201 }
202 else if (event == Event_CONNECT)
203 {
204 sprintf(text, "Port %d connected",port );
205 }
206 else if (event == Event_PREDEF_MOB_GET_COMPLETE)
207 {
208 info = (ManObjectInfoPtr)event_data;
209
210 sprintf(text, "Mob ID %d status %d", info->MOBId, info->status );
211 puts(text);
212 check_exit(info->status);
213 }
214
215 return( 0 );
216}
217
218static int initialize_uniporte(struct mgcp_ss7 *mgcp)
219{
220 ProfileT profile;
221 unsigned long mgw_address;
222 int rc;
223
224 LOGP(DMGCP, LOGL_NOTICE, "Initializing MGW on %s\n", mgcp->cfg->bts_ip);
225
226 MtnSaSetEthernetOnly();
227 rc = MtnSaStartup(uniporte_events);
228 if (rc != 0)
229 LOGP(DMGCP, LOGL_ERROR, "Failed to startup the MGW.\n");
230 SysEthGetHostAddress(mgcp->cfg->bts_ip, &mgw_address);
231 rc = MtnSaRegisterEthernetDevice(mgw_address, 0);
232 if (rc != 0)
233 LOGP(DMGCP, LOGL_ERROR, "Failed to register ethernet.\n");
234 Force_Poll(2000);
235 MtnSaTakeOverDevice(0);
236 Force_Poll(2000);
237 MtnSaSetReceiveTraps(1);
238 MtnSaSetTransparent();
239
240 /* change the voice profile to AMR */
241 MtnSaGetProfile(ProfileType_VOICE, 0, &profile);
242 profile.countryCode = CountryCode_INTERNAT_ALAW;
243 MtnSaSetProfile(ProfileType_VOICE, 0, &profile);
244
245 if (MtnSaGetPortCount() == 0)
246 return -1;
247
248 return 0;
249}
250
251
252static void* start_uniporte(void *_ss7) {
253 struct llist_head blocked;
254 struct mgcp_ss7_cmd *cmd, *tmp;
255 struct mgcp_ss7 *ss7 = _ss7;
256
257 s_ss7 = ss7;
258
259 if (initialize_uniporte(ss7) != 0) {
260 fprintf(stderr, "Failed to create Uniporte.\n");
261 exit(-1);
262 return 0;
263 }
264
265 fprintf(stderr, "Created the MGCP processing thread.\n");
266 INIT_LLIST_HEAD(&blocked);
267 for (;;) {
268 thread_swap(ss7->cmd_queue);
269start_over:
270 /* handle items that are currently blocked */
271 llist_for_each_entry_safe(cmd, tmp, &blocked, entry) {
272 if (ss7->mgw_end[cmd->port].block)
273 continue;
274
275 mgcp_ss7_do_exec(ss7, cmd->type, cmd->port, cmd->param);
276 llist_del(&cmd->entry);
277 free(cmd);
278
279 /* We might have unblocked something, make sure we operate in order */
280 MtnSaPoll();
281 goto start_over;
282 }
283
284 llist_for_each_entry_safe(cmd, tmp, ss7->cmd_queue->main_head, entry) {
285 if (ss7->mgw_end[cmd->port].block) {
286 llist_del(&cmd->entry);
287 llist_add_tail(&cmd->entry, &blocked);
288 continue;
289 }
290
291 mgcp_ss7_do_exec(ss7, cmd->type, cmd->port, cmd->param);
292 llist_del(&cmd->entry);
293 free(cmd);
294
295 /* We might have unblocked something, make sure we operate in order */
296 MtnSaPoll();
297 goto start_over;
298 }
299
300 Force_Poll(20);
301 }
302
303 return 0;
304}
305#endif
306
307static void update_mute_status(int mgw_port, int conn_mode)
308{
309#ifndef NO_UNIPORTE
310 if (conn_mode == MGCP_CONN_NONE) {
311 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 1, 0);
312 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 1, 0);
313 } else if (conn_mode == MGCP_CONN_RECV_ONLY) {
314 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 1, 0);
315 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 0, 0);
316 } else if (conn_mode == MGCP_CONN_SEND_ONLY) {
317 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 0, 0);
318 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 1, 0);
319 } else if (conn_mode == MGCP_CONN_RECV_SEND) {
320 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 0, 0);
321 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 0, 0);
322 } else {
323 LOGP(DMGCP, LOGL_ERROR, "Unhandled conn mode: %d\n", conn_mode);
324 }
325#endif
326}
327
328#ifndef NO_UNIPORTE
329static void allocate_endp(struct mgcp_ss7 *ss7, int endp_no)
330{
331 int mgw_port;
332 unsigned long mgw_address, loc_address;
333 struct mgcp_ss7_endpoint *mgw_endp = &ss7->mgw_end[endp_no];
334 struct mgcp_endpoint *mg_endp = &ss7->cfg->endpoints[endp_no];
335
336 mgw_port = TO_MGW_PORT(endp_no);
337 mgw_endp->port = MtnSaAllocate(mgw_port);
338 if (mgw_endp->port == UINT_MAX) {
339 fprintf(stderr, "Failed to allocate the port: %d\n", endp_no);
340 return;
341 }
342
343 /* Select AMR 5.9, Payload 98, no CRC, hardcoded */
344 MtnSaApplyProfile(mgw_port, ProfileType_VOICE, 0);
345 MtnSaSetManObject(mgw_port, ChannelType_PORT,
346 ManObj_G_DATA_PATH, DataPathT_ETHERNET, 0 );
347 MtnSaSetManObject(mgw_port, ChannelType_PORT,
348 ManObj_C_VOICE_RTP_TELEPHONE_EVENT_PT_TX, ss7->cfg->audio_payload, 0);
349 MtnSaSetManObject(mgw_port, ChannelType_PORT,
350 ManObj_G_RTP_AMR_PAYLOAD_TYPE, ss7->cfg->audio_payload, 0);
351 MtnSaSetManObject(mgw_port, ChannelType_PORT,
352 ManObj_G_RTP_AMR_PAYLOAD_FORMAT, RtpAmrPayloadFormat_OCTET_ALIGNED, 0);
353 MtnSaSetManObject(mgw_port, ChannelType_PORT,
354 ManObj_G_VOICE_ENCODING, Voice_Encoding_AMR_5_90, 0);
355
356 update_mute_status(mgw_port, mg_endp->conn_mode);
357
358 /* set the addresses */
359 SysEthGetHostAddress(ss7->cfg->bts_ip, &mgw_address);
360 SysEthGetHostAddress(ss7->cfg->local_ip, &loc_address);
361 MtnSaSetVoIpAddresses(mgw_port,
362 mgw_address, mg_endp->rtp_port,
363 loc_address, mg_endp->rtp_port);
364 MtnSaConnect(mgw_port, mgw_port);
365 mgw_endp->block = 1;
366}
367#endif
368
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +0800369static void mgcp_ss7_do_exec(struct mgcp_ss7 *mgcp, uint8_t type, uint32_t port, uint32_t param)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800370{
371#ifndef NO_UNIPORTE
372 struct mgcp_ss7_endpoint *mgw_endp = &mgcp->mgw_end[port];
373 int rc;
374
375 switch (type) {
376 case MGCP_SS7_MUTE_STATUS:
377 if (mgw_endp->port != UINT_MAX)
378 update_mute_status(TO_MGW_PORT(port), param);
379 break;
380 case MGCP_SS7_DELETE:
381 if (mgw_endp->port != UINT_MAX) {
382 rc = MtnSaDisconnect(mgw_endp->port);
383 if (rc != 0)
384 fprintf(stderr, "Failed to disconnect port: %u\n", mgw_endp->port);
385 rc = MtnSaDeallocate(mgw_endp->port);
386 if (rc != 0)
387 fprintf(stderr, "Failed to deallocate port: %u\n", mgw_endp->port);
388 mgw_endp->port = UINT_MAX;
389 mgw_endp->block = 1;
390 }
391 break;
392 case MGCP_SS7_ALLOCATE:
393 allocate_endp(mgcp, port);
394 break;
395 case MGCP_SS7_SHUTDOWN:
396 MtnSaShutdown();
397 break;
398 }
399#endif
400}
401
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +0800402void mgcp_ss7_exec(struct mgcp_ss7 *mgcp, uint8_t type, uint32_t port, uint32_t param)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800403{
404 struct mgcp_ss7_cmd *cmd = malloc(sizeof(*cmd));
405 memset(cmd, 0, sizeof(*cmd));
406 cmd->type = type;
407 cmd->port = port;
408 cmd->param = param;
409
410 thread_safe_add(mgcp->cmd_queue, &cmd->entry);
411}
412
413static int ss7_allocate_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
414{
415 struct mgcp_endpoint *mg_endp;
416
417 mg_endp = &ss7->cfg->endpoints[endp_no];
418 mg_endp->bts_rtp = htons(mg_endp->rtp_port);
419 mg_endp->bts_rtcp = htons(mg_endp->rtp_port + 1);
420 mg_endp->bts = ss7->cfg->bts_in;
421
422 mgcp_ss7_exec(ss7, MGCP_SS7_ALLOCATE, endp_no, 0);
423 return MGCP_POLICY_CONT;
424}
425
426static int ss7_modify_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
427{
428 struct mgcp_endpoint *mg_endp;
429
430 mg_endp = &ss7->cfg->endpoints[endp_no];
431 mgcp_ss7_exec(ss7, MGCP_SS7_MUTE_STATUS, endp_no, mg_endp->conn_mode);
432
433 /*
434 * this is a bad assumption of the network. We assume
435 * to have the remote addr now.
436 */
437 mgcp_send_dummy(mg_endp);
438
439 /* update the remote end */
440 return MGCP_POLICY_CONT;
441}
442
443static int ss7_delete_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
444{
445 mgcp_ss7_endp_free(ss7, endp_no);
446 return MGCP_POLICY_CONT;
447}
448
449static int mgcp_ss7_policy(struct mgcp_config *cfg, int endp_no, int state, const char *trans)
450{
451 int rc;
452 struct mgcp_ss7 *ss7;
453 struct mgcp_ss7_endpoint *endp;
454
455 ss7 = (struct mgcp_ss7 *) cfg->data;
456 endp = &ss7->mgw_end[endp_no];
457
458 /* TODO: Make it async and wait for the port to be connected */
459 rc = MGCP_POLICY_REJECT;
460 switch (state) {
461 case MGCP_ENDP_CRCX:
462 rc = ss7_allocate_endpoint(ss7, endp_no, endp);
463 break;
464 case MGCP_ENDP_MDCX:
465 rc = ss7_modify_endpoint(ss7, endp_no, endp);
466 break;
467 case MGCP_ENDP_DLCX:
468 rc = ss7_delete_endpoint(ss7, endp_no, endp);
469 break;
470 }
471
472 return rc;
473}
474
475static void enqueue_msg(struct write_queue *queue, struct sockaddr_in *addr, struct msgb *msg)
476{
477 struct sockaddr_in *data;
478
479 data = (struct sockaddr_in *) msgb_push(msg, sizeof(*data));
480 *data = *addr;
481 if (write_queue_enqueue(queue, msg) != 0) {
482 LOGP(DMGCP, LOGL_ERROR, "Failed to queue the message.\n");
483 msgb_free(msg);
484 }
485}
486
487static int write_call_agent(struct bsc_fd *bfd, struct msgb *msg)
488{
489 int rc;
490 struct sockaddr_in *addr;
491
492 addr = (struct sockaddr_in *) msg->data;
493 rc = sendto(bfd->fd, msg->l2h, msgb_l2len(msg), 0,
494 (struct sockaddr *) addr, sizeof(*addr));
495
496 if (rc != msgb_l2len(msg))
497 LOGP(DMGCP, LOGL_ERROR, "Failed to write MGCP message: rc: %d errno: %d\n", rc, errno);
498
499 return rc;
500}
501
502
503static int read_call_agent(struct bsc_fd *fd)
504{
505 struct sockaddr_in addr;
506 socklen_t slen = sizeof(addr);
507 struct msgb *resp;
508 struct mgcp_ss7 *cfg;
509 struct write_queue *queue;
510
511 cfg = (struct mgcp_ss7 *) fd->data;
512 queue = container_of(fd, struct write_queue, bfd);
513
514 /* read one less so we can use it as a \0 */
515 int rc = recvfrom(fd->fd, cfg->mgcp_msg->data, cfg->mgcp_msg->data_len - 1, 0,
516 (struct sockaddr *) &addr, &slen);
517
518 if (rc < 0) {
519 perror("Gateway failed to read");
520 return -1;
521 } else if (slen > sizeof(addr)) {
522 fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
523 slen, sizeof(addr));
524 return -1;
525 }
526
527 /* handle message now */
528 cfg->mgcp_msg->l2h = msgb_put(cfg->mgcp_msg, rc);
529 resp = mgcp_handle_message(cfg->cfg, cfg->mgcp_msg);
530 msgb_reset(cfg->mgcp_msg);
531
532 if (resp)
533 enqueue_msg(queue, &addr, resp);
534 return 0;
535}
536
537static int create_socket(struct mgcp_ss7 *cfg)
538{
539 int on;
540 struct sockaddr_in addr;
541 struct bsc_fd *bfd;
542
543 bfd = &cfg->mgcp_fd.bfd;
544
545 cfg->mgcp_fd.read_cb = read_call_agent;
546 cfg->mgcp_fd.write_cb = write_call_agent;
547 bfd->when = BSC_FD_READ;
548 bfd->fd = socket(AF_INET, SOCK_DGRAM, 0);
549 if (bfd->fd < 0) {
550 perror("Gateway failed to listen");
551 return -1;
552 }
553
554 on = 1;
555 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
556
557 memset(&addr, 0, sizeof(addr));
558 addr.sin_family = AF_INET;
559 addr.sin_port = htons(cfg->cfg->source_port);
560 addr.sin_addr.s_addr = INADDR_ANY;
561
562 if (bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
563 perror("Gateway failed to bind");
564 close(bfd->fd);
565 return -1;
566 }
567
568 bfd->data = cfg;
569 cfg->mgcp_msg = msgb_alloc(4096, "mgcp-msg");
570 if (!cfg->mgcp_msg) {
571 fprintf(stderr, "Gateway memory error.\n");
572 close(bfd->fd);
573 return -1;
574 }
575 talloc_steal(cfg, cfg->mgcp_msg);
576
577
578 if (bsc_register_fd(bfd) != 0) {
579 DEBUGP(DMGCP, "Failed to register the fd\n");
580 close(bfd->fd);
581 return -1;
582 }
583
584 return 0;
585}
586
587static void mgcp_ss7_endp_free(struct mgcp_ss7 *ss7, int endp)
588{
589 mgcp_ss7_exec(ss7, MGCP_SS7_DELETE, endp, 0);
590}
591
592static int reset_cb(struct mgcp_config *cfg)
593{
594 mgcp_ss7_reset((struct mgcp_ss7 *) cfg->data);
595 return 0;
596}
597
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800598static void mgcp_ss7_set_default(struct mgcp_config *cfg)
599{
600 /* do not attempt to allocate call ids */
601 cfg->early_bind = 1;
602
603 talloc_free(cfg->audio_name);
604 cfg->audio_payload = 126;
605 cfg->audio_name = talloc_strdup(cfg, "AMR/8000");
606}
607
608static struct mgcp_ss7 *mgcp_ss7_init(struct mgcp_config *cfg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800609{
610 int i;
611 struct mgcp_ss7 *conf = talloc_zero(NULL, struct mgcp_ss7);
612 if (!conf)
613 return NULL;
614
615 write_queue_init(&conf->mgcp_fd, 30);
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800616 conf->cfg = cfg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800617
618 /* take over the ownership */
619 talloc_steal(conf, conf->cfg);
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800620
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800621 conf->cfg->policy_cb = mgcp_ss7_policy;
622 conf->cfg->reset_cb = reset_cb;
623 conf->cfg->data = conf;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800624
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800625
626 if (mgcp_endpoints_allocate(conf->cfg) != 0) {
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800627 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate endpoints: %d\n",
628 g_cfg->number_endpoints);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800629 talloc_free(conf);
630 return NULL;
631 }
632
633 if (create_socket(conf) != 0) {
634 LOGP(DMGCP, LOGL_ERROR, "Failed to create socket.\n");
635 talloc_free(conf);
636 return NULL;
637 }
638
639 conf->mgw_end = _talloc_zero_array(conf, sizeof(struct mgcp_ss7_endpoint),
640 conf->cfg->number_endpoints, "mgw endpoints");
641 if (!conf->mgw_end) {
642 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGW endpoint array.\n");
643 talloc_free(conf);
644 return NULL;
645 }
646
647 for (i = 0; i < conf->cfg->number_endpoints; ++i) {
648 struct mgcp_endpoint *endp;
649 int rtp_port;
650
651 /* initialize the MGW part */
652 conf->mgw_end[i].port = UINT_MAX;
653
654 /* allocate the ports */
655 endp = &conf->cfg->endpoints[i];
656 rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), conf->cfg->rtp_base_port);
657 if (mgcp_bind_rtp_port(endp, rtp_port) != 0) {
658 LOGP(DMGCP, LOGL_ERROR, "Failed to bind: %d\n", rtp_port);
659 mgcp_ss7_free(conf);
660 return NULL;
661 }
662 }
663
664 conf->cmd_queue = thread_notifier_alloc();
665 if (!conf->cmd_queue) {
666 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate the command queue.\n");
667 talloc_free(conf);
668 return NULL;
669 }
670
671#ifndef NO_UNIPORTE
672 conf->cmd_queue->no_write = 1;
673 pthread_create(&conf->thread, NULL, start_uniporte, conf);
674#endif
675
676 return conf;
677}
678
679void mgcp_ss7_free(struct mgcp_ss7 *mgcp)
680{
681 /* close everything */
682 mgcp_ss7_reset(mgcp);
683
684 mgcp_ss7_exec(mgcp, MGCP_SS7_SHUTDOWN, 0, 0);
685
686 close(mgcp->mgcp_fd.bfd.fd);
687 bsc_unregister_fd(&mgcp->mgcp_fd.bfd);
688 bsc_del_timer(&mgcp->poll_timer);
689 talloc_free(mgcp);
690}
691
692void mgcp_ss7_reset(struct mgcp_ss7 *mgcp)
693{
694 int i;
695
696 if (!mgcp)
697 return;
698
699 LOGP(DMGCP, LOGL_INFO, "Resetting all endpoints.\n");
700
701 /* free UniPorted and MGCP data */
702 for (i = 0; i < mgcp->cfg->number_endpoints; ++i) {
703 mgcp_ss7_endp_free(mgcp, i);
704 mgcp_free_endp(&mgcp->cfg->endpoints[i]);
705 }
706}
707
708static void print_help()
709{
710 printf(" Some useful help...\n");
711 printf(" -h This help text.\n");
712 printf(" -c --config=CFG. The configuration file.\n");
713 printf(" -e --exit-on-failure. Exit the app on MGW failure.\n");
714}
715
716static void print_usage()
717{
718 printf("Usage: mgcp_mgw\n");
719}
720
721
722static void handle_options(int argc, char **argv)
723{
724 while (1) {
725 int option_index = 0, c;
726 static struct option long_options[] = {
727 {"help", 0, 0, 'h'},
728 {"config", 1, 0, 'c'},
729 {"exit", 0, 0, 'e'},
730 {0, 0, 0, 0},
731 };
732
733 c = getopt_long(argc, argv, "hc:e",
734 long_options, &option_index);
735 if (c == -1)
736 break;
737
738 switch (c) {
739 case 'h':
740 print_usage();
741 print_help();
742 exit(0);
743 case 'c':
744 config_file = optarg;
745 break;
746 case 'e':
747 exit_on_failure = 1;
748 break;
749 default:
750 fprintf(stderr, "Unknown option.\n");
751 break;
752 }
753 }
754}
755
756
757int main(int argc, char **argv)
758{
759 struct mgcp_ss7 *mgcp;
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +0800760 int rc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800761
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800762 log_init(&log_info);
763 stderr_target = log_target_create_stderr();
764 log_add_target(stderr_target);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800765
766 /* enable filters */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800767 log_set_all_filter(stderr_target, 1);
768 log_set_category_filter(stderr_target, DINP, 1, LOGL_INFO);
769 log_set_category_filter(stderr_target, DSCCP, 1, LOGL_INFO);
770 log_set_category_filter(stderr_target, DMSC, 1, LOGL_INFO);
771 log_set_category_filter(stderr_target, DMGCP, 1, LOGL_INFO);
772 log_set_print_timestamp(stderr_target, 1);
773 log_set_use_color(stderr_target, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800774
775 handle_options(argc, argv);
776
777 signal(SIGPIPE, SIG_IGN);
778
779 mgcp_mgw_vty_init();
Holger Hans Peter Freytherf41617b2010-08-04 07:08:33 +0800780
781 g_cfg = mgcp_config_alloc();
782 if (!g_cfg) {
783 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate mgcp config.\n");
784 return -1;
785 }
786
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800787 mgcp_ss7_set_default(g_cfg);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800788 if (vty_read_config_file(config_file, NULL) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800789 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
790 return -1;
791 }
792
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +0800793 rc = telnet_init(NULL, NULL, 4243);
794 if (rc < 0)
795 return rc;
796
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800797 printf("Creating MGCP MGW with endpoints: %d ip: %s mgw: %s rtp-base: %d payload: %d\n",
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800798 g_cfg->number_endpoints, g_cfg->local_ip, g_cfg->bts_ip,
799 g_cfg->rtp_base_port, g_cfg->audio_payload);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800800
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800801 mgcp = mgcp_ss7_init(g_cfg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800802 if (!mgcp) {
803 fprintf(stderr, "Failed to create MGCP\n");
804 exit(-1);
805 }
806 while (1) {
807 bsc_select_main(0);
808 }
809 return 0;
810}
811
812/* VTY code */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800813enum cellmgr_node {
814 MGCP_NODE = _LAST_OSMOVTY_NODE,
815};
816
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800817struct cmd_node mgcp_node = {
818 MGCP_NODE,
819 "%s(mgcp)#",
820 1,
821};
822
823DEFUN(cfg_mgcp,
824 cfg_mgcp_cmd,
825 "mgcp",
826 "Configure the MGCP")
827{
828 vty->node = MGCP_NODE;
829 return CMD_SUCCESS;
830}
831
832DEFUN(cfg_mgcp_local_ip,
833 cfg_mgcp_local_ip_cmd,
834 "local ip IP",
835 "Set the IP to be used in SDP records")
836{
837 struct hostent *hosts;
838 struct in_addr *addr;
839
840 hosts = gethostbyname(argv[0]);
841 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
842 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
843 return CMD_WARNING;
844 }
845
846 addr = (struct in_addr *) hosts->h_addr_list[0];
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800847 if (g_cfg->local_ip)
848 talloc_free(g_cfg->local_ip);
849 g_cfg->local_ip = talloc_strdup(g_cfg, inet_ntoa(*addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800850 return CMD_SUCCESS;
851}
852
853DEFUN(cfg_mgcp_mgw_ip,
854 cfg_mgcp_mgw_ip_cmd,
855 "mgw ip IP",
856 "Set the IP of the MGW for RTP forwarding")
857{
858 struct hostent *hosts;
859 struct in_addr *addr;
860
861 hosts = gethostbyname(argv[0]);
862 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
863 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
864 return CMD_WARNING;
865 }
866
867 addr = (struct in_addr *) hosts->h_addr_list[0];
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800868 if (g_cfg->bts_ip)
869 talloc_free(g_cfg->bts_ip);
870 g_cfg->bts_ip = talloc_strdup(g_cfg, inet_ntoa(*addr));
871 inet_aton(g_cfg->bts_ip, &g_cfg->bts_in);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800872 return CMD_SUCCESS;
873}
874
875DEFUN(cfg_mgcp_rtp_base_port,
876 cfg_mgcp_rtp_base_port_cmd,
877 "rtp base <0-65534>",
878 "Base port to use")
879{
880 unsigned int port = atoi(argv[0]);
881 if (port > 65534) {
882 vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
883 return CMD_WARNING;
884 }
885
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800886 g_cfg->rtp_base_port = port;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800887 return CMD_SUCCESS;
888}
889
890DEFUN(cfg_mgcp_rtp_ip_dscp,
891 cfg_mgcp_rtp_ip_dscp_cmd,
892 "rtp ip-dscp <0-255>",
893 "Set the IP_TOS socket attribute on the RTP/RTCP sockets.\n" "The TOS value.")
894{
895 int dscp = atoi(argv[0]);
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800896 g_cfg->endp_dscp = dscp;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800897 return CMD_SUCCESS;
898}
899
900ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd,
901 "rtp ip-tos <0-255>",
902 "Set the IP_TOS socket attribute on the RTP/RTCP sockets.\n" "The TOS value.")
903
904
905DEFUN(cfg_mgcp_sdp_payload_number,
906 cfg_mgcp_sdp_payload_number_cmd,
907 "sdp audio payload number <1-255>",
908 "Set the audio codec to use")
909{
910 unsigned int new_payload = atoi(argv[0]);
911 if (new_payload > 255) {
912 vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
913 return CMD_WARNING;
914 }
915
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800916 g_cfg->audio_payload = new_payload;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800917 return CMD_SUCCESS;
918}
919
920DEFUN(cfg_mgcp_number_endp,
921 cfg_mgcp_number_endp_cmd,
922 "number endpoints <0-65534>",
923 "The number of endpoints to allocate. This is not dynamic.")
924{
925 /* + 1 as we start counting at one */
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800926 g_cfg->number_endpoints = atoi(argv[0]) + 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800927 return CMD_SUCCESS;
928}
929
930static int config_write_mgcp()
931{
932 return CMD_SUCCESS;
933}
934
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800935static struct vty_app_info vty_info = {
936 .name = "mgcp_ss7",
937 .version = "0.0.1",
938 .go_parent_cb = NULL,
939};
940
Holger Hans Peter Freytherd2c46d42010-08-04 06:18:32 +0800941void logging_vty_add_cmds(void);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800942
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800943static void mgcp_mgw_vty_init(void)
944{
945 cmd_init(1);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800946 vty_init(&vty_info);
Holger Hans Peter Freytherd2c46d42010-08-04 06:18:32 +0800947 logging_vty_add_cmds();
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800948
949 install_element(CONFIG_NODE, &cfg_mgcp_cmd);
950 install_node(&mgcp_node, config_write_mgcp);
951 install_default(MGCP_NODE);
952 install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
953 install_element(MGCP_NODE, &cfg_mgcp_mgw_ip_cmd);
954 install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
955 install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
956 install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
957 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
958 install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
959}
960
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800961
962const char *openbsc_copyright = "";