1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2013 Damian Bogel. All rights reserved.
  14  */
  15 
  16 /*
  17  * Kernel module part of the Hello World pseudo-device driver for illumos.
  18  */
  19 
  20 /*
  21  * TODO:
  22  * - fsd_open(): check privilages
  23  */
  24 
  25 #include <sys/conf.h>
  26 #include <sys/cred.h>
  27 #include <sys/ddi.h>
  28 #include <sys/devops.h>
  29 #include <sys/errno.h>
  30 #include <sys/file.h>
  31 #include <sys/fsd.h>
  32 #include <sys/modctl.h>
  33 #include <sys/open.h>
  34 #include <sys/stat.h>
  35 #include <sys/sunddi.h>
  36 #include <sys/types.h>
  37 
  38 #include "fsd_impl.h"
  39 
  40 /* Internal fsd world variables */
  41 static dev_info_t       *fsd_devinfo;
  42 
  43 static int
  44 fsd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
  45 {
  46         if (cmd != DDI_ATTACH)
  47                 return (DDI_FAILURE);
  48 
  49         if (fsd_devinfo != NULL)
  50                 return (DDI_FAILURE);
  51 
  52         int instance;
  53         instance = ddi_get_instance(dip);
  54         if (ddi_create_minor_node(dip, "fsd", S_IFCHR, instance,
  55             DDI_PSEUDO, 0) == DDI_FAILURE) {
  56                 fsd_print("Failed to create minor node\n");
  57                 return (DDI_FAILURE);
  58         }
  59         fsd_devinfo = dip;
  60         return (DDI_SUCCESS);
  61 }
  62 
  63 static int
  64 fsd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
  65 {
  66         if (cmd != DDI_DETACH)
  67                 return (DDI_FAILURE);
  68         ddi_remove_minor_node(dip, NULL);
  69         fsd_devinfo = NULL;
  70         return (DDI_SUCCESS);
  71 }
  72 
  73 static int
  74 fsd_getinfo(
  75         dev_info_t *dip,
  76         ddi_info_cmd_t infocmd,
  77         void *arg,
  78         void **resultp
  79 )
  80 {
  81         _NOTE(ARGUNUSED(dip));
  82         switch (infocmd) {
  83         case DDI_INFO_DEVT2DEVINFO:
  84                 *resultp = (void*)(uintptr_t)getminor((dev_t)arg);
  85                 return (DDI_SUCCESS);
  86         case DDI_INFO_DEVT2INSTANCE:
  87                 *resultp = fsd_devinfo;
  88                 return (DDI_SUCCESS);
  89         default:
  90                 return (DDI_FAILURE);
  91         }
  92 }
  93 
  94 static int
  95 fsd_open(dev_t *devp, int oflag, int sflag, cred_t *cred_p)
  96 {
  97         _NOTE(ARGUNUSED(devp));
  98         _NOTE(ARGUNUSED(oflag));
  99         _NOTE(ARGUNUSED(sflag));
 100         _NOTE(ARGUNUSED(cred_p));
 101         return (0);
 102 }
 103 
 104 static int
 105 fsd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
 106 {
 107         _NOTE(ARGUNUSED(dev));
 108         _NOTE(ARGUNUSED(flag));
 109         _NOTE(ARGUNUSED(otyp));
 110         _NOTE(ARGUNUSED(cred_p));
 111         return (0);
 112 }
 113 
 114 static int
 115 fsd_ioctl(
 116         dev_t dev,
 117         int cmd,
 118         intptr_t arg,
 119         int mode,
 120         cred_t *cred_p,
 121         int *rval_p
 122 )
 123 {
 124         _NOTE(ARGUNUSED(dev));
 125         _NOTE(ARGUNUSED(cred_p));
 126         _NOTE(ARGUNUSED(rval_p));
 127 
 128         switch (cmd) {
 129         case FSD_PRINT_MSG:
 130         {
 131                 struct fsd_msg m;
 132                 if (ddi_copyin(
 133                     (void*)arg, &m.len, sizeof (m.len), mode) != 0)
 134                         return (EFAULT);
 135                 if (m.len > FSD_MAX_MSG_LEN)
 136                         return (EINVAL);
 137                 if (ddi_copyin(
 138                     (void*)((uintptr_t)arg + sizeof (m.len)),
 139                     m.s, m.len, mode) != 0)
 140                         return (EFAULT);
 141                 m.s[m.len] = '\0';
 142                 fsd_print(m.s);
 143                 break;
 144         }
 145         default:
 146                 return (EINVAL);
 147         }
 148         return (0);
 149 }
 150 
 151 
 152 static struct cb_ops cb_ops = {
 153         fsd_open,       /* open(9E) */
 154         fsd_close,      /* close(9E) */
 155         nodev,          /* strategy(9E) */
 156         nodev,          /* print(9E) */
 157         nodev,          /* dump(9E) */
 158         nodev,          /* read(9E) */
 159         nodev,          /* write(9E) */
 160         fsd_ioctl,      /* ioctl(9E) */
 161         nodev,          /* devmap(9E) */
 162         nodev,          /* mmap(9E) */
 163         nodev,          /* segmap(9E) */
 164         nochpoll,       /* chpoll(9E) */
 165         ddi_prop_op,    /* prop_op(9E) */
 166         NULL,           /* streamtab(9E) */
 167         D_MP | D_64BIT, /* cb_flag(9E) */
 168         CB_REV,         /* cb_rev(9E) */
 169         nodev,          /* aread(9E) */
 170         nodev,          /* awrite(9E) */
 171 };
 172 
 173 static struct dev_ops dev_ops = {
 174         DEVO_REV,               /* driver build version */
 175         0,                      /* reference count */
 176         fsd_getinfo,            /* getinfo */
 177         nulldev,
 178         nulldev,                /* probe */
 179         fsd_attach,             /* attach */
 180         fsd_detach,             /* detach */
 181         nodev,
 182         &cb_ops,            /* cb_ops */
 183         NULL,                   /* bus_ops */
 184         NULL,                   /* power */
 185         ddi_quiesce_not_needed, /* quiesce */
 186 };
 187 
 188 static struct modldrv modldrv = {
 189         &mod_driverops,     "Filesystem Disturber Driver", &dev_ops
 190 };
 191 
 192 static struct modlinkage modlinkage = {
 193         MODREV_1, &modldrv, NULL
 194 };
 195 
 196 int
 197 _init(void)
 198 {
 199         return (mod_install(&modlinkage));
 200 }
 201 
 202 int
 203 _info(struct modinfo *modinfop)
 204 {
 205         return (mod_info(&modlinkage, modinfop));
 206 }
 207 
 208 int
 209 _fini(void)
 210 {
 211         return (mod_remove(&modlinkage));
 212 }