00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include <stdio.h>
00072 #include <string.h>
00073 #include <unistd.h>
00074 #include <sys/socket.h>
00075 #include <sys/ioctl.h>
00076 #include <net/if.h>
00077 #include <errno.h>
00078 #include <stdlib.h>
00079 #include <fcntl.h>
00080 #include <netdb.h>
00081 #include <sys/signal.h>
00082 #include <signal.h>
00083 #include <netinet/in.h>
00084 #include <netinet/in_systm.h>
00085 #include <netinet/ip.h>
00086 #include <arpa/inet.h>
00087 #include <ctype.h>
00088
00089 #include "asterisk.h"
00090
00091 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53045 $")
00092
00093 #include "asterisk/lock.h"
00094 #include "asterisk/channel.h"
00095 #include "asterisk/config.h"
00096 #include "asterisk/logger.h"
00097 #include "asterisk/module.h"
00098 #include "asterisk/pbx.h"
00099 #include "asterisk/options.h"
00100 #include "asterisk/lock.h"
00101 #include "asterisk/sched.h"
00102 #include "asterisk/io.h"
00103 #include "asterisk/rtp.h"
00104 #include "asterisk/acl.h"
00105 #include "asterisk/callerid.h"
00106 #include "asterisk/cli.h"
00107 #include "asterisk/say.h"
00108 #include "asterisk/cdr.h"
00109 #include "asterisk/astdb.h"
00110 #include "asterisk/features.h"
00111 #include "asterisk/app.h"
00112 #include "asterisk/musiconhold.h"
00113 #include "asterisk/utils.h"
00114 #include "asterisk/causes.h"
00115 #include "asterisk/dsp.h"
00116
00117 #ifndef IPTOS_MINCOST
00118 #define IPTOS_MINCOST 0x02
00119 #endif
00120
00121
00122
00123
00124
00125
00126
00127 #define MGCPDUMPER
00128 #define DEFAULT_EXPIRY 120
00129 #define MAX_EXPIRY 3600
00130 #define CANREINVITE 1
00131
00132 #ifndef INADDR_NONE
00133 #define INADDR_NONE (in_addr_t)(-1)
00134 #endif
00135
00136 static const char desc[] = "Media Gateway Control Protocol (MGCP)";
00137 static const char type[] = "MGCP";
00138 static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";
00139 static const char config[] = "mgcp.conf";
00140
00141 #define MGCP_DTMF_RFC2833 (1 << 0)
00142 #define MGCP_DTMF_INBAND (1 << 1)
00143 #define MGCP_DTMF_HYBRID (1 << 2)
00144
00145 #define DEFAULT_MGCP_GW_PORT 2427
00146 #define DEFAULT_MGCP_CA_PORT 2727
00147 #define MGCP_MAX_PACKET 1500
00148 #define DEFAULT_RETRANS 1000
00149 #define MAX_RETRANS 5
00150
00151
00152 #define MGCP_CX_SENDONLY 0
00153 #define MGCP_CX_RECVONLY 1
00154 #define MGCP_CX_SENDRECV 2
00155 #define MGCP_CX_CONF 3
00156 #define MGCP_CX_CONFERENCE 3
00157 #define MGCP_CX_MUTE 4
00158 #define MGCP_CX_INACTIVE 4
00159
00160 static char *mgcp_cxmodes[] = {
00161 "sendonly",
00162 "recvonly",
00163 "sendrecv",
00164 "confrnce",
00165 "inactive"
00166 };
00167
00168
00169 #define MGCP_CMD_EPCF 0
00170 #define MGCP_CMD_CRCX 1
00171 #define MGCP_CMD_MDCX 2
00172 #define MGCP_CMD_DLCX 3
00173 #define MGCP_CMD_RQNT 4
00174 #define MGCP_CMD_NTFY 5
00175 #define MGCP_CMD_AUEP 6
00176 #define MGCP_CMD_AUCX 7
00177 #define MGCP_CMD_RSIP 8
00178
00179 static char context[AST_MAX_EXTENSION] = "default";
00180
00181 static char language[MAX_LANGUAGE] = "";
00182 static char musicclass[MAX_MUSICCLASS] = "";
00183 static char cid_num[AST_MAX_EXTENSION] = "";
00184 static char cid_name[AST_MAX_EXTENSION] = "";
00185
00186 static int dtmfmode = 0;
00187 static int nat = 0;
00188
00189
00190
00191
00192
00193
00194
00195 static ast_group_t cur_callergroup = 0;
00196 static ast_group_t cur_pickupgroup = 0;
00197
00198
00199
00200
00201
00202
00203 static int tos = 0;
00204
00205 static int immediate = 0;
00206
00207 static int callwaiting = 0;
00208
00209
00210
00211
00212
00213
00214
00215 static int callreturn = 0;
00216
00217 static int slowsequence = 0;
00218
00219 static int threewaycalling = 0;
00220
00221
00222 static int transfer = 0;
00223
00224 static int cancallforward = 0;
00225
00226 static int singlepath = 0;
00227
00228 static int canreinvite = CANREINVITE;
00229
00230
00231
00232
00233
00234 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
00235
00236 static char mailbox[AST_MAX_EXTENSION];
00237
00238 static int amaflags = 0;
00239
00240 static int adsi = 0;
00241
00242 static int usecnt =0;
00243 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00244
00245 static unsigned int oseq;
00246
00247
00248 static int firstdigittimeout = 16000;
00249
00250
00251 static int gendigittimeout = 8000;
00252
00253
00254 static int matchdigittimeout = 3000;
00255
00256
00257
00258 AST_MUTEX_DEFINE_STATIC(netlock);
00259
00260 AST_MUTEX_DEFINE_STATIC(monlock);
00261
00262
00263
00264 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00265
00266 static int restart_monitor(void);
00267
00268 static int capability = AST_FORMAT_ULAW;
00269 static int nonCodecCapability = AST_RTP_DTMF;
00270
00271 static char ourhost[MAXHOSTNAMELEN];
00272 static struct in_addr __ourip;
00273 static int ourport;
00274
00275 static int mgcpdebug = 0;
00276
00277 static struct sched_context *sched;
00278 static struct io_context *io;
00279
00280
00281
00282 #define MGCP_MAX_HEADERS 64
00283 #define MGCP_MAX_LINES 64
00284
00285 struct mgcp_request {
00286 int len;
00287 char *verb;
00288 char *identifier;
00289 char *endpoint;
00290 char *version;
00291 int headers;
00292 char *header[MGCP_MAX_HEADERS];
00293 int lines;
00294 char *line[MGCP_MAX_LINES];
00295 char data[MGCP_MAX_PACKET];
00296 int cmd;
00297 unsigned int trid;
00298 struct mgcp_request *next;
00299 };
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 struct mgcp_message {
00313 struct mgcp_endpoint *owner_ep;
00314 struct mgcp_subchannel *owner_sub;
00315 int retrans;
00316 unsigned long expire;
00317 unsigned int seqno;
00318 int len;
00319 struct mgcp_message *next;
00320 char buf[0];
00321 };
00322
00323 #define RESPONSE_TIMEOUT 30
00324
00325 struct mgcp_response {
00326 time_t whensent;
00327 int len;
00328 int seqno;
00329 struct mgcp_response *next;
00330 char buf[0];
00331 };
00332
00333 #define MAX_SUBS 2
00334
00335 #define SUB_REAL 0
00336 #define SUB_ALT 1
00337
00338 struct mgcp_subchannel {
00339
00340
00341
00342
00343
00344 #define MGCP_SUBCHANNEL_MAGIC "!978!"
00345 char magic[6];
00346 ast_mutex_t lock;
00347 int id;
00348 struct ast_channel *owner;
00349 struct mgcp_endpoint *parent;
00350 struct ast_rtp *rtp;
00351 struct sockaddr_in tmpdest;
00352 char txident[80];
00353
00354 char cxident[80];
00355 char callid[80];
00356
00357
00358
00359
00360 int cxmode;
00361 struct mgcp_request *cx_queue;
00362 ast_mutex_t cx_queue_lock;
00363 int nat;
00364 int iseq;
00365 int outgoing;
00366 int alreadygone;
00367
00368
00369
00370
00371 struct mgcp_subchannel *next;
00372 };
00373
00374 #define MGCP_ONHOOK 1
00375 #define MGCP_OFFHOOK 2
00376
00377 #define TYPE_TRUNK 1
00378 #define TYPE_LINE 2
00379
00380 struct mgcp_endpoint {
00381 ast_mutex_t lock;
00382 char name[80];
00383 struct mgcp_subchannel *sub;
00384 char accountcode[AST_MAX_ACCOUNT_CODE];
00385 char exten[AST_MAX_EXTENSION];
00386 char context[AST_MAX_EXTENSION];
00387 char language[MAX_LANGUAGE];
00388 char cid_num[AST_MAX_EXTENSION];
00389 char cid_name[AST_MAX_EXTENSION];
00390 char lastcallerid[AST_MAX_EXTENSION];
00391 char call_forward[AST_MAX_EXTENSION];
00392 char mailbox[AST_MAX_EXTENSION];
00393 char musicclass[MAX_MUSICCLASS];
00394 char curtone[80];
00395 ast_group_t callgroup;
00396 ast_group_t pickupgroup;
00397 int callwaiting;
00398 int hascallwaiting;
00399 int transfer;
00400 int threewaycalling;
00401 int singlepath;
00402 int cancallforward;
00403 int canreinvite;
00404 int callreturn;
00405 int dnd;
00406 int hascallerid;
00407 int hidecallerid;
00408 int dtmfmode;
00409 int amaflags;
00410 int type;
00411 int slowsequence;
00412 int group;
00413 int iseq;
00414 int lastout;
00415 int needdestroy;
00416 int capability;
00417 int nonCodecCapability;
00418 int onhooktime;
00419 int msgstate;
00420 int immediate;
00421 int hookstate;
00422 int adsi;
00423 char rqnt_ident[80];
00424 struct mgcp_request *rqnt_queue;
00425 ast_mutex_t rqnt_queue_lock;
00426 struct mgcp_request *cmd_queue;
00427 ast_mutex_t cmd_queue_lock;
00428 int delme;
00429 int needaudit;
00430 struct ast_dsp *dsp;
00431
00432
00433
00434
00435
00436 struct mgcp_endpoint *next;
00437 struct mgcp_gateway *parent;
00438 };
00439
00440 static struct mgcp_gateway {
00441
00442 char name[80];
00443 int isnamedottedip;
00444 struct sockaddr_in addr;
00445 struct sockaddr_in defaddr;
00446 struct in_addr ourip;
00447 int dynamic;
00448 int expire;
00449 struct mgcp_endpoint *endpoints;
00450 struct ast_ha *ha;
00451
00452
00453
00454
00455
00456
00457 char wcardep[30];
00458 struct mgcp_message *msgs;
00459 ast_mutex_t msgs_lock;
00460 int retransid;
00461 int delme;
00462 struct mgcp_response *responses;
00463 struct mgcp_gateway *next;
00464 } *gateways;
00465
00466 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
00467 static int mgcp_reloading = 0;
00468
00469 AST_MUTEX_DEFINE_STATIC(gatelock);
00470
00471 static int mgcpsock = -1;
00472
00473 static struct sockaddr_in bindaddr;
00474
00475 static struct ast_frame *mgcp_read(struct ast_channel *ast);
00476 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
00477 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
00478 static int transmit_modify_request(struct mgcp_subchannel *sub);
00479 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
00480 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
00481 static int transmit_connection_del(struct mgcp_subchannel *sub);
00482 static int transmit_audit_endpoint(struct mgcp_endpoint *p);
00483 static void start_rtp(struct mgcp_subchannel *sub);
00484 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
00485 int result, unsigned int ident, struct mgcp_request *resp);
00486 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);
00487 static int mgcp_do_reload(void);
00488 static int mgcp_reload(int fd, int argc, char *argv[]);
00489
00490 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
00491 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
00492 static int mgcp_hangup(struct ast_channel *ast);
00493 static int mgcp_answer(struct ast_channel *ast);
00494 static struct ast_frame *mgcp_read(struct ast_channel *ast);
00495 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
00496 static int mgcp_indicate(struct ast_channel *ast, int ind);
00497 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00498 static int mgcp_senddigit(struct ast_channel *ast, char digit);
00499
00500 static const struct ast_channel_tech mgcp_tech = {
00501 .type = type,
00502 .description = tdesc,
00503 .capabilities = AST_FORMAT_ULAW,
00504 .properties = AST_CHAN_TP_WANTSJITTER,
00505 .requester = mgcp_request,
00506 .call = mgcp_call,
00507 .hangup = mgcp_hangup,
00508 .answer = mgcp_answer,
00509 .read = mgcp_read,
00510 .write = mgcp_write,
00511 .indicate = mgcp_indicate,
00512 .fixup = mgcp_fixup,
00513 .send_digit = mgcp_senddigit,
00514 .bridge = ast_rtp_bridge,
00515 };
00516
00517 static int has_voicemail(struct mgcp_endpoint *p)
00518 {
00519 return ast_app_has_voicemail(p->mailbox, NULL);
00520 }
00521
00522 static int unalloc_sub(struct mgcp_subchannel *sub)
00523 {
00524 struct mgcp_endpoint *p = sub->parent;
00525 if (p->sub == sub) {
00526 ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
00527 return -1;
00528 }
00529 ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
00530
00531 sub->owner = NULL;
00532 if (!ast_strlen_zero(sub->cxident)) {
00533 transmit_connection_del(sub);
00534 }
00535 sub->cxident[0] = '\0';
00536 sub->callid[0] = '\0';
00537 sub->cxmode = MGCP_CX_INACTIVE;
00538 sub->outgoing = 0;
00539 sub->alreadygone = 0;
00540 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
00541 if (sub->rtp) {
00542 ast_rtp_destroy(sub->rtp);
00543 sub->rtp = NULL;
00544 }
00545 dump_cmd_queues(NULL, sub);
00546 return 0;
00547 }
00548
00549
00550 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
00551 {
00552 int res;
00553 if (gw->addr.sin_addr.s_addr)
00554 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
00555 else
00556 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
00557 if (res != len) {
00558 ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
00559 }
00560 return res;
00561 }
00562
00563 static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp)
00564 {
00565 struct mgcp_endpoint *p = sub->parent;
00566 int res;
00567 char iabuf[INET_ADDRSTRLEN];
00568 if (mgcpdebug) {
00569 ast_verbose("Retransmitting:\n%s\n to %s:%d\n", resp->buf, ast_inet_ntoa(iabuf, sizeof(iabuf), p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00570 }
00571 res = __mgcp_xmit(p->parent, resp->buf, resp->len);
00572 if (res > 0)
00573 res = 0;
00574 return res;
00575 }
00576
00577 static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
00578 {
00579 struct mgcp_endpoint *p = sub->parent;
00580 int res;
00581 char iabuf[INET_ADDRSTRLEN];
00582 if (mgcpdebug) {
00583 ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00584 }
00585 res = __mgcp_xmit(p->parent, req->data, req->len);
00586 if (res > 0)
00587 res = 0;
00588 return res;
00589 }
00590
00591
00592 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
00593 {
00594 struct mgcp_message *cur, *q = NULL, *w, *prev;
00595
00596 ast_mutex_lock(&gw->msgs_lock);
00597 prev = NULL, cur = gw->msgs;
00598 while (cur) {
00599 if (!p || cur->owner_ep == p) {
00600 if (prev)
00601 prev->next = cur->next;
00602 else
00603 gw->msgs = cur->next;
00604
00605 ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
00606 gw->name, cur->seqno);
00607
00608 w = cur;
00609 cur = cur->next;
00610 if (q) {
00611 w->next = q;
00612 } else {
00613 w->next = NULL;
00614 }
00615 q = w;
00616 } else {
00617 prev = cur, cur=cur->next;
00618 }
00619 }
00620 ast_mutex_unlock(&gw->msgs_lock);
00621
00622 while (q) {
00623 cur = q;
00624 q = q->next;
00625 free(cur);
00626 }
00627 }
00628
00629 static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
00630 {
00631 for(;;) {
00632 if (sub->owner) {
00633 if (!ast_mutex_trylock(&sub->owner->lock)) {
00634 ast_queue_frame(sub->owner, f);
00635 ast_mutex_unlock(&sub->owner->lock);
00636 break;
00637 } else {
00638 ast_mutex_unlock(&sub->lock);
00639 usleep(1);
00640 ast_mutex_lock(&sub->lock);
00641 }
00642 } else
00643 break;
00644 }
00645 }
00646
00647 static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
00648 {
00649 for(;;) {
00650 if (sub->owner) {
00651 if (!ast_mutex_trylock(&sub->owner->lock)) {
00652 ast_queue_hangup(sub->owner);
00653 ast_mutex_unlock(&sub->owner->lock);
00654 break;
00655 } else {
00656 ast_mutex_unlock(&sub->lock);
00657 usleep(1);
00658 ast_mutex_lock(&sub->lock);
00659 }
00660 } else
00661 break;
00662 }
00663 }
00664
00665 static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
00666 {
00667 struct ast_frame f = { AST_FRAME_CONTROL, };
00668 f.subclass = control;
00669 return mgcp_queue_frame(sub, &f);
00670 }
00671
00672 static int retrans_pkt(void *data)
00673 {
00674 struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
00675 struct mgcp_message *cur, *exq = NULL, *w, *prev;
00676 int res = 0;
00677
00678
00679 ast_mutex_lock(&gw->msgs_lock);
00680
00681 prev = NULL, cur = gw->msgs;
00682 while (cur) {
00683 if (cur->retrans < MAX_RETRANS) {
00684 cur->retrans++;
00685 if (mgcpdebug) {
00686 ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
00687 cur->retrans, cur->seqno, gw->name);
00688 }
00689 __mgcp_xmit(gw, cur->buf, cur->len);
00690
00691 prev = cur;
00692 cur = cur->next;
00693 } else {
00694 if (prev)
00695 prev->next = cur->next;
00696 else
00697 gw->msgs = cur->next;
00698
00699 ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
00700 cur->seqno, gw->name);
00701
00702 w = cur;
00703 cur = cur->next;
00704
00705 if (exq) {
00706 w->next = exq;
00707 } else {
00708 w->next = NULL;
00709 }
00710 exq = w;
00711 }
00712 }
00713
00714 if (!gw->msgs) {
00715 gw->retransid = -1;
00716 res = 0;
00717 } else {
00718 res = 1;
00719 }
00720 ast_mutex_unlock(&gw->msgs_lock);
00721
00722 while (exq) {
00723 cur = exq;
00724
00725 handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
00726 exq = exq->next;
00727 free(cur);
00728 }
00729
00730 return res;
00731 }
00732
00733
00734 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
00735 char *data, int len, unsigned int seqno)
00736 {
00737 struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len);
00738 struct mgcp_message *cur;
00739 struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL);
00740 struct timeval tv;
00741
00742 if (!msg) {
00743 return -1;
00744 }
00745 if (!gw) {
00746 return -1;
00747 }
00748
00749
00750
00751
00752
00753
00754
00755
00756 msg->owner_sub = sub;
00757 msg->owner_ep = p;
00758 msg->seqno = seqno;
00759 msg->next = NULL;
00760 msg->len = len;
00761 msg->retrans = 0;
00762 memcpy(msg->buf, data, msg->len);
00763
00764 ast_mutex_lock(&gw->msgs_lock);
00765 cur = gw->msgs;
00766 if (cur) {
00767 while(cur->next)
00768 cur = cur->next;
00769 cur->next = msg;
00770 } else {
00771 gw->msgs = msg;
00772 }
00773
00774 if (gettimeofday(&tv, NULL) < 0) {
00775
00776 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
00777 } else {
00778 msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
00779
00780 if (gw->retransid == -1)
00781 gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
00782 }
00783 ast_mutex_unlock(&gw->msgs_lock);
00784
00785
00786
00787
00788
00789
00790 __mgcp_xmit(gw, msg->buf, msg->len);
00791
00792
00793
00794
00795
00796 return 0;
00797 }
00798
00799
00800 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
00801 struct mgcp_request *req, unsigned int seqno)
00802 {
00803 int res = 0;
00804 struct mgcp_request **queue, *q, *r, *t;
00805 char iabuf[INET_ADDRSTRLEN];
00806 ast_mutex_t *l;
00807
00808 ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence);
00809 if (p->slowsequence) {
00810 queue = &p->cmd_queue;
00811 l = &p->cmd_queue_lock;
00812 ast_mutex_lock(l);
00813 } else {
00814 switch (req->cmd) {
00815 case MGCP_CMD_DLCX:
00816 queue = &sub->cx_queue;
00817 l = &sub->cx_queue_lock;
00818 ast_mutex_lock(l);
00819 q = sub->cx_queue;
00820
00821 while (q) {
00822 r = q->next;
00823 free(q);
00824 q = r;
00825 }
00826 *queue = NULL;
00827