Index: channels/h323/ast_h323.cxx
===================================================================
--- channels/h323/ast_h323.cxx	(revision 47619)
+++ channels/h323/ast_h323.cxx	(working copy)
@@ -739,6 +739,14 @@
 		if (opts->transfer_capability >= 0) {
 			transfer_capability = opts->transfer_capability;
 		}
+		if (!ast_strlen_zero(opts->callId)) {
+			callIdentifier = OpalGloballyUniqueID(opts->callId);
+		}
+		if (!ast_strlen_zero(opts->ospToken)) {
+			ospToken.SetSize(OSPTOKENSIZE);
+			int size = ast_base64decode(ospToken.GetPointer(), opts->ospToken, OSPTOKENSIZE);
+			ospToken.SetSize(size);
+		}
 	}
 	tunnelOptions = opts->tunnelOptions;
 }
@@ -816,6 +824,28 @@
 
 		/* Don't show local username as called party name */
 		SetDisplayName(cd->call_dest_e164);
+
+		if (setupPDU.m_h323_uu_pdu.m_h323_message_body.GetTag() == H225_H323_UU_PDU_h323_message_body::e_setup) {
+			const H225_Setup_UUIE& setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
+			if (setup.HasOptionalField(H225_Setup_UUIE::e_tokens)) {
+				const H225_ArrayOf_ClearToken& clearTokens = setup.m_tokens;
+				PINDEX tokenCount = clearTokens.GetSize();
+				for (PINDEX i = 0; i < tokenCount; i++) {
+					H235_ClearToken& clearToken = clearTokens[i];
+					if (clearToken.m_tokenOID == OpalOSP::ETSIXMLTokenOID &&
+						clearToken.HasOptionalField(H235_ClearToken::e_nonStandard) &&
+						clearToken.m_nonStandard.m_nonStandardIdentifier == OpalOSP::ETSIXMLTokenOID)
+					{
+						PBYTEArray token = clearToken.m_nonStandard.m_data;
+						cd->ospToken = (char*)malloc(OSPTOKENSIZE);
+						if (cd->ospToken != NULL) {
+							ast_base64encode(cd->ospToken, token.GetPointer(), token.GetSize(), OSPTOKENSIZE - 1);
+						}
+						break;
+					}
+				}
+			}
+		}
 	}
 
 	/* Convert complex strings */
@@ -1380,6 +1410,18 @@
 		}
 	}
 
+	if (ospToken.GetSize() != 0) {
+		setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
+		H225_ArrayOf_ClearToken& clearTokens = setup.m_tokens;
+		PINDEX tokenCount = clearTokens.GetSize();
+		clearTokens.SetSize(tokenCount + 1);
+		H235_ClearToken& clearToken = clearTokens[tokenCount];
+		clearToken.m_tokenOID = OpalOSP::ETSIXMLTokenOID;
+		clearToken.IncludeOptionalField(H235_ClearToken::e_nonStandard);
+		clearToken.m_nonStandard.m_nonStandardIdentifier = OpalOSP::ETSIXMLTokenOID;
+		clearToken.m_nonStandard.m_data = ospToken;
+	}
+
 #ifdef H323_TRANSNEXUS_OSP
 	// check for OSP server (if not using GK)
 	if (gatekeeper == NULL) {
Index: channels/h323/chan_h323.h
===================================================================
--- channels/h323/chan_h323.h	(revision 47619)
+++ channels/h323/chan_h323.h	(working copy)
@@ -43,6 +43,9 @@
 #define H323_HOLD_Q931ONLY	(1 << 1)
 #define H323_HOLD_H450		(1 << 2)
 
+#define CALLIDSIZE			64
+#define OSPTOKENSIZE		4096
+
 /** call_option struct holds various bits
  *         of information for each call */
 typedef struct call_options {
@@ -67,6 +70,8 @@
 	int				tunnelOptions;
 	int				holdHandling;
 	struct ast_codec_pref	prefs;
+	char			callId[CALLIDSIZE];
+	char            ospToken[OSPTOKENSIZE];
 } call_options_t;
 
 /* structure to hold the valid asterisk users */
@@ -121,6 +126,7 @@
 	int type_of_number;
 	int transfer_capability;
 	char *sourceIp;
+	char* ospToken;
 } call_details_t;
 
 typedef struct rtp_info {
Index: channels/h323/ast_h323.h
===================================================================
--- channels/h323/ast_h323.h	(revision 47619)
+++ channels/h323/ast_h323.h	(working copy)
@@ -125,6 +125,8 @@
 
 	RTP_DataFrame::PayloadTypes dtmfCodec[2];
 	int dtmfMode;
+
+	PBYTEArray ospToken;
 };
 
 class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
Index: channels/chan_h323.c
===================================================================
--- channels/chan_h323.c	(revision 47619)
+++ channels/chan_h323.c	(working copy)
@@ -446,6 +446,10 @@
 		free(cd->redirect_number);
 		cd->redirect_number = NULL;
 	}
+	if (cd->ospToken) {
+		free(cd->ospToken);
+		cd->ospToken = NULL;
+	}
 }
 
 static void __oh323_destroy(struct oh323_pvt *pvt)
@@ -593,6 +597,7 @@
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
 	const char *addr;
 	char called_addr[1024];
+	const char* value;
 
 	if (h323debug) {
 		ast_log(LOG_DEBUG, "Calling to %s on %s\n", dest, c->name);
@@ -649,6 +654,20 @@
 
 	pvt->options.transfer_capability = c->transfercapability;
 
+	value = pbx_builtin_getvar_helper(c, "~OH323~callid");
+	if (ast_strlen_zero(value)) {
+		pvt->options.callId[0] = '\0';
+	} else {
+		strncpy(pvt->options.callId, value, sizeof(pvt->options.callId));
+	}
+
+	value = pbx_builtin_getvar_helper(c, "~OH323~osptoken");
+	if (ast_strlen_zero(value)) {
+		pvt->options.ospToken[0] = '\0';
+	} else {
+		strncpy(pvt->options.ospToken, value, sizeof(pvt->options.ospToken));
+	}
+
 	/* indicate that this is an outgoing call */
 	pvt->outgoing = 1;
 
@@ -3187,6 +3206,80 @@
 	.set_rtp_peer = oh323_set_rtp_peer,
 };
 
+/*! \brief ${OH323CHANINFO()} Dialplan function - reads oh323 channel data */
+static int oh323_chaninfo_read(struct ast_channel *chan, char *cmd, char *varname, char *buf, size_t len)
+{
+	struct oh323_pvt *p;
+
+	*buf = 0;
+
+	if (!varname) {
+		ast_log(LOG_WARNING, "This function requires a parameter name.\n");
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (chan->tech != &oh323_tech) {
+		ast_log(LOG_WARNING, "This function can only be used on OH323 channels.\n");
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (!(p = chan->tech_pvt)) {
+		/* If there is no private structure, this channel is no longer alive */
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (!strcasecmp(varname, "peerip")) {
+		ast_copy_string(buf, p->cd.sourceIp ? p->cd.sourceIp : "", len);
+	} else  if (!strcasecmp(varname, "osptoken")) {
+		ast_copy_string(buf, p->cd.ospToken ? p->cd.ospToken : "", len);
+	} else {
+		ast_channel_unlock(chan);
+		return -1;
+	}
+	ast_channel_unlock(chan);
+
+	return 0;
+}
+
+/*! \brief ${OH323CHANINFO()} Dialplan function - writes oh323 channel data */
+static int oh323_chaninfo_write(struct ast_channel *chan, char *cmd, char *varname, const char *value)
+{
+	char tmp[256];
+
+	if (!varname) {
+		ast_log(LOG_WARNING, "This function requires a parameter name.\n");
+		return -1;
+	}
+
+	if (!strcasecmp(varname, "callid")) {
+		snprintf(tmp, sizeof(tmp), "_~OH323~%s", varname);
+		pbx_builtin_setvar_helper(chan, tmp, value);
+	} else  if (!strcasecmp(varname, "osptoken")) {
+		snprintf(tmp, sizeof(tmp), "_~OH323~%s", varname);
+		pbx_builtin_setvar_helper(chan, tmp, value);
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*! \brief Structure to declare a dialplan function: OH323CHANINFO */
+static struct ast_custom_function oh323_chaninfo_function = {
+    .name = "OH323CHANINFO",
+    .synopsis = "Gets the specified H.323 parameter from the current channel",
+    .syntax = "OH323CHANINFO(item)",
+    .read = oh323_chaninfo_read,
+    .write = oh323_chaninfo_write,
+    .desc = "Valid items are:\n"
+    "- peerip        The IP address of the source peer. Read only.\n"
+    "- callid        The call identifier to the destination. Write only.\n"
+    "- osptoken      The OSP token from the source or to the destination. Read and write.\n"
+};
+
 static enum ast_module_load_result load_module(void)
 {
 	int res;
@@ -3280,6 +3373,10 @@
 				res = AST_MODULE_LOAD_SUCCESS;
 			}
 		}
+
+	    /* Register dial plan functions */
+	    ast_custom_function_register(&oh323_chaninfo_function);
+
 		/* And start the monitor for the first time */
 		restart_monitor();
 	}
@@ -3290,6 +3387,9 @@
 {
 	struct oh323_pvt *p, *pl;
 
+	/* Unregister dial plan functions */
+	ast_custom_function_unregister(&oh323_chaninfo_function);
+
 	/* unregister commands */
 	ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
 	ast_cli_unregister(&cli_h323_reload);
