?? q931.c
字號:
q931_call *cur, *prev; prev = NULL; cur = *pri->callpool; while(cur) { if ((c && (cur == c)) || (!c && (cur->cr == cr))) { if (prev) prev->next = cur->next; else *pri->callpool = cur->next; if (pri->debug & PRI_DEBUG_Q931_STATE) pri_message("NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate)); if (cur->retranstimer) pri_schedule_del(pri, cur->retranstimer); free(cur); return; } prev = cur; cur = cur->next; } pri_error("Can't destroy call %d!\n", cr);}static void q931_destroycall(struct pri *pri, int cr){ return q931_destroy(pri, cr, NULL);}void __q931_destroycall(struct pri *pri, q931_call *c) { if (pri && c) q931_destroy(pri,0, c); return;}static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset){ unsigned int x; int res; int have_shift; for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) { if (ies[x].ie == ie) { /* This is our baby */ if (ies[x].transmit) { /* Prepend with CODE SHIFT IE if required */ if (*codeset != Q931_IE_CODESET(ies[x].ie)) { /* Locking shift to codeset 0 isn't possible */ iet->ie = Q931_IE_CODESET(ies[x].ie) | (Q931_IE_CODESET(ies[x].ie) ? Q931_LOCKING_SHIFT : Q931_NON_LOCKING_SHIFT); have_shift = 1; iet = (q931_ie *)((char *)iet + 1); maxlen--; } else have_shift = 0; iet->ie = ie; res = ies[x].transmit(ie, pri, call, msgtype, iet, maxlen); /* Error if res < 0 or ignored if res == 0 */ if (res <= 0) return res; if ((iet->ie & 0x80) == 0) /* Multibyte IE */ iet->len = res - 2; if (have_shift) { if (Q931_IE_CODESET(ies[x].ie)) *codeset = Q931_IE_CODESET(ies[x].ie); return res + 1; /* Shift is single-byte IE */ } return res; } else { pri_error("!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie); return -1; } } } pri_error("!! Unknown IE %d (%s)\n", ie, ie2str(ie)); return -1;}static char *disc2str(int disc){ static struct msgtype discs[] = { { Q931_PROTOCOL_DISCRIMINATOR, "Q.931" }, { GR303_PROTOCOL_DISCRIMINATOR, "GR-303" }, { 0x3, "AT&T Maintenance" }, { 0x43, "New AT&T Maintenance" }, }; return code2str(disc, discs, sizeof(discs) / sizeof(discs[0]));}void q931_dump(q931_h *h, int len, int txrx){ q931_mh *mh; char c; int x=0, r; int cur_codeset; int codeset; c = txrx ? '>' : '<'; pri_message("%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); pri_message("%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, q931_cr(h), q931_cr(h), (h->crv[0] & 0x80) ? "Terminator" : "Originator"); /* Message header begins at the end of the call reference number */ mh = (q931_mh *)(h->contents + h->crlen); pri_message("%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); /* Drop length of header, including call reference */ len -= (h->crlen + 3); codeset = cur_codeset = 0; while(x < len) { r = ielen((q931_ie *)(mh->data + x)); q931_dumpie(cur_codeset, (q931_ie *)(mh->data + x), c); switch (mh->data[x] & 0xf8) { case Q931_LOCKING_SHIFT: if ((mh->data[x] & 7) > 0) codeset = cur_codeset = mh->data[x] & 7; break; case Q931_NON_LOCKING_SHIFT: cur_codeset = mh->data[x] & 7; break; default: /* Reset temporary codeset change */ cur_codeset = codeset; } x += r; } if (x > len) pri_error("XXX Message longer than it should be?? XXX\n");}static int q931_handle_ie(int codeset, struct pri *pri, q931_call *c, int msg, q931_ie *ie){ unsigned int x; int full_ie = Q931_FULL_IE(codeset, ie->ie); if (pri->debug & PRI_DEBUG_Q931_STATE) pri_message("-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) { if (full_ie == ies[x].ie) { if (ies[x].receive) return ies[x].receive(full_ie, pri, c, msg, ie, ielen(ie)); else { if (pri->debug & PRI_DEBUG_Q931_ANOMALY) pri_error("!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); return -1; } } } pri_message("!! Unknown IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); return -1;}static void init_header(struct pri *pri, q931_call *call, char *buf, q931_h **hb, q931_mh **mhb, int *len){ /* Returns header and message header and modifies length in place */ q931_h *h = (q931_h *)buf; q931_mh * mh = (q931_mh *)(h->contents + 2); h->pd = pri->protodisc; h->x0 = 0; /* Reserved 0 */ h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */ if (call->cr || call->forceinvert) { h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8; h->crv[1] = (call->cr & 0xff); } else { /* Unless of course this has no call reference */ h->crv[0] = 0; h->crv[1] = 0; } if (pri->subchannel) { /* On GR-303, top bit is always 0 */ h->crv[0] &= 0x7f; } mh->f = 0; *hb = h; *mhb = mh; *len -= 5; }static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr){ q921_transmit_iframe(pri, h, len, cr); /* The transmit operation might dump the q921 header, so logging the q931 message body after the transmit puts the sections of the message in the right order in the log */ if (pri->debug & PRI_DEBUG_Q931_DUMP) q931_dump(h, len, 1);#ifdef LIBPRI_COUNTERS pri->q931_txcount++;#endif return 0;}static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[]){ unsigned char buf[1024]; q931_h *h; q931_mh *mh; int len; int res; int offset=0; int x; int codeset; memset(buf, 0, sizeof(buf)); len = sizeof(buf); init_header(pri, c, buf, &h, &mh, &len); mh->msg = msgtype; x=0; codeset = 0; while(ies[x] > -1) { res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset); if (res < 0) { pri_error("!! Unable to add IE '%s'\n", ie2str(ies[x])); return -1; } offset += res; len -= res; x++; } /* Invert the logic */ len = sizeof(buf) - len; q931_xmit(pri, h, len, 1); c->acked = 1; return 0;}static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 };static int q931_status(struct pri *pri, q931_call *c, int cause){ q931_call *cur = NULL; if (!cause) cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY; if (c->cr > -1) cur = *pri->callpool; while(cur) { if (cur->cr == c->cr) { cur->cause=cause; cur->causecode = CODE_CCITT; cur->causeloc = LOC_USER; break; } cur = cur->next; } if (!cur) { pri_message("YYY Here we get reset YYY\n"); /* something went wrong, respond with "no such call" */ c->ourcallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL; cur=c; } return send_message(pri, cur, Q931_STATUS, status_ies);}static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 };int q931_information(struct pri *pri, q931_call *c, char digit){ c->callednum[0]=digit; c->callednum[1]='\0'; return send_message(pri, c, Q931_INFORMATION, information_ies);}static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };static int restart_ack(struct pri *pri, q931_call *c){ c->ourcallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL; return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);}static int notify_ies[] = { Q931_IE_NOTIFY_IND, -1 };int q931_notify(struct pri *pri, q931_call *c, int channel, int info){ if (info >= 0) c->notify = info & 0x7F; else c->notify = -1; return send_message(pri, c, Q931_NOTIFY, notify_ies);}#ifdef ALERTING_NO_PROGRESSstatic int call_progress_ies[] = { -1 };#elsestatic int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 };#endifint q931_call_progress(struct pri *pri, q931_call *c, int channel, int info){ if (channel) { c->ds1no = (channel & 0xff00) >> 8; channel &= 0xff; c->channelno = channel; } if (info) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progress = Q931_PROG_INBAND_AVAILABLE; } else c->progress = -1; c->alive = 1; return send_message(pri, c, Q931_PROGRESS, call_progress_ies);}#ifdef ALERTING_NO_PROGRESSstatic int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, -1 };#elsestatic int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };#endifint q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info){ if (channel) { c->ds1no = (channel & 0xff00) >> 8; channel &= 0xff; c->channelno = channel; } c->chanflags &= ~FLAG_PREFERRED; c->chanflags |= FLAG_EXCLUSIVE; c->ourcallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING; c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING; if (info) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progress = Q931_PROG_INBAND_AVAILABLE; } else c->progress = -1; c->proc = 1; c->alive = 1; return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies);}#ifndef ALERTING_NO_PROGRESSstatic int alerting_ies[] = { Q931_PROGRESS_INDICATOR, -1 };#elsestatic int alerting_ies[] = { -1 };#endifint q931_alerting(struct pri *pri, q931_call *c, int channel, int info){ if (!c->proc) q931_call_proceeding(pri, c, channel, 0); if (info) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progress = Q931_PROG_INBAND_AVAILABLE; } else c->progress = -1; c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED; c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED; c->alive = 1; return send_message(pri, c, Q931_ALERTING, alerting_ies);}static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn){ if (channel) { c->ds1no = (channel & 0xff00) >> 8; channel &= 0xff; c->channelno = channel; } c->chanflags &= ~FLAG_PREFERRED; c->chanflags |= FLAG_EXCLUSIVE; if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progress = Q931_PROG_CALLED_NOT_ISDN; } else c->progress = -1; c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING; c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; c->alive = 1; return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);}static void pri_connect_timeout(void *data){ struct q931_call *c = data; struct pri *pri = c->pri; if (pri->debug & PRI_DEBUG_Q931_STATE) pri_message("Timed out looking for connect acknowledge\n"); q931_disconnect(pri, c, PRI_CAUSE_NORMAL_CLEARING); }static void pri_release_timeout(void *data){ struct q931_call *c = data; struct pri *pri = c->pri; if (pri->debug & PRI_DEBUG_Q931_STATE) pri_message("Timed out looking for release complete\n"); c->t308_timedout++; c->alive = 1; q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);}static void pri_release_finaltimeout(void *data){ struct q931_call *c = data; struct pri *pri = c->pri; c->alive = 1; if (pri->debug & PRI_DEBUG_Q931_STATE) pri_message("Final time-out looking for release complete\n"); c->t308_timedout++; c->ourcallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL; pri->schedev = 1; pri->ev.e = PRI_EVENT_HANGUP_ACK; pri->ev.hangup.channel = c->channelno; pri->ev.hangup.cref = c->cr; pri->ev.hangup.cause = c->cause; pri->ev.hangup.call = c; q931_hangup(pri, c, c->cause);}static void pri_disconnect_timeout(void *data){ struct q931_call *c = data; struct pri *pri = c->pri; if (pri->debug & PRI_DEBUG_Q931_STATE) p
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -