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