diff -rubBN linux-2.6.15.1/arch/alpha/kernel/systbls.S linux-2.6.15.1-dipc/arch/alpha/kernel/systbls.S
--- linux-2.6.15.1/arch/alpha/kernel/systbls.S	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/alpha/kernel/systbls.S	2007-02-23 08:37:38.000000000 -0500
@@ -466,7 +466,9 @@
 	.quad sys_inotify_init
 	.quad sys_inotify_add_watch		/* 445 */
 	.quad sys_inotify_rm_watch
-
+#ifdef CONFIG_SYSVIPC_DIPC
+	.quad sys_dipc
+#endif
 	.size sys_call_table, . - sys_call_table
 	.type sys_call_table, @object
 
diff -rubBN linux-2.6.15.1/arch/alpha/mm/fault.c linux-2.6.15.1-dipc/arch/alpha/mm/fault.c
--- linux-2.6.15.1/arch/alpha/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/alpha/mm/fault.c	2007-02-23 08:37:38.000000000 -0500
@@ -2,6 +2,8 @@
  *  linux/arch/alpha/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -31,6 +33,10 @@
 
 extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address,
+                          unsigned long error_code);
+#endif
 
 /*
  * Force a new ASN for a task.
@@ -121,6 +127,14 @@
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
+#ifdef CONFIG_SYSVIPC_DIPC             
+	if(vma->vm_flags & VM_SYSVSHM) {
+		if(dipc_shm_fault(vma, address, cause > 0)) {
+			up(&mm->mmap_sem);
+			goto out;
+		}
+	}
+#endif
 	if (vma->vm_start <= address)
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
diff -rubBN linux-2.6.15.1/arch/arm/kernel/calls.S linux-2.6.15.1-dipc/arch/arm/kernel/calls.S
--- linux-2.6.15.1/arch/arm/kernel/calls.S	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/arm/kernel/calls.S	2007-02-23 08:37:38.000000000 -0500
@@ -336,6 +336,9 @@
 		.long	sys_mbind
 /* 320 */	.long	sys_get_mempolicy
 		.long	sys_set_mempolicy
+#ifdef CONFIG_SYSVIPC_DIPC
+		.long 	sys_dipc
+#endif
 __syscall_end:
 
 		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
diff -rubBN linux-2.6.15.1/arch/arm/kernel/sys_arm.c linux-2.6.15.1-dipc/arch/arm/kernel/sys_arm.c
--- linux-2.6.15.1/arch/arm/kernel/sys_arm.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/arm/kernel/sys_arm.c	2007-02-23 08:37:38.000000000 -0500
@@ -11,7 +11,10 @@
  *  This file contains various random system calls that
  *  have a non-standard calling sequence on the Linux/arm
  *  platform.
+ *
+ *  DIPC (C) Kamran Karimi
  */
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -20,6 +23,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/stat.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
@@ -203,6 +209,11 @@
 	case MSGCTL:
 		return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
 
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	case DIPC:
+		return sys_dipc (first, second, (int *)third);
+#endif		        
+
 	case SHMAT:
 		switch (version) {
 		default: {
diff -rubBN linux-2.6.15.1/arch/arm/mm/fault.c linux-2.6.15.1-dipc/arch/arm/mm/fault.c
--- linux-2.6.15.1/arch/arm/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/arm/mm/fault.c	2007-02-23 08:37:38.000000000 -0500
@@ -7,6 +7,8 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * DIPC (C) Kamran Karimi
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -22,6 +24,11 @@
 
 #include "fault.h"
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 /*
  * This is useful to dump out the page tables associated with
  * 'addr' in mm 'mm'.
@@ -163,6 +170,15 @@
 	if (vma->vm_start > addr)
 		goto check_stack;
 
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
 	/*
 	 * Ok, we have a good vm_area for this
 	 * memory access, so we can handle it.
diff -rubBN linux-2.6.15.1/arch/i386/kernel/sys_i386.c linux-2.6.15.1-dipc/arch/i386/kernel/sys_i386.c
--- linux-2.6.15.1/arch/i386/kernel/sys_i386.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/i386/kernel/sys_i386.c	2007-02-23 08:37:38.000000000 -0500
@@ -4,6 +4,8 @@
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/i386
  * platform.
+ *
+ * DIPC parts (C) Kamran Karimi
  */
 
 #include <linux/errno.h>
@@ -14,6 +16,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/stat.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
@@ -153,6 +158,10 @@
 			return -EFAULT;
 		return sys_semctl (first, second, third, fourth);
 	}
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	case DIPC:
+		return sys_dipc (first, second, (int *)third);
+#endif		        
 
 	case MSGSND:
 		return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
diff -rubBN linux-2.6.15.1/arch/i386/mm/fault.c linux-2.6.15.1-dipc/arch/i386/mm/fault.c
--- linux-2.6.15.1/arch/i386/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/i386/mm/fault.c	2007-02-23 08:37:38.000000000 -0500
@@ -2,6 +2,9 @@
  *  linux/arch/i386/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ * 
+ *  DIPC parts Copyright (C) Kamran Karimi
+ *  port to kernel version 2.1.24 by Michael Schmitz
  */
 
 #include <linux/signal.h>
@@ -30,6 +33,11 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 /*
  * Unlock any spinlocks which will prevent us from getting the
  * message out 
@@ -305,6 +313,14 @@
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
 	if (vma->vm_start <= address)
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
diff -rubBN linux-2.6.15.1/arch/ia64/mm/fault.c linux-2.6.15.1-dipc/arch/ia64/mm/fault.c
--- linux-2.6.15.1/arch/ia64/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/ia64/mm/fault.c	2007-03-23 05:39:33.000000000 -0400
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * DIPC (C) Kamran Karimi
  */
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -17,6 +19,10 @@
 #include <asm/uaccess.h>
 #include <asm/kdebug.h>
 
+#ifdef CONFIG_SYSVIPC_DIPC 
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address,                                                      unsigned long error_code);
+#endif                                                                        
+
 extern void die (char *, struct pt_regs *, long);
 
 /*
@@ -98,7 +104,16 @@
   good_area:
 	code = SEGV_ACCERR;
 
-	/* OK, we've got a good vm_area for this memory area.  Check the access permissions: */
+#ifdef CONFIG_SYSVIPC_DIPC
+  if(vma->vm_flags & VM_SYSVSHM) {
+        if(dipc_shm_fault(vma, address, error_code & 2)) {
+             up_read(&mm->mmap_sem);                                           
+             return;                                                   
+        }                                                         
+  }                                                         
+#endif                                                            
+
+/* OK, we've got a good vm_area for this memory area.  Check the access permissions: */
 
 #	define VM_READ_BIT	0
 #	define VM_WRITE_BIT	1
diff -rubBN linux-2.6.15.1/arch/m68k/kernel/sys_m68k.c linux-2.6.15.1-dipc/arch/m68k/kernel/sys_m68k.c
--- linux-2.6.15.1/arch/m68k/kernel/sys_m68k.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/m68k/kernel/sys_m68k.c	2007-02-23 08:37:38.000000000 -0500
@@ -4,6 +4,8 @@
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/m68k
  * platform.
+ *
+ * DIPC parts (C) Kamran Karimi
  */
 
 #include <linux/errno.h>
@@ -14,6 +16,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/stat.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
@@ -257,6 +262,15 @@
 		default:
 			return -ENOSYS;
 		}
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	if (call <= DIPC)
+		switch (call) {
+		case DIPC:
+		        return sys_dipc (first, second, (int *)third);
+		default:
+			return -EINVAL;
+		}
+#endif
 
 	return -EINVAL;
 }
diff -rubBN linux-2.6.15.1/arch/m68k/mm/fault.c linux-2.6.15.1-dipc/arch/m68k/mm/fault.c
--- linux-2.6.15.1/arch/m68k/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/m68k/mm/fault.c	2007-02-23 08:37:38.000000000 -0500
@@ -2,6 +2,8 @@
  *  linux/arch/m68k/mm/fault.c
  *
  *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  DIPC (C) Kamran Karimi
  */
 
 #include <linux/mman.h>
@@ -17,6 +19,11 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 extern void die_if_kernel(char *, struct pt_regs *, long);
 extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
 
@@ -124,6 +131,15 @@
 	if (expand_stack(vma, address))
 		goto map_err;
 
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
diff -rubBN linux-2.6.15.1/arch/mips/kernel/syscall.c linux-2.6.15.1-dipc/arch/mips/kernel/syscall.c
--- linux-2.6.15.1/arch/mips/kernel/syscall.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/mips/kernel/syscall.c	2007-02-23 08:37:39.000000000 -0500
@@ -6,6 +6,8 @@
  * Copyright (C) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 MIPS Technologies, Inc.
+ *
+ * DIPC (C) Kamran Karimi
  */
 #include <linux/config.h>
 #include <linux/a.out.h>
@@ -26,6 +28,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/compiler.h>
 #include <linux/module.h>
 
@@ -375,6 +380,11 @@
 	case MSGCTL:
 		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
 
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	case DIPC:
+		return sys_dipc (first, second, (int *)third);
+#endif		        
+
 	case SHMAT:
 		switch (version) {
 		default: {
diff -rubBN linux-2.6.15.1/arch/mips/mm/fault.c linux-2.6.15.1-dipc/arch/mips/mm/fault.c
--- linux-2.6.15.1/arch/mips/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/mips/mm/fault.c	2007-02-23 08:37:39.000000000 -0500
@@ -4,6 +4,8 @@
  * for more details.
  *
  * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * DIPC (C) Kamran Karimi
  */
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -27,6 +29,11 @@
 #include <asm/ptrace.h>
 #include <asm/highmem.h>		/* For VMALLOC_END */
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -78,6 +85,16 @@
 		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
+
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
diff -rubBN linux-2.6.15.1/arch/powerpc/kernel/syscalls.c linux-2.6.15.1-dipc/arch/powerpc/kernel/syscalls.c
--- linux-2.6.15.1/arch/powerpc/kernel/syscalls.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/powerpc/kernel/syscalls.c	2007-02-23 08:37:39.000000000 -0500
@@ -17,6 +17,7 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  *
+ * DIPC (C) Kamran Karimi 
  */
 
 #include <linux/errno.h>
@@ -28,6 +29,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/stat.h>
 #include <linux/mman.h>
 #include <linux/sys.h>
@@ -117,6 +121,10 @@
 		ret = sys_msgctl(first, (int)second,
 				  (struct msqid_ds __user *)ptr);
 		break;
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	case DIPC:
+		return sys_dipc (first, second, (int *)third);
+#endif		        
 	case SHMAT: {
 		ulong raddr;
 		ret = do_shmat(first, (char __user *)ptr, (int)second, &raddr);
diff -rubBN linux-2.6.15.1/arch/powerpc/mm/fault.c linux-2.6.15.1-dipc/arch/powerpc/mm/fault.c
--- linux-2.6.15.1/arch/powerpc/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/powerpc/mm/fault.c	2007-02-23 08:37:39.000000000 -0500
@@ -15,6 +15,8 @@
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
+ *
+ *  DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -42,6 +44,11 @@
 #include <asm/kdebug.h>
 #include <asm/siginfo.h>
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 /*
  * Check whether the instruction at regs->nip is a store using
  * an update addressing form which will update r1.
@@ -206,6 +213,16 @@
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
 
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
+
 	/*
 	 * N.B. The POWER/Open ABI allows programs to access up to
 	 * 288 bytes below the stack pointer.
diff -rubBN linux-2.6.15.1/arch/ppc/mm/fault.c linux-2.6.15.1-dipc/arch/ppc/mm/fault.c
--- linux-2.6.15.1/arch/ppc/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/ppc/mm/fault.c	2007-02-23 08:37:39.000000000 -0500
@@ -13,6 +13,8 @@
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
+ *
+ *  DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -44,6 +46,11 @@
 int debugger_kernel_faults = 1;
 #endif
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 unsigned long htab_reloads;	/* updated by hashtable.S:hash_page() */
 unsigned long htab_evicts; 	/* updated by hashtable.S:hash_page() */
 unsigned long htab_preloads;	/* updated by hashtable.S:add_hash_page() */
@@ -144,6 +151,15 @@
 	if (!is_write)
                 goto bad_area;
 
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
 	/*
 	 * N.B. The rs6000/xcoff ABI allows programs to access up to
 	 * a few hundred bytes below the stack pointer.
diff -rubBN linux-2.6.15.1/arch/sparc/kernel/sys_sparc.c linux-2.6.15.1-dipc/arch/sparc/kernel/sys_sparc.c
--- linux-2.6.15.1/arch/sparc/kernel/sys_sparc.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/sparc/kernel/sys_sparc.c	2007-02-23 08:37:39.000000000 -0500
@@ -4,6 +4,8 @@
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/sparc
  * platform.
+ *
+ * DIPC parts (C) Kamran Karimi
  */
 
 #include <linux/errno.h>
@@ -15,6 +17,9 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <linux/stat.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
@@ -213,6 +218,17 @@
 			err = -ENOSYS;
 			goto out;
 		}
+#ifdef CONFIG_SYSVIPC_DIPC
+ 	if (call <= DIPC)
+ 		switch (call) {
+ 		case DIPC:
+		        err = sys_dipc (first, second, (int *)third);
+		        goto out;
+ 		default:
+			err = -EINVAL;
+			goto out;
+ 		}
+#endif
 	else
 		err = -ENOSYS;
 out:
diff -rubBN linux-2.6.15.1/arch/sparc/mm/fault.c linux-2.6.15.1-dipc/arch/sparc/mm/fault.c
--- linux-2.6.15.1/arch/sparc/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/sparc/mm/fault.c	2007-02-23 08:37:39.000000000 -0500
@@ -4,6 +4,8 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * DIPC parts (C) Kamran Karimi
  */
 
 #include <asm/head.h>
@@ -42,6 +44,11 @@
 int num_segmaps, num_contexts;
 int invalid_segment;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address,
+                          unsigned long error_code);
+#endif
+
 /* various Virtual Address Cache parameters we find at boot time... */
 
 int vac_size, vac_linesize, vac_do_hw_vac_flushes;
@@ -264,6 +271,14 @@
 	vma = find_vma(mm, address);
 	if(!vma)
 		goto bad_area;
+#ifdef CONFIG_SYSVIPC_DIPC             
+	if(vma->vm_flags & VM_SHM) {
+		if(dipc_shm_fault(vma, address, write)) {
+			up(&mm->mmap_sem);
+			return;
+		}
+	}
+#endif
 	if(vma->vm_start <= address)
 		goto good_area;
 	if(!(vma->vm_flags & VM_GROWSDOWN))
diff -rubBN linux-2.6.15.1/arch/x86_64/mm/fault.c linux-2.6.15.1-dipc/arch/x86_64/mm/fault.c
--- linux-2.6.15.1/arch/x86_64/mm/fault.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/arch/x86_64/mm/fault.c	2007-03-23 05:39:06.000000000 -0400
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Copyright (C) 2001,2002 Andi Kleen, SuSE Labs.
+ * 
+ *  DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -35,6 +37,11 @@
 #include <asm-generic/sections.h>
 #include <asm/kdebug.h>
 
+#ifdef CONFIG_SYSVIPC_DIPC
+extern int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                    unsigned long error_code);
+#endif
+
 void bust_spinlocks(int yes)
 {
 	int loglevel_save = console_loglevel;
@@ -404,8 +413,18 @@
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
- */
+*/                                                     
 good_area:
+
+#ifdef CONFIG_SYSVIPC_DIPC		
+	if(vma->vm_flags & VM_SYSVSHM) {
+	 	if(dipc_shm_fault(vma, address, error_code & 2)) {
+			up_read(&mm->mmap_sem);
+	 		return;
+	 	}
+	}
+#endif
+
 	info.si_code = SEGV_ACCERR;
 	write = 0;
 	switch (error_code & 3) {
diff -rubBN linux-2.6.15.1/include/linux/dipc.h linux-2.6.15.1-dipc/include/linux/dipc.h
--- linux-2.6.15.1/include/linux/dipc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.15.1-dipc/include/linux/dipc.h	2007-06-19 06:33:09.000000000 -0400
@@ -0,0 +1,208 @@
+/*
+ * include/linux/dipc.h
+ *
+ * Copyright (C) Kamran Karimi
+ */
+#ifndef _LINUX_DIPC_H
+#define _LINUX_DIPC_H 
+
+#ifdef __KERNEL__
+#include <linux/sched.h>
+#include <linux/wait.h>
+#endif
+
+extern int dipc(int first, int cmd, void *ptr);
+
+#define DIPC_VERSION "2.1 Beta-2"
+
+#define SHM 0
+#define MSG 1
+#define SEM 2
+
+#define NO  0
+#define YES 1
+
+#define DIPC_SUCCESS 0
+#define DIPC_FAIL -1
+
+#define DIPC_REMPROT  2 /* remove protection bits */
+#define DIPC_DEFPROT  3 /* set protection to default */
+
+#define DIPC_SLEEP    6 /* sleep till there is work */
+
+#define DIPC_SETMNG  10 /* set the dsm manager task */
+#define DIPC_REMMNG  11 /* remove the dsm manager */
+#define DIPC_GETWORK 13 /* get a work */
+#define DIPC_RETWORK 14 /* return the result of the work done */
+
+#define DISABLE_RD 50
+#define DISABLE_WR 51
+
+#define WANTRD     61
+#define WANTWR     62
+#define DETACH     63
+#define AK         64
+
+#define WRPROT_SND 72
+#define RDPROT     73
+#define RDPROT_SND 74 /* first read-protect, then send the contents */
+#define NOP_SND    75 /* nop, just send the contents to third party */
+#define RCV        76
+#define TSTGET     77
+
+#define RMID       81
+#define DELKEY     82
+#define SEARCH     83
+#define COMMIT     84
+
+#define SEM_EXIT   90
+
+#define NOT_FOUND   0
+#define FOUND_IPC   1
+#define FOUND_DIPC  2
+#define IS_SEGMENT  4
+
+#define SEGMENT 0
+#define PAGE    1
+
+struct dipc_info {
+	int key;
+	int type; /* SHM, SEM or MSG */
+	int pid; /* pid of the requesting task */
+	int uid; /* uid of the requesting task */
+	int func; /* what to do? (MSGCTL, SEMOP,...) */
+	int arg1; /* arg1 to arg4 are the original arguments */
+	int arg2; /* some of them may not be used */
+	int arg3;
+	int arg4;
+	int dsize; /* is there any data? */
+	int owner; /* network address of the owner;
+               assuming 4 byte int! */
+};
+
+#define DIPC_SEMOP	 1
+#define DIPC_SEMCTL	 3
+#define DIPC_MSGSND	11
+#define DIPC_MSGRCV	12
+#define DIPC_MSGCTL	14
+#define DIPC_SHMCTL	24
+
+#ifdef __KERNEL__
+
+struct dipc_request {
+	struct dipc_info info;
+	int working; /* shows if this request is already in works */
+	char *data; /* data for this request */
+	struct semaphore sem; /* requesting task will sleep here */
+	struct dipc_request *next, *prev;
+};
+
+extern asmlinkage int sys_dipc(int first, int cmd, void *ptr);
+ 
+extern int dipc_can_act(key_t key, struct task_struct *task);
+extern int dipc_manager(struct task_struct *task);
+extern int dipc_search_key(int key,int type,int distrib,int *size);
+extern int dipc_commit_key(int key, int type, int size, int mode);
+extern int dipc_test_key(int key, int type, int size, int flag);
+extern int dipc_del_key(int key, int type);
+extern int dipc_rmid_key(int key, int type);
+
+extern void dipc_add_request(struct dipc_request *dr);
+extern int dipc_find_owner_address(key_t key, int type, int silent);
+
+extern int dipc_excl(int key, int type, int page_num);
+extern void dipc_wake(int key, int type, int page_num);
+
+extern void dipc_shm_init(int key, int val, int size);
+extern void dipc_shm_del(int key);
+extern void dipc_shm_enable(int key, int val, int offset, int size);
+extern void dipc_shm_disable(int key, int val, int offset, int size);
+extern int dipc_shm_readable(int key, int address);
+extern int dipc_shm_writable(int key, int address);
+
+#endif
+
+/* the rest should be accessible to user programs */
+#define DIPC_SIG_WRITER  SIGPWR
+#define DIPC_SIG_READER  SIGURG
+
+/* repeat the number in all bytes, so that endian-ness is avoided.
+   there is enough space to define specific CPUs */
+#define LINUX_i386    0x01010101
+#define LINUX_m68k    0x11111111
+#define LINUX_ALPHA   0x21212121
+#define LINUX_SPARC   0x31313131
+#define LINUX_SPARC64 0x41414141
+#define LINUX_MIPS    0x51515151
+#define LINUX_PPC     0x61616161
+#define LINUX_ARM     0x71717171
+
+
+#define LINUX_LITTLE_32 0xE0E0E0E0
+#define LINUX_LITTLE_64 0xE1E1E1E1
+#define LINUX_BIG_32    0xF0F0F0F0
+#define LINUX_BIG_64    0xF1F1F1F1
+
+#define LINUX_NBOR 0xFFFFFFFF
+
+/* define architecture, according to build definitions - add new archs here! */
+#if defined(__i386__)
+#define MY_DIPC_ARCH LINUX_LITTLE_32
+#define MY_DIPC_CPU  LINUX_i386
+
+#elif defined(__x86_64__) || defined(__ia64__) 
+#define MY_DIPC_ARCH LINUX_LITTLE_64
+#define MY_DIPC_CPU  LINUX_i386
+
+#elif defined(__mc68000__)
+#define MY_DIPC_ARCH LINUX_BIG_32
+#define MY_DIPC_CPU  LINUX_m68k
+
+#elif defined(__sparc__)
+#define MY_DIPC_ARCH LINUX_BIG_32
+#define MY_DIPC_CPU  LINUX_SPARC
+
+#elif defined(__alpha__)
+#define MY_DIPC_ARCH LINUX_LITTLE_64
+#define MY_DIPC_CPU  LINUX_ALPHA
+
+#elif defined(__mips__)
+#ifdef __MIPSEB__
+#define MY_DIPC_ARCH LINUX_BIG_32
+#endif
+#ifdef __MIPSEL__
+#define MY_DIPC_ARCH LINUX_LITTLE_32
+#endif
+#define MY_DIPC_CPU  LINUX_MIPS
+
+#elif defined(__powerpc__)
+#ifdef CONFIG_PPC64
+#define MY_DIPC_ARCH LINUX_BIG_64
+#else
+#define MY_DIPC_ARCH LINUX_BIG_32
+#endif
+#define MY_DIPC_CPU  LINUX_PPC
+
+#else
+#error "Unsupported DIPC architecture!"
+#endif
+
+/* Back door definitions */
+#define REFEREE_BACKDOOR "referee_backdoor"
+#define SHM_BACKDOOR "shm_man_backdoor"
+
+#define BACK_DOOR_INFO   1
+#define BACK_DOOR_REMOVE 2
+#define BACK_DOOR_EXIT   3
+
+struct back_door_message {
+	int cmd; /* command */
+	int arg1; /* type (shm, sem, msg) or (WANT_ACCESS, PENDING, ACCESSOR */
+	int arg2; /* key, or (SHM_READER, SHM_WRITER) */
+	int arg3; /* size or unused */
+	int arg4; /* distributed? or unused */
+	int arg5; /* address */
+};
+/* end of Back door definitions */
+
+#endif /* _LINUX_DIPC_H */
diff -rubBN linux-2.6.15.1/include/linux/mm.h linux-2.6.15.1-dipc/include/linux/mm.h
--- linux-2.6.15.1/include/linux/mm.h	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/include/linux/mm.h	2007-02-23 08:37:39.000000000 -0500
@@ -164,6 +164,9 @@
 #define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
 #define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
 #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
+#ifdef CONFIG_SYSVIPC_DIPC
+#define VM_SYSVSHM	0x04000000	/* DIPC uses this to recognise a shm */
+#endif
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
diff -rubBN linux-2.6.15.1/init/Kconfig linux-2.6.15.1-dipc/init/Kconfig
--- linux-2.6.15.1/init/Kconfig	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/init/Kconfig	2007-02-23 08:37:39.000000000 -0500
@@ -119,6 +119,14 @@
 	  section 6.4 of the Linux Programmer's Guide, available from
 	  <http://www.tldp.org/guides.html>.
 
+config SYSVIPC_DIPC
+	bool "DIPC (Distributed IPC)"
+	depends on SYSVIPC
+	---help---
+	DIPC makes the System V IPC mechanisms (shared memories, messages, and 
+	semaphores), distributed. Processes can exchange data transparently 
+	from anywhere in a DIPC cluster.
+
 config POSIX_MQUEUE
 	bool "POSIX Message Queues"
 	depends on NET && EXPERIMENTAL
diff -rubBN linux-2.6.15.1/ipc/dipc.c linux-2.6.15.1-dipc/ipc/dipc.c
--- linux-2.6.15.1/ipc/dipc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/dipc.c	2007-02-23 08:37:39.000000000 -0500
@@ -0,0 +1,1204 @@
+/*
+ * linux/ipc/dipc.c
+ * 
+ * Copyright (C) Kamran Karimi
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
+#include <linux/msg.h>
+#include <linux/sem.h>
+#include <linux/stat.h>
+#include <linux/smp_lock.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#include <linux/dipc.h>
+
+//# define DIPCDEBUG
+
+/* this structure holds the network address of the ipc owner, and if 
+   applicable, the transfer mode of the shared memory */
+static struct dipc_address {
+	int type; /* SHM, SEM or MSG */
+	int key;
+	int address;
+	int shm_mode; /* used to note the owner's shared memory transfer mode */ 
+	struct dipc_address *next,*prev;
+} dipc_address_first = { 0, 0, 0, -1, NULL, NULL };
+static struct dipc_address *dipc_address_last = &dipc_address_first;
+
+static struct dipc_request dipc_request_first;
+static struct dipc_request *dipc_request_last = &dipc_request_first;
+
+static DECLARE_WAIT_QUEUE_HEAD(dipc_man_wait);
+
+static struct task_struct *dipc_task = NULL; /* dipc manager */
+static int My_Address;
+
+int dipc_transfer_mode, dipc_inhibit_shm_signal, dipc_page_size;
+
+static struct dipc_wait {
+	struct semaphore *sem;
+	key_t key;
+	int type;
+	int page_num;
+	int wcnt;
+	struct dipc_wait *next, *prev;
+}dipc_first_wait;
+
+/* for DIPC's memory mamanegment */
+static struct dipc_protect_t {
+	char *prot;
+	key_t key;
+	int size;
+	struct dipc_protect_t *next, *prev;
+}dipc_first_prot = {NULL, 0, 0, NULL, NULL};
+
+static struct dipc_sem_proxy_t {
+	key_t key;
+	int owner;
+	pid_t pid;
+	struct dipc_sem_proxy_t *next, *prev;
+}dipc_first_sem_proxy = {0, 0, -1, NULL, NULL};
+
+static DECLARE_MUTEX(dipc_exclude_sem);
+static DECLARE_MUTEX(dipc_request_sem);
+static DECLARE_MUTEX(dipc_prot_sem);
+static DECLARE_MUTEX(dipc_address_sem);
+static DECLARE_MUTEX(dipc_sem_proxy_sem);
+
+void dipc_init (void)
+{
+	printk("DIPC: Distributed System V IPC. Version %s\n", DIPC_VERSION);
+
+	dipc_first_wait.type = dipc_first_wait.wcnt = 0;
+	dipc_first_wait.page_num = -1;
+	dipc_first_wait.next = dipc_first_wait.prev = NULL;
+	dipc_request_first.next = dipc_request_first.prev = NULL;
+	init_MUTEX(&dipc_exclude_sem);
+	init_MUTEX(&dipc_request_sem);
+	init_MUTEX(&dipc_prot_sem);
+	init_MUTEX(&dipc_address_sem);
+	init_MUTEX(&dipc_sem_proxy_sem);
+}
+
+/* if it is the current task, the child or the grand child of the manager, 
+   return 1 */
+int dipc_manager(struct task_struct *task)
+{
+ 	if((task == dipc_task) || (task->real_parent == dipc_task) ||
+ 	  ((task->real_parent)->real_parent && ((task->real_parent)->real_parent == dipc_task))) 
+ 		return 1;
+	return 0;
+}
+
+/* test to see if: the key is not private + dipcd is present + the input
+   task is not spawned by dipcd
+*/
+int inline dipc_can_act(key_t key, struct task_struct *task)
+{
+	if((key != IPC_PRIVATE) && (dipc_task != NULL) && 
+ 			((task == NULL) ? 1 : !dipc_manager(task))) 
+ 		return 1;
+	return 0;
+} 
+ 
+/* The following dipc_shm_x routines partially implement a software 
+   Memory Management Unit*/
+
+/* Allocate and initialize the structure for an access mode (in val) */ 
+void dipc_shm_init(key_t key, int val, int size)
+{
+	struct dipc_protect_t *dp;
+	int count;
+
+# ifdef DIPCDEBUG
+ 	printk("dipc_shm_init(%d, %d, %d):\n", key, val, size);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		if(dp->key == key)
+  			break;
+ 		dp = dp->next;
+	}
+	if(dp == NULL) {
+ 		dp = kmalloc(sizeof(struct dipc_protect_t), GFP_KERNEL);
+ 		if(dp == NULL) {
+  			printk("dipc_shm_init(%d, %d, %d): Can't allocate memory\n", 
+	  						key, val, size);
+  			goto out; /* fatal */
+ 		} 
+ 		dp->size = size / dipc_page_size + 1;
+ 		dp->prot = kmalloc(dp->size, GFP_KERNEL);
+ 		if(dp->prot == NULL) {
+ 	 		printk("dipc_shm_init(%d, %d, %d): Can't allocate memory\n",
+ 	 						key, val, size);
+  			kfree(dp);
+  			goto out; /* fatal */
+ 		}
+ 		for(count = 0; count <= size / dipc_page_size; count++)
+	   		dp->prot[count] = (char)val;
+ 		dp->key = key;
+ 		dp->next = dipc_first_prot.next;
+ 		if(dipc_first_prot.next)
+  			dipc_first_prot.next->prev = dp;
+ 		dipc_first_prot.next = dp;
+ 		dp->prev = &dipc_first_prot; 
+	}
+	else
+ 		printk("dipc_shm_init(%d, %d, %d): duplicate shm protection structure\n",
+ 							key, val, size); 
+out:
+	up(&dipc_prot_sem);
+	return;
+}
+
+/* delete the shm protection structure */
+void dipc_shm_del(key_t key)
+{
+	struct dipc_protect_t *dp;
+
+# ifdef DIPCDEBUG
+	printk("dipc_shm_del(%d)\n", key);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		if(dp->key == key)
+  			break;
+ 		dp = dp->next;
+	}
+	if(dp) {
+ 		dp->prev->next = dp->next;
+ 		if(dp->next)
+  			dp->next->prev = dp->prev;
+ 		kfree(dp->prot); 
+ 		kfree(dp);
+	}
+	else
+ 		printk("dipc_shm_del(%d): Can't find the structure\n", key);
+ 	up(&dipc_prot_sem);
+	return;
+}
+ 
+/* The address can be read or written (depending on val) */
+void dipc_shm_enable(key_t key, int val, int offset, int mode)
+{
+	struct dipc_protect_t *dp;
+	int count, start, end;
+
+# ifdef DIPCDEBUG
+	printk("dipc_shm_enable(%d, %d, %d, %d)\n", key, val, offset, mode);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		if(dp->key == key)
+  			break;
+ 		dp = dp->next;
+	}
+	if(dp) { 
+ 		if(mode == SEGMENT) {
+  			start = 0;
+  			end = dp->size - 1;
+ 		}
+ 		else
+ 			start = end = offset / dipc_page_size;
+
+ 		for(count = start; count <= end; count++)
+  			dp->prot[count] |= val;
+	} 
+	else
+ 		printk("dipc_shm_enable(%d, %d, %d, %d): protection structure not found\n", 
+ 						key, val, offset, mode);
+	up(&dipc_prot_sem);
+	return;
+} 
+
+/* The address can not be read or written */
+void dipc_shm_disable(key_t key, int val, int offset, int mode)
+{
+	struct dipc_protect_t *dp;
+	int count, start, end;
+
+# ifdef DIPCDEBUG
+ 	printk("dipc_shm_disable(%d, %d, %d, %d)\n", key, val, offset, mode);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		if(dp->key == key)
+  			break;
+  		dp = dp->next;
+	}
+	if(dp) { 
+ 		if(mode == SEGMENT) {
+  			start = 0;
+  			end = dp->size - 1;
+  		}
+  		else
+  			start = end = offset / dipc_page_size;
+
+ 		for(count = start; count <= end; count++) {
+  			dp->prot[count] &= ~val;
+ 		} 
+	} 
+	else
+		printk("dipc_shm_disable(%d, %d, %d, %d): protection structure not found\n",
+						 key, val, offset, mode);
+	up(&dipc_prot_sem);
+	return;
+} 
+
+/* check to see if the address is readable */
+int dipc_shm_readable(key_t key, int offset)
+{
+	struct dipc_protect_t *dp;
+	int addr = offset / dipc_page_size;
+	int ret = 0;
+	
+# ifdef DIPCDEBUG
+	printk("dipc_shm_readable(%d, %d)\n", key, offset);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		if(dp->key == key)
+  			break;
+		dp = dp->next;
+	}
+	if(dp) {
+  		if(dp->size <= addr) {
+ 			printk("dipc_shm_readable(%d, %d): out of bound reference\n", key, offset);
+  			goto out;
+ 		}
+ 		ret = dp->prot[addr] & 1;
+	}
+	else
+ 		printk("dipc_shm_readable(%d, %d): Can't find the structure\n", key, offset);
+out:
+	up(&dipc_prot_sem);
+	return ret;
+}
+
+
+int dipc_shm_writable(key_t key, int offset)
+{
+	struct dipc_protect_t *dp;
+	int addr = offset / dipc_page_size;
+	int ret = 0;
+
+# ifdef DIPCDEBUG
+	printk("dipc_shm_writable(%d, %d)\n", key, offset);
+# endif
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+		if(dp->key == key)
+  			break;
+ 		dp = dp->next;
+	}
+	if(dp) {
+		if(dp->size <= addr) {
+ 			printk("dipc_shm_writable(%d, %d): out of bound reference. dp->size:%d, addr:%d\n", 
+           			 key, offset, dp->size, addr);
+ 			goto out;
+		}
+ 		ret = dp->prot[addr] & 2;
+	}
+	else
+ 		printk("dipc_shm_writable(%d, %d): Can't find the structure\n", key, offset);
+out:
+	up(&dipc_prot_sem);
+	return ret;
+}
+
+
+static int dipc_find_owner_transfer_mode(key_t key)
+{
+	struct dipc_address *da;
+	int ret;
+	
+# ifdef DIPCDEBUG
+	printk("dipc_find_owner_transfer_mode(%d)\n",key);
+# endif
+	down(&dipc_address_sem);
+	da = dipc_address_first.next;
+	while(da) {
+ 		if((da->key == key) && (da->type == SHM)) 
+ 			break;
+  		da = da->next;
+	}
+	if(da) {
+  		ret = da->shm_mode;
+  		goto out;
+  	}
+ 	printk("dipc_find_owner_transfer_mode(%d): Can't find the owner's shm transfer mode\n", key);
+ 	ret = -1;
+ out:
+	up(&dipc_address_sem);
+	return ret;
+}
+
+
+/* create a queue for other tasks to wait on */
+int dipc_excl(key_t key, int type, int page_num)
+{
+	struct dipc_wait *dw;
+	int ret = 0, tmode = 1;
+
+# ifdef DIPCDEBUG
+	printk("dipc_excl(%d, %d), by task %d\n", key, type, 
+                current->pid);
+# endif
+	down(&dipc_exclude_sem);
+	if(type == SHM && page_num != -1)
+		tmode = dipc_find_owner_transfer_mode(key);
+	dw = dipc_first_wait.next;
+	while(dw) {
+ 		if(dw->key == key && dw->type == type &&
+ 		((tmode == 0) ? (dw->page_num == page_num) : 1))
+  			break;
+ 		dw = dw->next;
+	}
+	if(dw == NULL) {
+ 		dw = kmalloc(sizeof(struct dipc_wait), GFP_KERNEL);
+ 		if(dw == NULL) {
+  			printk("dipc_excl(%d, %d): Can't allocate memory\n", key, type);
+  			goto out; /* fatal */
+ 		}
+ 		dw->key = key;
+ 		dw->type = type;
+ 		/* only for shared memory in page mode*/
+		dw->page_num = page_num; 
+ 		dw->sem = kmalloc(sizeof(struct semaphore), GFP_KERNEL);
+		if(dw->sem == NULL) {
+			printk("dipc_excl(%d, %d): Can't allocate memory\n", key, type);
+			goto out; /*fatal*/
+		}
+		init_MUTEX(dw->sem);	
+ 		down(dw->sem);
+ 		dw->wcnt = 0;
+ 		dw->next = dipc_first_wait.next;
+ 		if(dipc_first_wait.next)
+  			dipc_first_wait.next->prev = dw;
+ 		dipc_first_wait.next = dw;
+ 		dw->prev = &dipc_first_wait;
+	}
+	else {
+	 	dw->wcnt++;
+ 		up(&dipc_exclude_sem);
+ 
+ 		down(dw->sem);
+ 
+ 		down(&dipc_exclude_sem);
+ 		dw->wcnt--;
+ 		/*if (dw->wcnt == 0)
+   			kfree(dw);*/
+   		ret = 1;	
+	}
+out:	
+	up(&dipc_exclude_sem);
+	return ret;
+}
+
+
+/* wake up the tasks waiting on a queue */
+void dipc_wake(key_t key, int type, int page_num)
+{
+	struct dipc_wait *dw;
+	int tmode = 1;
+
+# ifdef DIPCDEBUG
+	printk("dipc_wake(%d, %d)\n", key, type);
+# endif
+	down(&dipc_exclude_sem);
+	if(type == SHM && page_num != -1)
+		tmode = dipc_find_owner_transfer_mode(key);
+	dw = dipc_first_wait.next;
+	while(dw) {
+ 		if(dw->key == key && dw->type == type &&
+ 		((tmode == 0) ? (dw->page_num == page_num) : 1))
+ 			break;
+ 		dw = dw->next;
+	}
+	if(dw) {
+		if (dw->wcnt > 0)
+ 			up(dw->sem);
+ 		else {
+ 			dw->prev->next = dw->next;
+ 			if(dw->next)
+  				dw->next->prev = dw->prev;
+   			kfree(dw);
+   		}	
+		goto out;
+	}
+	else
+ 		printk("dipc_wake(%d, %d): Can't find the structure\n", key, type);
+out:
+	up(&dipc_exclude_sem);
+	return;
+}
+
+/* save the IPC structure's owner address, as returned by the referee */
+static int dipc_add_owner_address(key_t key, int type, int net_address, 
+                                                               int shm_mode)
+{
+	struct dipc_address *da;
+	int ret;
+
+# ifdef DIPCDEBUG
+	printk("Kernel: dipc_add_owner_address(%d, %d, %d, %d)\n", key, type, 
+                                          net_address, shm_mode);
+# endif
+        down(&dipc_address_sem);        
+	da = dipc_address_first.next;
+	while(da) {
+ 		if((da->key == key) && (da->type == type))
+ 			break;
+ 		da = da->next;
+	}
+	if(da)
+ 		printk("dipc_add_owner_address(%d, %d): adding duplicate owner\n", key, type); 
+	da = kmalloc(sizeof(struct dipc_address), GFP_KERNEL);
+	if(da == NULL) {
+ 		printk("dipc_add_owner_address(%d, %d, %d, %d): Can't allocate memory\n", 
+	 				key, type, net_address, shm_mode); 
+ 		ret = -1;
+ 		goto out;
+	} 
+	da->type = type;
+	da->key = key;
+	da->address = net_address;
+	da->shm_mode = shm_mode; /* used only for shared memories */
+	da->next = NULL;
+	da->prev = dipc_address_last;
+	dipc_address_last->next = da;
+	dipc_address_last = da;
+	ret = 0;
+out:
+	up(&dipc_address_sem);
+	return ret;
+}
+
+
+/* dipcd will need this returned address to handle the request. It is also 
+   called from shm.c, msg.c and sem.c, where it runs "silent" (does not 
+   print any error messgaes if no owner address could be found) */
+int dipc_find_owner_address(key_t key, int type, int silent)
+{
+	struct dipc_address *da;
+	int ret;
+# ifdef DIPCDEBUG
+	printk("dipc_find_owner_address(%d, %d, %d)\n",key, type, silent);
+# endif
+	down(&dipc_address_sem);
+	da = dipc_address_first.next;
+	while(da) {
+ 		if((da->key == key) && (da->type == type)) 
+ 			break;
+ 		da = da->next;
+	}
+	if(da) {
+	
+		ret =  da->address;
+		goto out;
+	}
+	if(!silent)
+		printk("dipc_find_owner_address(%d, %d, %d): Can't find the owner address\n", 
+							key, type, silent);
+	ret =  -1;
+out:
+	up(&dipc_address_sem);
+	return ret;
+}
+
+
+static int dipc_del_owner_address(key_t key, int type)
+{
+	struct dipc_address *da;
+	int ret;
+
+# ifdef DIPCDEBUG
+	printk("dipc_del_owner_address(%d, %d)\n",key, type);
+# endif
+	down(&dipc_address_sem);
+	da = dipc_address_first.next;
+	while(da) {
+ 		if((da->key == key) && (da->type == type)) 
+ 			break;
+ 		da = da->next;
+	}
+	if(da) {
+  		if(dipc_address_last == da) 
+  			dipc_address_last = da->prev;
+ 		(da->prev)->next = da->next;
+ 		if(da->next)
+  			(da->next)->prev = da->prev;
+ 		kfree(da);
+ 		ret = 0;
+		goto out;
+	}
+	printk("dipc_del_owner_address(%d, %d): Can't find the address to delete\n", key, type);
+	ret = -1;
+out:	
+	up(&dipc_address_sem);
+	return ret;
+}
+
+
+
+void dipc_add_sem_proxy(key_t key)
+{
+	struct dipc_sem_proxy_t *sp;
+
+# ifdef DIPCDEBUG
+	printk("dipc_add_sem_proxy(%d)\n", key);
+# endif
+	down(&dipc_sem_proxy_sem);
+	sp = dipc_first_sem_proxy.next;
+	while(sp) {
+ 		if(sp->key == key && sp->pid == current->pid)
+  			break;
+ 		sp = sp->next;
+	}
+	if(sp == NULL) {
+ 		sp = kmalloc(sizeof(struct dipc_sem_proxy_t), GFP_KERNEL);
+ 		if(sp == NULL) 
+ 		{
+  			printk("dipc_add_sem_proxy(%d): Can't allocate memory\n", key);
+  			goto out;
+ 		}
+ 		sp->key = key;
+ 		sp->pid = current->pid;
+ 		sp->owner = dipc_find_owner_address(key, SEM, 0);
+ 		sp->next = dipc_first_sem_proxy.next;
+ 		sp->prev = &dipc_first_sem_proxy;
+ 		if(dipc_first_sem_proxy.next)
+  			dipc_first_sem_proxy.next->prev = sp;
+ 		dipc_first_sem_proxy.next = sp;
+	}
+out:
+	up(&dipc_sem_proxy_sem);	
+	return;
+}
+
+
+/* inform the proxies to exit */
+void dipc_inform_sem_proxy(void)
+{
+	struct dipc_request *dr;
+	struct dipc_sem_proxy_t *sp, *sp2;
+  
+# ifdef DIPCDEBUG
+	printk("dipc_inform_sem_proxy()\n");
+# endif
+	down(&dipc_sem_proxy_sem);
+	sp = dipc_first_sem_proxy.next;
+	while(sp) {
+ 		sp2 = sp->next;
+ 		if(sp->pid == current->pid) {
+  			dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+  			if(dr == NULL) {
+   				printk("dipc_inform_sem_proxy(): Can't allocate memory\n");
+				goto out;
+  			} 
+  			dr->info.key = sp->key;
+  			dr->info.type = SEM;
+  			dr->info.pid = current->pid;
+  			dr->info.uid = current->uid;
+  			dr->info.func = SEM_EXIT;
+  			dr->info.arg1 = sp->key;
+  			dr->info.arg2 = 0;
+  			dr->info.arg3 = 0;
+  			dr->info.arg4 = 0;
+  			dr->info.owner = sp->owner;
+  			dr->info.dsize = 0;
+  			dr->working = 0;
+  			dr->next = dr->prev = NULL;
+  			dr->data = NULL;
+  			init_MUTEX_LOCKED(&dr->sem);
+			up(&dipc_sem_proxy_sem);
+		
+   			dipc_add_request(dr); 
+  		
+			down(&dipc_sem_proxy_sem);
+			kfree(dr);
+  
+  			if(sp->next)
+   				sp->next->prev = sp->prev;
+  			sp->prev->next = sp->next;
+  			kfree(sp); 
+ 		} 
+ 		sp = sp2;
+	} 
+out:	
+	up(&dipc_sem_proxy_sem);
+
+	return;
+} /* dipc_inform_sem_proxy */
+
+
+/* Tasks use this routine to announce their need to search
+   for a new key of type "type". An employer should later handle it. */
+int dipc_search_key(key_t key, int type, int distrib, int *size)
+{
+	struct dipc_request *dr;
+	int result, shm_mode;
+
+# ifdef DIPCDEBUG
+	printk("dipc_search_key(%d, %d, %d, %ud)\n",key, type, distrib, *size);
+# endif
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = key;
+	dr->info.type = type;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = SEARCH;
+	dr->info.arg1 = key;
+	dr->info.arg2 = distrib;
+	dr->info.arg3 = dipc_transfer_mode; /* used only for shm */
+	dr->info.arg4 = 0;
+	dr->info.owner = -1;
+	dr->working = 0;
+ 	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = 0;
+	dr->data = NULL;
+
+	dipc_add_request(dr);
+
+	shm_mode = (dipc_transfer_mode == SEGMENT) ? IS_SEGMENT : 0;
+ 	if(dr->info.arg1 >= 0) {
+ 		result = dr->info.arg2;
+ 		if(result != NOT_FOUND)
+ 			shm_mode = result & IS_SEGMENT;
+ 		*size = dr->info.arg3;
+ 		dipc_add_owner_address(key, type, dr->info.arg4, shm_mode);
+ 		result &= ~IS_SEGMENT;
+	}
+	else {
+ 		result = NOT_FOUND;
+ 		*size = 0;
+	 	dipc_add_owner_address(key, type, My_Address, shm_mode);
+	}
+	kfree(dr); 
+	return result;
+}
+
+
+/* this routine tells if an attempt to get a new key succeeded or not.
+   in case of success, the result has some information about the key */ 
+int dipc_commit_key(key_t key, int type, int size, int mode)
+{
+	struct dipc_request *dr;
+
+# ifdef DIPCDEBUG
+	printk("dipc_commit_key(%d, %d, %d, %d)\n",key, type, size, mode);
+# endif
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) return -ENOMEM; /* set errno */
+	dr->info.key = key;
+	dr->info.type = type;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = COMMIT;
+	dr->info.arg1 = key;
+	dr->info.arg2 = size;
+	dr->info.arg3 = mode;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1; 
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = 0;
+	dr->data = NULL;
+	dipc_add_request(dr); /* ignores errors */
+	if(size <= 0) /* failed */
+ 		dipc_del_owner_address(key, type);
+	kfree(dr); 
+	return 0;
+}
+
+/* this routine tests to see if the struture can be created in the 
+   owner machine. This is for access checking. result is the id of the
+   remote key, or an error code */ 
+int dipc_test_key(key_t key, int type, int size, int flag)
+{
+	struct dipc_request *dr;
+	int result;
+
+# ifdef DIPCDEBUG
+	printk("dipc_test_key(%d, %d, %d, %d)\n",key, type, size, flag);
+# endif
+ 	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = key;
+	dr->info.type = type;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = TSTGET;
+	dr->info.arg1 = key;
+	dr->info.arg2 = size;
+	dr->info.arg3 = flag;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1; 
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = 0;
+	dr->data = NULL;
+
+	dipc_add_request(dr);
+
+	result = dr->info.arg1; /* any kind of error (network, test error...) */
+	kfree(dr); 
+	return result;
+}
+
+int dipc_rmid_key(key_t key, int type)
+{
+	struct dipc_request *dr;
+
+# ifdef DIPCDEBUG
+	printk("dipc_rmid_key(%d, %d)\n", key, type);
+# endif
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = key;
+	dr->info.type = type;
+ 	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+ 	dr->info.func = RMID;
+	dr->info.arg1 = key;
+	dr->info.arg2 = 0;
+	dr->info.arg3 = 0;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = 0;
+ 	dr->data = NULL;
+
+	dipc_add_request(dr); /* ignores errors */
+
+ 	kfree(dr);
+	return 0;
+}
+
+/* Tasks use this routine to announce that they are removing 
+   the specified key. This should be reflected in the referee tables */
+int dipc_del_key(key_t key, int type)
+{
+	struct dipc_request *dr;
+
+# ifdef DIPCDEBUG
+	printk("dipc_del_key(%d, %d)\n", key, type);
+# endif
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = key;
+	dr->info.type = type;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DELKEY;
+	dr->info.arg1 = key;
+	dr->info.arg2 = 0;
+	dr->info.arg3 = 0;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1; 
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = 0;
+	dr->data = NULL;
+
+	dipc_add_request(dr); /* ignores error */
+	
+	dipc_del_owner_address(key, type);
+	kfree(dr); 
+	return 0;
+}
+
+
+/* tasks call this to provide work for the back_end process */
+void dipc_add_request(struct dipc_request *dr)
+{
+	int owner;
+
+# ifdef DIPCDEBUG
+	printk("dipc_add_request(function: %d,  pid: %d)\n", dr->info.func, dr->info.pid);
+# endif
+	if(dipc_task == NULL)  {
+# ifdef DIPCDEBUG
+	printk("dipc_add_request dipc_task == NULL\n");
+# endif
+ 		dr->info.arg1 = -EIO;
+ 		return;
+	}
+	if(dr->info.func != RMID && dr->info.func != DELKEY &&
+   	   dr->info.func != SEARCH && dr->info.func != COMMIT &&
+   	   dr->info.func != SEM_EXIT) {
+ 		owner = dipc_find_owner_address(dr->info.arg1, dr->info.type, 0);
+ 		if(owner == -1) { 
+  			printk("dipc_add_request: Can't find the owner of key %d, type %d\n",
+                                      dr->info.arg1, dr->info.type);
+  			dr->info.arg1 = -EIO;
+  			return;
+ 		}
+ 		dr->info.owner = owner;
+	} 
+
+	down(&dipc_request_sem);
+	dr->next = NULL;
+	dr->prev = dipc_request_last;
+	dipc_request_last->next = dr;
+	dipc_request_last = dr;
+	up(&dipc_request_sem);
+
+	wake_up(&dipc_man_wait);
+
+ 	down_interruptible(&(dr->sem));
+ 
+	/* see if we were awakened by an interrupt */
+	if(signal_pending(current))
+		dr->info.arg1 = -EINTR;
+
+	down(&dipc_request_sem);	
+	if(dipc_request_last == dr)
+		dipc_request_last = dr->prev;
+	(dr->prev)->next = dr->next;
+	if(dr->next) 
+		(dr->next)->prev = dr->prev;
+	up(&dipc_request_sem);
+
+	return;
+}
+
+
+/* back_end calls this function to collect work */
+static int dipc_get_new_request(int type, void *ptr)
+{
+	struct dipc_request *dr;
+	int err;
+	void *pt[2];
+	struct dipc_info *info;
+	char *data;
+
+# ifdef DIPCDEBUG
+	printk("dipc_get_new_request(%d)\n", type);
+# endif
+	if(copy_from_user (pt, ptr, 2 * sizeof(void *)))
+		return -EFAULT;
+		
+	info = pt[0];
+	data = pt[1];
+
+	down(&dipc_request_sem);
+
+	dr = dipc_request_first.next;
+	while(dr) {
+ 		if(dr->working == 0) {
+  			/* if type == 0, return any request type */
+  			if(type == 0)
+  				break;
+  			else if(type == dr->info.type) 
+  				break;
+ 		}
+ 		dr = dr->next;
+	}
+	if(dr) {
+ 		dr->working = 1;
+ 
+ 		if(copy_to_user (info, &dr->info, sizeof(struct dipc_info))) {
+			err = -EFAULT;
+			goto out;
+		}	
+ 		if(dr->info.dsize) {
+  			if(copy_to_user (data, dr->data, dr->info.dsize)) {
+				err = -EFAULT;
+				goto out;
+			}	
+ 		}
+ 		err = DIPC_SUCCESS; 
+		goto out;
+	}
+	/* nothing suitable found */
+	err = DIPC_SUCCESS + 1;
+out:
+	up(&dipc_request_sem);
+
+	return err;
+} 
+
+/* this routine returns the result of a request, hopefully after
+   successful execution at the remote owner */
+static int dipc_put_result_of_request(int pid, void *ptr)
+{
+	struct dipc_request *dr;
+	int ret;
+	void *pt[2];
+	struct dipc_info *info;
+	char *data;
+
+# ifdef DIPCDEBUG
+	printk("dipc_put_result_of_request(%d)\n", pid);
+# endif
+	if(copy_from_user (pt, ptr, 2 * sizeof(void *)))
+		return -EFAULT;
+	info = pt[0];
+ 	data = pt[1];
+
+	down(&dipc_request_sem);
+
+	dr = dipc_request_first.next;
+	while(dr) {
+ 		if(dr->info.pid == pid)
+ 			break;
+ 		dr = dr->next;
+	}
+	if(dr) {
+ 		/* save the pointers before over write */
+ 		if(copy_from_user (&(dr->info), info, sizeof(struct dipc_info))) {
+			ret = -EFAULT;
+			goto out;
+		}	
+ 		if((dr->info.arg1 >= 0) && dr->info.dsize) {
+  			if(copy_from_user (dr->data, data, dr->info.dsize)) {
+				ret = -EFAULT;
+				goto out;
+			}	
+ 		}
+ 		/* Now wake it up */
+ 		up(&dr->sem);
+
+ 		ret = DIPC_SUCCESS;
+		goto out;
+	} /* if dr */  
+
+	printk("dipc_put_result_of_request(%d) Can't find the waiting task (exited?)\n", pid);
+
+	ret = DIPC_FAIL;
+out:
+	up(&dipc_request_sem);
+
+	return ret;
+}
+
+
+static int dipc_wait_for_work(void)
+{
+	struct dipc_request *dr;
+ 
+# ifdef DIPCDEBUG
+ 	printk("dipc_wait_for_work()\n");
+# endif
+
+	down(&dipc_request_sem);
+
+	dr = dipc_request_first.next;
+	while(dr) {
+ 		if(dr->working == 0)
+ 			break;
+ 		dr = dr->next;
+	}
+	up(&dipc_request_sem);
+
+	if(dr != NULL)
+ 		return DIPC_SUCCESS;
+
+	interruptible_sleep_on(&dipc_man_wait);
+
+	return DIPC_SUCCESS;
+}
+
+/* called when dipcd is going to die */
+static int dipc_quit_kernel(void)
+{
+	struct dipc_request *dr;
+	struct dipc_wait *dw;
+
+# ifdef DIPCDEBUG
+	printk("dipc_quit_kernel()\n");
+# endif
+	dipc_task = NULL;
+
+	/* wake up processes waiting for remote actions.
+   	   This should lead to all other structures getting freed */
+	down(&dipc_request_sem); 
+	dr = dipc_request_first.next;
+	while(dr) {
+ 		dr->info.arg1 = -EIO;
+ 		up(&dr->sem);
+ 		dr = dr->next;
+	}
+	up(&dipc_request_sem);
+
+	/* exclusion mechanism */
+	down(&dipc_exclude_sem); 
+	dw = dipc_first_wait.next;
+	while(dw) {
+		int count;
+		for(count = 0; count <= dw->wcnt; count++)
+ 			up(dw->sem);
+ 		dw = dw->next;
+	}
+	up(&dipc_exclude_sem);
+	
+	return DIPC_SUCCESS;
+}
+
+
+/* DIPC cleans the kernel data structure when dipcd starts runnung, not
+   when dipcd stops. This is because deleting the structures that could have
+   some tasks waiting on them can lead to problems. 
+   
+   The user/admin can make sure no tasks are waiting on DIPC's kernel 
+   structure before deleting them */
+static int dipc_set_manager(int first, void *ptr)
+{
+	struct dipc_request *dr, *dr2;
+	struct dipc_wait *dw, *dw2;
+	struct dipc_address *da, *da2;
+	struct dipc_protect_t *dp, *dp2;
+	struct dipc_sem_proxy_t *ds, *ds2;
+	int ret;
+	int pt[3];
+
+# ifdef DIPCDEBUG
+	printk("dipc_set_manager()\n");
+# endif
+
+	if(copy_from_user (pt, ptr, 3 * sizeof(int))) {
+		ret = -EFAULT;
+		goto out;
+	}	
+	dipc_transfer_mode = pt[0];
+	dipc_inhibit_shm_signal = pt[1];
+	dipc_page_size = pt[2];
+	dipc_task = current;
+	My_Address = first; /* ints are 32 bits */
+	
+	init_waitqueue_head(&dipc_man_wait);
+	
+	init_MUTEX(&dipc_exclude_sem);
+	init_MUTEX(&dipc_request_sem);
+	init_MUTEX(&dipc_prot_sem);
+	init_MUTEX(&dipc_address_sem);
+	init_MUTEX(&dipc_sem_proxy_sem);
+	
+	/* now make sure everything from previous runs is thrown away */
+	down(&dipc_request_sem); 
+	dr = dipc_request_first.next;
+	while(dr) {
+ 		dr2 = dr->next;
+ 		kfree(dr);
+  		dr = dr2;
+	}
+	dipc_request_first.next = dipc_request_first.prev = NULL;
+	dipc_request_last = &dipc_request_first;
+	up(&dipc_request_sem);
+
+	/* exclusion mechanism */
+	down(&dipc_exclude_sem);
+	dw = dipc_first_wait.next;
+	while(dw) {
+ 		dw2 = dw->next;
+ 		kfree(dw);  
+ 		dw = dw2;
+	}
+	dipc_first_wait.next = dipc_first_wait.prev = NULL; 
+	up(&dipc_exclude_sem);
+	
+	/* owner addresses */ 
+	down(&dipc_address_sem);
+	da = dipc_address_first.next;
+	while(da) {
+ 		da2 = da->next;
+ 		kfree(da);
+ 		da = da2;
+	}
+	dipc_address_first.next = dipc_address_first.prev = NULL;
+	dipc_address_last = &dipc_address_first;
+	up(&dipc_address_sem);
+ 	
+ 	/* MM data structures */
+	down(&dipc_prot_sem);
+	dp = dipc_first_prot.next;
+	while(dp) {
+ 		dp2 = dp->next;
+		kfree(dp->prot);
+ 		kfree(dp);
+ 		dp = dp2;
+	}
+	dipc_first_prot.next = dipc_first_prot.prev = NULL;
+	up(&dipc_prot_sem);
+
+ 	/* semaphore proxies */
+	down(&dipc_sem_proxy_sem);
+	ds = dipc_first_sem_proxy.next;
+	while(ds) {
+ 		ds2 = ds->next;
+ 		kfree(ds);
+ 		ds = ds2;
+	}
+	dipc_first_sem_proxy.next = dipc_first_sem_proxy.prev = NULL;
+	up(&dipc_sem_proxy_sem);
+	ret = DIPC_SUCCESS;
+out:
+	return ret;
+}
+
+
+/* in shm.c */
+extern int dipc_disable_prot(key_t key, int cmd, int *mask);
+ 
+asmlinkage int sys_dipc(int first, int cmd, void *ptr)
+{
+	if(!capable(CAP_SYS_ADMIN))
+ 		return -EPERM;
+
+	switch(cmd) {
+ 		case DIPC_GETWORK:
+  			return dipc_get_new_request(first, ptr);
+  			break;
+ 
+ 		case DIPC_RETWORK:
+  			return dipc_put_result_of_request(first, ptr);
+  			break;
+
+ 		case DIPC_SLEEP:
+  			return dipc_wait_for_work();
+  			break;
+  
+ 		case DIPC_SETMNG:
+  			return dipc_set_manager(first, ptr);
+  			break;
+  
+ 		case DIPC_REMMNG:
+  			return dipc_quit_kernel();
+  			break;
+
+  		case DIPC_REMPROT:
+  			return dipc_disable_prot(first, cmd, ptr);
+  			break;
+
+  		default:
+  			printk("sys_dipc(%d, %d): Unknown request\n", first, cmd);
+  			break;
+	}   
+	return DIPC_FAIL;
+}
diff -rubBN linux-2.6.15.1/ipc/Makefile linux-2.6.15.1-dipc/ipc/Makefile
--- linux-2.6.15.1/ipc/Makefile	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/Makefile	2007-02-23 08:37:39.000000000 -0500
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
-obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o
+obj-$(CONFIG_SYSVIPC) += util.o msgutil.o dipc.o msg.o sem.o shm.o
 obj_mq-$(CONFIG_COMPAT) += compat_mq.o
 obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
 
diff -rubBN linux-2.6.15.1/ipc/msg.c linux-2.6.15.1-dipc/ipc/msg.c
--- linux-2.6.15.1/ipc/msg.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/msg.c	2007-02-23 08:37:39.000000000 -0500
@@ -13,6 +13,8 @@
  * mostly rewritten, threaded and wake-one semantics added
  * MSGMAX limit removed, sysctl's added
  * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
+ *
+ * DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -29,6 +31,9 @@
 #include <linux/seq_file.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include "util.h"
 
 /* sysctl: */
@@ -78,6 +83,13 @@
 static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
 #endif
 
+#ifdef CONFIG_SYSVIPC_DIPC
+static int dipc_msgctl(key_t msgkey, int cmd, struct msqid_ds *buff);
+static int dipc_msgsnd(key_t msgkey, const struct msgbuf *msgptr, size_t msgsz, int msgflg);
+static int dipc_msgrcv(key_t msgkey, struct msgbuf *msgptr, size_t msgsz, long type, int msgflg);
+#endif
+
+
 void __init msg_init (void)
 {
 	ipc_init_ids(&msg_ids,msg_ctlmni);
@@ -97,6 +109,11 @@
 	if (!msq) 
 		return -ENOMEM;
 
+#ifdef CONFIG_SYSVIPC_DIPC	
+	if(dipc_can_act(key, NULL))
+	 	msq->q_perm.mode = (msgflg & (S_IRWXUGO | IPC_DIPC));
+	else
+#endif	
 	msq->q_perm.mode = (msgflg & S_IRWXUGO);
 	msq->q_perm.key = key;
 
@@ -185,11 +202,17 @@
 {
 	struct list_head *tmp;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_can_act(msq->q_perm.key, NULL)) {
+	 	/* if(!(msq->q_perm.mode & IPC_OWN)) */
+	 	dipc_del_key(msq->q_perm.key, MSG);
+	} 
+#endif
+
 	expunge_all(msq,-EIDRM);
 	ss_wakeup(&msq->q_senders,1);
 	msq = msg_rmid(id);
 	msg_unlock(msq);
-		
 	tmp = msq->q_messages.next;
 	while(tmp != &msq->q_messages) {
 		struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
@@ -200,6 +223,7 @@
 	atomic_sub(msq->q_cbytes, &msg_bytes);
 	security_msg_queue_free(msq);
 	ipc_rcu_putref(msq);
+
 }
 
 asmlinkage long sys_msgget (key_t key, int msgflg)
@@ -208,9 +232,58 @@
 	struct msg_queue *msq;
 	
 	down(&msg_ids.sem);
+	
 	if (key == IPC_PRIVATE) 
 		ret = newque(key, msgflg);
 	else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
+#ifdef CONFIG_SYSVIPC_DIPC
+		if(dipc_can_act(key, current)) {
+		 	int remote_found, result, distrib = msgflg & IPC_DIPC;
+		 		 
+		 	result = dipc_search_key(key, MSG, distrib, &remote_found);
+
+		 	if(result != NOT_FOUND) {
+		  		if(((msgflg & IPC_DIPC) && (result == FOUND_IPC)) ||
+		      		   (!(msgflg & IPC_DIPC) && (result == FOUND_DIPC))) {
+					up(&msg_ids.sem);//dipc_wake(key, MSG, -1);
+		   			dipc_commit_key(key, MSG, 0, 0);
+		   			return -EEXIST;
+			  	}
+			  	else if((msgflg & IPC_DIPC) && (result == FOUND_DIPC)) {  
+			  	
+					/* local and remote are DIPC, test remotely */
+			   		result = dipc_test_key(key, MSG, 0, msgflg);
+			   	
+					if(result < 0) {
+						up(&msg_ids.sem);//dipc_wake(key, MSG, -1);
+			    			dipc_commit_key(key, MSG, 0, 0);
+						return result;
+			   		}
+			  	}
+			}  
+			else { /* nothing was found in other machines */
+			  	if (!(msgflg & IPC_CREAT)) {
+			   		up(&msg_ids.sem);//dipc_wake(key, MSG, -1);
+			   		dipc_commit_key(key, MSG, 0, 0);
+					return -ENOENT;
+			  	}	
+			}
+			id = newque(key, msgflg);
+			if(id < 0)
+			  	dipc_commit_key(key, MSG, 0, 0);
+			else {
+			  	msq = msg_lock(id);
+			  	if(msgflg & IPC_DIPC) { 
+		 			if(remote_found == 0) /* this is a owner and DIPC */
+		    				msq->q_perm.mode |= IPC_OWN;
+		  		}
+			  	msg_unlock(msq);
+			  	dipc_commit_key(key, MSG, 1, msq->q_perm.mode);    
+			}
+			ret = id;
+		}
+	        else /* no DIPC manager */
+#endif
 		if (!(msgflg & IPC_CREAT))
 			ret = -ENOENT;
 		else
@@ -223,6 +296,13 @@
 			BUG();
 		if (ipcperms(&msq->q_perm, msgflg))
 			ret = -EACCES;
+#ifdef CONFIG_SYSVIPC_DIPC
+		else if(dipc_can_act(key, NULL) &&
+		        (((msq->q_perm.mode & IPC_DIPC) && !(msgflg & IPC_DIPC)) ||
+	  		 (!(msq->q_perm.mode & IPC_DIPC) && (msgflg & IPC_DIPC))))
+			  	ret = -EEXIST;
+#endif		
+
 		else {
 			int qid = msg_buildid(id, msq->q_perm.seq);
 		    	ret = security_msg_queue_associate(msq, msgflg);
@@ -336,6 +416,21 @@
 	if (msqid < 0 || cmd < 0)
 		return -EINVAL;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	msq = msg_lock(msqid);
+	if (msq == NULL)
+		return -EINVAL;
+
+        msg_unlock(msq);
+	if (dipc_can_act(msq->q_perm.key, current)) {
+	 	if((cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_RMID) && 
+		   (msq->q_perm.mode & IPC_DIPC) && !(msq->q_perm.mode & IPC_OWN)) {
+	   		err = dipc_msgctl(msq->q_perm.key, cmd, buf);	
+	   		return err;
+	 	}
+	}
+#endif	 
+
 	version = ipc_parse_version(&cmd);
 
 	switch (cmd) {
@@ -419,6 +514,9 @@
 		tbuf.msg_lspid  = msq->q_lspid;
 		tbuf.msg_lrpid  = msq->q_lrpid;
 		msg_unlock(msq);
+#ifdef CONFIG_SYSVIPC_DIPC
+		tbuf.__unused1 = (unsigned long) dipc_find_owner_address(msq->q_perm.key, MSG, 1);
+#endif
 		if (copy_msqid_to_user(buf, &tbuf, version))
 			return -EFAULT;
 		return success_return;
@@ -483,12 +581,21 @@
 		break;
 	}
 	case IPC_RMID:
+#ifdef CONFIG_SYSVIPC_DIPC
+		msg_unlock(msq);
+		if(dipc_can_act(msq->q_perm.key, NULL)) {
+		 	if((msq->q_perm.mode & IPC_DIPC) && (msq->q_perm.mode & IPC_OWN))
+		  		dipc_rmid_key(msq->q_perm.key, MSG);
+		}
+		msq = msg_lock(msqid);
+#endif
 		freeque (msq, msqid); 
 		break;
 	}
 	err = 0;
 out_up:
 	up(&msg_ids.sem);
+	
 	return err;
 out_unlock_up:
 	msg_unlock(msq);
@@ -560,11 +667,26 @@
 	
 	if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
 		return -EINVAL;
+
 	if (get_user(mtype, &msgp->mtype))
 		return -EFAULT; 
 	if (mtype < 1)
 		return -EINVAL;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	msq = msg_lock(msqid);
+	if(msq==NULL)
+		return -EINVAL;		
+	msg_unlock(msq);
+	
+	if(dipc_can_act(msq->q_perm.key, current) &&
+	  (msq->q_perm.mode & IPC_DIPC) && 
+	  !(msq->q_perm.mode & IPC_OWN)) {  	
+	  	err = dipc_msgsnd(msq->q_perm.key, msgp, msgsz, msgflg);
+	  	return err;
+	}   
+	
+#endif
 	msg = load_msg(msgp->mtext, msgsz);
 	if(IS_ERR(msg))
 		return PTR_ERR(msg);
@@ -573,7 +695,7 @@
 	msg->m_ts = msgsz;
 
 	msq = msg_lock(msqid);
-	err=-EINVAL;
+	err = -EINVAL;
 	if(msq==NULL)
 		goto out_free;
 
@@ -641,6 +763,7 @@
 out_free:
 	if(msg!=NULL)
 		free_msg(msg);
+
 	return err;
 }
 
@@ -669,6 +792,9 @@
 	struct msg_queue *msq;
 	struct msg_msg *msg;
 	int mode;
+#ifdef CONFIG_SYSVIPC_DIPC
+	int ret;
+#endif	
 
 	if (msqid < 0 || (long) msgsz < 0)
 		return -EINVAL;
@@ -678,6 +804,15 @@
 	if(msq==NULL)
 		return -EINVAL;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+        if(dipc_can_act(msq->q_perm.key, current) &&
+	 	(msq->q_perm.mode & IPC_DIPC) && 
+		!(msq->q_perm.mode & IPC_OWN)) {
+			msg_unlock(msq);
+	  		ret = dipc_msgrcv(msq->q_perm.key, msgp, msgsz, msgtyp, msgflg);
+			return ret;
+	  } 
+#endif	
 	msg = ERR_PTR(-EIDRM);
 	if (msg_checkid(msq,msqid))
 		goto out_unlock;
@@ -771,6 +906,7 @@
 		 * If there is a message or an error then accept it without
 		 * locking.
 		 */
+
 		if(msg != ERR_PTR(-EAGAIN)) {
 			rcu_read_unlock();
 			break;
@@ -832,3 +968,147 @@
 			  msq->q_ctime);
 }
 #endif
+
+#ifdef CONFIG_SYSVIPC_DIPC
+/*****************************/
+/* Implement DIPC's messages */
+
+static int dipc_msgctl(key_t msgkey, int cmd, struct msqid_ds *buff)
+{
+	struct dipc_request *dr;
+	int err;
+
+	/**printk("dipc_msgctl(msqid: %d)\n", msqid);*/
+	err = 0; 
+
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; 
+	dr->info.key = msgkey;
+	dr->info.type = MSG;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_MSGCTL;
+	dr->info.arg1 = msgkey;
+	dr->info.arg2 = cmd;
+	dr->info.arg3 = 0;
+	dr->info.arg4 = 0;
+	dr->info.dsize = 0;
+	dr->info.owner = -1;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	dr->data = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	if((cmd == IPC_SET) || (cmd == IPC_STAT)) {
+		dr->info.dsize = sizeof(struct msqid_ds);
+		dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+		if(dr->data == NULL) {
+			kfree(dr);
+			return -ENOMEM;
+		}
+	}
+	if(cmd == IPC_SET) 
+		if(copy_from_user (dr->data, buff, dr->info.dsize)) {	
+			err= -EFAULT;
+			goto out_free;
+		}	
+	dipc_add_request(dr);
+	err = dr->info.arg1;
+	if(err == 0 && (cmd == IPC_STAT))
+		err = copy_to_user (buff, dr->data, dr->info.dsize);
+out_free:
+	if((cmd == IPC_STAT) || (cmd == IPC_SET))
+		kfree(dr->data);
+	kfree(dr);
+	return err;
+} /* msgctl */
+  
+
+static int dipc_msgsnd(key_t msgkey, const struct msgbuf *msgptr, size_t msgsz, int msgflg)
+{
+	struct dipc_request *dr;
+	int err;
+
+	/**printk("dipc_msgsnd(msqid: %d)\n", msqid);*/
+ 	
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = msgkey;
+	dr->info.type = MSG;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_MSGSND;
+	dr->info.arg1 = msgkey;
+	dr->info.arg2 = msgsz;
+	dr->info.arg3 = msgflg;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = msgsz + sizeof(long);
+	dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+	if(dr->data == NULL) {
+		kfree(dr);
+		return -ENOMEM;
+	}
+	if(copy_from_user (dr->data, msgptr, dr->info.dsize)) {	
+	       err = -EFAULT;
+	       goto out_free;
+	}	       
+ 
+	dipc_add_request(dr);
+
+	err = dr->info.arg1;
+	
+out_free:
+	kfree(dr->data);
+	kfree(dr);
+	return err;
+} /* msgsnd */
+
+
+static int dipc_msgrcv(key_t msgkey, struct msgbuf *msgptr, size_t msgsz, long type, int msgflg)
+{
+	struct dipc_request *dr;
+	int err;
+
+	/**printk("dipc_msgrcv(msqid: %d)\n", msqid);*/
+
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = msgkey;
+	dr->info.type = MSG;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_MSGRCV;
+	dr->info.arg1 = msgkey;
+	dr->info.arg2 = msgsz;
+	dr->info.arg3 = type;
+	dr->info.arg4 = msgflg;
+	dr->info.owner = -1; 
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = msgsz + sizeof(long);
+	dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+
+	if(dr->data == NULL) {
+		kfree(dr);
+		return -ENOMEM;
+	} 
+
+	dipc_add_request(dr);
+
+	err = dr->info.arg1;
+	if(err >= 0)
+		if(copy_to_user (msgptr, dr->data, dr->info.dsize))
+			err = -EFAULT;
+	kfree(dr->data);
+	kfree(dr); 
+	return err;
+}
+
+#endif
\ No newline at end of file
diff -rubBN linux-2.6.15.1/ipc/sem.c linux-2.6.15.1-dipc/ipc/sem.c
--- linux-2.6.15.1/ipc/sem.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/sem.c	2007-02-23 08:37:39.000000000 -0500
@@ -21,7 +21,7 @@
  *   on success as stated in the manual page.
  * - There is some confusion over whether the set of undo adjustments
  *   to be performed at exit should be done in an atomic manner.
- *   That is, if we are attempting to decrement the semval should we queue
+ *   That is, if we are attempting to decrement the semval Fshould we queue
  *   up and wait until we can do so legally?
  *   The original implementation attempted to do this.
  *   The current implementation does not do so. This is because I don't
@@ -61,6 +61,8 @@
  * (c) 2001 Red Hat Inc <alan@redhat.com>
  * Lockless wakeup
  * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
+ *
+ * DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -75,6 +77,9 @@
 #include <linux/audit.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include "util.h"
 
 
@@ -87,6 +92,14 @@
 	ipc_buildid(&sem_ids, id, seq)
 static struct ipc_ids sem_ids;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+static int dipc_semctl(struct sem_array *sma, int semnum, int cmd, union semun arg);
+static int dipc_semop (key_t semkey, struct sembuf *tsops, unsigned nsops);
+extern void dipc_inform_sem_proxy(void);
+extern void dipc_add_sem_proxy(key_t key);
+#endif
+
+
 static int newary (key_t, int, int);
 static void freeary (struct sem_array *sma, int id);
 #ifdef CONFIG_PROC_FS
@@ -176,6 +189,11 @@
 	}
 	memset (sma, 0, size);
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_can_act(key, NULL))
+	 	sma->sem_perm.mode = (semflg & (S_IRWXUGO | IPC_DIPC));
+	else
+#endif		
 	sma->sem_perm.mode = (semflg & S_IRWXUGO);
 	sma->sem_perm.key = key;
 
@@ -213,11 +231,60 @@
 
 	if (nsems < 0 || nsems > sc_semmsl)
 		return -EINVAL;
+
 	down(&sem_ids.sem);
 	
 	if (key == IPC_PRIVATE) {
 		err = newary(key, nsems, semflg);
 	} else if ((id = ipc_findkey(&sem_ids, key)) == -1) {  /* key not used */
+#ifdef CONFIG_SYSVIPC_DIPC	
+ 	       if(dipc_can_act(key, current)) {
+ 			int remote_nsems, result, distrib = semflg & IPC_DIPC;
+ 			result = dipc_search_key(key, SEM, distrib, &remote_nsems); 
+ 			if(result != NOT_FOUND) {
+ 		 		if(((semflg & IPC_DIPC) && (result == FOUND_IPC)) ||
+ 		     		   (!(semflg & IPC_DIPC) && (result == FOUND_DIPC))) {
+ 		  			up(&sem_ids.sem);//dipc_wake(key, SEM, -1);
+ 		  			dipc_commit_key(key, SEM, 0, 0);
+					return -EEXIST;
+ 		 		}
+ 		 		else if((semflg & IPC_DIPC) && (result == FOUND_DIPC)) {  
+ 		 			/* local and remote are DIPC, treat remotely */
+ 		  			result = dipc_test_key(key, SEM, nsems, semflg);
+ 		  			if(result < 0) {
+ 		   				up(&sem_ids.sem);//dipc_wake(key, SEM, -1);
+ 		   				dipc_commit_key(key, SEM, 0, 0);
+						return result;
+ 		  			} 
+ 		 		}
+ 	        	}  
+ 	        	else { /* nothing was found in other machines */
+ 		 		if (!(semflg & IPC_CREAT)) {
+		  			up(&sem_ids.sem);//dipc_wake(key, SEM, -1);
+ 		  			dipc_commit_key(key, SEM, 0, 0);
+					return -ENOENT;
+ 		 		}	
+ 			}
+ 			/* take the size as specified remotely */
+ 			if(remote_nsems)
+ 		 		nsems = remote_nsems;  		  
+ 			id = newary(key, nsems, semflg);
+ 			if(id < 0)
+ 		 		dipc_commit_key(key, SEM, 0, 0);
+ 			else {
+ 		 		sma = sem_lock(id);
+ 		 		if(semflg & IPC_DIPC) { 
+ 		  			if(remote_nsems == 0) /* this is a owner and DIPC */
+ 		   				sma->sem_perm.mode |= IPC_OWN;
+ 		 		}
+				sem_unlock(sma);				    
+ 		 		dipc_commit_key(key, SEM, nsems, sma->sem_perm.mode);
+			}
+ 			err = id;	
+ 	       }
+ 	       else /* no manager */
+#endif
+
 		if (!(semflg & IPC_CREAT))
 			err = -ENOENT;
 		else
@@ -232,6 +299,13 @@
 			err = -EINVAL;
 		else if (ipcperms(&sma->sem_perm, semflg))
 			err = -EACCES;
+#ifdef CONFIG_SYSVIPC_DIPC		
+		else if(dipc_can_act(key, NULL) &&
+		        (((sma->sem_perm.mode & IPC_DIPC) && !(semflg & IPC_DIPC)) ||
+			(!(sma->sem_perm.mode & IPC_DIPC) && (semflg & IPC_DIPC))))
+				err = -EEXIST;
+#endif		
+
 		else {
 			int semid = sem_buildid(id, sma->sem_perm.seq);
 			err = security_sem_associate(sma, semflg);
@@ -446,6 +520,13 @@
 	struct sem_queue *q;
 	int size;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_can_act(sma->sem_perm.key, NULL)) {
+	 	/* if(!(sma->sem_perm.mode & IPC_OWN)) */
+	 	dipc_del_key(sma->sem_perm.key, SEM);
+	} 
+#endif	
+
 	/* Invalidate the existing undo structures for this semaphore set.
 	 * (They will be freed without any further action in exit_sem()
 	 * or during the next semop.)
@@ -468,6 +549,7 @@
 	}
 
 	/* Remove the semaphore set from the ID array*/
+
 	sma = sem_rmid(id);
 	sem_unlock(sma);
 
@@ -475,6 +557,7 @@
 	size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
 	security_sem_free(sma);
 	ipc_rcu_putref(sma);
+
 }
 
 static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
@@ -706,6 +789,9 @@
 		tbuf.sem_ctime  = sma->sem_ctime;
 		tbuf.sem_nsems  = sma->sem_nsems;
 		sem_unlock(sma);
+#ifdef CONFIG_SYSVIPC_DIPC
+ 		tbuf.__unused1 = (unsigned long) dipc_find_owner_address(sma->sem_perm.key, SEM, 1);
+#endif
 		if (copy_semid_to_user (arg.buf, &tbuf, version))
 			return -EFAULT;
 		return 0;
@@ -862,9 +948,31 @@
 	int err = -EINVAL;
 	int version;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	struct sem_array *sma;
+#endif	
+	
 	if (semid < 0)
 		return -EINVAL;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	sma = sem_lock(semid);
+	if(sma==NULL)
+		return -EINVAL;
+	sem_unlock(sma);
+
+	if(dipc_can_act(sma->sem_perm.key, current)) {
+	 	if((cmd == IPC_STAT || cmd == IPC_SET || cmd == GETALL || 
+           	    cmd == SETALL || cmd == IPC_RMID || cmd == GETVAL || 
+                cmd == SETVAL || cmd == GETPID || cmd == GETNCNT || 
+                cmd == GETZCNT) && (sma->sem_perm.mode & IPC_DIPC) && 
+	  	    !(sma->sem_perm.mode & IPC_OWN)) {
+				err = dipc_semctl(sma, semnum, cmd, arg);
+				return err;
+	 	}
+	}
+#endif
+
 	version = ipc_parse_version(&cmd);
 
 	switch(cmd) {
@@ -884,6 +992,18 @@
 		err = semctl_main(semid,semnum,cmd,version,arg);
 		return err;
 	case IPC_RMID:
+#ifdef CONFIG_SYSVIPC_DIPC
+		sma = sem_lock(semid);
+		if(sma==NULL)
+			return -EINVAL;
+		sem_unlock(sma);
+
+		if(dipc_can_act(sma->sem_perm.key, NULL)) {
+		 	if((sma->sem_perm.mode & IPC_DIPC) && (sma->sem_perm.mode & IPC_OWN))
+	  			dipc_rmid_key(sma->sem_perm.key, SEM);
+		}
+#endif
+
 	case IPC_SET:
 		down(&sem_ids.sem);
 		err = semctl_down(semid,semnum,cmd,version,arg);
@@ -1069,6 +1189,22 @@
 		if(sops==NULL)
 			return -ENOMEM;
 	}
+#ifdef CONFIG_SYSVIPC_DIPC
+	sma = sem_lock(semid);
+	error=-EINVAL;
+	if(sma==NULL)
+		goto out_free;
+	sem_unlock(sma);
+
+	if(dipc_can_act(sma->sem_perm.key, current)) {
+	 	if((sma->sem_perm.mode & IPC_DIPC) && 
+	 	   !(sma->sem_perm.mode & IPC_OWN)) {
+			error = dipc_semop(sma->sem_perm.key, tsops, nsops);
+			goto out_free;
+	  	}
+	} 
+#endif	
+
 	if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
 		error=-EFAULT;
 		goto out_free;
@@ -1329,6 +1465,12 @@
 		sem_unlock(sma);
 	}
 	kfree(undo_list);
+#ifdef CONFIG_SYSVIPC_DIPC
+	/* No need to test for IPC_PRIVATE keys */
+	if(dipc_can_act(IPC_PRIVATE + 1, current))
+	 	dipc_inform_sem_proxy();
+#endif
+
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1350,3 +1492,142 @@
 			  sma->sem_ctime);
 }
 #endif
+
+#ifdef CONFIG_SYSVIPC_DIPC
+/*******************************/
+/* Implement DIPC's semaphores */
+
+static int dipc_semctl(struct sem_array *sma, int semnum, int cmd, union semun arg)
+{
+	struct dipc_request *dr;
+	int err, nsems;
+
+	/**printk("dipc_semctl(key: %d)\n", sma->sem_perm.key);*/
+	err = 0;
+	nsems = sma->sem_nsems;
+	
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = sma->sem_perm.key;
+	dr->info.type = SEM;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_SEMCTL;
+	dr->info.arg1 = sma->sem_perm.key;
+	dr->info.arg2 = semnum;
+	dr->info.arg3 = cmd;
+	if(cmd == SETVAL)
+		dr->info.arg4 = arg.val;
+	else
+		dr->info.arg4 = 0;
+	dr->info.owner = -1;   
+	dr->info.dsize = 0;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	dr->data = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	if((cmd == IPC_SET) || (cmd == IPC_STAT))
+		dr->info.dsize = sizeof(struct semid_ds);
+	else if((cmd == GETALL) || (cmd == SETALL))
+		dr->info.dsize = sma->sem_nsems * sizeof(ushort);
+
+	if((cmd == IPC_STAT) || (cmd == IPC_SET) || 
+	   (cmd == GETALL) || (cmd == SETALL)) {
+	 	dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+	 	if(dr->data == NULL) {
+  			kfree(dr);
+			return -ENOMEM;
+ 		}
+ 	}
+	if(cmd == IPC_SET) {
+		if(copy_from_user (dr->data, arg.buf, dr->info.dsize)) {
+			err = -EFAULT;
+			goto out_free;
+		}
+	}	
+	else if(cmd == SETALL)
+		if(copy_from_user (dr->data, arg.array, dr->info.dsize)) {
+			err = -EFAULT;
+			goto out_free;
+		}
+			
+	dipc_add_request(dr); 
+
+	err = dr->info.arg1;
+	if(err >= 0) {
+		if(cmd == IPC_STAT)
+		{       	
+			if(copy_to_user (arg.buf, dr->data, dr->info.dsize)) {
+       				err = -EFAULT;
+				goto out_free;
+			}
+		}	
+		else if(cmd == GETALL)
+			if(copy_to_user (arg.array, dr->data, dr->info.dsize)) {
+		       		err = -EFAULT;
+				goto out_free;
+			}	
+	}
+
+out_free:
+	if((cmd == IPC_STAT) || (cmd == IPC_SET) || 
+	   (cmd == GETALL) || (cmd == SETALL))
+		kfree(dr->data);
+	kfree(dr);
+	return err;
+} /* semctl */
+
+
+static int dipc_semop (key_t semkey, struct sembuf *tsops, unsigned nsops)
+{
+	struct dipc_request *dr;
+	int count, err;
+ 
+	/**printk("dipc_semop(key: %d)\n", sma->sem_perm.key);*/
+
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = semkey;
+	dr->info.type = SEM;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_SEMOP;
+	dr->info.arg1 = semkey;
+	dr->info.arg2 = nsops;
+	dr->info.arg3 = 0;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1;
+	dr->info.dsize = 0;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	dr->data = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	dr->info.dsize = nsops * sizeof(struct sembuf);
+	dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+	if(dr->data == NULL) {
+		kfree(dr);
+		return -ENOMEM;
+	}
+	if(copy_from_user (dr->data, tsops, dr->info.dsize)) {
+		err = -EFAULT;
+		goto out_free;
+	}		
+	for(count = 0; count < nsops; count++)	{
+		if((((struct sembuf *)dr->data)[count]).sem_flg & SEM_UNDO)
+			dipc_add_sem_proxy(semkey);
+	}
+
+	dipc_add_request(dr); 
+
+	err = dr->info.arg1;
+
+out_free:
+	kfree(dr->data);
+	kfree(dr);
+	return err;
+} /* semop */
+
+#endif
+
diff -rubBN linux-2.6.15.1/ipc/shm.c linux-2.6.15.1-dipc/ipc/shm.c
--- linux-2.6.15.1/ipc/shm.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/shm.c	2007-02-23 08:37:39.000000000 -0500
@@ -13,6 +13,7 @@
  * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
  * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
  *
+ * DIPC (C) Kamran Karimi
  */
 
 #include <linux/config.h>
@@ -29,7 +30,9 @@
 #include <linux/audit.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
-
+#ifdef CONFIG_SYSVIPC_DIPC
+#include <linux/dipc.h>
+#endif
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -47,6 +50,16 @@
 #define shm_buildid(id, seq) \
 	ipc_buildid(&shm_ids, id, seq)
 
+#ifdef CONFIG_SYSVIPC_DIPC
+static int dipc_shmctl(key_t key, int cmd, struct shmid_ds *buff);
+extern int dipc_excl(key_t key, int type, int page_num);
+extern int dipc_inhibit_shm_signal, dipc_page_size, dipc_transfer_mode;
+/* from mm/mprotect.c */
+extern void change_protection(struct vm_area_struct *vma,
+		unsigned long addr, unsigned long end, pgprot_t newprot);
+#endif
+
+
 static int newseg (key_t key, int shmflg, size_t size);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
@@ -115,9 +128,20 @@
  */
 static void shm_destroy (struct shmid_kernel *shp)
 {
+
+
 	shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	shm_rmid (shp->id);
 	shm_unlock(shp);
+
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_can_act(shp->shm_perm.key, NULL)) {
+	 	/* if(shp->shm_perm.mode & IPC_OWN)*/
+	 	dipc_del_key(shp->shm_perm.key, SHM);	
+	 	dipc_shm_del(shp->shm_perm.key);
+	} 
+#endif	
+
 	if (!is_file_hugepages(shp->shm_file))
 		shmem_lock(shp->shm_file, 0, shp->mlock_user);
 	else
@@ -126,6 +150,7 @@
 	fput (shp->shm_file);
 	security_shm_free(shp);
 	ipc_rcu_putref(shp);
+
 }
 
 /*
@@ -159,6 +184,9 @@
 {
 	file_accessed(file);
 	vma->vm_ops = &shm_vm_ops;
+#ifdef CONFIG_SYSVIPC_DIPC
+	vma->vm_flags |= VM_SYSVSHM;
+#endif	
 	shm_inc(file->f_dentry->d_inode->i_ino);
 	return 0;
 }
@@ -197,9 +225,15 @@
 		return -ENOMEM;
 
 	shp->shm_perm.key = key;
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_can_act(key, NULL))
+		shp->shm_flags |= (shmflg & (S_IRWXUGO | IPC_DIPC));
+	else
+#endif
 	shp->shm_flags = (shmflg & S_IRWXUGO);
 	shp->mlock_user = NULL;
 
+
 	shp->shm_perm.security = NULL;
 	error = security_shm_alloc(shp);
 	if (error) {
@@ -263,10 +297,75 @@
 	struct shmid_kernel *shp;
 	int err, id = 0;
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	int dipc_mode;
+	int dipc_locked = 0;
+	/* if distributed, use DIPC's lock mechanism, so dipcd can act */
+	if(dipc_can_act(key, current))
+	{	
+		dipc_excl(key, SHM, -1);
+		dipc_locked = 1;
+	}		
+	else
+#endif	
 	down(&shm_ids.sem);
 	if (key == IPC_PRIVATE) {
 		err = newseg(key, shmflg, size);
 	} else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
+#ifdef CONFIG_SYSVIPC_DIPC
+		if(dipc_can_act(key, current)) {
+               		int remote_size, result, distrib = shmflg & IPC_DIPC;
+			result = dipc_search_key(key, SHM, distrib, &remote_size);
+			if(remote_size) {
+		 		if(((shmflg & IPC_DIPC) && (result == FOUND_IPC)) ||
+		     		   (!(shmflg & IPC_DIPC) && (result == FOUND_DIPC))) {
+		 			dipc_commit_key(key, SHM, 0, 0);
+		  			dipc_wake(key, SHM, -1);
+		  			return -EEXIST;
+		 		}
+		 		else if((shmflg & IPC_DIPC) && (result == FOUND_DIPC)) {
+		 			/* local and remote are DIPC, test remotely */
+		  			result = dipc_test_key(key, SHM, size, shmflg);
+		  			if(result < 0) {
+		   				dipc_commit_key(key, SHM, 0, 0);
+		   				dipc_wake(key, SHM, -1);
+		   				return result;
+		  			}
+		 		}
+			}  
+			else { /* nothing was found in other machines */
+		 		if (!(shmflg & IPC_CREAT)) {
+		  			dipc_commit_key(key, SHM, 0, 0);
+		  			dipc_wake(key, SHM, -1);
+		  			return -ENOENT;
+ 		 		}	
+			}
+			/* take the size as specified remotely */
+			if(remote_size)
+		 		size = remote_size;
+			id = newseg(key, shmflg, size);
+			if(id < 0) {
+		 		dipc_commit_key(key, SHM, 0, 0);
+			} 
+			else {
+		 		shp = shm_lock(id);
+		 		if(shmflg & IPC_DIPC) {
+		  			if(remote_size) /* this is not the owner */
+		   				dipc_shm_init(key, 0, remote_size);
+		  			else {
+		   				shp->shm_perm.mode |= IPC_OWN;
+		   				dipc_shm_init(key, 3, size);
+		  			} 
+		 		}
+		 		dipc_mode = shp->shm_perm.mode;
+				shm_unlock(shp);
+		 		dipc_commit_key(key, SHM, size, dipc_mode);  
+			}
+			dipc_wake(key, SHM, -1);
+			return  id;
+	      	}
+	      	else /* no manager */
+#endif
 		if (!(shmflg & IPC_CREAT))
 			err = -ENOENT;
 		else
@@ -281,6 +380,12 @@
 			err = -EINVAL;
 		else if (ipcperms(&shp->shm_perm, shmflg))
 			err = -EACCES;
+#ifdef CONFIG_SYSVIPC_DIPC
+		else if(dipc_can_act(key, NULL) && 
+			(((shp->shm_perm.mode & IPC_DIPC) && !(shmflg & IPC_DIPC)) ||
+			 (!(shp->shm_perm.mode & IPC_DIPC) && (shmflg & IPC_DIPC))))
+			 	err = -EEXIST;
+#endif
 		else {
 			int shmid = shm_buildid(id, shp->shm_perm.seq);
 			err = security_shm_associate(shp, shmflg);
@@ -289,6 +394,11 @@
 		}
 		shm_unlock(shp);
 	}
+#ifdef CONFIG_SYSVIPC_DIPC
+	if(dipc_locked && dipc_can_act(key, current))
+		dipc_wake(key, SHM, -1);
+	else	
+#endif	
 	up(&shm_ids.sem);
 
 	return err;
@@ -426,6 +536,25 @@
 		goto out;
 	}
 
+#ifdef CONFIG_SYSVIPC_DIPC
+	shp = shm_lock(shmid);
+	if(shp==NULL) {
+		err = -EINVAL;
+		goto out;
+	}
+	shm_unlock(shp);
+
+	if(dipc_can_act(shp->shm_perm.key, current)) {
+	 	if((cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_RMID) &&
+	  	   (shp->shm_perm.mode & IPC_DIPC) && 
+	  	   !(shp->shm_perm.mode & IPC_OWN)) {
+			err = dipc_shmctl(shp->shm_perm.key, cmd, buf);
+			return err;
+	 	}
+	}
+#endif
+
+
 	version = ipc_parse_version(&cmd);
 
 	switch (cmd) { /* replace with proc interface ? */
@@ -515,6 +644,9 @@
 		else
 			tbuf.shm_nattch = file_count(shp->shm_file) - 1;
 		shm_unlock(shp);
+#ifdef CONFIG_SYSVIPC_DIPC
+ 		tbuf.__unused1 = (unsigned long)dipc_find_owner_address(shp->shm_perm.key, SHM, 1);
+#endif
 		if(copy_shmid_to_user (buf, &tbuf, version))
 			err = -EFAULT;
 		else
@@ -581,6 +713,17 @@
 		err = -EINVAL;
 		if (shp == NULL) 
 			goto out_up;
+#ifdef CONFIG_SYSVIPC_DIPC
+		if(dipc_can_act(shp->shm_perm.key, NULL)) {
+			if((shp->shm_perm.mode & IPC_DIPC) &&
+	           	   (shp->shm_perm.mode & IPC_OWN)) {
+	           	   	shm_unlock(shp);
+	  			dipc_rmid_key(shp->shm_perm.key, SHM);
+	  			shp = shm_lock(shmid);
+	  		}	
+		} 
+#endif
+
 		err = shm_checkid(shp, shmid);
 		if(err)
 			goto out_unlock_up;
@@ -908,3 +1051,282 @@
 			  shp->shm_ctim);
 }
 #endif
+
+#ifdef CONFIG_SYSVIPC_DIPC
+/**********************************/
+/* Implement DIPC's shared memory */
+
+/* calls the change_protection routine in mm/mprotect.c */
+static void dipc_change_protection(struct vm_area_struct *vma, 
+				pgprot_t newprot, int offset, int mode)
+{
+	unsigned long start, end;
+
+	down_write(&vma->vm_mm->mmap_sem);		
+	if(mode == SEGMENT)
+		change_protection(vma, vma->vm_start, vma->vm_end, newprot);
+	else {
+		start = vma->vm_start + offset;
+		start = start - (offset % dipc_page_size);
+		if(start < vma->vm_start)
+			start = vma->vm_start;
+		end = start + dipc_page_size;
+		if(end > vma->vm_end)
+			end = vma->vm_end;
+		change_protection(vma, start, end, newprot);
+	}
+	vma->vm_page_prot = newprot;
+	up_write(&vma->vm_mm->mmap_sem);		
+	
+}
+
+
+static int dipc_enable_prot(key_t key, int enable_write, int offset, int mode)
+{
+	int id;
+	long signal;
+	struct shmid_kernel *shp;
+	struct task_struct *tsk;
+	struct vm_area_struct *vma;
+	struct address_space *mapping;
+	struct prio_tree_iter iter;
+ 
+	/**printk("dipc_enable_prot(%d, %d, %d, %d)\n", key, enable_write, offset, mode);*/
+
+	id = ipc_findkey(&shm_ids, key);
+	if(id == -1) {
+		printk("dipc_enable_prot(): Can't find the shm id\n");
+		return -EFAULT;
+	}
+
+        shp = shm_lock(id);
+	mapping = shp->shm_file->f_mapping;
+	shm_unlock(shp);
+
+	dipc_shm_enable(key, 1, offset, mode);
+	if(enable_write)
+		dipc_shm_enable(key, 2, offset, mode);
+
+	vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) {
+		read_lock_irq(&tasklist_lock);
+		for_each_process (tsk) {
+			if(tsk->mm == vma->vm_mm)
+				break;
+		}		
+		read_unlock_irq(&tasklist_lock);
+			
+		if(tsk && dipc_can_act(key, tsk)) {
+			pte_t tmp;
+
+			/* always enable to read */
+			signal = DIPC_SIG_READER;
+			tmp = __pte(pgprot_val(vma->vm_page_prot));
+			dipc_change_protection(vma,__pgprot(pte_val(pte_wrprotect(pte_mkread(tmp)))), offset, mode);
+
+			if(enable_write && (vma->vm_flags & VM_MAYWRITE)) {
+				/* only if the segment had this right in the first place */
+				pte_t tmp = __pte(pgprot_val(vma->vm_page_prot));
+				dipc_change_protection(vma,__pgprot(pte_val(pte_mkwrite(tmp))), offset, mode);
+				signal = DIPC_SIG_WRITER;
+			}
+			if(!dipc_inhibit_shm_signal)
+				send_sig(signal, tsk, 1);
+		}
+	}
+	return 0;
+}
+
+
+int dipc_disable_prot(key_t key, int cmd, int *mask)
+{
+	struct shmid_kernel *shp;
+	int id, op[3];
+	struct task_struct *tsk;
+	struct vm_area_struct *vma;
+	pte_t tmp;
+	struct address_space *mapping;
+	struct prio_tree_iter iter;
+
+	/*printk("dipc_disable_prot(%d, %d, %d)\n", key, cmd, *mask);*/
+	if(copy_from_user (&op, mask, 3 * sizeof(int)))
+		return -EFAULT;
+
+	id = ipc_findkey(&shm_ids, key);
+	if(id == -1) {
+		printk("dipc_disable_prot(): Can't find the shm id\n");
+		return -EFAULT;
+	}
+	 	
+	shp = shm_lock(id);
+	if(shp == NULL) {
+		printk("dipc_disable_prot(): Can't find the shp\n");
+		return -EFAULT;
+	}
+	mapping = shp->shm_file->f_mapping;
+	shm_unlock(shp);
+
+	dipc_shm_disable(key, 2, op[1], op[2]);
+	if(op[0] == DISABLE_RD)
+		dipc_shm_disable(key, 1, op[1], op[2]);
+
+	vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) {
+		read_lock_irq(&tasklist_lock);
+		for_each_process (tsk) {
+			if(tsk->mm == vma->vm_mm)
+				break;
+		}		
+		read_unlock_irq(&tasklist_lock);
+		
+		if(tsk && dipc_can_act(key, tsk)) {
+			/* Always write protect, because on some CPUs read-protecting may not
+			imply write-protecting */ 
+
+			tmp = __pte(pgprot_val(vma->vm_page_prot));
+			dipc_change_protection(vma,__pgprot(pte_val(pte_wrprotect(tmp))), op[1], op[2]);
+
+			if(op[0] == DISABLE_RD) { /* read protect */
+				tmp = __pte(pgprot_val(vma->vm_page_prot));
+				dipc_change_protection(vma,__pgprot(pte_val(pte_rdprotect(tmp))), op[1], op[2]);
+			}
+		}
+	}	
+	return DIPC_SUCCESS;
+}
+
+
+int dipc_shm_fault(struct vm_area_struct *vma, unsigned long address, 
+                                                  unsigned long write_access)
+{
+	int id, offset;
+	struct shmid_kernel *shp;
+	struct dipc_request *dr;
+ 	key_t key;
+ 	struct task_struct *tsk;
+ 	struct file * file;
+	struct address_space *mapping;
+ 	int ret = 0;
+ 
+	if(!(vma->vm_flags & VM_MAYWRITE) && write_access) return ret;
+
+        file = vma->vm_file;
+        id = file->f_dentry->d_inode->i_ino;
+        
+	shp = shm_lock(id);
+	if(shp == NULL)
+		return ret;		
+	
+	key = shp->shm_perm.key;
+	mapping = shp->shm_file->f_mapping;
+	shm_unlock(shp);
+
+	if(!(shp->shm_perm.mode & IPC_DIPC))
+		return ret;
+	/**printk("dipc_shm_fault() key %d\n", key);*/
+
+	read_lock_irq(&tasklist_lock);
+	for_each_process (tsk) {
+		if(tsk->mm == vma->vm_mm)	
+			break;
+	}
+	read_unlock_irq(&tasklist_lock);
+	
+ 	if(tsk && dipc_can_act(key, tsk)) { 
+		offset = address - vma->vm_start;
+		dipc_excl(key, SHM, offset / dipc_page_size);
+		if(!dipc_shm_readable(key, offset) || (!dipc_shm_writable(key, offset) && write_access)) {
+			dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+			if(dr == NULL) { 
+				dipc_wake(key, SHM, offset / dipc_page_size);
+				return ret; /* bad error */
+			}
+			dr->info.key = key;
+			dr->info.type = SHM;
+			dr->info.pid = current->pid;
+			dr->info.uid = current->uid;
+			if(write_access)
+				dr->info.func = WANTWR;
+			else
+				dr->info.func = WANTRD;
+			dr->info.arg1 = key;
+			dr->info.arg2 = offset; /*32 bits should be enough*/
+			dr->info.arg3 = dipc_transfer_mode;
+			dr->info.arg4 = 0;
+			dr->info.owner = -1;
+			dr->working = 0;
+			dr->next = dr->prev = NULL;
+			init_MUTEX_LOCKED(&dr->sem);
+			dr->info.dsize = 0;
+			dr->data = NULL;
+
+			up_read(&vma->vm_mm->mmap_sem);
+			dipc_add_request(dr);
+
+			if(dr->info.arg1 < 0)
+				send_sig(SIGSEGV, current, 1);
+			else
+				dipc_enable_prot(key, write_access, offset, dr->info.arg3);  
+			kfree(dr);
+			ret = 1;
+			down_read(&vma->vm_mm->mmap_sem);
+		}
+		dipc_wake(key, SHM, offset / dipc_page_size);
+	}
+	return ret;       	
+}
+
+
+static int dipc_shmctl(key_t shmkey, int cmd, struct shmid_ds *buff)
+{
+	struct dipc_request *dr;
+	int ret;
+ 
+	/**printk("dipc_shmctl(shmid: %d, cmd: %d)\n", shmid, cmd);*/
+	ret = 0;
+
+	dr = kmalloc(sizeof(struct dipc_request), GFP_KERNEL);
+	if(dr == NULL) 
+		return -ENOMEM; /* set errno */
+	dr->info.key = shmkey;
+	dr->info.type = SHM;
+	dr->info.pid = current->pid;
+	dr->info.uid = current->uid;
+	dr->info.func = DIPC_SHMCTL;
+	dr->info.arg1 = shmkey;
+	dr->info.arg2 = cmd;
+	dr->info.arg3 = 0;
+	dr->info.arg4 = 0;
+	dr->info.owner = -1; 
+	dr->info.dsize = 0;
+	dr->working = 0;
+	dr->next = dr->prev = NULL;
+	dr->data = NULL;
+	init_MUTEX_LOCKED(&dr->sem);
+	if(cmd == IPC_SET || cmd == IPC_STAT) {
+ 		dr->info.dsize = sizeof(struct shmid_ds);
+ 		dr->data = kmalloc(dr->info.dsize, GFP_KERNEL);
+ 		if(dr->data == NULL) {
+  			kfree(dr);
+  			return -ENOMEM;
+ 		}
+	}
+	if(cmd == IPC_SET)
+ 		if(copy_from_user (dr->data, buff, dr->info.dsize)) {
+			ret = -EFAULT;
+			goto out_free;
+		}	
+
+	dipc_add_request(dr); 
+	
+	ret = dr->info.arg1;
+	if(ret == 0 && cmd == IPC_STAT)
+		if(copy_to_user (buff, dr->data, dr->info.dsize))
+			ret = -EFAULT;
+
+out_free:
+	if(cmd == IPC_STAT || cmd == IPC_SET)
+ 		kfree(dr->data);
+	kfree(dr);
+	return ret;
+} /* shmctl */
+
+#endif
diff -rubBN linux-2.6.15.1/ipc/util.c linux-2.6.15.1-dipc/ipc/util.c
--- linux-2.6.15.1/ipc/util.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/ipc/util.c	2007-02-23 08:37:39.000000000 -0500
@@ -2,6 +2,8 @@
  * linux/ipc/util.c
  * Copyright (C) 1992 Krishna Balasubramanian
  *
+ * DIPC (C) Kamran Karimi  
+ *
  * Sep 1997 - Call suser() last after "normal" permission checks so we
  *            get BSD style process accounting right.
  *            Occurs in several places in the IPC code.
@@ -45,11 +47,18 @@
  *	memory are initialised
  */
  
+#ifdef CONFIG_SYSVIPC_DIPC
+extern void dipc_init(void);
+#endif
+
 static int __init ipc_init(void)
 {
 	sem_init();
 	msg_init();
 	shm_init();
+#ifdef CONFIG_SYSVIPC_DIPC
+	dipc_init();
+#endif	
 	return 0;
 }
 __initcall(ipc_init);
diff -rubBN linux-2.6.15.1/mm/mprotect.c linux-2.6.15.1-dipc/mm/mprotect.c
--- linux-2.6.15.1/mm/mprotect.c	2006-01-15 01:16:02.000000000 -0500
+++ linux-2.6.15.1-dipc/mm/mprotect.c	2007-02-23 08:37:39.000000000 -0500
@@ -78,8 +78,13 @@
 	} while (pud++, addr = next, addr != end);
 }
 
+#ifdef CONFIG_SYSVIPC_DIPC
+void change_protection(struct vm_area_struct *vma,
+		unsigned long addr, unsigned long end, pgprot_t newprot)
+#else
 static void change_protection(struct vm_area_struct *vma,
 		unsigned long addr, unsigned long end, pgprot_t newprot)
+#endif
 {
 	struct mm_struct *mm = vma->vm_mm;
 	pgd_t *pgd;
