--- linux/include/linux/kerneld.h.org	Wed Mar 20 10:34:01 1996
+++ linux/include/linux/kerneld.h	Wed Mar 20 10:39:35 1996
@@ -9,7 +9,8 @@
 #define KERNELD_REQUEST_ROUTE 6 /* from net/ipv4/route.c */
 #define KERNELD_BLANKER 7 /* from drivers/char/console.c */
 
-#define IPC_KERNELD 00040000   /* use the kerneld message channel */
+#define OLDIPC_KERNELD 00040000   /* use the kerneld message channel */
+#define IPC_KERNELD 00140000   /* use the kerneld message channel */
 #define KERNELD_MAXCMD 0x7ffeffff
 #define KERNELD_MINSEQ 0x7fff0000 /* "commands" legal up to 0x7ffeffff */
 #define KERNELD_WAIT 0x80000000
@@ -18,6 +19,8 @@
 struct kerneld_msg {
 	long mtype;
 	long id;
+	short int version;
+	short int pid;
 #ifdef __KERNEL__
 	char *text;
 #else
--- linux/ipc/msg.c.org	Wed Mar 20 10:36:13 1996
+++ linux/ipc/msg.c	Wed Mar 20 11:13:13 1996
@@ -35,6 +35,8 @@
 static int kerneld_arr[MAX_KERNELDS];
 static int n_kernelds = 0;
 
+#define KDHDR (sizeof(long) + sizeof(short int) + sizeof(short int))
+
 void msg_init (void)
 {
 	int id;
@@ -122,9 +124,8 @@
 		 * Note that the kernel supplies a pointer
 		 * but the user-level kerneld uses a char array...
 		 */
-		memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long)); 
-		memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
-			msgsz - sizeof(long)); 
+		memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), KDHDR); 
+		memcpy(msgh->msg_spot + KDHDR, kdmp->text, msgsz - KDHDR); 
 	}
 	else
 		memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
@@ -174,7 +175,7 @@
 		if (*(long *)(tmsg->msg_spot) == msgid)
 			break;
 	if (tmsg) { /* still there! */
-		struct kerneld_msg kmsp = { msgid, -ENODEV, "" };
+		struct kerneld_msg kmsp = { msgid, 2, 0, -ENODEV, "" };
 
 		printk(KERN_ALERT "Ouch, kerneld timed out, message failed\n");
 		real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp,
@@ -299,16 +300,15 @@
 				struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
 
 				memcpy((char *)(&(kdmp->id)),
-					nmsg->msg_spot,
-					sizeof(long)); 
+					nmsg->msg_spot, KDHDR);
 				/*
 				 * Note that kdmp->text is a pointer
 				 * when called from kernel space!
 				 */
-				if ((msgsz > sizeof(long)) && kdmp->text)
+				if ((msgsz > KDHDR) && kdmp->text)
 					memcpy(kdmp->text,
-						nmsg->msg_spot + sizeof(long),
-						msgsz - sizeof(long)); 
+						nmsg->msg_spot + KDHDR,
+						msgsz - KDHDR);
 			}
 			else {
 				put_user (nmsg->msg_type, &msgp->mtype);
@@ -423,6 +423,10 @@
 		int i;
 		if (!suser())
 			return -EPERM;
+		if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
+			printk("Please recompile your kerneld-type daemon (header changed)\n");
+			return -EINVAL;
+		}
 		if ((kerneld_msqid == -1) && (kerneld_msqid =
 				newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
 			return -ENOSPC;
@@ -640,11 +644,14 @@
  * The message type from the kernel to kerneld is used to specify _what_
  * function we want kerneld to perform. 
  *
- * The "normal" message area is divided into a long, followed by a char array.
+ * The "normal" message area is divided into a long, followed by
+ * two short ints and a char array. (The short ints are NEW to the protocol!)
  * The long is used to hold the sequence number of the request, which will
  * be used as the return message type from kerneld back to the kernel.
  * In the return message, the long will be used to store the exit status
  * of the kerneld "job", or task.
+ * The first short int is the kerneld protocol version, and the second
+ * short int is the pid of the process that triggered the call to kerneld.
  * The character array is used to pass parameters to kerneld and (optional)
  * return information from kerneld back to the kernel.
  * It is the responsibility of kerneld and the kernel level caller
@@ -672,7 +679,7 @@
 	int status = -ENOSYS;
 #ifdef CONFIG_KERNELD
 	static int id = KERNELD_MINSEQ;
-	struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
+	struct kerneld_msg kmsp = { msgtype, 0, 2, 0, (char *)text };
 	int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
 
 	if (kerneld_msqid == -1)
@@ -681,8 +688,10 @@
 	/* Do not wait for an answer at interrupt-time! */
 	if (intr_count)
 		ret_size &= ~KERNELD_WAIT;
+	else
+		kmsp.pid = current->pid; /* The pid of the "trigger" */
 
-	msgsz += sizeof(long);
+	msgsz += KDHDR;
 	if (ret_size & KERNELD_WAIT) {
 		if (++id <= 0)
 			id = KERNELD_MINSEQ;
@@ -694,7 +703,7 @@
 		ret_size &= ~KERNELD_WAIT;
 		kmsp.text = (char *)ret_val;
 		status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
-				sizeof(long) + ((ret_val)?ret_size:0),
+				KDHDR + ((ret_val)?ret_size:0),
 				kmsp.id, msgflg);
 		if (status > 0) /* a valid answer contains at least a long */
 			status = kmsp.id;
