1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #ifndef _IPC_IMPL_H
  26 #define _IPC_IMPL_H
  27 
  28 #include <sys/types.h>
  29 #include <sys/ipc.h>
  30 #include <sys/mutex.h>
  31 #include <sys/ipc_rctl.h>
  32 #include <sys/project.h>
  33 #include <sys/zone.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/avl.h>
  36 #include <sys/id_space.h>
  37 #include <sys/cred.h>
  38 #include <sys/list.h>
  39 
  40 #ifdef  __cplusplus
  41 extern "C" {
  42 #endif
  43 
  44 typedef uint64_t ipc_time_t;
  45 
  46 /* For xxxctl64 */
  47 #define IPC_SET64       13      /* set options */
  48 #define IPC_STAT64      14      /* get options */
  49 
  50 /*
  51  * There are two versions of the userland ipc_perm structure:
  52  *   ipc_perm     - the version used by user applications and by the kernel
  53  *                  when the user and kernel data models match (in ipc.h)
  54  *   ipc_perm32   - the 64-bit kernel's view of a 32-bit struct ipc_perm
  55  */
  56 #if     defined(_SYSCALL32)
  57 struct ipc_perm32 {
  58         uid32_t         uid;    /* owner's user id */
  59         gid32_t         gid;    /* owner's group id */
  60         uid32_t         cuid;   /* creator's user id */
  61         gid32_t         cgid;   /* creator's group id */
  62         mode32_t        mode;   /* access modes */
  63         uint32_t        seq;    /* slot usage sequence number */
  64         key32_t         key;    /* key */
  65         int32_t         pad[4]; /* reserve area */
  66 };
  67 #endif  /* _SYSCALL32 */
  68 
  69 /*
  70  * This is the ipc_perm equivalent used in the xxxid_ds64 structures.
  71  * It, like the structures it is used in, is intended only for use in
  72  * communication between the kernel and user programs, and has the same
  73  * layout across all data models.
  74  *
  75  * The xxxid_ds64 structures rely on ipc_perm64 being a multiple of
  76  * 8 bytes so subsequent fields are 64-bit aligned on x86.
  77  */
  78 typedef struct ipc_perm64 {
  79         uid_t   ipcx_uid;       /* owner's user id */
  80         gid_t   ipcx_gid;       /* owner's group id */
  81         uid_t   ipcx_cuid;      /* creator's user id */
  82         gid_t   ipcx_cgid;      /* creator's group id */
  83         mode_t  ipcx_mode;      /* access modes */
  84         key_t   ipcx_key;       /* key */
  85         projid_t ipcx_projid;   /* allocating project id */
  86         zoneid_t ipcx_zoneid;   /* creator's zone id */
  87 } ipc_perm64_t;
  88 
  89 /*
  90  * These are versions of xxxid_ds which are intended only for use in
  91  * communication between the kernel and user programs, and therefore
  92  * have the same layout across all data models.  Omitted are all
  93  * implementation-specific fields which would be of no use to user
  94  * programs.
  95  */
  96 struct shmid_ds64 {
  97         ipc_perm64_t    shmx_perm;      /* operation permission struct */
  98         pid_t           shmx_lpid;      /* pid of last shmop */
  99         pid_t           shmx_cpid;      /* pid of creator */
 100         uint64_t        shmx_segsz;     /* size of segment in bytes */
 101         uint64_t        shmx_nattch;    /* # of attaches */
 102         uint64_t        shmx_cnattch;   /* # of ISM attaches */
 103         uint64_t        shmx_lkcnt;     /* lock count ??? */
 104         ipc_time_t      shmx_atime;     /* last shmat time */
 105         ipc_time_t      shmx_dtime;     /* last shmdt time */
 106         ipc_time_t      shmx_ctime;     /* last change time */
 107 };
 108 
 109 struct semid_ds64 {
 110         ipc_perm64_t    semx_perm;      /* operation permission struct */
 111         ushort_t        semx_nsems;     /* # of semaphores in set */
 112         ushort_t        _semx_pad[3];   /* pad to 8-byte multiple */
 113         ipc_time_t      semx_otime;     /* last semop time */
 114         ipc_time_t      semx_ctime;     /* last change time */
 115 };
 116 
 117 struct msqid_ds64 {
 118         ipc_perm64_t    msgx_perm;      /* operation permission struct */
 119         uint64_t        msgx_cbytes;    /* current # bytes on q */
 120         uint64_t        msgx_qnum;      /* # of messages on q */
 121         uint64_t        msgx_qbytes;    /* max # of bytes on q */
 122         pid_t           msgx_lspid;     /* pid of last msgsnd */
 123         pid_t           msgx_lrpid;     /* pid of last msgrcv */
 124         ipc_time_t      msgx_stime;     /* last msgsnd time */
 125         ipc_time_t      msgx_rtime;     /* last msgrcv time */
 126         ipc_time_t      msgx_ctime;     /* last change time */
 127 };
 128 
 129 #ifdef _KERNEL
 130 
 131 /*
 132  * Implementation macros
 133  */
 134 #define IPC_FREE(x)     (((x)->ipc_mode & IPC_ALLOC) == 0)
 135 
 136 #define IPC_SEQ_BITS    7
 137 #define IPC_SEQ_MASK    ((1 << IPC_SEQ_BITS) - 1)
 138 #define IPC_SEQ_SHIFT   (31 - IPC_SEQ_BITS)
 139 #define IPC_INDEX_MASK  ((1 << IPC_SEQ_SHIFT) - 1)
 140 #define IPC_SEQ(x)      ((unsigned int)(x) >> IPC_SEQ_SHIFT)
 141 #define IPC_INDEX(x)    ((unsigned int)(x) & IPC_INDEX_MASK)
 142 
 143 #define IPC_IDS_MIN     (PAGESIZE / 64)         /* starting # of entries */
 144 #define IPC_IDS_MAX     (1 << IPC_SEQ_SHIFT)      /* maximum # of entries */
 145 #define IPC_ID_INVAL    UINT_MAX
 146 
 147 #define IPC_PROJ_USAGE(p, s) \
 148         (*(rctl_qty_t *)(((char *)&p->ipc_proj->kpj_data.kpd_ipc) + \
 149         s->ipcs_rctlofs))
 150 #define IPC_ZONE_USAGE(p, s) \
 151         (*(rctl_qty_t *)(((char *)&p->ipc_zone_ref.zref_zone->zone_ipc) + \
 152         s->ipcs_rctlofs))
 153 #define IPC_LOCKED(s, o) \
 154         MUTEX_HELD(&s->ipcs_table[IPC_INDEX(o->ipc_id)].ipct_lock)
 155 
 156 /*
 157  * The kernel's ipc_perm structure.
 158  */
 159 typedef struct kipc_perm {
 160         avl_node_t ipc_avl;     /* avl node if key is non-private */
 161         list_node_t ipc_list;   /* list node in list of all ids */
 162         uint_t  ipc_ref;        /* reference count              */
 163         uid_t   ipc_uid;        /* owner's user id              */
 164         gid_t   ipc_gid;        /* owner's group id             */
 165         uid_t   ipc_cuid;       /* creator's user id            */
 166         gid_t   ipc_cgid;       /* creator's group id           */
 167         mode_t  ipc_mode;       /* access modes                 */
 168         key_t   ipc_key;        /* key                          */
 169         kproject_t *ipc_proj;   /* creator's project            */
 170         uint_t  ipc_id;         /* id                           */
 171         zoneid_t ipc_zoneid;    /* creator's zone id            */
 172         zone_ref_t ipc_zone_ref; /* reference to creator's zone */
 173 } kipc_perm_t;
 174 
 175 typedef struct ipc_slot {
 176         kmutex_t        ipct_lock;      /* bucket lock          */
 177         kipc_perm_t     *ipct_data;     /* data                 */
 178         uint_t          ipct_seq;       /* sequence number      */
 179         struct ipc_slot *ipct_chain;    /* for stale arrays     */
 180         char            ipct_pad[64 - sizeof (kmutex_t) - 3 * sizeof (void *)];
 181 } ipc_slot_t;
 182 
 183 typedef void(ipc_func_t)(kipc_perm_t *);
 184 
 185 typedef struct ipc_service {
 186         kmutex_t        ipcs_lock;      /* lock for (de)allocation, keys */
 187         avl_tree_t      ipcs_keys;      /* objects sorted by key        */
 188         ipc_slot_t      *ipcs_table;    /* table of objects             */
 189         uint_t          ipcs_tabsz;     /* size of table                */
 190         uint_t          ipcs_count;     /* # of objects allocated       */
 191         rctl_hndl_t     ipcs_proj_rctl; /* id limiting rctl handle      */
 192         rctl_hndl_t     ipcs_zone_rctl; /* id limiting rctl handle      */
 193         size_t          ipcs_rctlofs;   /* offset in kproject_data_t    */
 194         id_space_t      *ipcs_ids;      /* id space for objects         */
 195         size_t          ipcs_ssize;     /* object size (for allocation) */
 196         ipc_func_t      *ipcs_dtor;     /* object destructor            */
 197         ipc_func_t      *ipcs_rmid;     /* object removal               */
 198         list_t          ipcs_usedids;   /* list of allocated ids        */
 199         int             ipcs_atype;     /* audit type (see c2/audit.h)  */
 200 } ipc_service_t;
 201 
 202 int ipcperm_access(kipc_perm_t *, int, cred_t *);
 203 int ipcperm_set(ipc_service_t *, struct cred *, kipc_perm_t *,
 204     struct ipc_perm *, model_t);
 205 void ipcperm_stat(struct ipc_perm *, kipc_perm_t *, model_t);
 206 int ipcperm_set64(ipc_service_t *, struct cred *, kipc_perm_t *,
 207     ipc_perm64_t *);
 208 void ipcperm_stat64(ipc_perm64_t *, kipc_perm_t *);
 209 
 210 ipc_service_t *ipcs_create(const char *, rctl_hndl_t, rctl_hndl_t, size_t,
 211     ipc_func_t *, ipc_func_t *, int, size_t);
 212 void ipcs_destroy(ipc_service_t *);
 213 void ipcs_lock(ipc_service_t *);
 214 void ipcs_unlock(ipc_service_t *);
 215 
 216 kmutex_t *ipc_lock(ipc_service_t *, int);
 217 kmutex_t *ipc_relock(ipc_service_t *, int, kmutex_t *);
 218 kmutex_t *ipc_lookup(ipc_service_t *, int, kipc_perm_t **);
 219 
 220 void ipc_hold(ipc_service_t *, kipc_perm_t *);
 221 void ipc_rele(ipc_service_t *, kipc_perm_t *);
 222 void ipc_rele_locked(ipc_service_t *, kipc_perm_t *);
 223 
 224 int ipc_get(ipc_service_t *, key_t, int, kipc_perm_t **, kmutex_t **);
 225 int ipc_commit_begin(ipc_service_t *, key_t, int, kipc_perm_t *);
 226 kmutex_t *ipc_commit_end(ipc_service_t *, kipc_perm_t *);
 227 void ipc_cleanup(ipc_service_t *, kipc_perm_t *);
 228 
 229 int ipc_rmid(ipc_service_t *, int, cred_t *);
 230 int ipc_ids(ipc_service_t *, int *, uint_t, uint_t *);
 231 
 232 void ipc_remove_zone(ipc_service_t *, zoneid_t);
 233 
 234 #else   /* _KERNEL */
 235 
 236 int msgctl64(int, int, struct msqid_ds64 *);
 237 int semctl64(int, int, int, ...);
 238 int shmctl64(int, int, struct shmid_ds64 *);
 239 
 240 #endif  /* _KERNEL */
 241 
 242 
 243 #ifdef  __cplusplus
 244 }
 245 #endif
 246 
 247 #endif  /* _IPC_IMPL_H */