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 
 269                 /* Check if there are any timers to process */
 270                 ftdm_sched_run(signal_data->sched);
 271                 
 272                 ret_status = ftdm_interrupt_multiple_wait(ftdm_sangoma_isdn_int, 2, sleep);
 273                 /* find out why we returned from the interrupt queue */
 274                 switch (ret_status) {
 275                         case FTDM_SUCCESS:  /* there was a state change on the span */
 276                                 /* process all pending state changes */                 
 277                                 while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
 278                                         /* double check that this channel has a state change pending */
 279                                         ftdm_channel_lock(ftdmchan);
 280                                         ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 281                                         ftdm_channel_unlock(ftdmchan);
 282                                 }
 283 
 284                                 while ((sngisdn_event = ftdm_queue_dequeue(signal_data->event_queue))) {
 285                                         ftdm_sangoma_isdn_process_stack_event(span, sngisdn_event);
 286                                         ftdm_safe_free(sngisdn_event);
 287                                 }
 288                                 ftdm_span_trigger_signals(span);
 289                                 break;
 290                         case FTDM_TIMEOUT:
 291                                 /* twiddle */
 292                                 break;
 293                         case FTDM_FAIL:
 294                                 ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name);
 295                                 break;
 296 
 297                         default:
 298                                 ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name);
 299                                 break;
 300                 }
 301 
 302                 /* Poll for events, e.g HW DTMF */
 303                 ret_status = ftdm_span_poll_event(span, 0);
 304                 switch(ret_status) {
 305                         case FTDM_SUCCESS:
 306                                 {
 307                                         ftdm_event_t *event;
 308                                         while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS);
 309                                 }
 310                                 break;
 311                         case FTDM_TIMEOUT:
 312                                 /* No events pending */
 313                                 break;
 314                         default:
 315                                 ftdm_log(FTDM_LOG_WARNING, "%s:Failed to poll span event\n", span->name);
 316                 }
 317                         
 318                 if (ftdm_sched_get_time_to_next_timer(signal_data->sched, &sleep) == FTDM_SUCCESS) {
 319                         if (sleep < 0 || sleep > SNGISDN_EVENT_POLL_RATE) {
 320                                 sleep = SNGISDN_EVENT_POLL_RATE;
 321                         }
 322                 }
 323         }
 324         
 325         /* clear the IN_THREAD flag so that we know the thread is done */
 326         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 327 
 328         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping.\n", span->name);
 329 
 330         return NULL;
 331 
 332 ftdm_sangoma_isdn_run_exit:
 333 
 334         /* clear the IN_THREAD flag so that we know the thread is done */
 335         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 336 
 337         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping due to error.\n", span->name);
 338 
 339         return NULL;
 340 }
 341 
 342 
 343 /**
 344  * \brief Checks if span has state changes pending and processes
 345  * \param span Span where event was fired
 346  * \param sngisdn_event Event to handle
 347  * \return The locked FTDM channel associated to the event if any, NULL otherwise
 348  */
 349 
 350 ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 351 {
 352         ftdm_channel_t *ftdmchan = NULL;
 353         switch (sngisdn_event->event_id) {
 354                 /* Events that do not have a channel associated to them */
 355                 case SNGISDN_EVENT_SRV_IND:
 356                 case SNGISDN_EVENT_SRV_CFM:
 357                 case SNGISDN_EVENT_RST_CFM:
 358                 case SNGISDN_EVENT_RST_IND:
 359                         return NULL;
 360                         break;
 361                 case SNGISDN_EVENT_CON_IND:
 362                 case SNGISDN_EVENT_CON_CFM:
 363                 case SNGISDN_EVENT_CNST_IND:
 364                 case SNGISDN_EVENT_DISC_IND:
 365                 case SNGISDN_EVENT_REL_IND:
 366                 case SNGISDN_EVENT_DAT_IND:
 367                 case SNGISDN_EVENT_SSHL_IND:
 368                 case SNGISDN_EVENT_SSHL_CFM:
 369                 case SNGISDN_EVENT_RMRT_IND:
 370                 case SNGISDN_EVENT_RMRT_CFM:
 371                 case SNGISDN_EVENT_FLC_IND:
 372                 case SNGISDN_EVENT_FAC_IND:
 373                 case SNGISDN_EVENT_STA_CFM:
 374                         ftdmchan = sngisdn_event->sngisdn_info->ftdmchan;
 375                         ftdm_assert_return(ftdmchan, NULL,"Event should have a channel associated\n");
 376                         break;
 377         }
 378         ftdm_channel_lock(ftdmchan);
 379         ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 380         return ftdmchan;
 381 }
 382 
 383 
 384 
 385 static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 386 {
 387         ftdm_channel_t *ftdmchan = NULL;
 388         
 389         ftdmchan = ftdm_sangoma_isdn_process_event_states(span, sngisdn_event);
 390         switch(sngisdn_event->event_id) {
 391                 case SNGISDN_EVENT_CON_IND:
 392                         sngisdn_process_con_ind(sngisdn_event);
 393                         break;
 394                 case SNGISDN_EVENT_CON_CFM:
 395                         sngisdn_process_con_cfm(sngisdn_event);
 396                         break;
 397                 case SNGISDN_EVENT_CNST_IND:
 398                         sngisdn_process_cnst_ind(sngisdn_event);
 399                         break;
 400                 case SNGISDN_EVENT_DISC_IND:
 401                         sngisdn_process_disc_ind(sngisdn_event);
 402                         break;
 403                 case SNGISDN_EVENT_REL_IND:
 404                         sngisdn_process_rel_ind(sngisdn_event);
 405                         break;
 406                 case SNGISDN_EVENT_DAT_IND:
 407                         sngisdn_process_dat_ind(sngisdn_event);
 408                         break;
 409                 case SNGISDN_EVENT_SSHL_IND:
 410                         sngisdn_process_sshl_ind(sngisdn_event);
 411                         break;
 412                 case SNGISDN_EVENT_SSHL_CFM:
 413                         sngisdn_process_sshl_cfm(sngisdn_event);
 414                         break;
 415                 case SNGISDN_EVENT_RMRT_IND:
 416                         sngisdn_process_rmrt_ind(sngisdn_event);
 417                         break;
 418                 case SNGISDN_EVENT_RMRT_CFM:
 419                         sngisdn_process_rmrt_cfm(sngisdn_event);
 420                         break;
 421                 case SNGISDN_EVENT_FLC_IND:
 422                         sngisdn_process_flc_ind(sngisdn_event);
 423                         break;
 424                 case SNGISDN_EVENT_FAC_IND:
 425                         sngisdn_process_fac_ind(sngisdn_event);
 426                         break;
 427                 case SNGISDN_EVENT_STA_CFM:
 428                         sngisdn_process_sta_cfm(sngisdn_event);
 429                         break;
 430                 case SNGISDN_EVENT_SRV_IND:
 431                         sngisdn_process_srv_ind(sngisdn_event);
 432                         break;
 433                 case SNGISDN_EVENT_SRV_CFM:
 434                         sngisdn_process_srv_cfm(sngisdn_event);
 435                         break;
 436                 case SNGISDN_EVENT_RST_CFM:
 437                         sngisdn_process_rst_cfm(sngisdn_event);
 438                         break;
 439                 case SNGISDN_EVENT_RST_IND:
 440                         sngisdn_process_rst_ind(sngisdn_event);
 441                         break;
 442         }
 443         if(ftdmchan != NULL) {
 444                 ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
 445                 ftdm_channel_unlock(ftdmchan);
 446         }
 447 }
 448 
 449 static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 450 {
 451         ftdm_sigmsg_t           sigev;
 452         ftdm_channel_state_t initial_state;
 453         sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
 454 
 455         memset(&sigev, 0, sizeof(sigev));
 456 
 457         sigev.chan_id = ftdmchan->chan_id;
 458         sigev.span_id = ftdmchan->span_id;
 459         sigev.channel = ftdmchan;
 460 
 461         /*first lock the channel*/
 462         ftdm_channel_lock(ftdmchan);
 463         /*clear the state change flag...since we might be setting a new state*/
 464         ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
 465 #ifdef FTDM_DEBUG_CHAN_MEMORY
 466         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 467                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
 468         }
 469 #endif
 470         
 471         /* Only needed for debugging */
 472         initial_state = ftdmchan->state;
 473 
 474         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state change to %s\n", ftdm_channel_state2str(ftdmchan->state));
 475 
 476         switch (ftdmchan->state) {
 477         case FTDM_CHANNEL_STATE_COLLECT:         /* SETUP received but waiting on digits */
 478                 {
 479                         /* TODO: Re-implement this. There is a way to re-evaluate new incoming digits from dialplan as they come */
 480                         sngisdn_snd_setup_ack(ftdmchan);
 481                         /* Just wait in this state until we get enough digits or T302 timeout */
 482                 }
 483                 break;
 484         case FTDM_CHANNEL_STATE_GET_CALLERID:
 485                 {
 486                         sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 487                         sngisdn_snd_proceed(ftdmchan);
 488                         /* Wait in this state until we get FACILITY msg */                      
 489                 }
 490                 break;
 491         case FTDM_CHANNEL_STATE_RING: /* incoming call request */
 492                 {
 493                         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);
 494 
 495                         /* we have enough information to inform FTDM of the call*/
 496                         sigev.event_id = FTDM_SIGEVENT_START;
 497                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 498                 }
 499                 break;
 500         case FTDM_CHANNEL_STATE_DIALING: /* outgoing call request */
 501                 {
 502                         sngisdn_snd_setup(ftdmchan);
 503                 }
 504                 break;
 505         case FTDM_CHANNEL_STATE_PROGRESS:
 506                 {
 507                         /*check if the channel is inbound or outbound*/
 508                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 509                                 /*OUTBOUND...so we were told by the line of this so noifiy the user*/
 510                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS;
 511                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 512                         } else if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
 513                                 sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 514                                 sngisdn_snd_proceed(ftdmchan);
 515                         }
 516                 }
 517                 break;
 518         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 519                 {
 520                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 521                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
 522                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 523                         } else {
 524                                 sngisdn_snd_progress(ftdmchan);
 525                         }
 526                 }
 527                 break; 
 528         case FTDM_CHANNEL_STATE_UP: /* call is answered */
 529                 {
 530                         /* check if the channel is inbound or outbound */
 531                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 532                                 /* OUTBOUND ... so we were told by the line that the other side answered */
 533                                 sigev.event_id = FTDM_SIGEVENT_UP;
 534                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 535 
 536                                 if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
 537                                         ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
 538                                         /* Assign the call to a specific equipment */
 539                                         sngisdn_snd_con_complete(ftdmchan);
 540                                 }
 541                         } else {
 542                                 /* INBOUND ... so FS told us it just answered ... tell the stack */
 543                                 sngisdn_snd_connect(ftdmchan);
 544                         }
 545                 }
 546                 break;
 547         case FTDM_CHANNEL_STATE_CANCEL:
 548                 {
 549                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call before informing user!\n");
 550 
 551                         /* Send a release complete */
 552                         sngisdn_snd_release(ftdmchan, 0);
 553                         /*now go to the HANGUP complete state*/                         
 554                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 555                 }
 556                 break;
 557         case FTDM_CHANNEL_STATE_TERMINATING: /* call is hung up by the remote end */
 558                 {
 559                         /* this state is set when the line is hanging up */
 560                         sigev.event_id = FTDM_SIGEVENT_STOP;
 561                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 562                 }
 563                 break;
 564         case FTDM_CHANNEL_STATE_HANGUP: /* call is hung up locally */
 565                 {
 566                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT)) {
 567                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote abort\n");
 568                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_REL)) {
 569                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote hangup\n");
 570                                 sngisdn_snd_release(ftdmchan, 0);
 571                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 572                                 /* We aborted this call before sending anything to the stack, so nothing to do anymore */
 573                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Clearing local states from local abort\n");
 574                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 575                                 /* We are hangup local call because there was a glare, we are waiting for a
 576                                 RELEASE on this call, before we can process the saved call */
 577                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for RELEASE on hungup glared call\n");
 578                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_SEND_DISC)) {
 579                                 /* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/
 580                                 sngisdn_snd_disconnect(ftdmchan);
 581                         } else {
 582                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n");
 583 
 584                                  /* set the flag to indicate this hangup is started from the local side */
 585                                 sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL);
 586 
 587                                 /* If we never sent ack to incoming call, we need to send release instead of disconnect */
 588                                 if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING ||
 589                                         ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALING) {
 590 
 591                                         sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 592                                         sngisdn_snd_release(ftdmchan, 0);
 593 
 594                                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 595                                                 sng_isdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
 596                                         }
 597                                 } else {
 598                                         sngisdn_snd_disconnect(ftdmchan);
 599                                 }
 600                         }
 601 
 602                         /* now go to the HANGUP complete state */
 603                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 604                 }
 605                 break;
 606         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
 607                 {
 608                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT) ||
 609                                 sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 610                                 /* If the remote side aborted, we will not get anymore message for this call */
 611                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 612                         } else {
 613                                 /* waiting on remote confirmation before moving to down */
 614                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for release from stack\n");
 615                         }
 616                 }
 617                 break;
 618         case FTDM_CHANNEL_STATE_DOWN: /* the call is finished and removed */
 619                 {
 620                         uint8_t glare = 0;
 621 
 622                         glare = sngisdn_test_flag(sngisdn_info, FLAG_GLARE);
 623                         /* clear all of the call specific data store in the channel structure */
 624                         clear_call_data(sngisdn_info);
 625 
 626                         /* Close the channel even if we had a glare, we will re-open it when processing state COLLECT for the
 627                                 "glared call" */
 628                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
 629                                 ftdm_channel_t *close_chan = ftdmchan;
 630                                 /* close the channel */
 631                                 ftdm_channel_close(&close_chan);
 632                         }
 633                         if (glare) {
 634 
 635                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare detected, processing saved call\n");
 636                                 /* We are calling sngisdn_rcv_con_ind with ftdmchan->mutex being locked,
 637                                         so no other threads will be able to touch this channel. The next time we will
 638                                         process this channel is in this function, and it should be in state COLLECT (set inside
 639                                         sngisdn_rcv_con_ind)*/
 640                                 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);
 641                         }
 642                 }
 643                 break;
 644         case FTDM_CHANNEL_STATE_RESTART:
 645                 {
 646                         /* IMPLEMENT ME */
 647                 }
 648 
 649                 break;
 650         case FTDM_CHANNEL_STATE_SUSPENDED:
 651                 {
 652                         /* IMPLEMENT ME */
 653                 }
 654                 break;
 655         default:
 656                 {
 657                         ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsupported sngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state));
 658                 }
 659                 break;
 660         }
 661         
 662         if (ftdmchan->state == initial_state) {
 663                 ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "state change flag is still set, but we did not change state\n");
 664         }
 665 #ifdef FTDM_DEBUG_CHAN_MEMORY
 666         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 667                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
 668         }
 669 #endif
 670         ftdm_channel_unlock(ftdmchan);
 671         return;
 672 }
 673 
 674 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call)
 675 {
 676         sngisdn_chan_data_t  *sngisdn_info = ftdmchan->call_data;
 677         ftdm_status_t status = FTDM_FAIL;       
 678         
 679         /* lock the channel while we check whether it is availble */
 680         ftdm_channel_lock(ftdmchan);
 681 
 682         switch (ftdmchan->state) {
 683 
 684                 case FTDM_CHANNEL_STATE_DOWN:
 685                         {
 686                                 if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 687                                         /* A call came in after we called ftdm_channel_open_chan for this call, but before we got here */
 688                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Glare detected - aborting outgoing call\n");
 689 
 690                                         sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 691                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 692 
 693                                         status = FTDM_BREAK;
 694                                 } else {
 695                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
 696                                         status = FTDM_SUCCESS;
 697                                 }
 698                         }
 699                         break;
 700                 default:
 701                 {
 702                         /* the channel is already used...this can't be, end the request */
 703                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Outgoing call requested channel in already in use\n");
 704                         status = FTDM_BREAK;
 705                 }
 706                 break;            
 707         }
 708 
 709         ftdm_channel_unlock(ftdmchan);
 710         return status;
 711 }
 712 
 713 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_chan_sig_status)
 714 {
 715         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 716                 *status = FTDM_SIG_STATE_UP;
 717         } else {
 718                 *status = FTDM_SIG_STATE_DOWN;
 719         }
 720 
 721         return FTDM_SUCCESS;
 722 }
 723 
 724 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_chan_sig_status)
 725 {
 726         ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n");
 727         return FTDM_NOTIMPL;
 728 }
 729 
 730 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_span_sig_status)
 731 {       
 732         if (ftdm_test_flag(span->channels[1], FTDM_CHANNEL_SIG_UP)) {
 733                 *status = FTDM_SIG_STATE_UP;
 734         } else {
 735                 *status = FTDM_SIG_STATE_DOWN;
 736         }
 737 
 738         return FTDM_SUCCESS;
 739 }
 740 
 741 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
 742 {
 743         ftdm_log(FTDM_LOG_ERROR,"Cannot set span status in this module\n");
 744         return FTDM_NOTIMPL;
 745 }
 746 
 747 static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
 748 {       
 749         ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
 750         if (sng_isdn_stack_start(span) != FTDM_SUCCESS) {
 751                 ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
 752                 return FTDM_FAIL;
 753         }
 754         /* clear the monitor thread stop flag */
 755         ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
 756         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 757 
 758         /*start the span monitor thread*/
 759         if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) {
 760                 ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n");
 761                 return FTDM_FAIL;
 762         }
 763 
 764         ftdm_log(FTDM_LOG_DEBUG,"Finished starting span %s\n", span->name);
 765         return FTDM_SUCCESS;
 766 }
 767 
 768 static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span)
 769 {       
 770         ftdm_iterator_t *chaniter = NULL;
 771         ftdm_iterator_t *curr = NULL;
 772         unsigned i;
 773         sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
 774         ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name);
 775         
 776         /* throw the STOP_THREAD flag to signal monitor thread stop */
 777         ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
 778 
 779         /* wait for the thread to stop */
 780         while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
 781                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for monitor thread to end for span %s\n", span->name);
 782                 ftdm_sleep(10);
 783         }
 784 
 785         if (sng_isdn_stack_stop(span) != FTDM_SUCCESS) {
 786                 ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s\n", span->name);
 787         }
 788         
 789         chaniter = ftdm_span_get_chan_iterator(span, NULL);
 790         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
 791                 ftdm_safe_free(((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data);
 792                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = NULL;
 793         }
 794         ftdm_iterator_free(chaniter);
 795 
 796         ftdm_sched_destroy(&signal_data->sched);
 797         ftdm_queue_destroy(&signal_data->event_queue);
 798         for (i = 0 ; i < signal_data->num_local_numbers ; i++) {
 799                 if (signal_data->local_numbers[i] != NULL) {
 800                         ftdm_safe_free(signal_data->local_numbers[i]);
 801                 }
 802         }
 803         ftdm_safe_free(span->signal_data);
 804 
 805         ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name);
 806 
 807         return FTDM_SUCCESS;
 808 }
 809 
 810 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
 811 {
 812         ftdm_iterator_t *chaniter = NULL;
 813         ftdm_iterator_t *curr = NULL;
 814 
 815         sngisdn_span_data_t *span_data;
 816         
 817         ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name);      
 818 
 819         span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t));
 820         span_data->ftdm_span = span;
 821         span->signal_data = span_data;
 822         
 823         chaniter = ftdm_span_get_chan_iterator(span, NULL);
 824         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
 825                 sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t));
 826                 chan_data->ftdmchan = ((ftdm_channel_t*)ftdm_iterator_current(curr));
 827                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = chan_data;
 828                 
 829         }
 830         ftdm_iterator_free(chaniter);
 831 
 832         if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) {
 833                 ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n");
 834                 return FTDM_FAIL;
 835         }
 836 
 837         if (sng_isdn_stack_cfg(span) != FTDM_SUCCESS) {
 838                 ftdm_log(FTDM_LOG_CRIT, "Sangoma ISDN Stack configuration failed\n");
 839                 return FTDM_FAIL;
 840         }
 841 
 842 
 843         span->start = ftdm_sangoma_isdn_start;
 844         span->stop = ftdm_sangoma_isdn_stop;
 845         span->signal_type = FTDM_SIGTYPE_ISDN;
 846         span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
 847         span->channel_request = NULL;
 848         span->signal_cb = sig_cb;
 849         span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
 850         span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status;
 851         span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
 852         span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
 853         span->state_map = &sangoma_isdn_state_map;
 854         ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
 855         ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
 856 
 857         if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
 858                 span->trunk_type == FTDM_TRUNK_BRI) {
 859 
 860                 ftdm_set_flag(span, FTDM_SPAN_USE_AV_RATE);
 861                 sng_isdn_set_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
 862         }
 863 
 864         /* Initialize scheduling context */
 865         ftdm_assert(ftdm_sched_create(&((sngisdn_span_data_t*)span->signal_data)->sched, "sngisdn_schedule") == FTDM_SUCCESS, "Failed to create a new schedule!!");
 866 
 867         /* Initialize the event queue */
 868         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!!");
 869 
 870         ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_isdn span = %s\n", span->name);
 871         return FTDM_SUCCESS;
 872 }
 873 
 874 static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
 875 {
 876         unsigned i;
 877         ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_isdn...\n");
 878 
 879         memset(&g_sngisdn_data, 0, sizeof(g_sngisdn_data));
 880 
 881         /* set callbacks */
 882         g_sngisdn_event_interface.cc.sng_con_ind        = sngisdn_rcv_con_ind;
 883         g_sngisdn_event_interface.cc.sng_con_cfm        = sngisdn_rcv_con_cfm;
 884         g_sngisdn_event_interface.cc.sng_cnst_ind       = sngisdn_rcv_cnst_ind;
 885         g_sngisdn_event_interface.cc.sng_disc_ind       = sngisdn_rcv_disc_ind;
 886         g_sngisdn_event_interface.cc.sng_rel_ind        = sngisdn_rcv_rel_ind;
 887         g_sngisdn_event_interface.cc.sng_dat_ind        = sngisdn_rcv_dat_ind;
 888         g_sngisdn_event_interface.cc.sng_sshl_ind       = sngisdn_rcv_sshl_ind;
 889         g_sngisdn_event_interface.cc.sng_sshl_cfm       = sngisdn_rcv_sshl_cfm;
 890         g_sngisdn_event_interface.cc.sng_rmrt_ind       = sngisdn_rcv_rmrt_ind;
 891         g_sngisdn_event_interface.cc.sng_rmrt_cfm       = sngisdn_rcv_rmrt_cfm;
 892         g_sngisdn_event_interface.cc.sng_flc_ind        = sngisdn_rcv_flc_ind;
 893         g_sngisdn_event_interface.cc.sng_fac_ind        = sngisdn_rcv_fac_ind;
 894         g_sngisdn_event_interface.cc.sng_sta_cfm        = sngisdn_rcv_sta_cfm;
 895         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_ind;
 896         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_cfm;
 897         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_cfm;
 898         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_ind;
 899         g_sngisdn_event_interface.cc.sng_rst_cfm        = sngisdn_rcv_rst_cfm;
 900 
 901         g_sngisdn_event_interface.lg.sng_log            = sngisdn_rcv_sng_log;
 902         g_sngisdn_event_interface.lg.sng_assert         = sngisdn_rcv_sng_assert;
 903         
 904         g_sngisdn_event_interface.sta.sng_phy_sta_ind   = sngisdn_rcv_phy_ind;
 905         g_sngisdn_event_interface.sta.sng_q921_sta_ind  = sngisdn_rcv_q921_ind;
 906         g_sngisdn_event_interface.sta.sng_q921_trc_ind  = sngisdn_rcv_q921_trace;
 907         g_sngisdn_event_interface.sta.sng_q931_sta_ind  = sngisdn_rcv_q931_ind;
 908         g_sngisdn_event_interface.sta.sng_q931_trc_ind  = sngisdn_rcv_q931_trace;
 909         g_sngisdn_event_interface.sta.sng_cc_sta_ind    = sngisdn_rcv_cc_ind;   
 910 
 911         for(i=1;i<=MAX_VARIANTS;i++) {          
 912                 ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex);
 913         }
 914         
 915         /* initalize sng_isdn library */
 916         sng_isdn_init(&g_sngisdn_event_interface);
 917         return FTDM_SUCCESS;
 918 }
 919 
 920 static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_isdn_unload)
 921 {
 922         unsigned i;
 923         ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_isdn unload...\n");
 924 
 925         sng_isdn_free();
 926         
 927         for(i=1;i<=MAX_VARIANTS;i++) {          
 928                 ftdm_mutex_destroy(&g_sngisdn_data.ccs[i].mutex);
 929         }
 930 
 931         ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_isdn unload!\n");
 932         return FTDM_SUCCESS;
 933 }
 934 
 935 static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
 936 {
 937         ftdm_status_t status = FTDM_SUCCESS;
 938         char *mycmd = NULL, *argv[10] = { 0 };
 939         int argc = 0;
 940 
 941         if (data) {
 942                 mycmd = ftdm_strdup(data);
 943                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
 944         }
 945 
 946         /*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]);*/
 947         if (argc <= 0) {
 948                 ftdm_log(FTDM_LOG_ERROR, "No parameters provided\n");
 949                 goto done;
 950         }
 951 
 952         if (!strcasecmp(argv[0], "trace")) {
 953                 char *trace_opt;
 954                 
 955                 ftdm_span_t *span;
 956 
 957                 if (argc < 3) {
 958                         ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn trace <q921|q931> <span name>\n");
 959                         status = FTDM_FAIL;
 960                         goto done;
 961                 }
 962                 trace_opt = argv[1];
 963                 
 964                 status = ftdm_span_find_by_name(argv[2], &span);
 965                 if (FTDM_SUCCESS != status) {
 966                         stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
 967                         goto done;
 968                 }
 969                 if (!strcasecmp(trace_opt, "q921")) {
 970                         sng_isdn_activate_trace(span, SNGISDN_TRACE_Q921);
 971                 } else if (!strcasecmp(trace_opt, "q931")) {
 972                         sng_isdn_activate_trace(span, SNGISDN_TRACE_Q931);
 973                 } else if (!strcasecmp(trace_opt, "disable")) {
 974                         sng_isdn_activate_trace(span, SNGISDN_TRACE_DISABLE);
 975                 } else {
 976                         stream->write_function(stream, "-ERR invalid trace option <q921|q931> <span name>\n");
 977                 }       
 978         }
 979         if (!strcasecmp(argv[0], "l1_stats")) {
 980                 ftdm_span_t *span;
 981                 if (argc < 2) {
 982                         stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats <span name>\n");
 983                         status = FTDM_FAIL;
 984                         goto done;
 985                 }
 986                 status = ftdm_span_find_by_name(argv[1], &span);
 987                 if (FTDM_SUCCESS != status) {
 988                         stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
 989                         /* Return SUCCESS because we do not want to print the general FTDM usage list */
 990                         status = FTDM_SUCCESS; 
 991                         goto done;
 992                 }
 993                 sngisdn_print_phy_stats(stream, span);
 994         }
 995 
 996         if (!strcasecmp(argv[0], "show_spans")) {
 997                 ftdm_span_t *span = NULL;
 998                 if (argc == 2) {
 999                         status = ftdm_span_find_by_name(argv[1], &span);
1000                         if (FTDM_SUCCESS != status) {
1001                                 stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
1002                                 /* Return SUCCESS because we do not want to print the general FTDM usage list */
1003                                 status = FTDM_SUCCESS;
1004                                 goto done;
1005                         }
1006                         sngisdn_print_span(stream, span);
1007                         status = FTDM_SUCCESS;
1008                         goto done;
1009                 }
1010                 sngisdn_print_spans(stream);
1011         }
1012         if (!strcasecmp(argv[0], "check_ids")) {
1013                 sngisdn_check_free_ids();
1014         }
1015 done:
1016         ftdm_safe_free(mycmd);
1017         return status;
1018 }
1019 
1020 static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
1021 {
1022         memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));
1023 
1024         g_sngisdn_io_interface.name = "sangoma_isdn";
1025         g_sngisdn_io_interface.api = ftdm_sangoma_isdn_api;
1026 
1027         *fio = &g_sngisdn_io_interface;
1028 
1029         return FTDM_SUCCESS;
1030 }
1031 
1032 ftdm_module_t ftdm_module =
1033 {
1034         "sangoma_isdn",                /* char name[256]; */
1035         ftdm_sangoma_isdn_io_init,     /* fio_io_load_t */
1036         NULL,                                              /* fio_io_unload_t */
1037         ftdm_sangoma_isdn_init,        /* fio_sig_load_t */
1038         NULL,                          /* fio_sig_configure_t */
1039         ftdm_sangoma_isdn_unload,      /* fio_sig_unload_t */
1040         ftdm_sangoma_isdn_span_config  /* fio_configure_span_signaling_t */
1041 };
1042 
1043 
1044 /* For Emacs:
1045  * Local Variables:
1046  * mode:c
1047  * indent-tabs-mode:t
1048  * tab-width:4
1049  * c-basic-offset:4
1050  * End:
1051  * For VIM:
1052  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
1053  */
1054 
1055 /******************************************************************************/
1056 
1057 

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