blob: 9feb2e5193a5cc4017fbdac9840032ec608d8cb8 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* Use the UniPorte library to allocate endpoints */
2/*
Holger Hans Peter Freyther1cf3a832011-01-26 12:51:22 +01003 * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010-2011 by On-Waves
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08005 * All Rights Reserved
6 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (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
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21
22#include <mgcp_ss7.h>
23#include <mgcp/mgcp.h>
24#include <mgcp/mgcp_internal.h>
25
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080026#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080027
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080028#include <osmocore/select.h>
29#include <osmocore/talloc.h>
30#include <osmocore/timer.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080031
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080032#include <osmocom/vty/command.h>
33#include <osmocom/vty/vty.h>
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +080034#include <osmocom/vty/telnet_interface.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>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080050
51#ifndef _GNU_SOURCE
52#define _GNU_SOURCE
53#endif
54#include <getopt.h>
55
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080056static struct log_target *stderr_target;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080057static char *config_file = "mgcp_mgw.cfg";
58static int exit_on_failure = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080059
Holger Hans Peter Freyther1cf3a832011-01-26 12:51:22 +010060static int s_endp_offset = 1;
61
62#define TO_MGW_PORT(no) (no-s_endp_offset)
63#define FROM_MGW_PORT(no) (no+s_endp_offset)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080064
65static struct mgcp_ss7 *s_ss7;
Holger Hans Peter Freyther757f1742010-09-17 22:03:08 +080066static struct mgcp_config *g_cfg;
Holger Hans Peter Freytherd5918ff2010-08-06 16:03:27 +000067static int s_vad_enabled = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080068
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +010069/* gain settings */
70int s_digital_inp_gain = 31;
71int s_digital_out_gain = 31;
72int s_upstr_agc_enbl = 0;
73int s_upstr_adp_rate = 100;
74int s_upstr_max_gain = 46;
75int s_upstr_target_lvl = 20;
76int s_dwnstr_agc_enbl = 0;
77int s_dwnstr_adp_rate = 100;
78int s_dwnstr_max_gain = 46;
79int s_dwnstr_target_lvl = 20;
80
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080081struct mgcp_ss7_endpoint {
82 unsigned int port;
83 int block;
84};
85
86static void mgcp_ss7_endp_free(struct mgcp_ss7* ss7, int endp);
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +080087static 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 +080088static void mgcp_mgw_vty_init();
89
90static void check_exit(int status)
91{
92 if (exit_on_failure && status == 21) {
93 LOGP(DMGCP, LOGL_ERROR, "Failure detected with the MGW. Exiting.\n");
94 exit(-1);
95 }
96}
97
98#ifndef NO_UNIPORTE
99static void Force_Poll( int milliseconds )
100{
101 int timeout = 0;
102 unsigned long startTime;
103
104 startTime = SysLyrGetTime();
105
106 /* Loop until the specified number of milliseconds
107 * have elapsed.
108 */
109 do {
110 MtnSaPoll();
111 SysLyrSleep( 20 );
112 } while ((SysLyrGetTime()-startTime)<(unsigned long)milliseconds);
113 return;
114}
115
116static char eventName[Event_TELEMETRY_DATA + 1][128] = {
117 { "Event_NOT_READY" },
118 { "Event_READY" },
119 { "Event_ANSWER" },
120 { "Event_OUTGOING_CALL" },
121 { "Event_ABORT" },
122 { "Event_CONNECT" },
123 { "Event_DISCONNECT" },
124 { "Event_MANAGED_OBJECT_GET_COMPLETE" },
125 { "Event_MANAGED_OBJECT_GET_AND_CLEAR_COMPLETE" },
126 { "Event_MANAGED_OBJECT_SET_COMPLETE" },
127 { "Event_MANAGED_OBJECT_TRAP" },
128 { "Event_PREDEF_MOB_SET_COMPLETE" },
129 { "Event_PREDEF_MOB_GET_COMPLETE" },
130 { "Event_USER_MOB_DEFINE_COMPLETE" },
131 { "Event_USER_MOB_SET_COMPLETE" },
132 { "Event_USER_MOB_GET_COMPLETE" },
133 { "Event_RECEIVE_DATA" },
134 { "Event_SEND_COMPLETE" },
135 { "Event_TDM_CONNECT_COMPLETE" },
136 { "Event_LOG" },
137 { "Event_DEVICE_IN_CONTACT" },
138 { "Event_DEVICE_MANAGED" },
139 { "Event_DEVICE_OUT_OF_CONTACT" },
140 { "Event_TELEMETRY_DATA" } };
141
142static char stateName[PortState_END_OF_ENUM][128] = {
143 { "PortState_IDLE" },
144 { "PortState_SIGNALING" },
145 { "PortState_INITIATING" },
146 { "PortState_LINK" },
147 { "PortState_TRAINING" },
148 { "PortState_EC_NEGOTIATING" },
149 { "PortState_DATA" },
150 { "PortState_RESYNCING" },
151 { "PortState_FAX" },
152 { "PortState_COMMAND_ESCAPE" },
153 { "PortState_TERMINATING" },
154 { "PortState_VOICE" },
155 { "PortState_PORT_RESET" },
156 { "PortState_DSP_RESET" },
157 { "PortState_ALLOCATED" },
158 { "PortState_OUT_OF_SERVICE" },
159 { "PortState_RECONFIGURE" },
160 { "PortState_ON_HOLD" } };
161static int uniporte_events(unsigned long port, EventTypeT event,
162 void *event_data, unsigned long event_data_length ) {
163 char text[128];
164 ManObjectInfoPtr info;
165 DataReceiveInfoPtr dataInfo;
166 int i;
167 ToneDetectionPtr tones;
168
169
170 /* Don't print output when we receive data or complete
171 * sending data. That would be too verbose.
172 */
173 if (event==Event_DEVICE_MANAGED) {
174 MtnSaSetManObject(0, ChannelType_ETHERNET, ManObj_C_MOE_COMM_LOSS_RESET_DELAY ,
175 10, 0);
176 }
177 else if (event==Event_MANAGED_OBJECT_TRAP ) {
178 info = (ManObjectInfoPtr)event_data;
179 if (info->trapId == Trap_PORT_STATE_CHANGE) {
180 sprintf(text, "Port #%ld, Change to state %s", port, stateName[info->value]);
181 puts(text);
182
183 /* update the mgcp state */
184 int mgcp_endp = FROM_MGW_PORT(port);
185 if (s_ss7->mgw_end[mgcp_endp].block != 1)
186 fprintf(stderr, "State change on a non blocked port. ERROR.\n");
187 s_ss7->mgw_end[mgcp_endp].block = 0;
188 }
189 }
190 else if ( event == Event_MANAGED_OBJECT_SET_COMPLETE ) {
191 info = (ManObjectInfoPtr)event_data;
192
193 sprintf(text, "Object %d value %d status %d", info->object, info->value,
194 info->status );
195 puts(text);
196 check_exit(info->status);
197 }
198 else if ( ( event == Event_USER_MOB_SET_COMPLETE ) ||
199 ( event == Event_USER_MOB_DEFINE_COMPLETE ) )
200 {
201 info = (ManObjectInfoPtr)event_data;
202
203 sprintf( text, "Mob ID %d status %d", info->MOBId, info->status );
204 puts(text);
205 check_exit(info->status);
206 }
207 else if ( event == Event_USER_MOB_GET_COMPLETE )
208 {
209 info = (ManObjectInfoPtr)event_data;
210
211 sprintf( text, "Mob ID %d status %d", info->MOBId, info->status );
212 puts(text);
213 check_exit(info->status);
214 }
215 else if (event == Event_CONNECT)
216 {
217 sprintf(text, "Port %d connected",port );
218 }
219 else if (event == Event_PREDEF_MOB_GET_COMPLETE)
220 {
221 info = (ManObjectInfoPtr)event_data;
222
223 sprintf(text, "Mob ID %d status %d", info->MOBId, info->status );
224 puts(text);
225 check_exit(info->status);
226 }
227
228 return( 0 );
229}
230
231static int initialize_uniporte(struct mgcp_ss7 *mgcp)
232{
233 ProfileT profile;
234 unsigned long mgw_address;
235 int rc;
236
237 LOGP(DMGCP, LOGL_NOTICE, "Initializing MGW on %s\n", mgcp->cfg->bts_ip);
238
239 MtnSaSetEthernetOnly();
240 rc = MtnSaStartup(uniporte_events);
241 if (rc != 0)
242 LOGP(DMGCP, LOGL_ERROR, "Failed to startup the MGW.\n");
243 SysEthGetHostAddress(mgcp->cfg->bts_ip, &mgw_address);
244 rc = MtnSaRegisterEthernetDevice(mgw_address, 0);
245 if (rc != 0)
246 LOGP(DMGCP, LOGL_ERROR, "Failed to register ethernet.\n");
247 Force_Poll(2000);
248 MtnSaTakeOverDevice(0);
249 Force_Poll(2000);
250 MtnSaSetReceiveTraps(1);
251 MtnSaSetTransparent();
252
253 /* change the voice profile to AMR */
254 MtnSaGetProfile(ProfileType_VOICE, 0, &profile);
255 profile.countryCode = CountryCode_INTERNAT_ALAW;
256 MtnSaSetProfile(ProfileType_VOICE, 0, &profile);
257
258 if (MtnSaGetPortCount() == 0)
259 return -1;
260
261 return 0;
262}
263
264
265static void* start_uniporte(void *_ss7) {
266 struct llist_head blocked;
267 struct mgcp_ss7_cmd *cmd, *tmp;
268 struct mgcp_ss7 *ss7 = _ss7;
269
270 s_ss7 = ss7;
271
272 if (initialize_uniporte(ss7) != 0) {
273 fprintf(stderr, "Failed to create Uniporte.\n");
274 exit(-1);
275 return 0;
276 }
277
278 fprintf(stderr, "Created the MGCP processing thread.\n");
279 INIT_LLIST_HEAD(&blocked);
280 for (;;) {
281 thread_swap(ss7->cmd_queue);
282start_over:
283 /* handle items that are currently blocked */
284 llist_for_each_entry_safe(cmd, tmp, &blocked, entry) {
285 if (ss7->mgw_end[cmd->port].block)
286 continue;
287
288 mgcp_ss7_do_exec(ss7, cmd->type, cmd->port, cmd->param);
289 llist_del(&cmd->entry);
290 free(cmd);
291
292 /* We might have unblocked something, make sure we operate in order */
293 MtnSaPoll();
294 goto start_over;
295 }
296
297 llist_for_each_entry_safe(cmd, tmp, ss7->cmd_queue->main_head, entry) {
298 if (ss7->mgw_end[cmd->port].block) {
299 llist_del(&cmd->entry);
300 llist_add_tail(&cmd->entry, &blocked);
301 continue;
302 }
303
304 mgcp_ss7_do_exec(ss7, cmd->type, cmd->port, cmd->param);
305 llist_del(&cmd->entry);
306 free(cmd);
307
308 /* We might have unblocked something, make sure we operate in order */
309 MtnSaPoll();
310 goto start_over;
311 }
312
313 Force_Poll(20);
314 }
315
316 return 0;
317}
318#endif
319
320static void update_mute_status(int mgw_port, int conn_mode)
321{
322#ifndef NO_UNIPORTE
323 if (conn_mode == MGCP_CONN_NONE) {
324 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 1, 0);
325 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 1, 0);
326 } else if (conn_mode == MGCP_CONN_RECV_ONLY) {
327 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 1, 0);
328 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 0, 0);
329 } else if (conn_mode == MGCP_CONN_SEND_ONLY) {
330 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 0, 0);
331 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 1, 0);
332 } else if (conn_mode == MGCP_CONN_RECV_SEND) {
333 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_UPSTREAM_MUTE, 0, 0);
334 MtnSaSetManObject(mgw_port, ChannelType_PORT, ManObj_C_VOICE_DOWNSTREAM_MUTE, 0, 0);
335 } else {
336 LOGP(DMGCP, LOGL_ERROR, "Unhandled conn mode: %d\n", conn_mode);
337 }
338#endif
339}
340
341#ifndef NO_UNIPORTE
342static void allocate_endp(struct mgcp_ss7 *ss7, int endp_no)
343{
344 int mgw_port;
345 unsigned long mgw_address, loc_address;
346 struct mgcp_ss7_endpoint *mgw_endp = &ss7->mgw_end[endp_no];
347 struct mgcp_endpoint *mg_endp = &ss7->cfg->endpoints[endp_no];
348
349 mgw_port = TO_MGW_PORT(endp_no);
350 mgw_endp->port = MtnSaAllocate(mgw_port);
351 if (mgw_endp->port == UINT_MAX) {
352 fprintf(stderr, "Failed to allocate the port: %d\n", endp_no);
353 return;
354 }
355
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100356 /* Gain settings, apply before switching the port to voice */
357 MtnSaSetManObject(mgw_port, ChannelType_PORT,
358 ManObj_C_VOICE_INPUT_DIGITAL_GAIN, s_digital_inp_gain, 0);
359 MtnSaSetManObject(mgw_port, ChannelType_PORT,
360 ManObj_C_VOICE_OUTPUT_DIGITAL_GAIN, s_digital_out_gain, 0);
361 MtnSaSetManObject(mgw_port, ChannelType_PORT,
Holger Hans Peter Freyther2c472a32010-12-17 17:11:35 +0100362 ManObj_G_US_AGC_ENABLE, s_upstr_agc_enbl, 0);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100363 MtnSaSetManObject(mgw_port, ChannelType_PORT,
Holger Hans Peter Freyther2c472a32010-12-17 17:11:35 +0100364 ManObj_G_DS_AGC_ENABLE, s_dwnstr_agc_enbl, 0);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100365 MtnSaSetManObject(mgw_port, ChannelType_PORT,
Holger Hans Peter Freyther2c472a32010-12-17 17:11:35 +0100366 ManObj_G_US_ADAPTATION_RATE, s_upstr_adp_rate, 0);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100367 MtnSaSetManObject(mgw_port, ChannelType_PORT,
Holger Hans Peter Freyther2c472a32010-12-17 17:11:35 +0100368 ManObj_G_DS_ADAPTATION_RATE, s_dwnstr_adp_rate, 0);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100369 MtnSaSetManObject(mgw_port, ChannelType_PORT,
370 ManObj_G_US_MAX_APPLIED_GAIN, s_upstr_max_gain, 0);
371 MtnSaSetManObject(mgw_port, ChannelType_PORT,
372 ManObj_G_DS_MAX_APPLIED_GAIN, s_dwnstr_max_gain, 0);
373 MtnSaSetManObject(mgw_port, ChannelType_PORT,
374 ManObj_C_US_TARGET_LEVEL, s_upstr_target_lvl, 0);
375 MtnSaSetManObject(mgw_port, ChannelType_PORT,
376 ManObj_C_US_TARGET_LEVEL, s_dwnstr_target_lvl, 0);
377
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800378 /* Select AMR 5.9, Payload 98, no CRC, hardcoded */
379 MtnSaApplyProfile(mgw_port, ProfileType_VOICE, 0);
380 MtnSaSetManObject(mgw_port, ChannelType_PORT,
381 ManObj_G_DATA_PATH, DataPathT_ETHERNET, 0 );
382 MtnSaSetManObject(mgw_port, ChannelType_PORT,
383 ManObj_C_VOICE_RTP_TELEPHONE_EVENT_PT_TX, ss7->cfg->audio_payload, 0);
384 MtnSaSetManObject(mgw_port, ChannelType_PORT,
385 ManObj_G_RTP_AMR_PAYLOAD_TYPE, ss7->cfg->audio_payload, 0);
386 MtnSaSetManObject(mgw_port, ChannelType_PORT,
387 ManObj_G_RTP_AMR_PAYLOAD_FORMAT, RtpAmrPayloadFormat_OCTET_ALIGNED, 0);
388 MtnSaSetManObject(mgw_port, ChannelType_PORT,
389 ManObj_G_VOICE_ENCODING, Voice_Encoding_AMR_5_90, 0);
Holger Hans Peter Freytherd5918ff2010-08-06 16:03:27 +0000390 MtnSaSetManObject(mgw_port, ChannelType_PORT,
391 ManObj_C_VOICE_VAD_CNG, s_vad_enabled, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800392
393 update_mute_status(mgw_port, mg_endp->conn_mode);
394
395 /* set the addresses */
396 SysEthGetHostAddress(ss7->cfg->bts_ip, &mgw_address);
397 SysEthGetHostAddress(ss7->cfg->local_ip, &loc_address);
398 MtnSaSetVoIpAddresses(mgw_port,
399 mgw_address, mg_endp->rtp_port,
400 loc_address, mg_endp->rtp_port);
401 MtnSaConnect(mgw_port, mgw_port);
402 mgw_endp->block = 1;
403}
404#endif
405
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +0800406static 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 +0800407{
408#ifndef NO_UNIPORTE
409 struct mgcp_ss7_endpoint *mgw_endp = &mgcp->mgw_end[port];
410 int rc;
411
412 switch (type) {
413 case MGCP_SS7_MUTE_STATUS:
414 if (mgw_endp->port != UINT_MAX)
415 update_mute_status(TO_MGW_PORT(port), param);
416 break;
417 case MGCP_SS7_DELETE:
418 if (mgw_endp->port != UINT_MAX) {
419 rc = MtnSaDisconnect(mgw_endp->port);
420 if (rc != 0)
421 fprintf(stderr, "Failed to disconnect port: %u\n", mgw_endp->port);
422 rc = MtnSaDeallocate(mgw_endp->port);
423 if (rc != 0)
424 fprintf(stderr, "Failed to deallocate port: %u\n", mgw_endp->port);
425 mgw_endp->port = UINT_MAX;
426 mgw_endp->block = 1;
427 }
428 break;
429 case MGCP_SS7_ALLOCATE:
430 allocate_endp(mgcp, port);
431 break;
432 case MGCP_SS7_SHUTDOWN:
433 MtnSaShutdown();
434 break;
435 }
436#endif
437}
438
Holger Hans Peter Freyther9ed3e1b2010-07-31 05:22:56 +0800439void 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 +0800440{
441 struct mgcp_ss7_cmd *cmd = malloc(sizeof(*cmd));
442 memset(cmd, 0, sizeof(*cmd));
443 cmd->type = type;
444 cmd->port = port;
445 cmd->param = param;
446
447 thread_safe_add(mgcp->cmd_queue, &cmd->entry);
448}
449
450static int ss7_allocate_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
451{
452 struct mgcp_endpoint *mg_endp;
453
454 mg_endp = &ss7->cfg->endpoints[endp_no];
455 mg_endp->bts_rtp = htons(mg_endp->rtp_port);
456 mg_endp->bts_rtcp = htons(mg_endp->rtp_port + 1);
457 mg_endp->bts = ss7->cfg->bts_in;
458
459 mgcp_ss7_exec(ss7, MGCP_SS7_ALLOCATE, endp_no, 0);
460 return MGCP_POLICY_CONT;
461}
462
463static int ss7_modify_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
464{
465 struct mgcp_endpoint *mg_endp;
466
467 mg_endp = &ss7->cfg->endpoints[endp_no];
468 mgcp_ss7_exec(ss7, MGCP_SS7_MUTE_STATUS, endp_no, mg_endp->conn_mode);
469
470 /*
Holger Hans Peter Freythere3abeb12010-10-18 19:36:50 +0200471 * Just assume that we have the data now.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800472 */
Holger Hans Peter Freythere3abeb12010-10-18 19:36:50 +0200473 mgcp_send_dummy(mg_endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800474
475 /* update the remote end */
476 return MGCP_POLICY_CONT;
477}
478
479static int ss7_delete_endpoint(struct mgcp_ss7 *ss7, int endp_no, struct mgcp_ss7_endpoint *endp)
480{
481 mgcp_ss7_endp_free(ss7, endp_no);
482 return MGCP_POLICY_CONT;
483}
484
485static int mgcp_ss7_policy(struct mgcp_config *cfg, int endp_no, int state, const char *trans)
486{
487 int rc;
488 struct mgcp_ss7 *ss7;
489 struct mgcp_ss7_endpoint *endp;
490
491 ss7 = (struct mgcp_ss7 *) cfg->data;
492 endp = &ss7->mgw_end[endp_no];
493
494 /* TODO: Make it async and wait for the port to be connected */
495 rc = MGCP_POLICY_REJECT;
496 switch (state) {
497 case MGCP_ENDP_CRCX:
498 rc = ss7_allocate_endpoint(ss7, endp_no, endp);
499 break;
500 case MGCP_ENDP_MDCX:
501 rc = ss7_modify_endpoint(ss7, endp_no, endp);
502 break;
503 case MGCP_ENDP_DLCX:
504 rc = ss7_delete_endpoint(ss7, endp_no, endp);
505 break;
506 }
507
508 return rc;
509}
510
511static void enqueue_msg(struct write_queue *queue, struct sockaddr_in *addr, struct msgb *msg)
512{
513 struct sockaddr_in *data;
514
515 data = (struct sockaddr_in *) msgb_push(msg, sizeof(*data));
516 *data = *addr;
517 if (write_queue_enqueue(queue, msg) != 0) {
518 LOGP(DMGCP, LOGL_ERROR, "Failed to queue the message.\n");
519 msgb_free(msg);
520 }
521}
522
523static int write_call_agent(struct bsc_fd *bfd, struct msgb *msg)
524{
525 int rc;
526 struct sockaddr_in *addr;
527
528 addr = (struct sockaddr_in *) msg->data;
529 rc = sendto(bfd->fd, msg->l2h, msgb_l2len(msg), 0,
530 (struct sockaddr *) addr, sizeof(*addr));
531
532 if (rc != msgb_l2len(msg))
533 LOGP(DMGCP, LOGL_ERROR, "Failed to write MGCP message: rc: %d errno: %d\n", rc, errno);
534
535 return rc;
536}
537
538
539static int read_call_agent(struct bsc_fd *fd)
540{
541 struct sockaddr_in addr;
542 socklen_t slen = sizeof(addr);
543 struct msgb *resp;
544 struct mgcp_ss7 *cfg;
545 struct write_queue *queue;
546
547 cfg = (struct mgcp_ss7 *) fd->data;
548 queue = container_of(fd, struct write_queue, bfd);
549
550 /* read one less so we can use it as a \0 */
551 int rc = recvfrom(fd->fd, cfg->mgcp_msg->data, cfg->mgcp_msg->data_len - 1, 0,
552 (struct sockaddr *) &addr, &slen);
553
554 if (rc < 0) {
555 perror("Gateway failed to read");
556 return -1;
557 } else if (slen > sizeof(addr)) {
558 fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
559 slen, sizeof(addr));
560 return -1;
561 }
562
563 /* handle message now */
564 cfg->mgcp_msg->l2h = msgb_put(cfg->mgcp_msg, rc);
565 resp = mgcp_handle_message(cfg->cfg, cfg->mgcp_msg);
566 msgb_reset(cfg->mgcp_msg);
567
568 if (resp)
569 enqueue_msg(queue, &addr, resp);
570 return 0;
571}
572
573static int create_socket(struct mgcp_ss7 *cfg)
574{
575 int on;
576 struct sockaddr_in addr;
577 struct bsc_fd *bfd;
578
579 bfd = &cfg->mgcp_fd.bfd;
580
581 cfg->mgcp_fd.read_cb = read_call_agent;
582 cfg->mgcp_fd.write_cb = write_call_agent;
583 bfd->when = BSC_FD_READ;
584 bfd->fd = socket(AF_INET, SOCK_DGRAM, 0);
585 if (bfd->fd < 0) {
586 perror("Gateway failed to listen");
587 return -1;
588 }
589
590 on = 1;
591 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
592
593 memset(&addr, 0, sizeof(addr));
594 addr.sin_family = AF_INET;
595 addr.sin_port = htons(cfg->cfg->source_port);
596 addr.sin_addr.s_addr = INADDR_ANY;
597
598 if (bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
599 perror("Gateway failed to bind");
600 close(bfd->fd);
601 return -1;
602 }
603
604 bfd->data = cfg;
605 cfg->mgcp_msg = msgb_alloc(4096, "mgcp-msg");
606 if (!cfg->mgcp_msg) {
607 fprintf(stderr, "Gateway memory error.\n");
608 close(bfd->fd);
609 return -1;
610 }
611 talloc_steal(cfg, cfg->mgcp_msg);
612
613
614 if (bsc_register_fd(bfd) != 0) {
615 DEBUGP(DMGCP, "Failed to register the fd\n");
616 close(bfd->fd);
617 return -1;
618 }
619
620 return 0;
621}
622
623static void mgcp_ss7_endp_free(struct mgcp_ss7 *ss7, int endp)
624{
625 mgcp_ss7_exec(ss7, MGCP_SS7_DELETE, endp, 0);
626}
627
628static int reset_cb(struct mgcp_config *cfg)
629{
630 mgcp_ss7_reset((struct mgcp_ss7 *) cfg->data);
631 return 0;
632}
633
Holger Hans Peter Freyther95cac742010-09-18 03:16:52 +0800634static int realloc_cb(struct mgcp_config *cfg, int endp)
635{
636 mgcp_ss7_endp_free((struct mgcp_ss7 *) cfg->data, endp);
637 return 0;
638}
639
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800640static void mgcp_ss7_set_default(struct mgcp_config *cfg)
641{
642 /* do not attempt to allocate call ids */
643 cfg->early_bind = 1;
644
645 talloc_free(cfg->audio_name);
646 cfg->audio_payload = 126;
647 cfg->audio_name = talloc_strdup(cfg, "AMR/8000");
648}
649
650static struct mgcp_ss7 *mgcp_ss7_init(struct mgcp_config *cfg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800651{
652 int i;
653 struct mgcp_ss7 *conf = talloc_zero(NULL, struct mgcp_ss7);
654 if (!conf)
655 return NULL;
656
657 write_queue_init(&conf->mgcp_fd, 30);
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800658 conf->cfg = cfg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800659
660 /* take over the ownership */
661 talloc_steal(conf, conf->cfg);
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800662
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800663 conf->cfg->policy_cb = mgcp_ss7_policy;
664 conf->cfg->reset_cb = reset_cb;
Holger Hans Peter Freyther95cac742010-09-18 03:16:52 +0800665 conf->cfg->realloc_cb = realloc_cb;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800666 conf->cfg->data = conf;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800667
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800668
669 if (mgcp_endpoints_allocate(conf->cfg) != 0) {
Holger Hans Peter Freytherf9e99772010-08-04 07:10:55 +0800670 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate endpoints: %d\n",
Holger Hans Peter Freythere8073762010-08-04 07:34:21 +0800671 cfg->number_endpoints);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800672 talloc_free(conf);
673 return NULL;
674 }
675
676 if (create_socket(conf) != 0) {
677 LOGP(DMGCP, LOGL_ERROR, "Failed to create socket.\n");
678 talloc_free(conf);
679 return NULL;
680 }
681
682 conf->mgw_end = _talloc_zero_array(conf, sizeof(struct mgcp_ss7_endpoint),
683 conf->cfg->number_endpoints, "mgw endpoints");
684 if (!conf->mgw_end) {
685 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGW endpoint array.\n");
686 talloc_free(conf);
687 return NULL;
688 }
689
690 for (i = 0; i < conf->cfg->number_endpoints; ++i) {
691 struct mgcp_endpoint *endp;
692 int rtp_port;
693
694 /* initialize the MGW part */
695 conf->mgw_end[i].port = UINT_MAX;
696
697 /* allocate the ports */
698 endp = &conf->cfg->endpoints[i];
699 rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), conf->cfg->rtp_base_port);
700 if (mgcp_bind_rtp_port(endp, rtp_port) != 0) {
701 LOGP(DMGCP, LOGL_ERROR, "Failed to bind: %d\n", rtp_port);
702 mgcp_ss7_free(conf);
703 return NULL;
704 }
705 }
706
707 conf->cmd_queue = thread_notifier_alloc();
708 if (!conf->cmd_queue) {
709 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate the command queue.\n");
710 talloc_free(conf);
711 return NULL;
712 }
713
714#ifndef NO_UNIPORTE
715 conf->cmd_queue->no_write = 1;
716 pthread_create(&conf->thread, NULL, start_uniporte, conf);
717#endif
718
719 return conf;
720}
721
722void mgcp_ss7_free(struct mgcp_ss7 *mgcp)
723{
724 /* close everything */
725 mgcp_ss7_reset(mgcp);
726
727 mgcp_ss7_exec(mgcp, MGCP_SS7_SHUTDOWN, 0, 0);
728
729 close(mgcp->mgcp_fd.bfd.fd);
730 bsc_unregister_fd(&mgcp->mgcp_fd.bfd);
731 bsc_del_timer(&mgcp->poll_timer);
732 talloc_free(mgcp);
733}
734
735void mgcp_ss7_reset(struct mgcp_ss7 *mgcp)
736{
737 int i;
738
739 if (!mgcp)
740 return;
741
742 LOGP(DMGCP, LOGL_INFO, "Resetting all endpoints.\n");
743
744 /* free UniPorted and MGCP data */
745 for (i = 0; i < mgcp->cfg->number_endpoints; ++i) {
746 mgcp_ss7_endp_free(mgcp, i);
747 mgcp_free_endp(&mgcp->cfg->endpoints[i]);
748 }
749}
750
751static void print_help()
752{
753 printf(" Some useful help...\n");
754 printf(" -h This help text.\n");
755 printf(" -c --config=CFG. The configuration file.\n");
756 printf(" -e --exit-on-failure. Exit the app on MGW failure.\n");
757}
758
759static void print_usage()
760{
761 printf("Usage: mgcp_mgw\n");
762}
763
764
765static void handle_options(int argc, char **argv)
766{
767 while (1) {
768 int option_index = 0, c;
769 static struct option long_options[] = {
770 {"help", 0, 0, 'h'},
771 {"config", 1, 0, 'c'},
772 {"exit", 0, 0, 'e'},
773 {0, 0, 0, 0},
774 };
775
776 c = getopt_long(argc, argv, "hc:e",
777 long_options, &option_index);
778 if (c == -1)
779 break;
780
781 switch (c) {
782 case 'h':
783 print_usage();
784 print_help();
785 exit(0);
786 case 'c':
787 config_file = optarg;
788 break;
789 case 'e':
790 exit_on_failure = 1;
791 break;
792 default:
793 fprintf(stderr, "Unknown option.\n");
794 break;
795 }
796 }
797}
798
799
800int main(int argc, char **argv)
801{
802 struct mgcp_ss7 *mgcp;
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +0800803 int rc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800804
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800805 log_init(&log_info);
806 stderr_target = log_target_create_stderr();
807 log_add_target(stderr_target);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800808
809 /* enable filters */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800810 log_set_all_filter(stderr_target, 1);
811 log_set_category_filter(stderr_target, DINP, 1, LOGL_INFO);
812 log_set_category_filter(stderr_target, DSCCP, 1, LOGL_INFO);
813 log_set_category_filter(stderr_target, DMSC, 1, LOGL_INFO);
814 log_set_category_filter(stderr_target, DMGCP, 1, LOGL_INFO);
815 log_set_print_timestamp(stderr_target, 1);
816 log_set_use_color(stderr_target, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800817
818 handle_options(argc, argv);
819
820 signal(SIGPIPE, SIG_IGN);
821
822 mgcp_mgw_vty_init();
Holger Hans Peter Freytherf41617b2010-08-04 07:08:33 +0800823
Holger Hans Peter Freyther757f1742010-09-17 22:03:08 +0800824 g_cfg = mgcp_config_alloc();
825 if (!g_cfg) {
Holger Hans Peter Freytherf41617b2010-08-04 07:08:33 +0800826 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate mgcp config.\n");
827 return -1;
828 }
829
Holger Hans Peter Freyther757f1742010-09-17 22:03:08 +0800830 mgcp_ss7_set_default(g_cfg);
831 mgcp_vty_set_config(g_cfg);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800832 if (vty_read_config_file(config_file, NULL) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800833 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
834 return -1;
835 }
836
Holger Hans Peter Freythercc1a9382010-08-04 06:24:04 +0800837 rc = telnet_init(NULL, NULL, 4243);
838 if (rc < 0)
839 return rc;
840
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800841 printf("Creating MGCP MGW with endpoints: %d ip: %s mgw: %s rtp-base: %d payload: %d\n",
Holger Hans Peter Freyther757f1742010-09-17 22:03:08 +0800842 g_cfg->number_endpoints, g_cfg->local_ip, g_cfg->bts_ip,
843 g_cfg->rtp_base_port, g_cfg->audio_payload);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800844
Holger Hans Peter Freyther757f1742010-09-17 22:03:08 +0800845 mgcp = mgcp_ss7_init(g_cfg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800846 if (!mgcp) {
847 fprintf(stderr, "Failed to create MGCP\n");
848 exit(-1);
849 }
850 while (1) {
851 bsc_select_main(0);
852 }
853 return 0;
854}
855
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800856static struct vty_app_info vty_info = {
857 .name = "mgcp_ss7",
858 .version = "0.0.1",
859 .go_parent_cb = NULL,
860};
861
Holger Hans Peter Freytherd2c46d42010-08-04 06:18:32 +0800862void logging_vty_add_cmds(void);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800863
Holger Hans Peter Freytherd5918ff2010-08-06 16:03:27 +0000864DEFUN(cfg_mgcp_vad, cfg_mgcp_vad_cmd,
865 "vad (enabled|disabled)",
866 "Enable the Voice Activity Detection\n"
867 "Enable\n" "Disable\n")
868{
869 if (argv[0][0] == 'e')
870 s_vad_enabled = 1;
871 else
872 s_vad_enabled = 0;
873 return CMD_SUCCESS;
874}
875
Holger Hans Peter Freyther33cdb7e2010-09-17 22:03:47 +0800876DEFUN(cfg_mgcp_realloc, cfg_mgcp_realloc_cmd,
877 "force-realloc (0|1)",
878 "Force the reallocation of an endpoint\n"
879 "Disable\n" "Enable\n")
880{
881 g_cfg->force_realloc = atoi(argv[0]);
882 return CMD_SUCCESS;
883}
884
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100885DEFUN(cfg_mgcp_inp_dig_gain, cfg_mgcp_inp_dig_gain_cmd,
886 "input-digital-gain <0-62>",
887 "Static Digital Input Gain\n"
888 "Gain value")
889{
890 s_digital_inp_gain = atoi(argv[0]);
891 return CMD_SUCCESS;
892}
893
894DEFUN(cfg_mgcp_out_dig_gain, cfg_mgcp_out_dig_gain_cmd,
895 "outut-digital-gain <0-62>",
896 "Static Digital Output Gain\n"
897 "Gain value")
898{
899 s_digital_out_gain = atoi(argv[0]);
900 return CMD_SUCCESS;
901}
902
903DEFUN(cfg_mgcp_upstr_agc, cfg_mgcp_upstr_agc_cmd,
904 "upstream-automatic-gain (0|1)",
905 "Enable automatic gain control on upstream\n"
906 "Disable\n" "Enabled\n")
907{
908 s_upstr_agc_enbl = argv[0][0] == '1';
909 return CMD_SUCCESS;
910}
911
912DEFUN(cfg_mgc_upstr_adp, cfg_mgcp_upstr_adp_cmd,
Holger Hans Peter Freyther882082c2010-12-17 17:15:44 +0100913 "upstream-adaptiton-rate <1-128>",
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100914 "Set the adaption rate in (dB/sec) * 10\n"
915 "Range\n")
916{
917 s_upstr_adp_rate = atoi(argv[0]);
918 return CMD_SUCCESS;
919}
920
921DEFUN(cfg_mgcp_upstr_max_gain, cfg_mgcp_upstr_max_gain_cmd,
922 "upstream-max-applied-gain <0-49>",
923 "Maximum applied gain from -31db to 18db\n"
924 "Gain level\n")
925{
926 s_upstr_max_gain = atoi(argv[0]);
927 return CMD_SUCCESS;
928}
929
930DEFUN(cfg_mgcp_upstr_target, cfg_mgcp_upstr_target_cmd,
931 "upstream-target-level <6-37>",
932 "Set the desired level in db\n"
933 "Desired lievel\n")
934{
935 s_upstr_target_lvl = atoi(argv[0]);
936 return CMD_SUCCESS;
937}
938
939DEFUN(cfg_mgcp_dwnstr_agc, cfg_mgcp_dwnstr_agc_cmd,
940 "downstream-automatic-gain (0|1)",
941 "Enable automatic gain control on downstream\n"
942 "Disable\n" "Enabled\n")
943{
944 s_dwnstr_agc_enbl = argv[0][0] == '1';
945 return CMD_SUCCESS;
946}
947
948DEFUN(cfg_mgc_dwnstr_adp, cfg_mgcp_dwnstr_adp_cmd,
Holger Hans Peter Freyther882082c2010-12-17 17:15:44 +0100949 "downstream-adaptation-rate <1-128>",
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100950 "Set the adaption rate in (dB/sec) * 10\n"
951 "Range\n")
952{
953 s_dwnstr_adp_rate = atoi(argv[0]);
954 return CMD_SUCCESS;
955}
956
957DEFUN(cfg_mgcp_dwnstr_max_gain, cfg_mgcp_dwnstr_max_gain_cmd,
958 "downstream-max-applied-gain <0-49>",
959 "Maximum applied gain from -31db to 18db\n"
960 "Gain level\n")
961{
962 s_dwnstr_max_gain = atoi(argv[0]);
963 return CMD_SUCCESS;
964}
965
966DEFUN(cfg_mgcp_dwnstr_target, cfg_mgcp_dwnstr_target_cmd,
967 "downstream-target-level <6-37>",
968 "Set the desired level in db\n"
969 "Desired lievel\n")
970{
971 s_dwnstr_target_lvl = atoi(argv[0]);
972 return CMD_SUCCESS;
973}
974
Holger Hans Peter Freyther1cf3a832011-01-26 12:51:22 +0100975DEFUN(endpoint_offset, endpoint_offset_cmd,
976 "endpoint-offset <-60-60>",
977 "Offset to the CIC map\n" "Value to set\n")
978{
979 s_endp_offset = atoi(argv[0]);
Holger Hans Peter Freyther1cf3a832011-01-26 12:51:22 +0100980 return CMD_SUCCESS;
981}
982
Holger Hans Peter Freythered304632010-10-27 19:32:53 +0200983void mgcp_write_extra(struct vty *vty)
984{
985 vty_out(vty, " force-realloc %d%s", g_cfg->force_realloc, VTY_NEWLINE);
986 vty_out(vty, " vad %s%s", s_vad_enabled ? "enabled" : "disabled", VTY_NEWLINE);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100987 vty_out(vty, " input-digital-gain %d%s", s_digital_inp_gain, VTY_NEWLINE);
988 vty_out(vty, " output-digital-gain %d%s", s_digital_out_gain, VTY_NEWLINE);
989 vty_out(vty, " upstream-automatic-gain %d%s", s_upstr_agc_enbl, VTY_NEWLINE);
Holger Hans Peter Freyther882082c2010-12-17 17:15:44 +0100990 vty_out(vty, " upstream-adaptation-rate %d%s", s_upstr_adp_rate, VTY_NEWLINE);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100991 vty_out(vty, " upstream-max-applied-gain %d%s", s_upstr_max_gain, VTY_NEWLINE);
992 vty_out(vty, " upstream-target-level %d%s", s_upstr_target_lvl, VTY_NEWLINE);
993 vty_out(vty, " downstream-automatic-gain %d%s", s_dwnstr_agc_enbl, VTY_NEWLINE);
Holger Hans Peter Freyther882082c2010-12-17 17:15:44 +0100994 vty_out(vty, " downstream-adaptation-rate %d%s", s_dwnstr_adp_rate, VTY_NEWLINE);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +0100995 vty_out(vty, " downstream-max-applied-gain %d%s", s_dwnstr_max_gain, VTY_NEWLINE);
996 vty_out(vty, " downstream-target-level %d%s", s_dwnstr_target_lvl, VTY_NEWLINE);
Holger Hans Peter Freyther122d6042011-01-26 13:20:32 +0100997 vty_out(vty, " endpoint-offset %d%s", s_endp_offset, VTY_NEWLINE);
Holger Hans Peter Freythered304632010-10-27 19:32:53 +0200998}
999
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001000static void mgcp_mgw_vty_init(void)
1001{
1002 cmd_init(1);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001003 vty_init(&vty_info);
Holger Hans Peter Freytherd2c46d42010-08-04 06:18:32 +08001004 logging_vty_add_cmds();
Holger Hans Peter Freythere8073762010-08-04 07:34:21 +08001005 mgcp_vty_init();
Holger Hans Peter Freytherd5918ff2010-08-06 16:03:27 +00001006
1007 install_element(MGCP_NODE, &cfg_mgcp_vad_cmd);
Holger Hans Peter Freyther33cdb7e2010-09-17 22:03:47 +08001008 install_element(MGCP_NODE, &cfg_mgcp_realloc_cmd);
Holger Hans Peter Freyther8fa8e582010-12-01 23:14:57 +01001009 install_element(MGCP_NODE, &cfg_mgcp_inp_dig_gain_cmd);
1010 install_element(MGCP_NODE, &cfg_mgcp_out_dig_gain_cmd);
1011 install_element(MGCP_NODE, &cfg_mgcp_upstr_agc_cmd);
1012 install_element(MGCP_NODE, &cfg_mgcp_upstr_adp_cmd);
1013 install_element(MGCP_NODE, &cfg_mgcp_upstr_max_gain_cmd);
1014 install_element(MGCP_NODE, &cfg_mgcp_upstr_target_cmd);
1015 install_element(MGCP_NODE, &cfg_mgcp_dwnstr_agc_cmd);
1016 install_element(MGCP_NODE, &cfg_mgcp_dwnstr_adp_cmd);
1017 install_element(MGCP_NODE, &cfg_mgcp_dwnstr_max_gain_cmd);
1018 install_element(MGCP_NODE, &cfg_mgcp_dwnstr_target_cmd);
Holger Hans Peter Freyther122d6042011-01-26 13:20:32 +01001019 install_element(MGCP_NODE, &endpoint_offset_cmd);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001020}
1021
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001022
1023const char *openbsc_copyright = "";