57#if defined(__NetBSD__) || defined(__FreeBSD__)
60#include <sys/sysmacros.h>
76#error "Upgrade your libpri"
82#if !defined(LIBSS7_ABI_COMPATIBILITY)
83#error "Upgrade your libss7"
84#elif LIBSS7_ABI_COMPATIBILITY != 2
85#error "Your installed libss7 is not compatible"
89#if defined(HAVE_OPENR2)
91#define SIG_MFCR2_MAX_CHANNELS 672
603#define SMDI_MD_WAIT_TIMEOUT 1500
606"0 db (CSU)/0-133 feet (DSX-1)",
607"133-266 feet (DSX-1)",
608"266-399 feet (DSX-1)",
609"399-533 feet (DSX-1)",
610"533-655 feet (DSX-1)",
622 .resync_threshold = 1000,
640#define DEFAULT_CIDRINGS 1
642#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
646#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
648static const char tdesc[] =
"DAHDI Telephony"
649#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
651 #if defined(HAVE_PRI)
654 #if defined(HAVE_SS7)
655 #if defined(HAVE_PRI)
660 #if defined(HAVE_OPENR2)
661 #if defined(HAVE_PRI) || defined(HAVE_SS7)
669static const char config[] =
"chan_dahdi.conf";
672#define NUM_SPANS DAHDI_MAX_SPANS
677#define CHAN_PSEUDO -2
679#define CALLPROGRESS_PROGRESS 1
680#define CALLPROGRESS_FAX_OUTGOING 2
681#define CALLPROGRESS_FAX_INCOMING 4
682#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
684#define NUM_CADENCE_MAX 25
691 { { 125, 125, 2000, 4000 } },
692 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } },
693 { { 125, 125, 125, 125, 125, 4000 } },
694 { { 1000, 500, 2500, 5000 } },
711#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
712 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
714#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) )
715#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) )
722#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
736#define REPORT_CHANNEL_ALARMS 1
737#define REPORT_SPAN_ALARMS 2
741static int pridebugfd = -1;
742static char pridebugfilename[1024] =
"";
776 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
785 i = DAHDI_IOMUX_SIGEVENT;
786 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
788 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
796#define MASK_AVAIL (1 << 0)
797#define MASK_INUSE (1 << 1)
799#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE)
800#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE)
801#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE)
802#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE)
803#define MIN_MS_SINCE_FLASH ((2000) )
804#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE)
805#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE)
819static struct dahdi_ss7 linksets[
NUM_SPANS];
821static int cur_ss7type = -1;
822static int cur_slc = -1;
823static int cur_linkset = -1;
824static int cur_pointcode = -1;
825static int cur_cicbeginswith = -1;
826static int cur_adjpointcode = -1;
827static int cur_networkindicator = -1;
828static int cur_defaultdpc = -1;
832struct dahdi_mfcr2_conf {
833 openr2_variant_t variant;
835 int metering_pulse_timeout;
838#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
842#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
843 int dtmf_end_timeout;
845 signed int get_ani_first:2;
846#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
847 signed int skip_category_request:2;
849 unsigned int call_files:1;
850 unsigned int allow_collect_calls:1;
851 unsigned int charge_calls:1;
852 unsigned int accept_on_offer:1;
853 unsigned int forced_release:1;
854 unsigned int double_answer:1;
855 signed int immediate_accept:2;
856#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
857 signed int dtmf_dialing:2;
858 signed int dtmf_detection:2;
860 char logdir[OR2_MAX_PATH];
861 char r2proto_file[OR2_MAX_PATH];
862 openr2_log_level_t loglevel;
863 openr2_calling_party_category_t category;
870 openr2_context_t *protocol_context;
875 struct dahdi_mfcr2_conf
conf;
879 struct dahdi_mfcr2 mfcr2;
887static int r2links_count = 0;
895 int mastertrunkgroup;
902#if defined(HAVE_PRI_CCSS)
904static const char dahdi_pri_cc_type[] =
"DAHDI/PRI";
913#define POLARITY_IDLE 0
914#define POLARITY_REV 1
934static struct dahdi_parms_pseudo {
955 struct dahdi_pri pri;
959 struct dahdi_ss7 ss7;
963 struct dahdi_mfcr2_conf mfcr2;
999 .switchtype = PRI_SWITCH_NI2,
1000 .dialplan = PRI_UNKNOWN + 1,
1001 .localdialplan = PRI_NATIONAL_ISDN + 1,
1002 .nodetype = PRI_CPE,
1005#if defined(HAVE_PRI_CCSS)
1006 .cc_ptmp_recall_mode = 1,
1007 .cc_qsig_signaling_link_req = 1,
1008 .cc_qsig_signaling_link_rsp = 1,
1014 .internationalprefix =
"",
1015 .nationalprefix =
"",
1017 .privateprefix =
"",
1018 .unknownprefix =
"",
1020 .resetinterval = -1,
1023#if defined(HAVE_SS7)
1025 .called_nai = SS7_NAI_NATIONAL,
1026 .calling_nai = SS7_NAI_NATIONAL,
1027 .internationalprefix =
"",
1028 .nationalprefix =
"",
1029 .subscriberprefix =
"",
1030 .unknownprefix =
"",
1031 .networkroutedprefix =
""
1036 .variant = OR2_VAR_ITU,
1037 .mfback_timeout = -1,
1038 .metering_pulse_timeout = -1,
1041 .get_ani_first = -1,
1042#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1043 .skip_category_request = -1,
1046 .allow_collect_calls = 0,
1048 .accept_on_offer = 1,
1049 .forced_release = 0,
1051 .immediate_accept = -1,
1052#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1054 .dtmf_detection = -1,
1055 .dtmf_time_on = OR2_DEFAULT_DTMF_ON,
1056 .dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
1058#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1059 .dtmf_end_timeout = -1,
1063 .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
1064 .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1068 .context =
"default",
1073 .mohinterpret =
"default",
1076 .transfertobusy = 1,
1079 .ani_info_digits = 2,
1080 .ani_wink_time = 1000,
1081 .ani_timeout = 10000,
1085 .dahditrcallerid = 0,
1094 .echocancel.head.tap_length = 1,
1102#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1105 .polarityonanswerdelay = 600,
1109 .buf_policy = DAHDI_POLICY_IMMEDIATE,
1128 .ignore_failed_channels = 1,
1129 .smdi_port =
"/dev/ttyS0",
1138 const char *
data,
int *cause);
1159 .description =
tdesc,
1180#define GET_CHANNEL(p) ((p)->channel)
1237 return DAHDI_TONE_RINGTONE;
1239 return DAHDI_TONE_STUTTER;
1241 return DAHDI_TONE_CONGESTION;
1243 return DAHDI_TONE_DIALTONE;
1245 return DAHDI_TONE_DIALRECALL;
1247 return DAHDI_TONE_INFO;
1257 switch (analogsub) {
1286 struct doomed_pri *
entry;
1292 ast_debug(4,
"Destroying span %d from doomed queue.\n",
1294 pri_destroy_span(
entry->pri);
1313static void pri_queue_for_destruction(
struct sig_pri_span *pri)
1315 struct doomed_pri *
entry;
1319 if (
entry->pri == pri) {
1332 ast_debug(4,
"Queue span %d for destruction.\n", pri->
span);
1355 struct dahdi_dialoperation zo = {
1361 for (offset = 0; offset <
sizeof(zo.dialstr) - 1; ++offset) {
1368 if (offset >=
sizeof(zo.dialstr) - 3) {
1372 zo.dialstr[offset] =
'w';
1374 zo.dialstr[offset] =
'w';
1377 zo.dialstr[offset] = *pos++;
1381 ast_debug(1,
"Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1382 pvt->
channel, dial_str, zo.dialstr);
1433 struct pollfd poller;
1437 unsigned char buf[256];
1442 poller.events = POLLPRI | POLLIN;
1445 res = poll(&poller, 1, timeout);
1447 if (poller.revents & POLLPRI) {
1452 if (poller.revents & POLLIN) {
1464 if (analog_p->
ringt > 0) {
1465 if (!(--analog_p->
ringt)) {
1528 unsigned char buf[256];
1536 int checkaftercid = 0;
1537 const char *matched_context;
1541 if (ringdata ==
NULL) {
1542 ringdata = curRingData;
1550 for (receivedRingT = 0; receivedRingT <
RING_PATTERNS; receivedRingT++)
1551 ringdata[receivedRingT] = 0;
1555 ast_verb(3,
"Detecting post-CID distinctive ring\n");
1559 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
1560 res = ioctl(p->
subs[idx].
dfd, DAHDI_IOMUX, &i);
1566 if (i & DAHDI_IOMUX_SIGEVENT) {
1569 if (res == DAHDI_EVENT_NOALARM) {
1572 }
else if (res == DAHDI_EVENT_RINGOFFHOOK) {
1574 ringdata[receivedRingT] = analog_p->
ringt;
1585 }
else if (i & DAHDI_IOMUX_READ) {
1588 if (
errno != ELAST) {
1595 if (analog_p->
ringt > 0) {
1596 if (!(--analog_p->
ringt)) {
1605 ast_verb(3,
"Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
1607 for (counter = 0; counter < 3; counter++) {
1611 ast_verb(3,
"Checking %d,%d,%d with +/- %d range\n",
1616 for (counter1 = 0; counter1 < 3; counter1++) {
1620 ast_verb(3,
"Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1621 ringdata[counter1]);
1623 }
else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
1624 ast_verb(3,
"Ring pattern %d is in range: %d to %d\n",
1625 ringdata[counter1], ring - range, ring + range);
1633 if (distMatches == 3) {
1636 ast_verb(3,
"Matched Distinctive Ring context %s\n", matched_context);
1642 if (strcmp(p->
context, matched_context) != 0) {
1730 ast_verb(3,
"CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1806 ast_log(
LOG_ERROR,
"We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1823 ast_debug(1,
"%s DTMF digit: 0x%02X '%c' on %s\n",
1833 struct dahdi_bufferinfo bi = {
1840 if ((res = ioctl(p->
subs[idx].
dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
1878 ast_debug(1,
"Already in a fax extension, not redirecting\n");
1887 *dest = &p->
subs[idx].
f;
1917 if (!channel_string) {
1927 "DAHDIGroup: %llu\r\n"
1929 "DAHDIChannel: %s\r\n",
1950 "channel", dahdi_channel);
1974 snprintf(ch_name,
sizeof(ch_name),
"no-media (%d)", p->
channel);
1977 strcpy(ch_name,
"pseudo");
1980 snprintf(ch_name,
sizeof(ch_name),
"%d", p->
channel);
1994static void my_ami_channel_event(
void *pvt,
struct ast_channel *chan)
2054 return p->
subs[dahdi_sub].
dfd;
2097#if defined(HAVE_PRI) || defined(HAVE_SS7)
2098static void my_set_digital(
void *pvt,
int is_digital)
2106#if defined(HAVE_SS7)
2107static void my_set_inservice(
void *pvt,
int is_inservice)
2115#if defined(HAVE_SS7)
2116static void my_set_locallyblocked(
void *pvt,
int is_blocked)
2124#if defined(HAVE_SS7)
2125static void my_set_remotelyblocked(
void *pvt,
int is_blocked)
2238 p->
owner = new_owner;
2289 for (i = 0; i < 3; i++) {
2326 int needconf = needconference;
2433#if defined(HAVE_PRI) || defined(HAVE_SS7)
2434static int dahdi_setlaw(
int dfd,
int law)
2437 res = ioctl(dfd, DAHDI_SETLAW, &
law);
2444#if defined(HAVE_PRI)
2483 newlaw = DAHDI_LAW_ALAW;
2486 newlaw = DAHDI_LAW_MULAW;
2496#if defined(HAVE_PRI) || defined(HAVE_SS7)
2504static void my_pri_ss7_open_media(
void *p)
2515 res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
2522 res = dahdi_setlaw(dfd, pvt->
law);
2544#if defined(HAVE_PRI)
2555static void my_pri_dial_digits(
void *p,
const char *dial_string)
2557 char dial_str[DAHDI_MAX_DTMF_BUF];
2561 snprintf(dial_str,
sizeof(dial_str),
"T%s", dial_string);
2611 case DAHDI_EVENT_ONHOOK:
2614 case DAHDI_EVENT_RINGOFFHOOK:
2617 case DAHDI_EVENT_WINKFLASH:
2620 case DAHDI_EVENT_ALARM:
2623 case DAHDI_EVENT_NOALARM:
2626 case DAHDI_EVENT_DIALCOMPLETE:
2629 case DAHDI_EVENT_RINGERON:
2632 case DAHDI_EVENT_RINGEROFF:
2635 case DAHDI_EVENT_HOOKCOMPLETE:
2638 case DAHDI_EVENT_PULSE_START:
2641 case DAHDI_EVENT_POLARITY:
2644 case DAHDI_EVENT_RINGBEGIN:
2647 case DAHDI_EVENT_EC_DISABLED:
2650 case DAHDI_EVENT_REMOVED:
2653 case DAHDI_EVENT_NEONMWI_ACTIVE:
2656 case DAHDI_EVENT_NEONMWI_INACTIVE:
2659#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2660 case DAHDI_EVENT_TX_CED_DETECTED:
2663 case DAHDI_EVENT_RX_CED_DETECTED:
2666 case DAHDI_EVENT_EC_NLP_DISABLED:
2669 case DAHDI_EVENT_EC_NLP_ENABLED:
2673 case DAHDI_EVENT_PULSEDIGIT:
2676 case DAHDI_EVENT_DTMFDOWN:
2679 case DAHDI_EVENT_DTMFUP:
2683 switch(
event & 0xFFFF0000) {
2684 case DAHDI_EVENT_PULSEDIGIT:
2685 case DAHDI_EVENT_DTMFDOWN:
2686 case DAHDI_EVENT_DTMFUP:
2728 struct dahdi_params par;
2730 memset(&par, 0,
sizeof(par));
2737 par.rxisoffhook = 0;
2747 return (par.rxbits > -1) || par.rxisoffhook;
2750 return par.rxisoffhook;
2777 int func = DAHDI_FLASH;
2845 struct dahdi_params dahdip;
2853 memset(&dahdip, 0,
sizeof(dahdip));
2860 if (!(dahdip.sigtype & __DAHDI_SIG_FXO)) {
2883 snprintf(buffer, buflen,
"%d", pvt->
polarity);
2898 if (!strcasecmp(
value,
"idle")) {
2900 }
else if (!strcasecmp(
value,
"reverse")) {
2924 int x = DAHDI_START;
2939 ast_log(
LOG_ERROR,
"Trying to dial_digits '%s' on channel %d subchannel %u\n",
2966 if (ioctl(p->
subs[index].
dfd, DAHDI_DIALING, &x)) {
2967 ast_debug(1,
"DAHDI_DIALING ioctl failed!\n");
2980#if defined(HAVE_PRI)
2981static void my_pri_fixup_chans(
void *chan_old,
void *chan_new)
2988 if (new_chan->
owner) {
2995 new_chan->
dsp = old_chan->
dsp;
3009 new_chan->
law = old_chan->
law;
3014#if defined(HAVE_PRI)
3015static int sig_pri_tone_to_dahditone(
enum sig_pri_tone tone)
3019 return DAHDI_TONE_RINGTONE;
3021 return DAHDI_TONE_STUTTER;
3023 return DAHDI_TONE_CONGESTION;
3025 return DAHDI_TONE_DIALTONE;
3027 return DAHDI_TONE_DIALRECALL;
3029 return DAHDI_TONE_INFO;
3031 return DAHDI_TONE_BUSY;
3038#if defined(HAVE_PRI)
3039static void my_handle_dchan_exception(
struct sig_pri_span *pri,
int index)
3043 ioctl(pri->
fds[index], DAHDI_GETEVENT, &x);
3045 case DAHDI_EVENT_NONE:
3047 case DAHDI_EVENT_ALARM:
3048 case DAHDI_EVENT_NOALARM:
3060 case DAHDI_EVENT_ALARM:
3063 case DAHDI_EVENT_NOALARM:
3066 case DAHDI_EVENT_REMOVED:
3067 pri_queue_for_destruction(pri);
3075#if defined(HAVE_PRI)
3076static int my_pri_play_tone(
void *pvt,
enum sig_pri_tone tone)
3080 return tone_zone_play_tone(p->
subs[
SUB_REAL].
dfd, sig_pri_tone_to_dahditone(tone));
3084#if defined(HAVE_PRI) || defined(HAVE_SS7)
3093static void my_set_callerid(
void *pvt,
const struct ast_party_caller *caller)
3108 if (caller->
id.
tag) {
3113 sizeof(p->cid_ani));
3118#if defined(HAVE_PRI) || defined(HAVE_SS7)
3127static void my_set_dnid(
void *pvt,
const char *
dnid)
3135#if defined(HAVE_PRI)
3144static void my_set_rdnis(
void *pvt,
const char *
rdnis)
3152#if defined(HAVE_PRI)
3179static void my_pri_make_cc_dialstring(
void *priv,
char *
buf,
size_t buf_size)
3200 snprintf(
buf, buf_size,
"%s/i%d-",
args.tech, pvt->pri->span);
3203 if (isdigit(
args.group[0]) ||
args.group[0] ==
'i' || strchr(
args.group,
'!')) {
3210 snprintf(
buf, buf_size,
"%s/i%d-%s",
args.tech, pvt->pri->span,
args.group);
3214#if defined(HAVE_PRI)
3224static void dahdi_pri_update_span_devstate(
struct sig_pri_span *pri)
3227 unsigned num_b_chans;
3236 for (idx = pri->
numchans; idx--;) {
3260#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3264 }
else if (!in_use) {
3266 }
else if (!pri->user_busy_threshold) {
3272 if (pri->threshold_devstate != new_state) {
3273 pri->threshold_devstate = new_state;
3280#if defined(HAVE_PRI)
3286static void my_module_ref(
void)
3292#if defined(HAVE_PRI)
3298static void my_module_unref(
void)
3304#if defined(HAVE_PRI)
3305#if defined(HAVE_PRI_CALL_WAITING)
3306static void my_pri_init_config(
void *priv,
struct sig_pri_span *pri);
3308static int dahdi_new_pri_nobch_channel(
struct sig_pri_span *pri);
3313 .play_tone = my_pri_play_tone,
3319 .new_ast_channel = my_new_pri_ast_channel,
3320 .fixup_chans = my_pri_fixup_chans,
3324 .set_digital = my_set_digital,
3325 .set_callerid = my_set_callerid,
3326 .set_dnid = my_set_dnid,
3327 .set_rdnis = my_set_rdnis,
3328 .new_nobch_intf = dahdi_new_pri_nobch_channel,
3329#if defined(HAVE_PRI_CALL_WAITING)
3330 .init_config = my_pri_init_config,
3333 .make_cc_dialstring = my_pri_make_cc_dialstring,
3334 .update_span_devstate = dahdi_pri_update_span_devstate,
3335 .module_ref = my_module_ref,
3336 .module_unref = my_module_unref,
3337 .dial_digits = my_pri_dial_digits,
3338 .open_media = my_pri_ss7_open_media,
3339 .ami_channel_event = my_ami_channel_event,
3340 .destroy_later = pri_queue_for_destruction,
3344#if defined(HAVE_SS7)
3353static void my_handle_link_exception(
struct sig_ss7_linkset *linkset,
int which)
3357 if (ioctl(linkset->
fds[which], DAHDI_GETEVENT, &
event)) {
3359 linkset->
span, which);
3363 case DAHDI_EVENT_NONE:
3365 case DAHDI_EVENT_ALARM:
3370 case DAHDI_EVENT_NOALARM:
3383#if defined(HAVE_SS7)
3384static void my_ss7_set_loopback(
void *pvt,
int enable)
3395#if defined(HAVE_SS7)
3415 if (linksets[idx].
ss7.ss7 ==
ss7) {
3416 return &linksets[idx].ss7;
3423#if defined(HAVE_SS7)
3466 newlaw = DAHDI_LAW_ALAW;
3469 newlaw = DAHDI_LAW_MULAW;
3476#if defined(HAVE_SS7)
3477static int sig_ss7_tone_to_dahditone(
enum sig_ss7_tone tone)
3481 return DAHDI_TONE_RINGTONE;
3483 return DAHDI_TONE_STUTTER;
3485 return DAHDI_TONE_CONGESTION;
3487 return DAHDI_TONE_DIALTONE;
3489 return DAHDI_TONE_DIALRECALL;
3491 return DAHDI_TONE_INFO;
3493 return DAHDI_TONE_BUSY;
3500#if defined(HAVE_SS7)
3501static int my_ss7_play_tone(
void *pvt,
enum sig_ss7_tone tone)
3505 return tone_zone_play_tone(p->
subs[
SUB_REAL].
dfd, sig_ss7_tone_to_dahditone(tone));
3509#if defined(HAVE_SS7)
3517 .set_loopback = my_ss7_set_loopback,
3519 .new_ast_channel = my_new_ss7_ast_channel,
3520 .play_tone = my_ss7_play_tone,
3522 .handle_link_exception = my_handle_link_exception,
3526 .set_digital = my_set_digital,
3527 .set_inservice = my_set_inservice,
3528 .set_locallyblocked = my_set_locallyblocked,
3529 .set_remotelyblocked = my_set_remotelyblocked,
3530 .set_callerid = my_set_callerid,
3531 .set_dnid = my_set_dnid,
3532 .open_media = my_pri_ss7_open_media,
3533 .find_linkset = my_ss7_find_linkset,
3603#define gen_pvt_field_callback(type, field) \
3604 static type my_get_##field(void *pvt) \
3606 struct dahdi_pvt *p = pvt; \
3614#undef gen_pvt_field_callback
3684 .get_firstdigit_timeout = my_get_firstdigit_timeout,
3685 .get_matchdigit_timeout = my_get_matchdigit_timeout,
3686 .get_interdigit_timeout = my_get_interdigit_timeout,
3705 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3798#if defined(HAVE_PRI)
3813static void mfcr2_queue_for_destruction(
const struct dahdi_pvt *p)
3815 const struct dahdi_mfcr2 *r2link = p->mfcr2;
3816 struct r2link_entry *cur;
3819 if (r2link == &cur->mfcr2) {
3829static int dahdi_r2_answer(
struct dahdi_pvt *p)
3835#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3837 int wants_double_answer =
ast_true(double_answer) ? 1 : 0;
3838 if (!double_answer) {
3841 res = openr2_chan_answer_call(p->r2chan);
3842 }
else if (wants_double_answer) {
3843 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
3845 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
3848 res = openr2_chan_answer_call(p->r2chan);
3856static openr2_calling_party_category_t dahdi_r2_get_channel_category(
struct ast_channel *
c)
3858 openr2_calling_party_category_t cat;
3862 ast_debug(1,
"No MFC/R2 category specified for chan %s, using default %s\n",
3864 return p->mfcr2_category;
3866 if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
3867 ast_log(
LOG_WARNING,
"Invalid category specified '%s' for chan %s, using default %s\n",
3868 catstr,
ast_channel_name(
c), openr2_proto_get_category_string(p->mfcr2_category));
3869 return p->mfcr2_category;
3871 ast_debug(1,
"Using category %s\n", catstr);
3875static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
3877 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3886 ast_log(
LOG_ERROR,
"Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
3896 p->mfcr2_ani_index =
'\0';
3897 p->mfcr2_dnis_index =
'\0';
3898 p->mfcr2_dnis_matched = 0;
3899 p->mfcr2_answer_pending = 0;
3900 p->mfcr2_call_accepted = 0;
3902 ast_verbose(
"New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
3905static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan,
int alarm)
3908 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3913 if (res == DAHDI_ALARM_NOTOPEN) {
3914 mfcr2_queue_for_destruction(p);
3923static void dahdi_r2_on_os_error(openr2_chan_t *r2chan,
int errorcode)
3925 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3927 ast_log(
LOG_ERROR,
"OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
3930 if (errorcode == ENODEV) {
3931 struct dahdi_mfcr2 *r2link = p->mfcr2;
3940static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
3942 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3943 ast_log(
LOG_ERROR,
"MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
3953static void dahdi_r2_disconnect_call(
struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
3955 if (openr2_chan_disconnect_call(p->r2chan, cause)) {
3956 ast_log(
LOG_NOTICE,
"Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
3957 p->
channel, openr2_proto_get_disconnect_string(cause));
3959 openr2_chan_set_idle(p->r2chan);
3966static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan,
const char *ani,
const char *dnis, openr2_calling_party_category_t category)
3972 ast_verbose(
"MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
3973 openr2_chan_get_number(r2chan), ani ? ani :
"(restricted)", dnis,
3974 openr2_proto_get_category_string(category));
3975 p = openr2_chan_get_client_data(r2chan);
3977 if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
3979 dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
3980 goto dahdi_r2_on_call_offered_cleanup;
3983 p->mfcr2_recvd_category = category;
3986 ast_debug(1,
"No CID allowed in configuration, CID is being cleared!\n");
3991 if (p->
immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
3992 ast_debug(1,
"Setting exten => s because of immediate or 0 DNIS configured\n");
3998 ast_log(
LOG_NOTICE,
"MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
4000 dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
4001 goto dahdi_r2_on_call_offered_cleanup;
4003 if (!p->mfcr2_accept_on_offer) {
4010 goto dahdi_r2_on_call_offered_cleanup;
4013 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4014 }
else if (p->mfcr2_charge_calls) {
4015 ast_debug(1,
"Accepting MFC/R2 call with charge on chan %d\n", p->
channel);
4016 openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
4018 ast_debug(1,
"Accepting MFC/R2 call with no charge on chan %d\n", p->
channel);
4019 openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
4022dahdi_r2_on_call_offered_cleanup:
4026static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
4028 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4035static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
4041 p = openr2_chan_get_client_data(r2chan);
4043 p->mfcr2_call_accepted = 1;
4045 if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
4046 ast_verbose(
"MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
4051 if (!p->mfcr2_accept_on_offer) {
4052 openr2_chan_disable_read(r2chan);
4053 if (p->mfcr2_answer_pending) {
4054 ast_debug(1,
"Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
4057 goto dahdi_r2_on_call_accepted_cleanup;
4063 openr2_chan_disable_read(r2chan);
4064 goto dahdi_r2_on_call_accepted_cleanup;
4068 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4069 goto dahdi_r2_on_call_accepted_cleanup;
4076 openr2_chan_disable_read(r2chan);
4078dahdi_r2_on_call_accepted_cleanup:
4082static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
4084 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4085 ast_verbose(
"MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan));
4089static void dahdi_r2_on_call_read(openr2_chan_t *r2chan,
const unsigned char *
buf,
int buflen)
4094static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
4097 case OR2_CAUSE_BUSY_NUMBER:
4099 case OR2_CAUSE_NETWORK_CONGESTION:
4101 case OR2_CAUSE_OUT_OF_ORDER:
4103 case OR2_CAUSE_UNALLOCATED_NUMBER:
4105 case OR2_CAUSE_NO_ANSWER:
4107 case OR2_CAUSE_NORMAL_CLEARING:
4109 case OR2_CAUSE_UNSPECIFIED:
4115static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
4117 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4120 int datalen =
sizeof(*cause_code);
4122 ast_verbose(
"MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
4127 dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
4131 snprintf(cause_str,
sizeof(cause_str),
"R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
4132 datalen += strlen(cause_str);
4134 memset(cause_code, 0, datalen);
4135 cause_code->
ast_cause = dahdi_r2_cause_to_ast_cause(cause);
4147 }
else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
4150 case OR2_CAUSE_BUSY_NUMBER:
4153 case OR2_CAUSE_NETWORK_CONGESTION:
4154 case OR2_CAUSE_OUT_OF_ORDER:
4155 case OR2_CAUSE_UNALLOCATED_NUMBER:
4156 case OR2_CAUSE_NO_ANSWER:
4157 case OR2_CAUSE_UNSPECIFIED:
4158 case OR2_CAUSE_NORMAL_CLEARING:
4173static void dahdi_r2_write_log(openr2_log_level_t level,
char *logmessage)
4176 case OR2_LOG_NOTICE:
4179 case OR2_LOG_WARNING:
4185 case OR2_LOG_STACK_TRACE:
4186 case OR2_LOG_MF_TRACE:
4187 case OR2_LOG_CAS_TRACE:
4189 case OR2_LOG_EX_DEBUG:
4199static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
4201 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4205 ast_log(
LOG_NOTICE,
"Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
4208static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
4210 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4214 ast_log(
LOG_NOTICE,
"Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
4217static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level,
const char *fmt, va_list ap)
4218 __attribute__((format (printf, 3, 0)));
4219static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level,
const char *fmt, va_list ap)
4221#define CONTEXT_TAG "Context - "
4223 char completemsg[
sizeof(
logmsg) * 2];
4225 snprintf(completemsg,
sizeof(completemsg), CONTEXT_TAG
"%s",
logmsg);
4226 dahdi_r2_write_log(level, completemsg);
4230static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level,
const char *fmt, va_list ap)
4231 __attribute__((format (printf, 3, 0)));
4232static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level,
const char *fmt, va_list ap)
4234#define CHAN_TAG "Chan "
4236 char completemsg[
sizeof(
logmsg) * 2];
4238 snprintf(completemsg,
sizeof(completemsg), CHAN_TAG
"%d - %s", openr2_chan_get_number(r2chan),
logmsg);
4239 dahdi_r2_write_log(level, completemsg);
4243static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan,
char digit)
4245 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4252 p->mfcr2_dnis_index++;
4253 p->
exten[p->mfcr2_dnis_index] = 0;
4254 p->
rdnis[p->mfcr2_dnis_index] = 0;
4256 if ((p->mfcr2_dnis_matched ||
4265static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan,
char digit)
4267 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4270 p->mfcr2_ani_index++;
4271 p->
cid_num[p->mfcr2_ani_index] = 0;
4272 p->
cid_name[p->mfcr2_ani_index] = 0;
4275static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
4277 ast_verbose(
"MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
4280static openr2_event_interface_t dahdi_r2_event_iface = {
4281 .on_call_init = dahdi_r2_on_call_init,
4282 .on_call_offered = dahdi_r2_on_call_offered,
4283 .on_call_accepted = dahdi_r2_on_call_accepted,
4284 .on_call_answered = dahdi_r2_on_call_answered,
4285 .on_call_disconnect = dahdi_r2_on_call_disconnect,
4286 .on_call_end = dahdi_r2_on_call_end,
4287 .on_call_read = dahdi_r2_on_call_read,
4288 .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
4289 .on_os_error = dahdi_r2_on_os_error,
4290 .on_protocol_error = dahdi_r2_on_protocol_error,
4291 .on_line_blocked = dahdi_r2_on_line_blocked,
4292 .on_line_idle = dahdi_r2_on_line_idle,
4294 .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
4295 .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
4296 .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
4298 .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
4301static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
4306static inline uint8_t dahdi_r2_linear_to_alaw(
int sample)
4311static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
4312 dahdi_r2_alaw_to_linear,
4313 dahdi_r2_linear_to_alaw
4354 for (
x = 0;
x < strlen(fn);
x++) {
4355 if (!isdigit(fn[
x])) {
4366 fn =
"/dev/dahdi/channel";
4368 fd = open(fn, O_RDWR | O_NONBLOCK);
4374 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
4383 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &
bs) == -1) {
4402 chan_pvt->
subs[sub_num].
dfd = -1;
4405#if defined(HAVE_PRI)
4406static void dahdi_close_pri_fd(
struct dahdi_pri *pri,
int fd_num)
4409 pri->pri.fds[fd_num] = -1;
4413#if defined(HAVE_SS7)
4414static void dahdi_close_ss7_fd(
struct dahdi_ss7 *ss7,
int fd_num)
4417 ss7->ss7.fds[fd_num] = -1;
4423 return ioctl(dfd, DAHDI_SETLINEAR, &linear);
4429 struct dahdi_bufferinfo bi;
4442 res = ioctl(p->
subs[x].
dfd, DAHDI_GET_BUFINFO, &bi);
4447 res = ioctl(p->
subs[x].
dfd, DAHDI_SET_BUFINFO, &bi);
4484 return DAHDI_TONE_DTMF_BASE + (
digit -
'0');
4486 return DAHDI_TONE_DTMF_A + (
digit -
'A');
4488 return DAHDI_TONE_DTMF_A + (
digit -
'a');
4489 else if (
digit ==
'*')
4490 return DAHDI_TONE_DTMF_s;
4491 else if (
digit ==
'#')
4492 return DAHDI_TONE_DTMF_p;
4531 char dial_str[] = {
'T',
digit,
'\0' };
4542 dtmf = DAHDI_FLUSH_WRITE;
4545 ast_log(
LOG_WARNING,
"Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4549 ast_debug(1,
"Channel %s started VLDTMF digit '%c'\n",
4584 ast_debug(1,
"Channel %s ending VLDTMF digit '%c'\n",
4610 "Hook Transition Complete",
4615 "Polarity Reversal",
4623 { DAHDI_ALARM_RED,
"Red Alarm" },
4624 { DAHDI_ALARM_YELLOW,
"Yellow Alarm" },
4625 { DAHDI_ALARM_BLUE,
"Blue Alarm" },
4626 { DAHDI_ALARM_RECOVER,
"Recovering" },
4627 { DAHDI_ALARM_LOOPBACK,
"Loopback" },
4628 { DAHDI_ALARM_NOTOPEN,
"Not Open" },
4629 { DAHDI_ALARM_NONE,
"None" },
4639 return alm ?
"Unknown Alarm" :
"No Alarm";
4644 static char buf[256];
4653 static char buf[256];
4656 return "E & M Immediate";
4658 return "E & M Wink";
4662 return "Feature Group D (DTMF)";
4664 return "Feature Group D (MF)";
4666 return "Feature Group D (MF) Tandem Access";
4668 return "Feature Group B (MF)";
4672 return "FGC/CAMA (Dialpulse)";
4674 return "FGC/CAMA (MF)";
4676 return "FXS Loopstart";
4678 return "FXS Groundstart";
4680 return "FXS Kewlstart";
4682 return "FXO Loopstart";
4684 return "FXO Groundstart";
4686 return "FXO Kewlstart";
4690 return "ISDN BRI Point to Point";
4692 return "ISDN BRI Point to MultiPoint";
4698 return "SF (Tone) Immediate";
4700 return "SF (Tone) Wink";
4702 return "SF (Tone) with Feature Group D (DTMF)";
4704 return "SF (Tone) with Feature Group D (MF)";
4706 return "SF (Tone) with Feature Group B (MF)";
4710 snprintf(
buf,
sizeof(
buf),
"Unknown signalling %d", sig);
4715#define sig2str dahdi_sig2str
4721 struct dahdi_confinfo zi;
4723 memset(&zi, 0,
sizeof(zi));
4726 if (slavechannel > 0) {
4728 zi.confmode = DAHDI_CONF_DIGITALMON;
4729 zi.confno = slavechannel;
4733 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
4734 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4736 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
4739 if ((zi.confno ==
c->curconf.confno) && (zi.confmode ==
c->curconf.confmode))
4743 if (ioctl(
c->dfd, DAHDI_SETCONF, &zi)) {
4744 ast_log(
LOG_WARNING,
"Failed to add %d to conference %d/%d: %s\n",
c->dfd, zi.confmode, zi.confno, strerror(
errno));
4747 if (slavechannel < 1) {
4751 ast_debug(1,
"Added %d to conference %d/%d\n",
c->dfd,
c->curconf.confmode,
c->curconf.confno);
4758 if ((p->
channel ==
c->curconf.confno) && (
c->curconf.confmode == DAHDI_CONF_DIGITALMON))
4761 if ((p->
confno > 0) && (p->
confno ==
c->curconf.confno) && (
c->curconf.confmode & DAHDI_CONF_TALKER))
4768 struct dahdi_confinfo zi;
4775 memset(&zi, 0,
sizeof(zi));
4776 if (ioctl(
c->dfd, DAHDI_SETCONF, &zi)) {
4777 ast_log(
LOG_WARNING,
"Failed to drop %d from conference %d/%d: %s\n",
c->dfd,
c->curconf.confmode,
c->curconf.confno, strerror(
errno));
4780 ast_debug(1,
"Removed %d from conference %d/%d\n",
c->dfd,
c->curconf.confmode,
c->curconf.confno);
4781 memcpy(&
c->curconf, &zi,
sizeof(
c->curconf));
4793 for (x = 0; x < 3; x++) {
4801 if (useslavenative) {
4820 else if (slave->
law != p->
law) {
4826 return useslavenative;
4834 struct dahdi_confinfo zi;
4836 memset(&zi, 0,
sizeof(zi));
4852 for (x = 0; x < 3; x++) {