[interface] Fix debug message values for temporary interfaces

The interface debug message values constructed by INTF_DBG() et al
rely on the interface being embedded within a containing object.  This
assumption is not valid for the temporary outbound-only interfaces
constructed on the stack by intf_shutdown() and xfer_vredirect().

Formalise the notion of a temporary outbound-only interface as having
a NULL interface descriptor, and overload the "original interface
descriptor" field to contain a pointer to the original interface that
the temporary interface is shadowing.

Originally-fixed-by: Vincent Fazio <vfazio@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/core/interface.c b/src/core/interface.c
index 34a4180..ea06068 100644
--- a/src/core/interface.c
+++ b/src/core/interface.c
@@ -285,6 +285,7 @@
 	intf_nullify ( intf );
 
 	/* Transfer destination to temporary interface */
+	intf_temp_init ( &tmp, intf );
 	tmp.dest = intf->dest;
 	intf->dest = &null_intf;
 
diff --git a/src/core/xfer.c b/src/core/xfer.c
index 0faf329..269359e 100644
--- a/src/core/xfer.c
+++ b/src/core/xfer.c
@@ -60,7 +60,7 @@
  * @ret rc		Return status code
  */
 int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
-	struct interface tmp = INTF_INIT ( null_intf_desc );
+	struct interface tmp;
 	struct interface *dest;
 	xfer_vredirect_TYPE ( void * ) *op =
 		intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
@@ -85,6 +85,7 @@
 		 * If redirection fails, then send intf_close() to the
 		 * parent interface.
 		 */
+		intf_temp_init ( &tmp, intf );
 		intf_plug ( &tmp, dest );
 		rc = xfer_vreopen ( dest, type, args );
 		if ( rc == 0 ) {
diff --git a/src/include/ipxe/interface.h b/src/include/ipxe/interface.h
index 19f58a4..d2fa819 100644
--- a/src/include/ipxe/interface.h
+++ b/src/include/ipxe/interface.h
@@ -133,17 +133,30 @@
 	struct interface *dest;
 	/** Reference counter
 	 *
-	 * If this interface is not part of a reference-counted
-	 * object, this field may be NULL.
+	 * If this interface is not part of a reference-counted object
+	 * then this field is NULL.
 	 */
 	struct refcnt *refcnt;
-	/** Interface descriptor */
-	struct interface_descriptor *desc;
-	/** Original interface descriptor
+	/** Interface descriptor
 	 *
-	 * Used by intf_reinit().
+	 * If this is a temporary outbound-only interface created by
+	 * intf_temp_init() then this field is NULL.
 	 */
-	struct interface_descriptor *original;
+	struct interface_descriptor *desc;
+	/** Original interface properties */
+	union {
+		/** Original interface descriptor
+		 *
+		 * Used by intf_reinit().
+		 */
+		struct interface_descriptor *desc;
+		/** Original interface
+		 *
+		 * Used for temporary outbound-only interfaces created
+		 * by intf_temp_init().
+		 */
+		struct interface *intf;
+	} original;
 };
 
 extern void intf_plug ( struct interface *intf, struct interface *dest );
@@ -193,7 +206,7 @@
 	intf->dest = &null_intf;
 	intf->refcnt = refcnt;
 	intf->desc = desc;
-	intf->original = desc;
+	intf->original.desc = desc;
 }
 
 /**
@@ -201,14 +214,39 @@
  *
  * @v descriptor	Object interface descriptor
  */
-#define INTF_INIT( descriptor ) {		\
-		.dest = &null_intf,		\
-		.refcnt = NULL,			\
-		.desc = &(descriptor),		\
-		.original = &(descriptor),	\
+#define INTF_INIT( descriptor ) {					\
+		.dest = &null_intf,					\
+		.refcnt = NULL,						\
+		.desc = &(descriptor),					\
+		.original = {						\
+			.desc = &(descriptor),				\
+		},							\
 	}
 
 /**
+ * Initialise a temporary outbound-only object interface
+ *
+ * @v intf		Temporary outbound-only object interface
+ * @v original		Original object interface
+ */
+static inline void intf_temp_init ( struct interface *intf,
+				    struct interface *original ) {
+	intf->dest = &null_intf;
+	intf->desc = NULL;
+	intf->original.intf = original;
+}
+
+/**
+ * Get original interface
+ *
+ * @v intf		Object interface (possibly a temporary interface)
+ * @ret intf		Original object interface
+ */
+static inline struct interface * intf_origin ( struct interface *intf ) {
+	return ( intf->desc ? intf : intf->original.intf );
+}
+
+/**
  * Get object interface destination and operation method (without pass-through)
  *
  * @v intf		Object interface
@@ -240,7 +278,7 @@
  *
  * Use as the first argument to DBGC() or equivalent macro.
  */
-#define INTF_COL( intf ) intf_object ( intf )
+#define INTF_COL( intf ) intf_object ( intf_origin ( intf ) )
 
 /** printf() format string for INTF_DBG() */
 #define INTF_FMT "%p+%zx"
@@ -251,7 +289,9 @@
  * @v intf		Object interface
  * @ret args		printf() argument list corresponding to INTF_FMT
  */
-#define INTF_DBG( intf ) intf_object ( intf ), (intf)->desc->offset
+#define INTF_DBG( intf )						\
+	intf_object ( intf_origin ( intf ) ),				\
+	intf_origin ( intf )->desc->offset
 
 /** printf() format string for INTF_INTF_DBG() */
 #define INTF_INTF_FMT INTF_FMT "->" INTF_FMT
@@ -273,7 +313,7 @@
 static inline void intf_reinit ( struct interface *intf ) {
 
 	/* Restore original interface descriptor */
-	intf->desc = intf->original;
+	intf->desc = intf->original.desc;
 }
 
 #endif /* _IPXE_INTERFACE_H */