Index: apps/app_forkcdr.c
===================================================================
--- apps/app_forkcdr.c	(revision 225404)
+++ apps/app_forkcdr.c	(working copy)
@@ -184,7 +184,7 @@
 	while (cdr->next)
 		cdr = cdr->next;
 	
-	if (!(newcdr = ast_cdr_dup(cdr)))
+	if (!(newcdr = ast_cdr_dup(cdr, chan)))
 		return;
 	
 	ast_cdr_append(cdr, newcdr);
Index: funcs/func_cdr.c
===================================================================
--- funcs/func_cdr.c	(revision 225404)
+++ funcs/func_cdr.c	(working copy)
@@ -99,6 +99,9 @@
 					<enum name="channel">
 						<para>Channel name.</para>
 					</enum>
+					<enum name="sequence">
+						<para>CDR sequence number.</param>
+					</enum>
 				</enumlist>
 			</parameter>
 			<parameter name="options" required="false">
Index: include/asterisk/cdr.h
===================================================================
--- include/asterisk/cdr.h	(revision 225404)
+++ include/asterisk/cdr.h	(working copy)
@@ -110,6 +110,8 @@
 	char linkedid[32];
 	/*! User field */
 	char userfield[AST_MAX_USER_FIELD];
+	/*! Sequence field */
+	int sequence;
 
 	/*! A linked list for variables */
 	struct varshead varshead;
@@ -144,10 +146,13 @@
 
 /*! 
  * \brief Duplicate a record 
+ * \param cdr the record to duplicate
+ * \param chan the channel to pull a new seq value from, if this is NULL the
+ * existing sequence value will be used
  * \retval a malloc'd ast_cdr structure, 
  * \retval NULL on error (malloc failure)
  */
-struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
+struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr, struct ast_channel *chan);
 
 /*! 
  * \brief Free a CDR record 
Index: main/cdr.c
===================================================================
--- main/cdr.c	(revision 225404)
+++ main/cdr.c	(working copy)
@@ -74,6 +74,14 @@
 	struct ast_cdr_batch_item *tail;
 } *batch = NULL;
 
+static void cdr_seq_free(void *data);
+static int cdr_seq_init(struct ast_cdr *cdr, struct ast_channel *c);
+
+static struct ast_datastore_info cdr_seq_info = {
+	.type = "CDR_SEQ",
+	.destroy = cdr_seq_free,
+};
+
 static struct sched_context *sched;
 static int cdr_sched = -1;
 static pthread_t cdr_thread = AST_PTHREADT_NULL;
@@ -168,7 +176,7 @@
 /*! Duplicate a CDR record 
 	\returns Pointer to new CDR record
 */
-struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr) 
+struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr, struct ast_channel *c) 
 {
 	struct ast_cdr *newcdr;
 	
@@ -184,6 +192,9 @@
 	ast_cdr_copy_vars(newcdr, cdr);
 	newcdr->next = NULL;
 
+	if (c)
+		cdr_seq_init(newcdr, c);
+
 	return newcdr;
 }
 
@@ -279,6 +290,8 @@
 		ast_copy_string(workspace, cdr->linkedid, workspacelen);
 	else if (!strcasecmp(name, "userfield"))
 		ast_copy_string(workspace, cdr->userfield, workspacelen);
+	else if (!strcasecmp(name, "sequence"))
+		snprintf(workspace, workspacelen, "%d", cdr->sequence);
 	else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
 		ast_copy_string(workspace, varbuf, workspacelen);
 	else
@@ -292,7 +305,7 @@
 static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
 						  "lastapp", "lastdata", "start", "answer", "end", "duration",
 						  "billsec", "disposition", "amaflags", "accountcode", "uniqueid", "linkedid",
-						  "userfield", NULL };
+						  "userfield", "sequence", NULL };
 /*! Set a CDR channel variable 
 	\note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
 */
@@ -552,9 +565,9 @@
 			from->next = NULL;
 			/* rip off the last entry and put a copy of the to at the end */
 			if (llfrom == from)
-				to = to->next = ast_cdr_dup(&tcdr);
+				to = to->next = ast_cdr_dup(&tcdr, NULL);
 			else
-				to = llfrom->next = ast_cdr_dup(&tcdr);
+				to = llfrom->next = ast_cdr_dup(&tcdr, NULL);
 			from = lfrom;
 		}
 	}
@@ -847,6 +860,38 @@
 	return 0;
 }
 
+static void cdr_seq_free(void *data)
+{
+	ast_free(data);
+}
+
+static int cdr_seq_init(struct ast_cdr *cdr, struct ast_channel *c)
+{
+	struct ast_datastore *seq;
+
+	ast_channel_lock(c);
+	if (!(seq = ast_channel_datastore_find(c, &cdr_seq_info, NULL))) {
+		seq = ast_datastore_alloc(&cdr_seq_info, NULL);
+		if (!seq)
+			goto e_channel_unlock;
+
+		seq->data = ast_calloc(1, sizeof(int));
+		if (seq->data)
+			goto e_datastore_free;
+
+		ast_channel_datastore_add(c, seq);
+	}
+	ast_channel_unlock(c);
+
+	return (cdr->sequence = ast_atomic_fetchadd_int(seq->data, 1));
+
+e_datastore_free:
+	ast_datastore_free(seq);
+e_channel_unlock:
+	ast_channel_unlock(c);
+	return -1;
+}
+
 int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
 {
 	char *chan;
@@ -856,6 +901,7 @@
 			chan = S_OR(cdr->channel, "<unknown>");
 			ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
 			set_one_cid(cdr, c);
+			cdr_seq_init(cdr, c);
 
 			cdr->disposition = (c->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
 			cdr->amaflags = c->amaflags ? c->amaflags :  ast_default_amaflags;
@@ -1116,7 +1162,7 @@
 		if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
 			if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
 				ast_cdr_end(cdr);
-				if ((duplicate = ast_cdr_dup(cdr))) {
+				if ((duplicate = ast_cdr_dup(cdr, NULL))) {
 					ast_cdr_detach(duplicate);
 				}
 				ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
Index: main/features.c
===================================================================
--- main/features.c	(revision 225404)
+++ main/features.c	(working copy)
@@ -2804,7 +2804,7 @@
 		if (chan_cdr) {
 			ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
 			ast_cdr_update(chan);
-			bridge_cdr = ast_cdr_dup(chan_cdr);
+			bridge_cdr = ast_cdr_dup(chan_cdr, chan);
 			ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
 			ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
 		} else {
Index: main/pbx.c
===================================================================
--- main/pbx.c	(revision 225404)
+++ main/pbx.c	(working copy)
@@ -7645,7 +7645,7 @@
 		} else {
 			if (chan->cdr) {
 				ast_cdr_discard(tmpchan->cdr);
-				tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
+				tmpchan->cdr = ast_cdr_dup(chan->cdr, NULL);  /* share the love */
 			}
 			/* Make formats okay */
 			tmpchan->readformat = chan->readformat;
Index: configs/cdr_custom.conf.sample
===================================================================
--- configs/cdr_custom.conf.sample	(revision 225404)
+++ configs/cdr_custom.conf.sample	(working copy)
@@ -7,6 +7,6 @@
 ; Master.csv, Simple.csv, or both.
 ;
 ;[mappings]
-;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}
+;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)}
 ;Simple.csv => ${CSV_QUOTE(${EPOCH})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})}
 
Index: cdr/cdr_custom.c
===================================================================
--- cdr/cdr_custom.c	(revision 225404)
+++ cdr/cdr_custom.c	(working copy)
@@ -134,7 +134,7 @@
 	/* We need to dup here since the cdr actually belongs to the other channel,
 	   so when we release this channel we don't want the CDR getting cleaned
 	   up prematurely. */
-	dummy->cdr = ast_cdr_dup(cdr);
+	dummy->cdr = ast_cdr_dup(cdr, NULL);
 
 	AST_RWLIST_RDLOCK(&sinks);
 
Index: cdr/cdr_manager.c
===================================================================
--- cdr/cdr_manager.c	(revision 225404)
+++ cdr/cdr_manager.c	(working copy)
@@ -161,7 +161,7 @@
 			ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
 			return 0;
 		}
-		dummy->cdr = ast_cdr_dup(cdr);
+		dummy->cdr = ast_cdr_dup(cdr, NULL);
 		pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
 		ast_channel_release(dummy);
 	}
Index: cdr/cdr_sqlite3_custom.c
===================================================================
--- cdr/cdr_sqlite3_custom.c	(revision 225404)
+++ cdr/cdr_sqlite3_custom.c	(working copy)
@@ -248,7 +248,7 @@
 			ast_mutex_unlock(&lock);
 			return 0;
 		}
-		dummy->cdr = ast_cdr_dup(cdr);
+		dummy->cdr = ast_cdr_dup(cdr, NULL);
 		AST_LIST_TRAVERSE(&sql_values, value, list) {
 			pbx_substitute_variables_helper(dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
 			escaped = sqlite3_mprintf("%q", subst_buf);
Index: cdr/cdr_syslog.c
===================================================================
--- cdr/cdr_syslog.c	(revision 225404)
+++ cdr/cdr_syslog.c	(working copy)
@@ -91,7 +91,7 @@
 	/* We need to dup here since the cdr actually belongs to the other channel,
 	   so when we release this channel we don't want the CDR getting cleaned
 	   up prematurely. */
-	dummy->cdr = ast_cdr_dup(cdr);
+	dummy->cdr = ast_cdr_dup(cdr, NULL);
 
 	AST_RWLIST_RDLOCK(&sinks);
 
