#ifndef _S_CONTEXT_H_

#define _S_CONTEXT_H_

#include <asm/atomic.h>
#include <linux/types.h>
#include <linux/utsname.h>

/*
        We may have a different domainname and nodename for each security
        context. By default, a security context share the same as its
        parent, potentially the information in system_utsname
*/
#define S_CTX_INFO_LOCK         1       /* Can't request a new s_context */
#define S_CTX_INFO_SCHED        2       /* All process in the s_context */
                                        /* Contribute to the schedular */
#define S_CTX_INFO_NPROC        4       /* Limit number of processes in a context */
#define S_CTX_INFO_PRIVATE      8       /* Noone can join this security context */
#define S_CTX_INFO_INIT         16      /* This process wants to become the */
                                        /* logical process 1 of the security */
                                        /* context */
#define NB_IPV4ROOT             16
#define NB_S_CONTEXT            16
#define VSERVER_VERSION         "ctx-12"
#define MAX_S_CONTEXT           65535   /* Arbitrary limit */
#define MAX_S_CONTEXT_SLEEP     HZ/10
/*
#define S_CONTEXT_DEBUG 1
#define S_CONTEXT_DEBUG_LIST 1
*/
struct task_box
{
    struct task_box *next;
    struct task_struct *task;
};

struct s_context
{
    struct s_context *prev;
    struct s_context *next;
    /****************************/
    int id;
    /* root is allowed to switch the current */
    /* security context using any in this table */
    char nodename[sizeof(system_utsname.nodename)];
    char domainname[sizeof(system_utsname.domainname)];

    int flags;               /* S_CTX_INFO_xxx */
    __u32 cap_bset;          /* Maximum capability of this context and children */
    int nbipv4;
    __u32 ipv4[NB_IPV4ROOT]; /* Process can only bind to these IPs */
                             /* The first one is used to connect */
                             /* and for bind any service */
                             /* The other must be used explicity when */
                             /* binding */
    __u32 v4_bcast;          /* Broadcast address used to receive UDP packets */
    int initpid;             /* PID of the logical process 1 of the */
    unsigned int PROC_RLIMIT; /* processes limit on context */
    atomic_t sleeptime;

    /* statistic */
    atomic_t ticks;          /* Number of ticks used by all process */
                             /* in the s_context */

    rwlock_t tasks_lock;
    unsigned int task_count;
    struct task_box *tasklist;

    rwlock_t socket_lock;
    unsigned int socket_count;
};

extern struct s_context root_context;
extern rwlock_t s_context_lock;

#define INIT_S_CONTEXT \
{                           \
prev:                  NULL,\
next:                  NULL,\
id:                    0,\
nodename:              {0},\
domainname:            {0},\
flags:                 0,\
cap_bset:              CAP_INIT_EFF_SET,\
nbipv4:                0,\
ipv4:                  {0},\
v4_bcast:              ~0,\
initpid:               1,\
PROC_RLIMIT:           0,\
sleeptime:             {0},\
ticks:                 {0},\
tasks_lock:            RW_LOCK_UNLOCKED, \
task_count:            0,\
tasklist:              NULL,\
socket_lock:           RW_LOCK_UNLOCKED,\
socket_count:          0 \
}

#define for_each_s_context(p) \
 for(p = &root_context; (p=p->next) != &root_context; )

#define check_s_context_proc_limit(p) \
 (p != NULL) && ( (p->flags & S_CTX_INFO_NPROC)!=0 ) \
             && ( p->task_count >=p->PROC_RLIMIT )

#define for_each_task_in_context(ctx,task) \
 for( task = ctx->tasklist; task != NULL; task = task -> next )


/* syscall */
int sys_new_s_context(int ctx, __u32 remove_cap, int flags);
int sys_set_ipv4root (__u32 ip[], int nbip, __u32 bcast);
/***********************/
/* new api*/
void context_procfs_init(void);
void s_context_init(void);
/* work with task list locked */
void s_context_addtask(unsigned int context,struct task_struct *task);
void s_context_deltask(struct task_struct *task);

#endif
