root/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ftdm_sangoma_isdn_advance_chan_states
  2. ftdm_sangoma_isdn_run
  3. ftdm_sangoma_isdn_process_event_states
  4. ftdm_sangoma_isdn_process_stack_event
  5. ftdm_sangoma_isdn_process_state_change
  6. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  7. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  8. FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
  9. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  10. FIO_SPAN_SET_SIG_STATUS_FUNCTION
  11. ftdm_sangoma_isdn_start
  12. ftdm_sangoma_isdn_stop
  13. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
  14. FIO_SIG_LOAD_FUNCTION
  15. FIO_SIG_UNLOAD_FUNCTION
  16. FIO_API_FUNCTION
  17. FIO_IO_LOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2010, Sangoma Technologies 
   3  * David Yat Sin <davidy@sangoma.com>
   4  * Moises Silva <moy@sangoma.com>
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  * * Redistributions of source code must retain the above copyright
  12  * notice, this list of conditions and the following disclaimer.
  13  *
  14  * * Redistributions in binary form must reproduce the above copyright
  15  * notice, this list of conditions and the following disclaimer in the
  16  * documentation and/or other materials provided with the distribution.
  17  *
  18  * * Neither the name of the original author; nor the names of any contributors
  19  * may be used to endorse or promote products derived from this software
  20  * without specific prior written permission.
  21  *
  22  *
  23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  26  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  27  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34  */
  35 
  36 
  37 #include "ftmod_sangoma_isdn.h"
  38 
  39 #ifdef FTDM_DEBUG_CHAN_MEMORY
  40 #include <sys/mman.h>
  41 #endif
  42 
  43 static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
  44 
  45 static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
  46 static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
  47 
  48 ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
  49 static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan);
  50 
  51 static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
  52 static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
  53 
  54 static ftdm_io_interface_t                      g_sngisdn_io_interface;
  55 static sng_isdn_event_interface_t               g_sngisdn_event_interface;
  56 
  57 ftdm_sngisdn_data_t                             g_sngisdn_data;
  58 
  59 extern ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
  60 extern ftdm_status_t sngisdn_check_free_ids(void);
  61 
  62 ftdm_state_map_t sangoma_isdn_state_map = {
  63         {
  64         {
  65                 ZSD_INBOUND,
  66                 ZSM_UNACCEPTABLE,
  67                 {FTDM_ANY_STATE, FTDM_END},
  68                 {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END}
  69         },
  70         {
  71                 ZSD_INBOUND,
  72                 ZSM_UNACCEPTABLE,
  73                 {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
  74                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
  75         },
  76         {
  77                 ZSD_INBOUND,
  78                 ZSM_UNACCEPTABLE,
  79                 {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
  80                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
  81         },
  82         {
  83                 ZSD_INBOUND,
  84                 ZSM_UNACCEPTABLE,
  85                 {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
  86                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
  87                  FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
  88                  FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
  89         },
  90         {
  91                 ZSD_INBOUND,
  92                 ZSM_UNACCEPTABLE,
  93                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
  94                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_GET_CALLERID, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
  95         },
  96         {
  97                 ZSD_INBOUND,
  98                 ZSM_UNACCEPTABLE,
  99                 {FTDM_CHANNEL_STATE_GET_CALLERID, FTDM_END},
 100                 {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
 101         },
 102         {
 103                 ZSD_INBOUND,
 104                 ZSM_UNACCEPTABLE,
 105                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_END},
 106                 {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
 107         },
 108         {
 109                 ZSD_INBOUND,
 110                 ZSM_UNACCEPTABLE,
 111                 {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END},
 112                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 113         },
 114         {
 115                 ZSD_INBOUND,
 116                 ZSM_UNACCEPTABLE,
 117                 {FTDM_CHANNEL_STATE_RING, FTDM_END},
 118                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
 119         },
 120         {
 121                 ZSD_INBOUND,
 122                 ZSM_UNACCEPTABLE,
 123                 {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 124                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 125         },
 126         {
 127                 ZSD_INBOUND,
 128                 ZSM_UNACCEPTABLE,
 129                 {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 130                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
 131         },
 132         {
 133                 ZSD_INBOUND,
 134                 ZSM_UNACCEPTABLE,
 135                 {FTDM_CHANNEL_STATE_UP, FTDM_END},
 136                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 137         },
 138         {
 139                 ZSD_INBOUND,
 140                 ZSM_UNACCEPTABLE,
 141                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 142                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 143         },
 144         {
 145                 ZSD_INBOUND,
 146                 ZSM_UNACCEPTABLE,
 147                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 148                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 149         },
 150         {
 151                 ZSD_INBOUND,
 152                 ZSM_UNACCEPTABLE,
 153                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 154                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 155         },      
 156         {
 157                 ZSD_OUTBOUND,
 158                 ZSM_UNACCEPTABLE,
 159                 {FTDM_ANY_STATE, FTDM_END},
 160                 {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
 161         },
 162         {
 163                 ZSD_OUTBOUND,
 164                 ZSM_UNACCEPTABLE,
 165                 {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
 166                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
 167         },
 168         {
 169                 ZSD_OUTBOUND,
 170                 ZSM_UNACCEPTABLE,
 171                 {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
 172                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
 173         },
 174         {
 175                 ZSD_OUTBOUND,
 176                 ZSM_UNACCEPTABLE,
 177                 {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
 178                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
 179                  FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
 180                  FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
 181         },
 182         {
 183                 ZSD_OUTBOUND,
 184                 ZSM_UNACCEPTABLE,
 185                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 186                 {FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
 187         },
 188         {
 189                 ZSD_OUTBOUND,
 190                 ZSM_UNACCEPTABLE,
 191                 {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
 192                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS,
 193                  FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 194         },
 195         {
 196                 ZSD_OUTBOUND,
 197                 ZSM_UNACCEPTABLE,
 198                 {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 199                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 200         },
 201         {
 202                 ZSD_OUTBOUND,
 203                 ZSM_UNACCEPTABLE,
 204                 {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 205                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
 206         },
 207         {
 208                 ZSD_OUTBOUND,
 209                 ZSM_UNACCEPTABLE,
 210                 {FTDM_CHANNEL_STATE_UP, FTDM_END},
 211                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 212         },
 213         {
 214                 ZSD_OUTBOUND,
 215                 ZSM_UNACCEPTABLE,
 216                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 217                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 218         },
 219         {
 220                 ZSD_OUTBOUND,
 221                 ZSM_UNACCEPTABLE,
 222                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 223                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 224         },
 225         {
 226                 ZSD_OUTBOUND,
 227                 ZSM_UNACCEPTABLE,
 228                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 229                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 230         }
 231         }
 232 };
 233 
 234 static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan)
 235 {
 236         while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
 237                 ftdm_sangoma_isdn_process_state_change(ftdmchan);
 238         }
 239 }
 240 
 241 static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
 242 {
 243         ftdm_interrupt_t        *ftdm_sangoma_isdn_int[2];
 244         ftdm_status_t           ret_status;
 245         ftdm_span_t             *span   = (ftdm_span_t *) obj;
 246         ftdm_channel_t  *ftdmchan = NULL;
 247         sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
 248         sngisdn_event_data_t *sngisdn_event = NULL;
 249         int32_t sleep = SNGISDN_EVENT_POLL_RATE;
 250 
 251         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span=%u started.\n", span->span_id);
 252 
 253         /* set IN_THREAD flag so that we know this thread is running */
 254         ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
 255 
 256         /* get an interrupt queue for this span */
 257         if (ftdm_queue_get_interrupt(span->pendingchans, &ftdm_sangoma_isdn_int[0]) != FTDM_SUCCESS) {
 258                 ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a ftdm_interrupt for span = %s!\n", span->name);
 259                 goto ftdm_sangoma_isdn_run_exit;
 260         }
 261 
 262         if (ftdm_queue_get_interrupt(signal_data->event_queue, &ftdm_sangoma_isdn_int[1]) != FTDM_SUCCESS) {
 263                 ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a event interrupt for span = %s!\n", span->name);
 264                 goto ftdm_sangoma_isdn_run_exit;
 265         }
 266 
 267         while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
 268                 /* find out why we returned from the interrupt queue */
 269                 ret_status = ftdm_interrupt_multiple_wait(ftdm_sangoma_isdn_int, 2, sleep);
 270                 /* Check if there are any timers to process */
 271                 ftdm_sched_run(signal_data->sched);
 272                 switch (ret_status) {
 273                         case FTDM_SUCCESS:  /* there was a state change on the span */
 274                                 /* process all pending state changes */                 
 275                                 while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
 276                                         /* double check that this channel has a state change pending */
 277                                         ftdm_channel_lock(ftdmchan);
 278                                         ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 279                                         ftdm_channel_unlock(ftdmchan);
 280                                 }
 281 
 282                                 while ((sngisdn_event = ftdm_queue_dequeue(signal_data->event_queue))) {
 283                                         ftdm_sangoma_isdn_process_stack_event(span, sngisdn_event);
 284                                         ftdm_safe_free(sngisdn_event);
 285                                 }
 286                                 ftdm_span_trigger_signals(span);
 287                                 break;
 288                         case FTDM_TIMEOUT:
 289                                 /* twiddle */
 290                                 break;
 291                         case FTDM_FAIL:
 292                                 ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned error!\non span = %s\n", span->name);
 293                                 break;
 294 
 295                         default:
 296                                 ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned with unknown code on span = %s\n", span->name);
 297                                 break;
 298                 }
 299                 if (ftdm_sched_get_time_to_next_timer(signal_data->sched, &sleep) == FTDM_SUCCESS) {
 300                         if (sleep < 0 || sleep > SNGISDN_EVENT_POLL_RATE) {
 301                                 sleep = SNGISDN_EVENT_POLL_RATE;
 302                         }
 303                 }
 304         }
 305         
 306         /* clear the IN_THREAD flag so that we know the thread is done */
 307         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 308 
 309         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping.\n", span->name);
 310 
 311         return NULL;
 312 
 313 ftdm_sangoma_isdn_run_exit:
 314 
 315         /* clear the IN_THREAD flag so that we know the thread is done */
 316         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 317 
 318         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping due to error.\n", span->name);
 319 
 320         return NULL;
 321 }
 322 
 323 
 324 /**
 325  * \brief Checks if span has state changes pending and processes
 326  * \param span Span where event was fired
 327  * \param sngisdn_event Event to handle
 328  * \return The locked FTDM channel associated to the event if any, NULL otherwise
 329  */
 330 
 331 ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 332 {
 333         ftdm_channel_t *ftdmchan = NULL;
 334         switch (sngisdn_event->event_id) {
 335                 /* Events that do not have a channel associated to them */
 336                 case SNGISDN_EVENT_SRV_IND:
 337                 case SNGISDN_EVENT_SRV_CFM:
 338                 case SNGISDN_EVENT_RST_CFM:
 339                 case SNGISDN_EVENT_RST_IND:
 340                         return NULL;
 341                         break;
 342                 case SNGISDN_EVENT_CON_IND:
 343                 case SNGISDN_EVENT_CON_CFM:
 344                 case SNGISDN_EVENT_CNST_IND:
 345                 case SNGISDN_EVENT_DISC_IND:
 346                 case SNGISDN_EVENT_REL_IND:
 347                 case SNGISDN_EVENT_DAT_IND:
 348                 case SNGISDN_EVENT_SSHL_IND:
 349                 case SNGISDN_EVENT_SSHL_CFM:
 350                 case SNGISDN_EVENT_RMRT_IND:
 351                 case SNGISDN_EVENT_RMRT_CFM:
 352                 case SNGISDN_EVENT_FLC_IND:
 353                 case SNGISDN_EVENT_FAC_IND:
 354                 case SNGISDN_EVENT_STA_CFM:
 355                         ftdmchan = sngisdn_event->sngisdn_info->ftdmchan;
 356                         ftdm_assert_return(ftdmchan, NULL,"Event should have a channel associated\n");
 357                         break;
 358         }
 359         ftdm_channel_lock(ftdmchan);
 360         ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 361         return ftdmchan;
 362 }
 363 
 364 
 365 
 366 static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 367 {
 368         ftdm_channel_t *ftdmchan = NULL;
 369         
 370         ftdmchan = ftdm_sangoma_isdn_process_event_states(span, sngisdn_event);
 371         switch(sngisdn_event->event_id) {
 372                 case SNGISDN_EVENT_CON_IND:
 373                         sngisdn_process_con_ind(sngisdn_event);
 374                         break;
 375                 case SNGISDN_EVENT_CON_CFM:
 376                         sngisdn_process_con_cfm(sngisdn_event);
 377                         break;
 378                 case SNGISDN_EVENT_CNST_IND:
 379                         sngisdn_process_cnst_ind(sngisdn_event);
 380                         break;
 381                 case SNGISDN_EVENT_DISC_IND:
 382                         sngisdn_process_disc_ind(sngisdn_event);
 383                         break;
 384                 case SNGISDN_EVENT_REL_IND:
 385                         sngisdn_process_rel_ind(sngisdn_event);
 386                         break;
 387                 case SNGISDN_EVENT_DAT_IND:
 388                         sngisdn_process_dat_ind(sngisdn_event);
 389                         break;
 390                 case SNGISDN_EVENT_SSHL_IND:
 391                         sngisdn_process_sshl_ind(sngisdn_event);
 392                         break;
 393                 case SNGISDN_EVENT_SSHL_CFM:
 394                         sngisdn_process_sshl_cfm(sngisdn_event);
 395                         break;
 396                 case SNGISDN_EVENT_RMRT_IND:
 397                         sngisdn_process_rmrt_ind(sngisdn_event);
 398                         break;
 399                 case SNGISDN_EVENT_RMRT_CFM:
 400                         sngisdn_process_rmrt_cfm(sngisdn_event);
 401                         break;
 402                 case SNGISDN_EVENT_FLC_IND:
 403                         sngisdn_process_flc_ind(sngisdn_event);
 404                         break;
 405                 case SNGISDN_EVENT_FAC_IND:
 406                         sngisdn_process_fac_ind(sngisdn_event);
 407                         break;
 408                 case SNGISDN_EVENT_STA_CFM:
 409                         sngisdn_process_sta_cfm(sngisdn_event);
 410                         break;
 411                 case SNGISDN_EVENT_SRV_IND:
 412                         sngisdn_process_srv_ind(sngisdn_event);
 413                         break;
 414                 case SNGISDN_EVENT_SRV_CFM:
 415                         sngisdn_process_srv_cfm(sngisdn_event);
 416                         break;
 417                 case SNGISDN_EVENT_RST_CFM:
 418                         sngisdn_process_rst_cfm(sngisdn_event);
 419                         break;
 420                 case SNGISDN_EVENT_RST_IND:
 421                         sngisdn_process_rst_ind(sngisdn_event);
 422                         break;
 423         }
 424         if(ftdmchan != NULL) {
 425                 ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 426                 ftdm_channel_unlock(ftdmchan);
 427         }
 428 }
 429 
 430 static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 431 {
 432         ftdm_sigmsg_t           sigev;
 433         ftdm_channel_state_t initial_state;
 434         sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
 435 
 436         memset(&sigev, 0, sizeof(sigev));
 437 
 438         sigev.chan_id = ftdmchan->chan_id;
 439         sigev.span_id = ftdmchan->span_id;
 440         sigev.channel = ftdmchan;
 441 
 442         /*first lock the channel*/
 443         ftdm_channel_lock(ftdmchan);
 444         /*clear the state change flag...since we might be setting a new state*/
 445         ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
 446 #ifdef FTDM_DEBUG_CHAN_MEMORY
 447         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 448                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
 449         }
 450 #endif
 451         
 452         /* Only needed for debugging */
 453         initial_state = ftdmchan->state;
 454 
 455         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state change to %s\n", ftdm_channel_state2str(ftdmchan->state));
 456 
 457         switch (ftdmchan->state) {
 458         case FTDM_CHANNEL_STATE_COLLECT:         /* SETUP received but waiting on digits */
 459                 {
 460                         /* TODO: Re-implement this. There is a way to re-evaluate new incoming digits from dialplan as they come */
 461                         sngisdn_snd_setup_ack(ftdmchan);
 462                         /* Just wait in this state until we get enough digits or T302 timeout */
 463                 }
 464                 break;
 465         case FTDM_CHANNEL_STATE_GET_CALLERID:
 466                 {
 467                         sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 468                         sngisdn_snd_proceed(ftdmchan);
 469                         /* Wait in this state until we get FACILITY msg */                      
 470                 }
 471                 break;
 472         case FTDM_CHANNEL_STATE_RING: /* incoming call request */
 473                 {
 474                         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits);
 475 
 476                         /* we have enough information to inform FTDM of the call*/
 477                         sigev.event_id = FTDM_SIGEVENT_START;
 478                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 479                 }
 480                 break;
 481         case FTDM_CHANNEL_STATE_DIALING: /* outgoing call request */
 482                 {
 483                         sngisdn_snd_setup(ftdmchan);
 484                 }
 485                 break;
 486         case FTDM_CHANNEL_STATE_PROGRESS:
 487                 {
 488                         /*check if the channel is inbound or outbound*/
 489                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 490                                 /*OUTBOUND...so we were told by the line of this so noifiy the user*/
 491                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS;
 492                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 493                         } else if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
 494                                 sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 495                                 sngisdn_snd_proceed(ftdmchan);
 496                         }
 497                 }
 498                 break;
 499         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 500                 {
 501                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 502                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
 503                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 504                         } else {
 505                                 sngisdn_snd_progress(ftdmchan);
 506                         }
 507                 }
 508                 break; 
 509         case FTDM_CHANNEL_STATE_UP: /* call is answered */
 510                 {
 511                         /* check if the channel is inbound or outbound */
 512                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 513                                 /* OUTBOUND ... so we were told by the line that the other side answered */
 514                                 sigev.event_id = FTDM_SIGEVENT_UP;
 515                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 516 
 517                                 if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
 518                                         ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
 519                                         /* Assign the call to a specific equipment */
 520                                         sngisdn_snd_con_complete(ftdmchan);
 521                                 }
 522                         } else {
 523                                 /* INBOUND ... so FS told us it just answered ... tell the stack */
 524                                 sngisdn_snd_connect(ftdmchan);
 525                         }
 526                 }
 527                 break;
 528         case FTDM_CHANNEL_STATE_CANCEL:
 529                 {
 530                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call before informing user!\n");
 531 
 532                         /* Send a release complete */
 533                         sngisdn_snd_release(ftdmchan, 0);
 534                         /*now go to the HANGUP complete state*/                         
 535                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 536                 }
 537                 break;
 538         case FTDM_CHANNEL_STATE_TERMINATING: /* call is hung up by the remote end */
 539                 {
 540                         /* this state is set when the line is hanging up */
 541                         sigev.event_id = FTDM_SIGEVENT_STOP;
 542                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 543                 }
 544                 break;
 545         case FTDM_CHANNEL_STATE_HANGUP: /* call is hung up locally */
 546                 {
 547                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT)) {
 548                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote abort\n");
 549                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_REL)) {
 550                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote hangup\n");
 551                                 sngisdn_snd_release(ftdmchan, 0);
 552                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 553                                 /* We aborted this call before sending anything to the stack, so nothing to do anymore */
 554                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Clearing local states from local abort\n");
 555                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 556                                 /* We are hangup local call because there was a glare, we are waiting for a
 557                                 RELEASE on this call, before we can process the saved call */
 558                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for RELEASE on hungup glared call\n");
 559                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_SEND_DISC)) {
 560                                 /* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/
 561                                 sngisdn_snd_disconnect(ftdmchan);
 562                         } else {
 563                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n");
 564 
 565                                  /* set the flag to indicate this hangup is started from the local side */
 566                                 sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL);
 567 
 568                                 /* If we never sent ack to incoming call, we need to send release instead of disconnect */
 569                                 if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING ||
 570                                         ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALING) {
 571 
 572                                         sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 573                                         sngisdn_snd_release(ftdmchan, 0);
 574 
 575                                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 576                                                 sng_isdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
 577                                         }
 578                                 } else {
 579                                         sngisdn_snd_disconnect(ftdmchan);
 580                                 }
 581                         }
 582 
 583                         /* now go to the HANGUP complete state */
 584                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 585                 }
 586                 break;
 587         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
 588                 {
 589                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT) ||
 590                                 sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 591                                 /* If the remote side aborted, we will not get anymore message for this call */
 592                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 593                         } else {
 594                                 /* waiting on remote confirmation before moving to down */
 595                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for release from stack\n");
 596                         }
 597                 }
 598                 break;
 599         case FTDM_CHANNEL_STATE_DOWN: /* the call is finished and removed */
 600                 {
 601                         uint8_t glare = 0;
 602 
 603                         glare = sngisdn_test_flag(sngisdn_info, FLAG_GLARE);
 604                         /* clear all of the call specific data store in the channel structure */
 605                         clear_call_data(sngisdn_info);
 606 
 607                         /* Close the channel even if we had a glare, we will re-open it when processing state COLLECT for the
 608                                 "glared call" */
 609                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
 610                                 ftdm_channel_t *close_chan = ftdmchan;
 611                                 /* close the channel */
 612                                 ftdm_channel_close(&close_chan);
 613                         }
 614                         if (glare) {
 615 
 616                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare detected, processing saved call\n");
 617                                 /* We are calling sngisdn_rcv_con_ind with ftdmchan->mutex being locked,
 618                                         so no other threads will be able to touch this channel. The next time we will
 619                                         process this channel is in this function, and it should be in state COLLECT (set inside
 620                                         sngisdn_rcv_con_ind)*/
 621                                 sngisdn_rcv_con_ind(sngisdn_info->glare.suId, sngisdn_info->glare.suInstId, sngisdn_info->glare.spInstId, &sngisdn_info->glare.setup, sngisdn_info->glare.dChan, sngisdn_info->glare.ces);
 622                         }
 623                 }
 624                 break;
 625         case FTDM_CHANNEL_STATE_RESTART:
 626                 {
 627                         /* IMPLEMENT ME */
 628                 }
 629 
 630                 break;
 631         case FTDM_CHANNEL_STATE_SUSPENDED:
 632                 {
 633                         /* IMPLEMENT ME */
 634                 }
 635                 break;
 636         default:
 637                 {
 638                         ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsupported sngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state));
 639                 }
 640                 break;
 641         }
 642         
 643         if (ftdmchan->state == initial_state) {
 644                 ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "state change flag is still set, but we did not change state\n");
 645         }
 646 #ifdef FTDM_DEBUG_CHAN_MEMORY
 647         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 648                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
 649         }
 650 #endif
 651         ftdm_channel_unlock(ftdmchan);
 652         return;
 653 }
 654 
 655 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call)
 656 {
 657         sngisdn_chan_data_t  *sngisdn_info = ftdmchan->call_data;
 658         ftdm_status_t status = FTDM_FAIL;       
 659         
 660         /* lock the channel while we check whether it is availble */
 661         ftdm_channel_lock(ftdmchan);
 662 
 663         switch (ftdmchan->state) {
 664 
 665                 case FTDM_CHANNEL_STATE_DOWN:
 666                         {
 667                                 if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 668                                         /* A call came in after we called ftdm_channel_open_chan for this call, but before we got here */
 669                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Glare detected - aborting outgoing call\n");
 670 
 671                                         sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 672                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 673 
 674                                         status = FTDM_BREAK;
 675                                 } else {
 676                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
 677                                         status = FTDM_SUCCESS;
 678                                 }
 679                         }
 680                         break;
 681                 default:
 682                 {
 683                         /* the channel is already used...this can't be, end the request */
 684                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Outgoing call requested channel in already in use\n");
 685                         status = FTDM_BREAK;
 686                 }
 687                 break;            
 688         }
 689 
 690         ftdm_channel_unlock(ftdmchan);
 691         return status;
 692 }
 693 
 694 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_chan_sig_status)
 695 {
 696         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 697                 *status = FTDM_SIG_STATE_UP;
 698         } else {
 699                 *status = FTDM_SIG_STATE_DOWN;
 700         }
 701 
 702         return FTDM_SUCCESS;
 703 }
 704 
 705 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_chan_sig_status)
 706 {
 707         ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n");
 708         return FTDM_NOTIMPL;
 709 }
 710 
 711 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_span_sig_status)
 712 {       
 713         if (ftdm_test_flag(span->channels[1], FTDM_CHANNEL_SIG_UP)) {
 714                 *status = FTDM_SIG_STATE_UP;
 715         } else {
 716                 *status = FTDM_SIG_STATE_DOWN;
 717         }
 718 
 719         return FTDM_SUCCESS;
 720 }
 721 
 722 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
 723 {
 724         ftdm_log(FTDM_LOG_ERROR,"Cannot set span status in this module\n");
 725         return FTDM_NOTIMPL;
 726 }
 727 
 728 static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
 729 {
 730         ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
 731         if (sng_isdn_stack_start(span) != FTDM_SUCCESS) {
 732                 ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
 733                 return FTDM_FAIL;
 734         }
 735         /* clear the monitor thread stop flag */
 736         ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
 737         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 738 
 739         /*start the span monitor thread*/
 740         if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) {
 741                 ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n");
 742                 return FTDM_FAIL;
 743         }
 744 
 745         ftdm_log(FTDM_LOG_DEBUG,"Finished starting span %s\n", span->name);
 746         return FTDM_SUCCESS;
 747 }
 748 
 749 static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span)
 750 {
 751         ftdm_iterator_t *chaniter = NULL;
 752         ftdm_iterator_t *curr = NULL;
 753         ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name);
 754         
 755         /* throw the STOP_THREAD flag to signal monitor thread stop */
 756         ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
 757 
 758         /* wait for the thread to stop */
 759         while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
 760                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for monitor thread to end for span %s\n", span->name);
 761                 ftdm_sleep(10);
 762         }
 763 
 764         if (sng_isdn_stack_stop(span) != FTDM_SUCCESS) {
 765                 ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s\n", span->name);
 766         }
 767         
 768         chaniter = ftdm_span_get_chan_iterator(span, NULL);
 769         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
 770                 ftdm_safe_free(((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data);
 771                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = NULL;
 772         }
 773         ftdm_iterator_free(chaniter);
 774 
 775         ftdm_sched_destroy(&((sngisdn_span_data_t*)span->signal_data)->sched);
 776         ftdm_queue_destroy(&((sngisdn_span_data_t*)span->signal_data)->event_queue);
 777         ftdm_safe_free(span->signal_data);
 778 
 779         ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name);
 780 
 781         return FTDM_SUCCESS;
 782 }
 783 
 784 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
 785 {
 786         ftdm_iterator_t *chaniter = NULL;
 787         ftdm_iterator_t *curr = NULL;
 788 
 789         sngisdn_span_data_t *span_data;
 790         
 791         ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name);      
 792 
 793         span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t));
 794         span_data->ftdm_span = span;
 795         span->signal_data = span_data;
 796         
 797         chaniter = ftdm_span_get_chan_iterator(span, NULL);
 798         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
 799                 sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t));
 800                 chan_data->ftdmchan = ((ftdm_channel_t*)ftdm_iterator_current(curr));
 801                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = chan_data;
 802                 
 803         }
 804         ftdm_iterator_free(chaniter);
 805 
 806         if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) {
 807                 ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n");
 808                 return FTDM_FAIL;
 809         }
 810 
 811         if (sng_isdn_stack_cfg(span) != FTDM_SUCCESS) {
 812                 ftdm_log(FTDM_LOG_CRIT, "Sangoma ISDN Stack configuration failed\n");
 813                 return FTDM_FAIL;
 814         }
 815 
 816 
 817         span->start = ftdm_sangoma_isdn_start;
 818         span->stop = ftdm_sangoma_isdn_stop;
 819         span->signal_type = FTDM_SIGTYPE_ISDN;
 820         span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
 821         span->channel_request = NULL;
 822         span->signal_cb = sig_cb;
 823         span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
 824         span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status;
 825         span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
 826         span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
 827         span->state_map = &sangoma_isdn_state_map;
 828         ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
 829         ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
 830 
 831         if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
 832                 span->trunk_type == FTDM_TRUNK_BRI) {
 833 
 834                 ftdm_set_flag(span, FTDM_SPAN_USE_AV_RATE);
 835                 sng_isdn_set_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
 836         }
 837 
 838         /* Initialize scheduling context */
 839         ftdm_assert(ftdm_sched_create(&((sngisdn_span_data_t*)span->signal_data)->sched, "sngisdn_schedule") == FTDM_SUCCESS, "Failed to create a new schedule!!");
 840 
 841         /* Initialize the event queue */
 842         ftdm_assert(ftdm_queue_create(&((sngisdn_span_data_t*)span->signal_data)->event_queue, SNGISDN_EVENT_QUEUE_SIZE) == FTDM_SUCCESS, "Failed to create a new queue!!");
 843 
 844         ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_isdn span = %s\n", span->name);
 845         return FTDM_SUCCESS;
 846 }
 847 
 848 static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
 849 {
 850         unsigned i;
 851         ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_isdn...\n");
 852 
 853         memset(&g_sngisdn_data, 0, sizeof(g_sngisdn_data));
 854 
 855         /* set callbacks */
 856         g_sngisdn_event_interface.cc.sng_con_ind        = sngisdn_rcv_con_ind;
 857         g_sngisdn_event_interface.cc.sng_con_cfm        = sngisdn_rcv_con_cfm;
 858         g_sngisdn_event_interface.cc.sng_cnst_ind       = sngisdn_rcv_cnst_ind;
 859         g_sngisdn_event_interface.cc.sng_disc_ind       = sngisdn_rcv_disc_ind;
 860         g_sngisdn_event_interface.cc.sng_rel_ind        = sngisdn_rcv_rel_ind;
 861         g_sngisdn_event_interface.cc.sng_dat_ind        = sngisdn_rcv_dat_ind;
 862         g_sngisdn_event_interface.cc.sng_sshl_ind       = sngisdn_rcv_sshl_ind;
 863         g_sngisdn_event_interface.cc.sng_sshl_cfm       = sngisdn_rcv_sshl_cfm;
 864         g_sngisdn_event_interface.cc.sng_rmrt_ind       = sngisdn_rcv_rmrt_ind;
 865         g_sngisdn_event_interface.cc.sng_rmrt_cfm       = sngisdn_rcv_rmrt_cfm;
 866         g_sngisdn_event_interface.cc.sng_flc_ind        = sngisdn_rcv_flc_ind;
 867         g_sngisdn_event_interface.cc.sng_fac_ind        = sngisdn_rcv_fac_ind;
 868         g_sngisdn_event_interface.cc.sng_sta_cfm        = sngisdn_rcv_sta_cfm;
 869         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_ind;
 870         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_cfm;
 871         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_cfm;
 872         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_ind;
 873         g_sngisdn_event_interface.cc.sng_rst_cfm        = sngisdn_rcv_rst_cfm;
 874 
 875         g_sngisdn_event_interface.lg.sng_log            = sngisdn_rcv_sng_log;
 876         g_sngisdn_event_interface.lg.sng_assert         = sngisdn_rcv_sng_assert;
 877         
 878         g_sngisdn_event_interface.sta.sng_phy_sta_ind   = sngisdn_rcv_phy_ind;
 879         g_sngisdn_event_interface.sta.sng_q921_sta_ind  = sngisdn_rcv_q921_ind;
 880         g_sngisdn_event_interface.sta.sng_q921_trc_ind  = sngisdn_rcv_q921_trace;
 881         g_sngisdn_event_interface.sta.sng_q931_sta_ind  = sngisdn_rcv_q931_ind;
 882         g_sngisdn_event_interface.sta.sng_q931_trc_ind  = sngisdn_rcv_q931_trace;
 883         g_sngisdn_event_interface.sta.sng_cc_sta_ind    = sngisdn_rcv_cc_ind;   
 884 
 885         for(i=1;i<=MAX_VARIANTS;i++) {          
 886                 ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex);
 887         }
 888         
 889         /* initalize sng_isdn library */
 890         sng_isdn_init(&g_sngisdn_event_interface);
 891         return FTDM_SUCCESS;
 892 }
 893 
 894 static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_isdn_unload)
 895 {
 896         unsigned i;
 897         ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_isdn unload...\n");
 898 
 899         sng_isdn_free();
 900         
 901         for(i=1;i<=MAX_VARIANTS;i++) {          
 902                 ftdm_mutex_destroy(&g_sngisdn_data.ccs[i].mutex);
 903         }
 904 
 905         ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_isdn unload!\n");
 906         return FTDM_SUCCESS;
 907 }
 908 
 909 static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
 910 {
 911         ftdm_status_t status = FTDM_SUCCESS;
 912         char *mycmd = NULL, *argv[10] = { 0 };
 913         int argc = 0;
 914 
 915         if (data) {
 916                 mycmd = ftdm_strdup(data);
 917                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
 918         }
 919 
 920         /*ftdm_log(FTDM_LOG_DEBUG, "Sangoma argc:%d argv[0]:%s argv[1]:%s argv[2]:%s \n", argc, argv[0], argv[1], argv[2]);*/
 921         if (argc <= 0) {
 922                 ftdm_log(FTDM_LOG_ERROR, "No parameters provided\n");
 923                 goto done;
 924         }
 925 
 926         if (!strcasecmp(argv[0], "trace")) {
 927                 char *trace_opt;
 928                 
 929                 ftdm_span_t *span;
 930 
 931                 if (argc < 3) {
 932                         ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn trace <q921|q931> <span name>\n");
 933                         status = FTDM_FAIL;
 934                         goto done;
 935                 }
 936                 trace_opt = argv[1];
 937                 
 938                 status = ftdm_span_find_by_name(argv[2], &span);
 939                 if (FTDM_SUCCESS != status) {
 940                         stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
 941                         goto done;
 942                 }
 943                 if (!strcasecmp(trace_opt, "q921")) {
 944                         sng_isdn_activate_trace(span, SNGISDN_TRACE_Q921);
 945                 } else if (!strcasecmp(trace_opt, "q931")) {
 946                         sng_isdn_activate_trace(span, SNGISDN_TRACE_Q931);
 947                 } else if (!strcasecmp(trace_opt, "disable")) {
 948                         sng_isdn_activate_trace(span, SNGISDN_TRACE_DISABLE);
 949                 } else {
 950                         stream->write_function(stream, "-ERR invalid trace option <q921|q931> <span name>\n");
 951                 }       
 952         }
 953         if (!strcasecmp(argv[0], "l1_stats")) {
 954                 ftdm_span_t *span;
 955                 if (argc < 2) {
 956                         stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats <span name>\n");
 957                         status = FTDM_FAIL;
 958                         goto done;
 959                 }
 960                 status = ftdm_span_find_by_name(argv[1], &span);
 961                 if (FTDM_SUCCESS != status) {
 962                         stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
 963                         /* Return SUCCESS because we do not want to print the general FTDM usage list */
 964                         status = FTDM_SUCCESS; 
 965                         goto done;
 966                 }
 967                 sngisdn_print_phy_stats(stream, span);
 968         }
 969 
 970         if (!strcasecmp(argv[0], "show_spans")) {
 971                 ftdm_span_t *span = NULL;
 972                 if (argc == 2) {
 973                         status = ftdm_span_find_by_name(argv[1], &span);
 974                         if (FTDM_SUCCESS != status) {
 975                                 stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
 976                                 /* Return SUCCESS because we do not want to print the general FTDM usage list */
 977                                 status = FTDM_SUCCESS;
 978                                 goto done;
 979                         }
 980                         sngisdn_print_span(stream, span);
 981                         status = FTDM_SUCCESS;
 982                         goto done;
 983                 }
 984                 sngisdn_print_spans(stream);
 985         }
 986         if (!strcasecmp(argv[0], "check_ids")) {
 987                 sngisdn_check_free_ids();
 988         }
 989 done:
 990         ftdm_safe_free(mycmd);
 991         return status;
 992 }
 993 
 994 static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
 995 {
 996         memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));
 997 
 998         g_sngisdn_io_interface.name = "sangoma_isdn";
 999         g_sngisdn_io_interface.api = ftdm_sangoma_isdn_api;
1000 
1001         *fio = &g_sngisdn_io_interface;
1002 
1003         return FTDM_SUCCESS;
1004 }
1005 
1006 ftdm_module_t ftdm_module =
1007 {
1008         "sangoma_isdn",                /* char name[256]; */
1009         ftdm_sangoma_isdn_io_init,     /* fio_io_load_t */
1010         NULL,                                              /* fio_io_unload_t */
1011         ftdm_sangoma_isdn_init,        /* fio_sig_load_t */
1012         NULL,                          /* fio_sig_configure_t */
1013         ftdm_sangoma_isdn_unload,      /* fio_sig_unload_t */
1014         ftdm_sangoma_isdn_span_config  /* fio_configure_span_signaling_t */
1015 };
1016 
1017 
1018 /* For Emacs:
1019  * Local Variables:
1020  * mode:c
1021  * indent-tabs-mode:t
1022  * tab-width:4
1023  * c-basic-offset:4
1024  * End:
1025  * For VIM:
1026  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
1027  */
1028 
1029 /******************************************************************************/
1030 
1031 

/* [<][>][^][v][top][bottom][index][help] */