diff -rc2P linux-2.4.19ctx-14/Makefile linux-2.4.19ctx-15/Makefile
*** linux-2.4.19ctx-14/Makefile Sat Dec  7 09:56:39 2002
--- linux-2.4.19ctx-15/Makefile Fri Nov  1 11:56:40 2002
***************
*** 2,6 ****
 PATCHLEVEL = 4
 SUBLEVEL = 19
! EXTRAVERSION =ctx-14

 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
--- 2,6 ----
 PATCHLEVEL = 4
 SUBLEVEL = 19
! EXTRAVERSION =ctx-15

 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff -rc2P linux-2.4.19ctx-14/fs/proc/array.c linux-2.4.19ctx-15/fs/proc/array.c
*** linux-2.4.19ctx-14/fs/proc/array.c  Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/fs/proc/array.c  Tue Nov 19 15:38:19 2002
***************
*** 333,336 ****
--- 333,338 ----
               buffer += sprintf (buffer,"ipv4root_bcast: %08x\n"
                       ,task->ip_info->v4_bcast);
+               buffer += sprintf (buffer,"ipv4root_refcnt: %d\n"
+                       ,task->ip_info->refcount);
       }else{
               buffer += sprintf (buffer,"ipv4root: 0\n");
diff -rc2P linux-2.4.19ctx-14/include/linux/sched.h linux-2.4.19ctx-15/include/linux/sched.h
*** linux-2.4.19ctx-14/include/linux/sched.h    Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/include/linux/sched.h    Thu Nov 28 00:05:24 2002
***************
*** 1005,1010 ****
 void sys_assign_s_info (struct task_struct *);
 void sys_alloc_s_info (void);
! void sys_release_ip_info (struct task_struct *);
! void sys_assign_ip_info (struct task_struct *);
 void sys_alloc_ip_info (void);

--- 1005,1010 ----
 void sys_assign_s_info (struct task_struct *);
 void sys_alloc_s_info (void);
! void sys_release_ip_info (struct iproot_info *);
! void sys_assign_ip_info (struct iproot_info *);
 void sys_alloc_ip_info (void);

diff -rc2P linux-2.4.19ctx-14/include/net/sock.h linux-2.4.19ctx-15/include/net/sock.h
*** linux-2.4.19ctx-14/include/net/sock.h       Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/include/net/sock.h       Sat Dec  7 01:19:32 2002
***************
*** 488,491 ****
--- 488,492 ----

 struct sock {
+       /* See tcp.h comment on tcp_tw_bucket */
       /* Socket demultiplex comparisons on incoming packets. */
       __u32                   daddr;          /* Foreign IPv4 addr                    */
***************
*** 509,512 ****
--- 510,515 ----
       unsigned char           shutdown;
       atomic_t                refcnt;         /* Reference count                      */
+       struct iproot_info      *ip_info;
+       /* End of common section with tcp_tw_bucket */

       socket_lock_t           lock;           /* Synchronizer...                      */
***************
*** 526,530 ****
       unsigned int            allocation;     /* Allocation mode                      */
       int                     sndbuf;         /* Size of send buffer in bytes         */
!       __u32                   bcast_addr;     /* Local bcast addr, for ipv4root */
       struct sock             *prev;

--- 529,533 ----
       unsigned int            allocation;     /* Allocation mode                      */
       int                     sndbuf;         /* Size of send buffer in bytes         */
!       __u32                   rcv_saddr2;     /* Second bound ipv4 addr, for ipv4root */
       struct sock             *prev;

diff -rc2P linux-2.4.19ctx-14/include/net/tcp.h linux-2.4.19ctx-15/include/net/tcp.h
*** linux-2.4.19ctx-14/include/net/tcp.h        Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/include/net/tcp.h        Sat Dec  7 01:31:51 2002
***************
*** 173,176 ****
--- 173,177 ----
                               rcv_wscale; /* It is also TW bucket specific */
       atomic_t                refcnt;
+       struct ipv4_info        *ip_info;

       /* And these are ours. */
diff -rc2P linux-2.4.19ctx-14/kernel/exit.c linux-2.4.19ctx-15/kernel/exit.c
*** linux-2.4.19ctx-14/kernel/exit.c    Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/kernel/exit.c    Wed Nov 20 14:48:07 2002
***************
*** 68,72 ****
                       current->counter = MAX_COUNTER;
               sys_release_s_info(p);
!               sys_release_ip_info(p);
               p->pid = 0;
               free_task_struct(p);
--- 68,72 ----
                       current->counter = MAX_COUNTER;
               sys_release_s_info(p);
!               sys_release_ip_info(p->ip_info);
               p->pid = 0;
               free_task_struct(p);
diff -rc2P linux-2.4.19ctx-14/kernel/fork.c linux-2.4.19ctx-15/kernel/fork.c
*** linux-2.4.19ctx-14/kernel/fork.c    Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/kernel/fork.c    Thu Nov 28 00:07:02 2002
***************
*** 619,623 ****

       sys_assign_s_info (p);
!       sys_assign_ip_info (p);

       atomic_inc(&p->user->__count);
--- 619,623 ----

       sys_assign_s_info (p);
!       sys_assign_ip_info (p->ip_info);

       atomic_inc(&p->user->__count);
diff -rc2P linux-2.4.19ctx-14/kernel/sys.c linux-2.4.19ctx-15/kernel/sys.c
*** linux-2.4.19ctx-14/kernel/sys.c     Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/kernel/sys.c     Fri Dec  6 23:52:43 2002
***************
*** 1089,1117 ****
       }
 }
 /*
!       Decrease the reference count on the ip_info member of a task
       Free the struct if the reference count reach 0.
 */
! void sys_release_ip_info (struct task_struct *p)
 {
!       down_write (&uts_sem);
!       if (p->ip_info != NULL){
!               p->ip_info->refcount--;
!               if (p->ip_info->refcount == 0){
                       // printk ("vfree s_info %d\n",p->pid);
!                       vfree (p->ip_info);
!                       p->ip_info = NULL;
               }
       }
-       up_write (&uts_sem);
 }
 /*
       Increase the reference count on the ip_info member of a task
 */
! void sys_assign_ip_info (struct task_struct *p)
 {
!       down_write (&uts_sem);
!       if (p->ip_info != NULL) p->ip_info->refcount++;
!       up_write (&uts_sem);
 }

--- 1089,1119 ----
       }
 }
+
 /*
!       Decrease the reference count on the ip_info struct
       Free the struct if the reference count reach 0.
 */
! void sys_release_ip_info (struct iproot_info *ip_info)
 {
!       if (ip_info != NULL){
!               down_write (&uts_sem);
!               ip_info->refcount--;
!               if (ip_info->refcount == 0){
                       // printk ("vfree s_info %d\n",p->pid);
!                       vfree (ip_info);
               }
+               up_write (&uts_sem);
       }
 }
 /*
       Increase the reference count on the ip_info member of a task
 */
! void sys_assign_ip_info (struct iproot_info *ip_info)
 {
!       if (ip_info != NULL){
!               down_write (&uts_sem);
!               ip_info->refcount++;
!               up_write (&uts_sem);
!       }
 }

***************
*** 1126,1130 ****
       memset (ip_info,0,sizeof(*ip_info));
       ip_info->refcount = 1;
!       sys_release_ip_info (current);
       current->ip_info = ip_info;
 }
--- 1128,1132 ----
       memset (ip_info,0,sizeof(*ip_info));
       ip_info->refcount = 1;
!       sys_release_ip_info (current->ip_info);
       current->ip_info = ip_info;
 }
diff -rc2P linux-2.4.19ctx-14/net/ipv4/af_inet.c linux-2.4.19ctx-15/net/ipv4/af_inet.c
*** linux-2.4.19ctx-14/net/ipv4/af_inet.c       Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/net/ipv4/af_inet.c       Thu Nov 28 00:04:52 2002
***************
*** 178,181 ****
--- 178,183 ----
       if (sk->protinfo.af_inet.opt)
               kfree(sk->protinfo.af_inet.opt);
+       sys_release_ip_info (sk->ip_info);
+       sk->ip_info = NULL;
       dst_release(sk->dst_cache);
 #ifdef INET_REFCNT_DEBUG
***************
*** 395,398 ****
--- 397,401 ----

       sk->s_context = current->s_context;
+       sk->ip_info = NULL;

 #ifdef INET_REFCNT_DEBUG
***************
*** 480,486 ****
       int chk_addr_ret;
       int err;
!       __u32 s_addr;
!       __u32 bcast_addr = 0xffffffffl;
!       __u32 ipv4root;

       /* If the socket has its own bind function then use it. (RAW) */
--- 483,491 ----
       int chk_addr_ret;
       int err;
!       __u32 s_addr;   /* Address used for validation */
!       __u32 s_addr1;
!       __u32 s_addr2 = 0xffffffffl;    /* Optional address of the socket */
!                                       /* bcast in ipv4root world */
!       struct iproot_info *ip_info;

       /* If the socket has its own bind function then use it. (RAW) */
***************
*** 491,518 ****
               return -EINVAL;

!       s_addr = addr->sin_addr.s_addr;
!       ipv4root = current->ip_info != NULL ? current->ip_info->ipv4[0] : 0;
!       if (ipv4root != 0){
               // printk ("ipv4root0 %08lx %08x\n",ipv4root,s_addr);
-               __u32 v4_bcast =  current->ip_info->v4_bcast;
               if (s_addr == 0){
                       s_addr = ipv4root;
!                       bcast_addr = v4_bcast;
               }else if (s_addr == 0x0100007f){
!                       s_addr = ipv4root;
               }else if (s_addr != v4_bcast
                       && s_addr != ipv4root){
                       int i;
-                       int nbipv4 = current->ip_info->nbipv4;
                       for (i=0; i<nbipv4; i++){
!                               if (s_addr == current->ip_info->ipv4[i]){
                                       break;
                               }
                       }
                       if (i == nbipv4) return -EADDRNOTAVAIL;
               }
       }
       chk_addr_ret = inet_addr_type(s_addr);
-       // printk ("ipv4root %08lx %08x %d\n",ipv4root,s_addr,chk_addr_ret);

       /* Not specified by any standard per-se, however it breaks too
--- 496,533 ----
               return -EINVAL;

!       s_addr = s_addr1 = addr->sin_addr.s_addr;
!       ip_info = current->ip_info;
!       if (ip_info != NULL){
!               __u32 v4_bcast = ip_info->v4_bcast;
!               __u32 ipv4root = ip_info->ipv4[0];
!               int nbipv4 = ip_info->nbipv4;
               // printk ("ipv4root0 %08lx %08x\n",ipv4root,s_addr);
               if (s_addr == 0){
                       s_addr = ipv4root;
!                       if (nbipv4 > 1){
!                               s_addr1 = 0;
!                       }else{
!                               s_addr1 = ipv4root;
!                               ip_info = NULL;
!                       }
!                       s_addr2 = v4_bcast;
               }else if (s_addr == 0x0100007f){
!                       s_addr = s_addr1 = ipv4root;
!                       ip_info = NULL;
               }else if (s_addr != v4_bcast
                       && s_addr != ipv4root){
                       int i;
                       for (i=0; i<nbipv4; i++){
!                               if (s_addr == ip_info->ipv4[i]){
                                       break;
                               }
                       }
                       if (i == nbipv4) return -EADDRNOTAVAIL;
+                       ip_info = NULL;
               }
+               //printk ("bind: ip_info != NULL, s_addr %x, s_addr1 %x, s_addr2 %x\n"
+               //      ,s_addr,s_addr1,s_addr2);
       }
       chk_addr_ret = inet_addr_type(s_addr);

       /* Not specified by any standard per-se, however it breaks too
***************
*** 550,555 ****
               goto out;

!       sk->rcv_saddr = sk->saddr = s_addr;
!       sk->bcast_addr = bcast_addr;
       if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
               sk->saddr = 0;  /* Use device */
--- 565,572 ----
               goto out;

!       sk->rcv_saddr = sk->saddr = s_addr1;
!       sk->rcv_saddr2 = s_addr2;
!       sk->ip_info = ip_info;
!       if (ip_info != NULL) sys_assign_ip_info (ip_info);
       if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
               sk->saddr = 0;  /* Use device */
***************
*** 558,561 ****
--- 575,580 ----
       if (sk->prot->get_port(sk, snum) != 0) {
               sk->saddr = sk->rcv_saddr = 0;
+               sk->ip_info = NULL;
+               sys_release_ip_info (ip_info);
               err = -EADDRINUSE;
               goto out;
diff -rc2P linux-2.4.19ctx-14/net/ipv4/raw.c linux-2.4.19ctx-15/net/ipv4/raw.c
*** linux-2.4.19ctx-14/net/ipv4/raw.c   Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/net/ipv4/raw.c   Wed Nov 27 23:33:36 2002
***************
*** 97,100 ****
--- 97,132 ----
 }

+
+ /*
+       Check if an address is in the list
+ */
+ static inline int raw_addr_in_list (
+       u32 rcv_saddr1,
+       u32 rcv_saddr2,
+       u32 loc_addr,
+       struct iproot_info *ip_info)
+ {
+       int ret = 0;
+       if (loc_addr != 0
+               && (rcv_saddr1 == loc_addr || rcv_saddr2 == loc_addr)){
+               ret = 1;
+       }else if (rcv_saddr1 == 0){
+               /* Accept any address or only the one in the list */
+               if (ip_info == NULL){
+                       ret = 1;
+               }else{
+                       int n = ip_info->nbipv4;
+                       int i;
+                       for (i=0; i<n; i++){
+                               if (ip_info->ipv4[i] == loc_addr){
+                                       ret = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       return ret;
+ }
+
 struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
                            unsigned long raddr, unsigned long laddr,
***************
*** 102,110 ****
 {
       struct sock *s = sk;
-
       for (s = sk; s; s = s->next) {
               if (s->num == num                               &&
                   !(s->daddr && s->daddr != raddr)            &&
!                   !(s->rcv_saddr && s->rcv_saddr != laddr)    &&
                   !(s->bound_dev_if && s->bound_dev_if != dif))
                       break; /* gotcha */
--- 134,142 ----
 {
       struct sock *s = sk;
       for (s = sk; s; s = s->next) {
               if (s->num == num                               &&
                   !(s->daddr && s->daddr != raddr)            &&
!                   raw_addr_in_list(s->rcv_saddr,s->rcv_saddr2,laddr,s->ip_info) &&
! //                !(s->rcv_saddr && s->rcv_saddr != laddr)    &&
                   !(s->bound_dev_if && s->bound_dev_if != dif))
                       break; /* gotcha */
diff -rc2P linux-2.4.19ctx-14/net/ipv4/tcp_ipv4.c linux-2.4.19ctx-15/net/ipv4/tcp_ipv4.c
*** linux-2.4.19ctx-14/net/ipv4/tcp_ipv4.c      Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/net/ipv4/tcp_ipv4.c      Tue Nov 19 16:38:22 2002
***************
*** 175,178 ****
--- 175,228 ----
 }

+ /*
+       Return 1 if addr match the socket IP list
+       or the socket is INADDR_ANY
+ */
+ static inline int tcp_in_list (struct sock *sk, u32 addr)
+ {
+       int ret = 0;
+       struct iproot_info *ip_info = sk->ip_info;
+       if (ip_info != NULL){
+               int n = ip_info->nbipv4;
+               int i;
+               for (i=0; i<n; i++){
+                       if (ip_info->ipv4[i] == addr){
+                               ret = 1;
+                               break;
+                       }
+               }
+       }else if (!sk->rcv_saddr || sk->rcv_saddr == addr){
+               ret = 1;
+       }
+       return ret;
+ }
+
+ /*
+       Check if the addresses in sk1 conflict with those in sk2
+ */
+ int tcp_ipv4_addr_conflict (struct sock *sk1, struct sock *sk2)
+ {
+       int ret = 0;
+       if (sk1->rcv_saddr){
+               /* Bind to one address only */
+               ret = tcp_in_list (sk2,sk1->rcv_saddr);
+       }else if (sk1->ip_info != NULL){
+               /* A restricted bind(any) */
+               struct iproot_info *ip_info = sk1->ip_info;
+               int n = ip_info->nbipv4;
+               int i;
+               for (i=0; i<n; i++){
+                       if (tcp_in_list (sk2,ip_info->ipv4[i])){
+                               ret = 1;
+                               break;
+                       }
+               }
+       }else{
+               /* A bind(any) do not allow other bind on the same port */
+               ret = 1;
+       }
+       return ret;
+ }
+
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
 {
***************
*** 187,193 ****
                           !sk2->reuse ||
                           sk2->state == TCP_LISTEN) {
!                               if (!sk2->rcv_saddr     ||
!                                   !sk->rcv_saddr      ||
!                                   (sk2->rcv_saddr == sk->rcv_saddr))
                                       break;
                       }
--- 237,241 ----
                           !sk2->reuse ||
                           sk2->state == TCP_LISTEN) {
!                               if (tcp_ipv4_addr_conflict(sk,sk2))
                                       break;
                       }
***************
*** 408,411 ****
--- 456,490 ----
 }

+ /*
+       Check if an address is in the list
+ */
+ static inline int tcp_addr_in_list (
+       u32 rcv_saddr,
+       u32 daddr,
+       struct iproot_info *ip_info)
+ {
+       int ret = 0;
+       if (rcv_saddr == daddr){
+               ret = 1;
+       }else if (rcv_saddr == 0){
+               /* Accept any address or only the one in the list */
+               if (ip_info == NULL){
+                       ret = 1;
+               }else{
+                       int n = ip_info->nbipv4;
+                       int i;
+                       for (i=0; i<n; i++){
+                               if (ip_info->ipv4[i] == daddr){
+                                       ret = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       return ret;
+ }
+
+
+
 /* Don't inline this cruft.  Here are some nice properties to
  * exploit here.  The BSD API does not allow a listening TCP
***************
*** 425,432 ****

                       score = 1;
!                       if(rcv_saddr) {
!                               if (rcv_saddr != daddr)
!                                       continue;
                               score++;
                       }
                       if (sk->bound_dev_if) {
--- 504,511 ----

                       score = 1;
!                       if (tcp_addr_in_list(rcv_saddr,daddr,sk->ip_info)){
                               score++;
+                       }else{
+                               continue;
                       }
                       if (sk->bound_dev_if) {
***************
*** 456,460 ****
               if (sk->num == hnum &&
                   sk->next == NULL &&
!                   (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
                   !sk->bound_dev_if)
                       goto sherry_cache;
--- 535,539 ----
               if (sk->num == hnum &&
                   sk->next == NULL &&
!                   tcp_addr_in_list(sk->rcv_saddr,daddr,sk->ip_info) &&
                   !sk->bound_dev_if)
                       goto sherry_cache;
diff -rc2P linux-2.4.19ctx-14/net/ipv4/tcp_minisocks.c linux-2.4.19ctx-15/net/ipv4/tcp_minisocks.c
*** linux-2.4.19ctx-14/net/ipv4/tcp_minisocks.c Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/net/ipv4/tcp_minisocks.c Sat Dec  7 01:20:15 2002
***************
*** 382,385 ****
--- 382,386 ----

               tw->s_context   = sk->s_context;
+               tw->ip_info     = NULL;

 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
***************
*** 652,655 ****
--- 653,657 ----

               memcpy(newsk, sk, sizeof(*newsk));
+               sys_assign_ip_info (newsk->ip_info);
               newsk->state = TCP_SYN_RECV;

diff -rc2P linux-2.4.19ctx-14/net/ipv4/udp.c linux-2.4.19ctx-15/net/ipv4/udp.c
*** linux-2.4.19ctx-14/net/ipv4/udp.c   Sat Dec  7 09:56:40 2002
--- linux-2.4.19ctx-15/net/ipv4/udp.c   Tue Nov 19 17:11:03 2002
***************
*** 107,110 ****
--- 107,113 ----
 int udp_port_rover;

+ int tcp_ipv4_addr_conflict (struct sock *sk1, struct sock *sk2);
+
+
 static int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
***************
*** 161,167 ****
                           sk2 != sk &&
                           sk2->bound_dev_if == sk->bound_dev_if &&
!                           (!sk2->rcv_saddr ||
!                            !sk->rcv_saddr ||
!                            sk2->rcv_saddr == sk->rcv_saddr) &&
                           (!sk2->reuse || !sk->reuse))
                               goto fail;
--- 164,168 ----
                           sk2 != sk &&
                           sk2->bound_dev_if == sk->bound_dev_if &&
!                           tcp_ipv4_addr_conflict (sk2,sk) &&
                           (!sk2->reuse || !sk->reuse))
                               goto fail;
***************
*** 206,209 ****
--- 207,224 ----
 }

+ static int udp_in_list (struct iproot_info *ip_info, u32 addr)
+ {
+       int ret = 0;
+       int n = ip_info->nbipv4;
+       int i;
+       for (i=0; i<n; i++){
+               if (ip_info->ipv4[i] == addr){
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+ }
+
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
***************
*** 222,225 ****
--- 237,246 ----
                                       continue;
                               score++;
+                       }else if (sk->ip_info != NULL){
+                               if (udp_in_list (sk->ip_info,daddr)){
+                                       score++;
+                               }else{
+                                       continue;
+                               }
                       }
                       if(sk->daddr) {
***************
*** 262,265 ****
--- 283,287 ----
 }

+
 static inline struct sock *udp_v4_mcast_next(struct sock *sk,
                                            u16 loc_port, u32 loc_addr,
***************
*** 273,277 ****
                   (s->daddr && s->daddr!=rmt_addr)                    ||
                   (s->dport != rmt_port && s->dport != 0)                     ||
!                   (s->rcv_saddr  && s->rcv_saddr != loc_addr && s->bcast_addr != loc_addr)            ||
                   (s->bound_dev_if && s->bound_dev_if != dif))
                       continue;
--- 295,299 ----
                   (s->daddr && s->daddr!=rmt_addr)                    ||
                   (s->dport != rmt_port && s->dport != 0)                     ||
!                   (s->rcv_saddr  && s->rcv_saddr != loc_addr && s->rcv_saddr2 != loc_addr)    ||
                   (s->bound_dev_if && s->bound_dev_if != dif))
                       continue;
***************
*** 518,521 ****
--- 540,561 ----

       if (rt == NULL) {
+               struct iproot_info *ip_info = current->ip_info;
+               if (ip_info != NULL) {
+                       __u32 ipv4root = ip_info->ipv4[0];
+                       if (ipv4root != 0){
+                               if (daddr == 0x0100007f && current->s_context != 0){
+                                       daddr = ipv4root;
+                               }
+                               if (ufh.saddr == 0){
+                                       ufh.saddr = ipv4root;
+                               }
+                               #if 0
+                               else if (!udp_in_list(ip_info,ufh.saddr)){
+                                       err = EADDRNOTAVAIL;
+                                       goto out;
+                               }
+                               #endif
+                       }
+               }
               err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
               if (err)