--- chan_dahdi.c-rel.invalid 2008-09-04 14:31:54.000000000 +0200 +++ chan_dahdi.c 2008-09-05 16:38:06.000000000 +0200 @@ -9105,13 +9105,14 @@ static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block) { - int i; + int i, offset = 0; for (i = 0; i < linkset->numchans; i++) { if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) { if (state) { - if (state[i]) + if (state[offset]) linkset->pvts[i]->remotelyblocked = block; + offset++; } else linkset->pvts[i]->remotelyblocked = block; } @@ -9321,6 +9322,7 @@ struct pollfd pollers[NUM_DCHANS]; int cic; unsigned int dpc; + unsigned char state[255]; int nextms = 0; ss7_start(ss7); @@ -9480,11 +9482,17 @@ p->inservice = 1; p->remotelyblocked = 0; dpc = p->dpc; + if(p->locallyblocked) + isup_blo(ss7, e->rsc.cic, dpc); isup_set_call_dpc(e->rsc.call, dpc); if (p->ss7call) p->ss7call = NULL; - if (p->owner) + if (p->owner) { + p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; p->owner->_softhangup |= AST_SOFTHANGUP_DEV; + /* End the loopback if we have one */ + dahdi_loopback(p, 0); + } ast_mutex_unlock(&p->lock); @@ -9492,14 +9500,45 @@ break; case ISUP_EVENT_GRS: ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic); + /* TODO: check ANSI! */ + if (e->grs.endcic <= e->grs.startcic || e->grs.endcic - e->grs.startcic > 31) { + ast_log(LOG_WARNING, "Got GRS with invalid range on CIC %d\n", e->grs.startcic); + break; + } chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc); if (chanpos < 0) { ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic); break; } - p = linkset->pvts[chanpos]; - isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc); + i = 0; /* Send CGB to restore the blocking states */ ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0); + for(cic = e->grs.startcic;cic <= e->grs.endcic;cic++) { + chanpos = ss7_find_cic(linkset, cic, e->grs.opc); + if (chanpos < 0) { + ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", cic); + } else { + p = linkset->pvts[chanpos]; + ast_mutex_lock(&p->lock); + p->inservice = 1; + if(p->locallyblocked) { + i = 1; + state[cic - e->grs.startcic] = 1; + } else { + state[cic - e->grs.startcic] = 0; + } + if (p->ss7call) + p->ss7call = NULL; + if (p->owner) { + p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; + p->owner->_softhangup |= AST_SOFTHANGUP_DEV; + /* End the loopback if we have one */ + dahdi_loopback(p, 0); + } + ast_mutex_unlock(&p->lock); + } + } + if (i) isup_cgb(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc, state, 0); + isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc); break; case ISUP_EVENT_CQM: ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic); @@ -9520,11 +9559,24 @@ } p = linkset->pvts[chanpos]; ast_mutex_lock(&p->lock); + if(p->remotelyblocked) { + ast_log(LOG_DEBUG, "Got IAM on remotely blocked CIC %d, remove blocking\n", e->iam.cic); + p->remotelyblocked = 0; + p->inservice = 1; + } if (p->owner) { if (p->ss7call == e->iam.call) { - ast_mutex_unlock(&p->lock); - ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic); - break; + ast_log(LOG_WARNING, "Dual seizure on CIC %d!\n", e->iam.cic); + if ((e->iam.opc > ss7_get_pc(ss7)) ? (e->iam.cic & 1) : (~e->iam.cic & 1)) { + ast_log(LOG_NOTICE, "We are the controlling on CIC: %d, the remote party will step back, ignoring IAM\n", e->iam.cic); + ast_mutex_unlock(&p->lock); + break; + } else { + ast_log(LOG_NOTICE, "The remote party is the controlling on CIC: %d, we must step back!\n", e->iam.cic); + p->ss7call = NULL; + dahdi_hangup(p->owner); + p->owner = NULL; + } } else { ast_mutex_unlock(&p->lock); ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic); @@ -13087,6 +13139,290 @@ return CLI_SUCCESS; } +static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int linkset, cic; + int i; + struct dahdi_pvt *p; + + switch (cmd) { + case CLI_INIT: + e->command = "ss7 reset cic"; + e->usage = + "Usage: ss7 reset cic \n" + " Send a RSC for the given CIC on the specified linkset\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + if (a->argc == 5) + linkset = atoi(a->argv[3]); + else + return CLI_SHOWUSAGE; + + if ((linkset < 1) || (linkset > NUM_SPANS)) { + ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS); + return CLI_SUCCESS; + } + + if (!linksets[linkset-1].ss7) { + ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset); + return CLI_SUCCESS; + } + + cic = atoi(a->argv[4]); + + if (cic < 1) { + ast_cli(a->fd, "Invalid CIC specified!\n"); + return CLI_SUCCESS; + } + + for (i = 0; i < linksets[linkset-1].numchans; i++) { + p = linksets[linkset-1].pvts[i]; + if (p->cic == cic) { + ast_mutex_lock(&p->lock); + if(p->owner) { + ast_cli(a->fd, "CIC %d in use, hangup the owner!!!\n", cic); + p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; + p->owner->_softhangup |= AST_SOFTHANGUP_DEV; + dahdi_loopback(p, 0); + p->ss7call = NULL; + } + p->locallyblocked = 0; + ast_mutex_unlock(&p->lock); + + ast_mutex_lock(&linksets[linkset-1].lock); + isup_rsc(linksets[linkset-1].ss7, cic, p->dpc); + ast_mutex_unlock(&linksets[linkset-1].lock); + } + } + + ast_cli(a->fd, "Sent RSC for linkset %d on CIC %d\n", linkset, cic); + + /* Break poll on the linkset so it sends our messages */ + pthread_kill(linksets[linkset-1].master, SIGURG); + + return CLI_SUCCESS; +} + +static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int linkset, cic, range; + int i; + struct dahdi_pvt *p; + switch (cmd) { + case CLI_INIT: + e->command = "ss7 group reset"; + e->usage = + "Usage: ss7 group reset <1st CIC> \n" + " Send a GRS for the given CIC range on the specified linkset\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + if (a->argc == 6) + linkset = atoi(a->argv[3]); + else + return CLI_SHOWUSAGE; + + if ((linkset < 1) || (linkset > NUM_SPANS)) { + ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS); + return CLI_SUCCESS; + } + + if (!linksets[linkset-1].ss7) { + ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset); + return CLI_SUCCESS; + } + + cic = atoi(a->argv[4]); + + if (cic < 1) { + ast_cli(a->fd, "Invalid CIC specified!\n"); + return CLI_SUCCESS; + } + + range = atoi(a->argv[5]); + if (range < 1 || range > 31) { + ast_cli(a->fd, "Invalid range specified!\n"); + return CLI_SUCCESS; + } + + for (i = 0; i < linksets[linkset-1].numchans; i++) { + p = linksets[linkset-1].pvts[i]; + if (p->cic >= cic && p->cic <= cic + range) { + ast_mutex_lock(&p->lock); + p->locallyblocked = 0; + if(p->owner) { + ast_cli(a->fd, "CIC %d in use, hangup the owner!!!\n", cic); + p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; + p->owner->_softhangup |= AST_SOFTHANGUP_DEV; + dahdi_loopback(p, 0); + p->ss7call = NULL; + } + ast_mutex_unlock(&p->lock); + } + if (p->cic == cic) { + ast_mutex_lock(&linksets[linkset-1].lock); + isup_grs(linksets[linkset-1].ss7, cic, cic + range, p->dpc); + ast_mutex_unlock(&linksets[linkset-1].lock); + } + } + + ast_cli(a->fd, "Sent GRS for linkset %d on CIC %d range %d\n", linkset, cic, range); + + /* Break poll on the linkset so it sends our messages */ + pthread_kill(linksets[linkset-1].master, SIGURG); + + return CLI_SUCCESS; +} + +static char *handle_ss7_group_block(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int linkset, cic, cic_offset, range, chanpos = -1; + int i; + unsigned char state[255]; + struct dahdi_pvt *p; + + switch (cmd) { + case CLI_INIT: + e->command = "ss7 group block"; + e->usage = + "Usage: ss7 group block <1st. CIC> \n" + " Sends a remote blocking request for CIC range on the specified linkset\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + if (a->argc == 6) + linkset = atoi(a->argv[3]); + else + return CLI_SHOWUSAGE; + + if ((linkset < 1) || (linkset > NUM_SPANS)) { + ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS); + return CLI_SUCCESS; + } + + if (!linksets[linkset-1].ss7) { + ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset); + return CLI_SUCCESS; + } + + cic = atoi(a->argv[4]); + + if (cic < 1) { + ast_cli(a->fd, "Invalid CIC specified!\n"); + return CLI_SUCCESS; + } + + range = atoi(a->argv[5]); + if (range < 1 || range > 31) { + ast_cli(a->fd, "Invalid range specified!\n"); + return CLI_SUCCESS; + } + cic_offset = 0; + memset(state, 0, sizeof(state)); + for (i = 0; i < linksets[linkset-1].numchans; i++) { + p = linksets[linkset-1].pvts[i]; + if (p->cic >= cic && p->cic <= cic + range) { + ast_mutex_lock(&p->lock); + p->locallyblocked = 1; + ast_mutex_unlock(&p->lock); + state[cic_offset] = 1; + cic_offset ++; + } + if (p->cic == cic) { + chanpos = i; + } + } + + if (chanpos >= 0) { + ast_mutex_lock(&linksets[linkset-1].lock); + isup_cgb(linksets[linkset-1].ss7, cic, cic + range, linksets[linkset-1].pvts[chanpos]->dpc, state, 0); /* Maintenance oriented */ + ast_mutex_unlock(&linksets[linkset-1].lock); + ast_cli(a->fd, "Sending remote blocking request linkset %d on CIC %d range %d\n", linkset, cic, range); + /* Break poll on the linkset so it sends our messages */ + pthread_kill(linksets[linkset-1].master, SIGURG); + } + + return CLI_SUCCESS; +} + +static char *handle_ss7_group_unblock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int linkset, cic, cic_offset, range, chanpos = -1; + int i; + unsigned char state[255]; + struct dahdi_pvt *p; + + switch (cmd) { + case CLI_INIT: + e->command = "ss7 group unblock"; + e->usage = + "Usage: ss7 group unblock <1st. CIC> \n" + " Sends a remote unblocking request for CIC range on the specified linkset\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + if (a->argc == 6) + linkset = atoi(a->argv[3]); + else + return CLI_SHOWUSAGE; + + if ((linkset < 1) || (linkset > NUM_SPANS)) { + ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS); + return CLI_SUCCESS; + } + + if (!linksets[linkset-1].ss7) { + ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset); + return CLI_SUCCESS; + } + + cic = atoi(a->argv[4]); + + if (cic < 1) { + ast_cli(a->fd, "Invalid CIC specified!\n"); + return CLI_SUCCESS; + } + + range = atoi(a->argv[5]); + if (range < 1 || range > 31) { + ast_cli(a->fd, "Invalid range specified!\n"); + return CLI_SUCCESS; + } + + cic_offset = 0; + memset(state, 0, sizeof(state)); + for (i = 0; i < linksets[linkset-1].numchans; i++) { + p = linksets[linkset-1].pvts[i]; + if (p->cic >= cic && p->cic <= cic + range) { + ast_mutex_lock(&p->lock); + p->locallyblocked = 0; + ast_mutex_unlock(&p->lock); + state[cic_offset] = 1; + cic_offset ++; + } + if (p->cic == cic) { + chanpos = i; + } + } + + if (chanpos >= 0) { + ast_mutex_lock(&linksets[linkset-1].lock); + isup_cgu(linksets[linkset-1].ss7, cic, cic + range, linksets[linkset-1].pvts[chanpos]->dpc, state, 0); /* Maintenance oriented */ + ast_mutex_unlock(&linksets[linkset-1].lock); + ast_cli(a->fd, "Sending remote blocking request linkset %d on CIC %d range %d\n", linkset, cic, range); + /* Break poll on the linkset so it sends our messages */ + pthread_kill(linksets[linkset-1].master, SIGURG); + } + + return CLI_SUCCESS; +} + + static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { int linkset; @@ -13267,6 +13603,10 @@ AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"), + AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"), + AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"), + AST_CLI_DEFINE(handle_ss7_group_block, "Blocks the given CIC range"), + AST_CLI_DEFINE(handle_ss7_group_unblock, "Unblocks the given CIC range"), AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"), AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"), AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),