diff --git a/CHANGES b/CHANGES
index e6da22224e3228ff13d0c4c4deecee68b5585d5c..3223822ba6b0bddb9aadf8124298838c796c86e8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -136,6 +136,10 @@ Core
    feature on the bridge peer in a multi-party bridge will execute it on all
    peers of the activating channel.
 
+ * A channel variable ATTENDEDTRANSFER is now set which indicates which channel
+   was responsible for an attended transfer in a similar fashion to
+   BLINDTRANSFER.
+
 AMI (Asterisk Manager Interface)
 ------------------
  * The SIPshowpeer action will now include a 'SubscribeContext' field for a peer
@@ -176,12 +180,24 @@ AMI (Asterisk Manager Interface)
 
  * The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
    'UnParkedCall' have changed significantly in the new res_parking module.
-   First, channel snapshot data is included for both the parker and the parkee
-   in lieu of the "From" and "Channel" fields. They follow standard channel
-   snapshot format but each field is suffixed with 'Parker' or 'Parkee'
-   depending on which side it applies to. The 'Exten' field is replaced with
-   'ParkingSpace' since the registration of extensions as for parking spaces
-   is no longer mandatory.
+
+   The 'Channel' and 'From' headers are gone. For the channel that was parked
+   or is coming out of parking, a 'Parkee' channel snapshot is issued and it
+   has a number of fields associated with it. The old 'Channel' header relayed
+   the same data as the new 'ParkeeChannel' header.
+
+   The 'From' field was ambiguous and changed meaning depending on the event.
+   for most of these, it was the name of the channel that parked the call
+   (the 'Parker'). There is no longer a header that provides this channel name,
+   however the 'ParkerDialString' will contain a dialstring to redial the
+   device that parked the call.
+
+   On UnParkedCall events, the 'From' header would instead represent the
+   channel responsible for retrieving the parkee. It receives a channel
+   snapshot labeled 'Retriever'. The 'from' field is is replaced with
+   'RetrieverChannel'.
+
+   Lastly, the 'Exten' field has been replaced with 'ParkingSpace'.
 
  * The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar
    fashion has changed the field names 'StartExten' and 'StopExten' to
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 7a5261b94d7da4c2f4fbb45f38617b13f99e296d..bcb2de4db1efecb61937d5ffdda67ae1129170e1 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -75,6 +75,22 @@ AMI:
    - Channels no longer swap Uniqueid's as a result of the masquerade.
    - Instead of a shell game of renames, there's now a single rename, appending
      <ZOMBIE> to the name of the original channel.
+ - The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
+   'UnParkedCall' have changed significantly in the new res_parking module.
+   - The 'Channel' and 'From' headers are gone. For the channel that was parked
+     or is coming out of parking, a 'Parkee' channel snapshot is issued and it
+     has a number of fields associated with it. The old 'Channel' header relayed
+     the same data as the new 'ParkeeChannel' header.
+   - The 'From' field was ambiguous and changed meaning depending on the event.
+     for most of these, it was the name of the channel that parked the call
+     (the 'Parker'). There is no longer a header that provides this channel name,
+     however the 'ParkerDialString' will contain a dialstring to redial the
+     device that parked the call.
+   - On UnParkedCall events, the 'From' header would instead represent the
+     channel responsible for retrieving the parkee. It receives a channel
+     snapshot labeled 'Retriever'. The 'from' field is is replaced with
+     'RetrieverChannel'.
+   - Lastly, the 'Exten' field has been replaced with 'ParkingSpace'.
 
 CEL:
  - The Uniqueid field for a channel is now a stable identifier, and will not
diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c
index b53e0db5c56adc267f77a5151ad2eb2a321424b0..f0c4c24379bcc2cb9e374fcc353f1cdf8886a283 100644
--- a/bridges/bridge_builtin_features.c
+++ b/bridges/bridge_builtin_features.c
@@ -140,6 +140,9 @@ static struct ast_channel *dial_transfer(struct ast_channel *caller, const char
 	/* Who is transferring the call. */
 	pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller));
 
+	/* To work as an analog to BLINDTRANSFER */
+	pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFER", ast_channel_name(caller));
+
 	/* Before we actually dial out let's inherit appropriate information. */
 	copy_caller_data(chan, caller);
 
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index d61494141d549c39a70722b798a77f153d2bd42a..2e74684183c9a8ec9b10d21ca6f54b6334541a42 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -4375,5 +4375,13 @@ int ast_channel_forward_endpoint(struct ast_channel *chan, struct ast_endpoint *
 */
 const char *ast_channel_oldest_linkedid(const char *a, const char *b);
 
+/*!
+ * \brief Removes the trailing identifiers from a channel name string
+ * \since 12.0.0
+ *
+ * \param channel_name string that you wish to turn into a dial string.
+ *                     This string will be edited in place.
+ */
+void ast_channel_name_to_dial_string(char *channel_name);
 
 #endif /* _ASTERISK_CHANNEL_H */
diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h
index c4019d9cb63fbe4da8d1063ecbfbcf4efcfeaec4..dd8a67bf28789a044c58134510bd4d92675ec770 100644
--- a/include/asterisk/parking.h
+++ b/include/asterisk/parking.h
@@ -45,14 +45,14 @@ enum ast_parked_call_event_type {
  */
 struct ast_parked_call_payload {
 	struct ast_channel_snapshot *parkee;             /*!< Snapshot of the channel that is parked */
-	struct ast_channel_snapshot *parker;             /*!< Snapshot of the channel that parked the call */
-	struct ast_channel_snapshot *retriever;          /*!< Snapshot of the channel that retrieved the call */
+	struct ast_channel_snapshot *retriever;          /*!< Snapshot of the channel that retrieved the call (may be NULL) */
 	enum ast_parked_call_event_type event_type;      /*!< Reason for issuing the parked call message */
 	long unsigned int timeout;                       /*!< Time remaining before the call times out (seconds ) */
 	long unsigned int duration;                      /*!< How long the parkee has been parked (seconds) */
 	unsigned int parkingspace;                       /*!< Which Parking Space the parkee occupies */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(parkinglot);                /*!< Name of the parking lot used to park the parkee */
+		AST_STRING_FIELD(parker_dial_string);          /*!< The device string used for call control on parking timeout */
 	);
 };
 
@@ -64,7 +64,7 @@ struct ast_exten;
  *
  * \param event_type What kind of parked call event is happening
  * \param parkee_snapshot channel snapshot of the parkee
- * \param parker_snapshot channel snapshot of the parker
+ * \param parker_dial_string dialstring used when the call times out
  * \param retriever_snapshot channel snapshot of the retriever (NULL allowed)
  * \param parkinglot name of the parking lot where the parked call is parked
  * \param parkingspace what numerical parking space the parked call is parked in
@@ -75,7 +75,7 @@ struct ast_exten;
  * \retval reference to a newly created parked call payload
  */
 struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
-		struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot,
+		struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
 		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
 		unsigned int parkingspace, unsigned long int timeout, unsigned long int duration);
 
diff --git a/main/bridging.c b/main/bridging.c
index 110f5255b1a21b21ed515d7b266f593c2b6beb1f..348ce48e82d91540a9bcfda9c1dba69628c5b79f 100644
--- a/main/bridging.c
+++ b/main/bridging.c
@@ -719,8 +719,9 @@ static int bridge_channel_push(struct ast_bridge_channel *bridge_channel)
 		bridge_channel_pull(swap);
 	}
 
-	/* Clear any BLINDTRANSFER since the transfer has completed. */
+	/* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */
 	pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL);
+	pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL);
 
 	bridge->reconfigured = 1;
 	return 0;
diff --git a/main/cel.c b/main/cel.c
index 30838f369e727e937671e0a26d46e5e46ee414bf..bc1182aa747c5aa89a4183addab51c7670680d3c 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -1333,7 +1333,7 @@ static void cel_parking_cb(
 	case PARKED_CALL:
 		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_START, NULL,
 			parked_payload->parkinglot,
-			S_COR(parked_payload->parker, parked_payload->parker->name, NULL));
+			parked_payload->parker_dial_string);
 		break;
 	case PARKED_CALL_TIMEOUT:
 		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
diff --git a/main/channel.c b/main/channel.c
index 3bc5c0a75c9e02f4de1086f90ed0e164b8494d07..ce11e50b75b8c3453ac493999fb59bb234b9798c 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -6565,6 +6565,17 @@ const char *ast_channel_oldest_linkedid(const char *a, const char *b)
 	}
 }
 
+void ast_channel_name_to_dial_string(char *channel_name)
+{
+	char *dash;
+
+	/* Truncate after the dash */
+	dash = strrchr(channel_name, '-');
+	if (dash) {
+		*dash = '\0';
+	}
+}
+
 /*!
  * \internal
  * \brief Transfer COLP between target and transferee channels.
diff --git a/main/features.c b/main/features.c
index 577a1765502f9a14a504b94a7fb4050e43a83b53..9128551d88fab020aa9a2aecb2399aa00cbbda93 100644
--- a/main/features.c
+++ b/main/features.c
@@ -282,46 +282,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 			<para>Bridge together two channels already in the PBX.</para>
 		</description>
 	</manager>
-	<managerEvent language="en_US" name="ParkedCallTimeOut">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a parked call times out.</synopsis>
-			<syntax>
-				<parameter name="Exten">
-					<para>The parking lot extension.</para>
-				</parameter>
-				<parameter name="Channel"/>
-				<parameter name="Parkinglot">
-					<para>The name of the parking lot.</para>
-				</parameter>
-				<parameter name="CallerIDNum"/>
-				<parameter name="CallerIDName"/>
-				<parameter name="ConnectedLineNum"/>
-				<parameter name="ConnectedLineName"/>
-				<parameter name="UniqueID"/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ParkedCall</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ParkedCallGiveUp">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a parked call hangs up while in the parking lot.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Exten'])" />
-				<parameter name="Channel"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
-				<parameter name="CallerIDNum"/>
-				<parameter name="CallerIDName"/>
-				<parameter name="ConnectedLineNum"/>
-				<parameter name="ConnectedLineName"/>
-				<parameter name="UniqueID"/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ParkedCall</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
 	<managerEvent language="en_US" name="Pickup">
 		<managerEventInstance class="EVENT_FLAG_CALL">
 			<synopsis>Raised when a call pickup occurs.</synopsis>
diff --git a/main/parking.c b/main/parking.c
index a3da860b73d7bcef40023cc99c0e5b14270a7569..02695cd01ceac3fcf3546f2a284382d3e4d1906f 100644
--- a/main/parking.c
+++ b/main/parking.c
@@ -79,13 +79,12 @@ static void parked_call_payload_destructor(void *obj)
 	struct ast_parked_call_payload *park_obj = obj;
 
 	ao2_cleanup(park_obj->parkee);
-	ao2_cleanup(park_obj->parker);
 	ao2_cleanup(park_obj->retriever);
 	ast_string_field_free_memory(park_obj);
 }
 
 struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
-		struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot,
+		struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
 		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
 		unsigned int parkingspace, unsigned long int timeout,
 		unsigned long int duration)
@@ -106,11 +105,6 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c
 	ao2_ref(parkee_snapshot, +1);
 	payload->parkee = parkee_snapshot;
 
-	if (parker_snapshot) {
-		ao2_ref(parker_snapshot, +1);
-		payload->parker = parker_snapshot;
-	}
-
 	if (retriever_snapshot) {
 		ao2_ref(retriever_snapshot, +1);
 		payload->retriever = retriever_snapshot;
@@ -120,6 +114,10 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c
 		ast_string_field_set(payload, parkinglot, parkinglot);
 	}
 
+	if (parker_dial_string) {
+		ast_string_field_set(payload, parker_dial_string, parker_dial_string);
+	}
+
 	payload->parkingspace = parkingspace;
 	payload->timeout = timeout;
 	payload->duration = duration;
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
index eceeaca18a450406cc5043025eda8e862cde5882..f7e27976610e53a6f697679d8b731c033587d337 100644
--- a/res/parking/parking_applications.c
+++ b/res/parking/parking_applications.c
@@ -284,14 +284,24 @@ static int park_app_parse_data(const char *data, int *disable_announce, int *use
 	return 0;
 }
 
-static void park_common_datastore_destroy(void *data)
+void park_common_datastore_free(struct park_common_datastore *datastore)
 {
-	struct park_common_datastore *datastore = data;
+	if (!datastore) {
+		return;
+	}
+
 	ast_free(datastore->parker_uuid);
+	ast_free(datastore->parker_dial_string);
 	ast_free(datastore->comeback_override);
 	ast_free(datastore);
 }
 
+static void park_common_datastore_destroy(void *data)
+{
+	struct park_common_datastore *datastore = data;
+	park_common_datastore_free(datastore);
+}
+
 static const struct ast_datastore_info park_common_info = {
 	.type = "park entry data",
 	.destroy = park_common_datastore_destroy,
@@ -314,6 +324,9 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p
 {
 	struct ast_datastore *datastore = NULL;
 	struct park_common_datastore *park_datastore;
+	const char *attended_transfer;
+	const char *blind_transfer;
+	char *parker_dial_string = NULL;
 
 	wipe_park_common_datastore(parkee);
 
@@ -326,7 +339,27 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p
 		return -1;
 	}
 
-	park_datastore->parker_uuid = ast_strdup(parker_uuid);
+	if (parker_uuid) {
+		park_datastore->parker_uuid = ast_strdup(parker_uuid);
+	}
+
+	ast_channel_lock(parkee);
+
+	attended_transfer = pbx_builtin_getvar_helper(parkee, "ATTENDEDTRANSFER");
+	blind_transfer = pbx_builtin_getvar_helper(parkee, "BLINDTRANSFER");
+
+	if (attended_transfer || blind_transfer) {
+		parker_dial_string = ast_strdupa(S_OR(attended_transfer, blind_transfer));
+	}
+
+	ast_channel_unlock(parkee);
+
+	if (!ast_strlen_zero(parker_dial_string)) {
+		ast_channel_name_to_dial_string(parker_dial_string);
+		ast_verb(5, "Setting dial string to %s from %s value", parker_dial_string, attended_transfer ? "ATTENDEDTRANSFER" : "BLINDTRANSFER");
+		park_datastore->parker_dial_string = ast_strdup(parker_dial_string);
+	}
+
 	park_datastore->randomize = randomize;
 	park_datastore->time_limit = time_limit;
 	park_datastore->silence_announce = silence_announce;
@@ -344,16 +377,15 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p
 	return 0;
 }
 
-void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uuid, char **comeback_override,
-		int *randomize, int *time_limit, int *silence_announce)
+struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee)
 {
 	struct ast_datastore *datastore;
 	struct park_common_datastore *data;
+	struct park_common_datastore *data_copy;
 
-	ast_channel_lock(parkee);
+	SCOPED_CHANNELLOCK(lock, parkee);
 	if (!(datastore = ast_channel_datastore_find(parkee, &park_common_info, NULL))) {
-		ast_channel_unlock(parkee);
-		return;
+		return NULL;
 	}
 
 	data = datastore->data;
@@ -363,16 +395,37 @@ void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uu
 		ast_assert(0);
 	}
 
-	*parker_uuid = ast_strdup(data->parker_uuid);
-	*randomize = data->randomize;
-	*time_limit = data->time_limit;
-	*silence_announce = data->silence_announce;
+	data_copy = ast_calloc(1, sizeof(*data_copy));
+	if (!data_copy) {
+		return NULL;
+	}
+
+	if (!(data_copy->parker_uuid = ast_strdup(data->parker_uuid))) {
+		park_common_datastore_free(data_copy);
+		return NULL;
+	}
+
+	data_copy->randomize = data->randomize;
+	data_copy->time_limit = data->time_limit;
+	data_copy->silence_announce = data->silence_announce;
 
 	if (data->comeback_override) {
-		*comeback_override = ast_strdup(data->comeback_override);
+		data_copy->comeback_override = ast_strdup(data->comeback_override);
+		if (!data_copy->comeback_override) {
+			park_common_datastore_free(data_copy);
+			return NULL;
+		}
 	}
 
-	ast_channel_unlock(parkee);
+	if (data->parker_dial_string) {
+		data_copy->parker_dial_string = ast_strdup(data->parker_dial_string);
+		if (!data_copy->parker_dial_string) {
+			park_common_datastore_free(data_copy);
+			return NULL;
+		}
+	}
+
+	return data_copy;
 }
 
 struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
@@ -382,6 +435,10 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan
 	struct ast_bridge *parking_bridge;
 	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
 
+	if (!parker) {
+		parker = parkee;
+	}
+
 	/* If the name of the parking lot isn't specified in the arguments, find it based on the channel. */
 	if (ast_strlen_zero(lot_name)) {
 		ast_channel_lock(parker);
@@ -433,18 +490,6 @@ struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast
 
 }
 
-/* XXX BUGBUG - determining the parker when transferred to deep park priority
- *     Currently all parking by the park application is treated as calls parking themselves.
- *     However, it's possible for calls to be transferred here when the Park application is
- *     set after the first priority of an extension. In that case, there used to be a variable
- *     (BLINDTRANSFER) set indicating which channel placed that call here.
- *
- *     If BLINDTRANSFER is set, this channel name will need to be referenced in Park events
- *     generated by stasis. Ideally we would get a whole channel snapshot and use that for the
- *     parker, but that would likely require applying the channel snapshot to a channel datastore
- *     on all transfers. Alternatively just the name of the parking channel could be applied along
- *     with an indication that it's dead.
- */
 int park_app_exec(struct ast_channel *chan, const char *data)
 {
 	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
@@ -452,7 +497,7 @@ int park_app_exec(struct ast_channel *chan, const char *data)
 	struct ast_bridge_features chan_features;
 	int res;
 	int silence_announcements = 0;
-	const char *blind_transfer;
+	const char *transferer;
 
 	/* Answer the channel if needed */
 	if (ast_channel_state(chan) != AST_STATE_UP) {
@@ -460,14 +505,15 @@ int park_app_exec(struct ast_channel *chan, const char *data)
 	}
 
 	ast_channel_lock(chan);
-	if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
-		blind_transfer = ast_strdupa(blind_transfer);
+	if (!(transferer = pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER"))) {
+		transferer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
 	}
+	transferer = ast_strdupa(S_OR(transferer, ""));
 	ast_channel_unlock(chan);
 
 	/* Handle the common parking setup stuff */
-	if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
-		if (!silence_announcements && !blind_transfer) {
+	if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) {
+		if (!silence_announcements && !transferer) {
 			ast_stream_and_wait(chan, "pbx-parkingfailed", "");
 		}
 		return 0;
@@ -767,7 +813,7 @@ int park_and_announce_app_exec(struct ast_channel *chan, const char *data)
 	}
 
 	/* Handle the common parking setup stuff */
-	if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
+	if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) {
 		return 0;
 	}
 
diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c
index 60d05ed59d93c8d081d89735ecbb85618edcbcb6..d0566a8984ba12d67c2f62ff579ac5ba498dc90f 100644
--- a/res/parking/parking_bridge.c
+++ b/res/parking/parking_bridge.c
@@ -66,8 +66,23 @@ static void destroy_parked_user(void *obj)
 	struct parked_user *pu = obj;
 
 	ao2_cleanup(pu->lot);
-	ao2_cleanup(pu->parker);
 	ao2_cleanup(pu->retriever);
+	ast_free(pu->parker_dial_string);
+}
+
+/* Only call this on a parked user that hasn't had its parker_dial_string set already */
+static int parked_user_set_parker_dial_string(struct parked_user *pu, struct ast_channel *parker)
+{
+	char *dial_string = ast_strdupa(ast_channel_name(parker));
+
+	ast_channel_name_to_dial_string(dial_string);
+	pu->parker_dial_string = ast_strdup(dial_string);
+
+	if (!pu->parker_dial_string) {
+		return -1;
+	}
+
+	return 0;
 }
 
 /*!
@@ -78,6 +93,7 @@ static void destroy_parked_user(void *obj)
  * \param lot The parking lot we are assigning the user to
  * \param parkee The channel being parked
  * \param parker The channel performing the park operation (may be the same channel)
+ * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
  * \param use_random_space if true, prioritize using a random parking space instead
  *        of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
  * \param time_limit If using a custom timeout, this should be supplied so that the
@@ -89,7 +105,7 @@ static void destroy_parked_user(void *obj)
  *
  * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
  */
-static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, int use_random_space, int time_limit)
+static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit)
 {
 	struct parked_user *new_parked_user;
 	int preferred_space = -1; /* Initialize to use parking lot defaults */
@@ -106,10 +122,6 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct
 		return NULL;
 	}
 
-	ast_channel_lock(chan);
-	ast_copy_string(new_parked_user->blindtransfer, S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ""), AST_CHANNEL_NAME);
-	ast_channel_unlock(chan);
-
 	if (use_random_space) {
 		preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
 		preferred_space += lot->cfg->parking_start;
@@ -150,8 +162,18 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct
 
 	new_parked_user->start = ast_tvnow();
 	new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
-	new_parked_user->parker = ast_channel_snapshot_create(parker);
-	if (!new_parked_user->parker) {
+
+	if (parker_dial_string) {
+		new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
+	} else {
+		if (parked_user_set_parker_dial_string(new_parked_user, parker)) {
+			ao2_ref(new_parked_user, -1);
+			ao2_unlock(lot);
+			return NULL;
+		}
+	}
+
+	if (!new_parked_user->parker_dial_string) {
 		ao2_ref(new_parked_user, -1);
 		ao2_unlock(lot);
 		return NULL;
@@ -183,13 +205,9 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct
 static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 {
 	struct parked_user *pu;
-	int randomize = 0;
-	int time_limit = -1;
-	int silence = 0;
 	const char *blind_transfer;
-	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
-	RAII_VAR(char *, parker_uuid, NULL, ast_free);
-	RAII_VAR(char *, comeback_override, NULL, ast_free);
+	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); /* XXX replace with ast_channel_cleanup when available */
+	RAII_VAR(struct park_common_datastore *, park_datastore, NULL, park_common_datastore_free);
 
 	ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
 
@@ -231,11 +249,14 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg
 		return 0;
 	}
 
-	get_park_common_datastore_data(bridge_channel->chan, &parker_uuid, &comeback_override, &randomize, &time_limit, &silence);
-	parker = ast_channel_get_by_name(parker_uuid);
+	if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) {
+		/* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */
+		return -1;
+	}
+	parker = ast_channel_get_by_name(park_datastore->parker_uuid);
 
 	/* If the parker and the parkee are the same channel pointer, then the channel entered using
-	 * the park application. It's possible the the blindtransfer channel is still alive (particularly
+	 * the park application. It's possible that the channel that transferred it is still alive (particularly
 	 * when a multichannel bridge is parked), so try to get the real parker if possible. */
 	ast_channel_lock(bridge_channel->chan);
 	blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
@@ -253,19 +274,17 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg
 		}
 	}
 
-	if (!parker) {
-		return -1;
-	}
+	pu = generate_parked_user(self->lot, bridge_channel->chan, parker,
+		park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit);
 
-	pu = generate_parked_user(self->lot, bridge_channel->chan, parker, randomize, time_limit);
 	if (!pu) {
 		publish_parked_call_failure(bridge_channel->chan);
 		return -1;
 	}
 
 	/* If a comeback_override was provided, set it for the parked user's comeback string. */
-	if (comeback_override) {
-		strncpy(pu->comeback, comeback_override, sizeof(pu->comeback));
+	if (park_datastore->comeback_override) {
+		strncpy(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback));
 		pu->comeback[sizeof(pu->comeback) - 1] = '\0';
 	}
 
@@ -273,7 +292,7 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg
 	publish_parked_call(pu, PARKED_CALL);
 
 	/* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
-	if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !silence) {
+	if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !park_datastore->silence_announce) {
 		char saynum_buf[16];
 		snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 0, pu->parking_space);
 		ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
index f0cf0ae448055f5cc15872cfb4b61b2280cc9ed3..aee4edbab2dce06d5f046af1a4f864ea04922b31 100644
--- a/res/parking/parking_bridge_features.c
+++ b/res/parking/parking_bridge_features.c
@@ -367,23 +367,6 @@ static void parking_duration_cb_destroyer(void *hook_pvt)
 	ao2_ref(user, -1);
 }
 
-/*!
- * \brief Removes the identification information from a channel name string
- * \since 12.0
- *
- * \param channel name string that you wish to turn into a dial string. This will be edited in place.
- */
-static void channel_name_to_dial_string(char *peername)
-{
-	char *dash;
-
-	/* Truncate after the dash */
-	dash = strrchr(peername, '-');
-	if (dash) {
-		*dash = '\0';
-	}
-}
-
 /*! \internal
  * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
  *
@@ -396,8 +379,8 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg
 	struct parked_user *user = hook_pvt;
 	struct ast_channel *chan = user->chan;
 	struct ast_context *park_dial_context;
-	char *peername;
-	char *peername_flat;
+	const char *dial_string;
+	char *dial_string_flat;
 	char parking_space[AST_MAX_EXTENSION];
 
 	char returnexten[AST_MAX_EXTENSION];
@@ -426,14 +409,12 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg
 	pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
 	pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
 
-	peername = ast_strdupa(S_OR(user->blindtransfer, user->parker->name));
-	channel_name_to_dial_string(peername);
-
-	peername_flat = ast_strdupa(user->parker->name);
-	flatten_peername(peername_flat);
+	dial_string = user->parker_dial_string;
+	dial_string_flat = ast_strdupa(dial_string);
+	flatten_dial_string(dial_string_flat);
 
-	pbx_builtin_setvar_helper(chan, "PARKER", peername);
-	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", peername_flat);
+	pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
+	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
 
 	/* Dialplan generation for park-dial extensions */
 
@@ -462,26 +443,26 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg
 		ast_assert(0);
 	}
 
-	snprintf(returnexten, sizeof(returnexten), "%s,%u", peername,
+	snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
 		user->lot->cfg->comebackdialtime);
 
 	duplicate_returnexten = ast_strdup(returnexten);
 
 	if (!duplicate_returnexten) {
 		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
-			peername_flat, PARK_DIAL_CONTEXT, returnexten);
+			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
 	}
 
 	/* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
-	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, peername_flat, 1, NULL, NULL, E_MATCH)) &&
+	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
 	    (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
 		ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
-			peername_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
-	} else if (ast_add_extension2_nolock(park_dial_context, 1, peername_flat, 1, NULL, NULL,
+			dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
+	} else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
 			"Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
 			ast_free(duplicate_returnexten);
 		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
-			peername_flat, PARK_DIAL_CONTEXT, returnexten);
+			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
 	}
 
 	if (ast_unlock_context(park_dial_context)) {
diff --git a/res/parking/parking_controller.c b/res/parking/parking_controller.c
index 2764f50d4ffa236d9ba4afc9d52a3664bb048a04..aa2baf5ccee453bf9dbc1276a2e8d0ceb2c00cd9 100644
--- a/res/parking/parking_controller.c
+++ b/res/parking/parking_controller.c
@@ -220,22 +220,14 @@ void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parki
 	return;
 }
 
-void flatten_peername(char *peername)
+void flatten_dial_string(char *dialstring)
 {
 	int i;
-	char *dash;
 
-	/* Truncate after the dash */
-	dash = strrchr(peername, '-');
-	if (dash) {
-		*dash = '\0';
-	}
-
-	/* Replace slashes with underscores since slashes are reserved characters for extension matching */
-	for (i = 0; peername[i]; i++) {
-		if (peername[i] == '/') {
+	for (i = 0; dialstring[i]; i++) {
+		if (dialstring[i] == '/') {
 			/* The underscore is the flattest character of all. */
-			peername[i] = '_';
+			dialstring[i] = '_';
 		}
 	}
 }
@@ -243,39 +235,37 @@ void flatten_peername(char *peername)
 int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
 {
 	struct ast_channel *chan = pu->chan;
-	char *peername;
-
-	peername = ast_strdupa(S_OR(pu->blindtransfer, pu->parker->name));
+	char *peername_flat = ast_strdupa(pu->parker_dial_string);
 
 	/* Flatten the peername so that it can be used for performing the timeout PBX operations */
-	flatten_peername(peername);
+	flatten_dial_string(peername_flat);
 
 	if (lot->cfg->comebacktoorigin) {
-		if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername, 1, NULL)) {
-			ast_async_goto(chan, PARK_DIAL_CONTEXT, peername, 1);
+		if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) {
+			ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1);
 			return 0;
 		} else {
 			ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
-				ast_channel_name(chan), PARK_DIAL_CONTEXT, peername);
+				ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat);
 			return -1;
 		}
 	}
 
-	if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername, 1, NULL)) {
-		ast_async_goto(chan, lot->cfg->comebackcontext, peername, 1);
+	if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) {
+		ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1);
 		return 0;
 	}
 
 	if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) {
 		ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
-			lot->cfg->comebackcontext, peername, lot->cfg->comebackcontext);
+			lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
 		ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1);
 		return 0;
 	}
 
 	ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's@default'\n",
 		ast_channel_name(chan),
-		lot->cfg->comebackcontext, peername, lot->cfg->comebackcontext);
+		lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
 	ast_async_goto(chan, "default", "s", 1);
 
 	return 0;
diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c
index 5a2b3f6fdf3930558e0209e84473bb75170d45ab..b26f90e359dfc271cecba3393780acf8f5a4b433 100644
--- a/res/parking/parking_manager.c
+++ b/res/parking/parking_manager.c
@@ -134,43 +134,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 				</parameter>
 				<parameter name="ParkeeUniqueid">
 				</parameter>
-				<parameter name="ParkerChannel">
-				</parameter>
-				<parameter name="ParkerChannelState">
-				<para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
-				</parameter>
-				<parameter name="ParkerChannelStateDesc">
-					<enumlist>
-						<enum name="Down"/>
-						<enum name="Rsrvd"/>
-						<enum name="OffHook"/>
-						<enum name="Dialing"/>
-						<enum name="Ring"/>
-						<enum name="Ringing"/>
-						<enum name="Up"/>
-						<enum name="Busy"/>
-						<enum name="Dialing Offhook"/>
-						<enum name="Pre-ring"/>
-						<enum name="Unknown"/>
-					</enumlist>
-				</parameter>
-				<parameter name="ParkerCallerIDNum">
-				</parameter>
-				<parameter name="ParkerCallerIDName">
-				</parameter>
-				<parameter name="ParkerConnectedLineNum">
-				</parameter>
-				<parameter name="ParkerConnectedLineName">
-				</parameter>
-				<parameter name="ParkerAccountCode">
-				</parameter>
-				<parameter name="ParkerContext">
-				</parameter>
-				<parameter name="ParkerExten">
-				</parameter>
-				<parameter name="ParkerPriority">
-				</parameter>
-				<parameter name="ParkerUniqueid">
+				<parameter name="ParkerDialString">
+					<para>Dial String that can be used to call back the parker on ParkingTimeout.</para>
 				</parameter>
 				<parameter name="Parkinglot">
 					<para>Name of the parking lot that the parkee is parked in</para>
@@ -276,10 +241,6 @@ static struct ast_parked_call_payload *parked_call_payload_from_parked_user(stru
 	struct timeval now = ast_tvnow();
 	const char *lot_name = pu->lot->name;
 
-	if (!pu->parker) {
-		return NULL;
-	}
-
 	parkee_snapshot = ast_channel_snapshot_create(pu->chan);
 
 	if (!parkee_snapshot) {
@@ -289,7 +250,7 @@ static struct ast_parked_call_payload *parked_call_payload_from_parked_user(stru
 	timeout = pu->start.tv_sec + (long) pu->time_limit - now.tv_sec;
 	duration = now.tv_sec - pu->start.tv_sec;
 
-	return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker, pu->retriever, lot_name, pu->parking_space, timeout, duration);
+	return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker_dial_string, pu->retriever, lot_name, pu->parking_space, timeout, duration);
 
 }
 
@@ -298,7 +259,6 @@ static struct ast_str *manager_build_parked_call_string(const struct ast_parked_
 {
 	struct ast_str *out = ast_str_create(1024);
 	RAII_VAR(struct ast_str *, parkee_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, parker_string, NULL, ast_free);
 	RAII_VAR(struct ast_str *, retriever_string, NULL, ast_free);
 
 	if (!out) {
@@ -307,26 +267,22 @@ static struct ast_str *manager_build_parked_call_string(const struct ast_parked_
 
 	parkee_string = ast_manager_build_channel_state_string_prefix(payload->parkee, "Parkee");
 
-	if (payload->parker) {
-		parker_string = ast_manager_build_channel_state_string_prefix(payload->parker, "Parker");
-	}
-
 	if (payload->retriever) {
 		retriever_string = ast_manager_build_channel_state_string_prefix(payload->retriever, "Retriever");
 	}
 
 	ast_str_set(&out, 0,
 		"%s" /* parkee channel state */
-		"%s" /* parker channel state */
 		"%s" /* retriever channel state (when available) */
+		"ParkerDialString: %s\r\n"
 		"Parkinglot: %s\r\n"
 		"ParkingSpace: %u\r\n"
 		"ParkingTimeout: %lu\r\n"
 		"ParkingDuration: %lu\r\n",
 
 		ast_str_buffer(parkee_string),
-		parker_string ? ast_str_buffer(parker_string) : "",
 		retriever_string ? ast_str_buffer(retriever_string) : "",
+		payload->parker_dial_string,
 		payload->parkinglot,
 		payload->parkingspace,
 		payload->timeout,
diff --git a/res/parking/parking_ui.c b/res/parking/parking_ui.c
index f3eeafa4c6cfcb3770f25bdb895ea5b6854dd5c1..2f54e8637e0fff6423587882b47012918de34a7b 100644
--- a/res/parking/parking_ui.c
+++ b/res/parking/parking_ui.c
@@ -40,9 +40,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 static void display_parked_call(struct parked_user *user, int fd)
 {
-	ast_cli(fd, "  Space: %d\n", user->parking_space);
-	ast_cli(fd, "  Channel: %s\n", ast_channel_name(user->chan));
-	ast_cli(fd, "  Parker: %s\n", user->parker ? user->parker->name : "<unknown>");
+	ast_cli(fd, "  Space               :  %d\n", user->parking_space);
+	ast_cli(fd, "  Channel             :  %s\n", ast_channel_name(user->chan));
+	ast_cli(fd, "  Parker Dial String  :  %s\n", user->parker_dial_string);
 	ast_cli(fd, "\n");
 }
 
diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h
index 2955f87e1d88deafcdc67675f823ae6ae8f43167..b128ee3358cd4184dfef15d276e2f160d855a8b0 100644
--- a/res/parking/res_parking.h
+++ b/res/parking/res_parking.h
@@ -100,12 +100,11 @@ struct parking_lot {
 
 struct parked_user {
 	struct ast_channel *chan;                 /*!< Parked channel */
-	struct ast_channel_snapshot *parker;      /*!< Snapshot of the channel that parked the call at the time of parking */
 	struct ast_channel_snapshot *retriever;   /*!< Snapshot of the channel that retrieves a parked call */
 	struct timeval start;                     /*!< When the call was parked */
 	int parking_space;                        /*!< Which parking space is used */
 	char comeback[AST_MAX_CONTEXT];           /*!< Where to go on parking timeout */
-	char blindtransfer[AST_CHANNEL_NAME];     /*!< What the BLINDTRANSFER variable was at the time of entry */
+	char *parker_dial_string;                 /*!< dialstring to call back with comebacktoorigin. Used timeout extension generation and call control */
 	unsigned int time_limit;                  /*!< How long this specific channel may remain in the parking lot before timing out */
 	struct parking_lot *lot;                  /*!< Which parking lot the user is parked to */
 	enum park_call_resolution resolution;     /*!< How did the parking session end? If the call is in a bridge, lock parked_user before checking/setting */
@@ -285,11 +284,11 @@ const char *find_channel_parking_lot_name(struct ast_channel *chan);
 
 /*!
  * \since 12.0.0
- * \brief Flattens a peer name so that it can be written to/found from PBX extensions
+ * \brief Flattens a dial string so that it can be written to/found from PBX extensions
  *
- * \param peername unflattened peer name. This will be flattened in place, so expect it to change.
+ * \param peername unflattened dial string. This will be flattened in place.
  */
-void flatten_peername(char *peername);
+void flatten_dial_string(char *dialstring);
 
 /*!
  * \since 12.0.0
@@ -370,7 +369,7 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan
  *        channel.
  *
  * \param parkee The channel being preparred for parking
- * \param parker The channel initiating the park; may be the parkee as well
+ * \param parker The channel initiating the park; may be the parkee as well. May be NULL.
  * \param app_data arguments supplied to the Park application. May be NULL.
  * \param silence_announcements optional pointer to an integer where we want to store the silence option flag
  *        this value should be initialized to 0 prior to calling park_common_setup.
@@ -385,6 +384,7 @@ struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast
 
 struct park_common_datastore {
 	char *parker_uuid;           /*!< Unique ID of the channel parking the call. */
+	char *parker_dial_string;    /*!< Dial string that we would attempt to call when timing out when comebacktoorigin=yes */
 	char *comeback_override;     /*!< Optional goto string for where to send the call after we are done */
 	int randomize;               /*!< Pick a parking space to enter on at random */
 	int time_limit;              /*!< time limit override. -1 values don't override, 0 for unlimited time, >0 for custom time limit in seconds */
@@ -393,19 +393,22 @@ struct park_common_datastore {
 
 /*!
  * \since 12.0.0
- * \brief Function that pulls data from the park common datastore on a channel in order to apply it to
- *        the parked user struct upon bridging.
+ * \brief Get a copy of the park_common_datastore from a channel that is being parked
  *
  * \param parkee The channel entering parking with the datastore we are checking
- * \param parker_uuid pointer to a string pointer for placing the name of the channel that parked parkee
- * \param comeback_override pointer to a string pointer for placing the comeback_override option
- * \param randomize integer pointer to an integer for placing the randomize option
- * \param time_limit integer pointer to an integer for placing the time limit option
- * \param silence_announce pointer to an integer for placing the silence_announcements option
- */
-void get_park_common_datastore_data(struct ast_channel *parkee,
-		char **parker_uuid, char **comeback_override,
-		int *randomize, int *time_limit, int *silence_announce);
+ *
+ * \retval Pointer to a copy of the park common datastore for parkee if it could be cloned. This needs to be free'd with park_common_datastore free.
+ * \retval NULL if the park_common_datastore could not be copied off of the channel.
+ */
+struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee);
+
+/*!
+ * \since 12.0.0
+ * \brief Free a park common datastore struct
+ *
+ * \param datastore The park_common_datastore being free'd. (NULL tolerant)
+ */
+void park_common_datastore_free(struct park_common_datastore *datastore);
 
 /*!
  * \since 12.0.0