xref: /illumos-gate/usr/src/uts/common/io/bl.c (revision 2f172c55ef76964744bc62b4500ece87f3089b4d)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * Blacklist special file
29  */
30 
31 #include <sys/types.h>
32 #include <sys/conf.h>
33 #include <sys/stat.h>
34 #include <sys/modctl.h>
35 #include <sys/kmem.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/open.h>
39 #include <sys/policy.h>
40 #include <sys/fm/protocol.h>
41 #include <sys/bl.h>
42 
43 static dev_info_t *bl_dip;	/* private copy of devinfo pointer */
44 
45 static int
46 bl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
47 {
48 	switch (cmd) {
49 	case DDI_ATTACH:
50 		break;
51 	case DDI_RESUME:
52 		return (DDI_SUCCESS);
53 	default:
54 		return (DDI_FAILURE);
55 	}
56 
57 	if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
58 	    ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS)
59 		return (DDI_FAILURE);
60 
61 	bl_dip = dip;
62 	return (DDI_SUCCESS);
63 }
64 
65 /*ARGSUSED*/
66 static int
67 bl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
68 {
69 	switch (cmd) {
70 	case DDI_DETACH:
71 		break;
72 	case DDI_SUSPEND:
73 		return (DDI_SUCCESS);
74 	default:
75 		return (DDI_FAILURE);
76 	}
77 
78 	ddi_remove_minor_node(bl_dip, NULL);
79 	return (DDI_SUCCESS);
80 }
81 
82 /*ARGSUSED*/
83 static int
84 bl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
85 {
86 	int rc = DDI_SUCCESS;
87 
88 	switch (infocmd) {
89 	case DDI_INFO_DEVT2DEVINFO:
90 		*result = bl_dip;
91 		break;
92 
93 	case DDI_INFO_DEVT2INSTANCE:
94 		*result = (void *)(uintptr_t)getminor((dev_t)arg);
95 		break;
96 
97 	default:
98 		*result = NULL;
99 		rc = DDI_FAILURE;
100 	}
101 
102 	return (rc);
103 }
104 
105 /*ARGSUSED*/
106 static int
107 bl_open(dev_t *devp, int flag, int otyp, struct cred *credp)
108 {
109 	if (otyp != OTYP_CHR)
110 		return (EINVAL);
111 
112 	if (secpolicy_blacklist(credp) != 0)
113 		return (EPERM);
114 
115 	return (0);
116 }
117 
118 /*ARGSUSED*/
119 static int
120 bl_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
121 {
122 	bl_req_t blr;
123 	nvlist_t *fmri;
124 	const char *scheme;
125 	char class[128];
126 	char *buf;
127 	int err;
128 
129 #ifdef _SYSCALL32
130 	if (get_udatamodel() != DATAMODEL_NATIVE) {
131 		bl_req32_t blr32;
132 
133 		if (copyin((void *)data, &blr32, sizeof (bl_req32_t)) != 0)
134 			return (EFAULT);
135 
136 		blr.bl_fmri = (caddr_t)(uintptr_t)blr32.bl_fmri;
137 		blr.bl_fmrisz = blr32.bl_fmrisz;
138 
139 		blr.bl_class = (caddr_t)(uintptr_t)blr32.bl_class;
140 	} else
141 #endif
142 	{
143 		if (copyin((void *)data, &blr, sizeof (bl_req_t)) != 0)
144 			return (EFAULT);
145 	}
146 
147 	if (blr.bl_fmri == NULL || blr.bl_fmrisz > BL_FMRI_MAX_BUFSIZE ||
148 	    blr.bl_class == NULL)
149 		return (EINVAL);
150 
151 	if (copyinstr(blr.bl_class, class, sizeof (class), NULL) != 0)
152 		return (EFAULT);
153 
154 	buf = kmem_zalloc(blr.bl_fmrisz, KM_SLEEP);
155 	if (copyin(blr.bl_fmri, buf, blr.bl_fmrisz) != 0) {
156 		kmem_free(buf, blr.bl_fmrisz);
157 		return (EFAULT);
158 	}
159 
160 	err = nvlist_unpack(buf, blr.bl_fmrisz, &fmri, KM_SLEEP);
161 	kmem_free(buf, blr.bl_fmrisz);
162 	if (err != 0)
163 		return (err);
164 
165 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, (char **)&scheme) != 0) {
166 		nvlist_free(fmri);
167 		return (EINVAL);
168 	}
169 
170 	switch (cmd) {
171 	case BLIOC_INSERT:
172 	case BLIOC_DELETE:
173 		err = blacklist(cmd, scheme, fmri, class);
174 		break;
175 	default:
176 		err = ENOTSUP;
177 	}
178 
179 	nvlist_free(fmri);
180 	return (err);
181 
182 }
183 
184 static struct cb_ops bl_cb_ops = {
185 	bl_open,		/* open */
186 	nulldev,		/* close */
187 	nodev,			/* strategy */
188 	nodev,			/* print */
189 	nodev,			/* dump */
190 	nodev,			/* read */
191 	nodev,			/* write */
192 	bl_ioctl,		/* ioctl */
193 	nodev,			/* devmap */
194 	nodev,			/* mmap */
195 	nodev,			/* segmap */
196 	nochpoll,		/* poll */
197 	ddi_prop_op,		/* cb_prop_op */
198 	0,			/* streamtab  */
199 	D_NEW | D_MP | D_64BIT	/* Driver compatibility flag */
200 };
201 
202 static struct dev_ops bl_ops = {
203 	DEVO_REV,		/* devo_rev */
204 	0,			/* devo_refcnt  */
205 	bl_getinfo,		/* devo_getinfo */
206 	nulldev,		/* devo_identify */
207 	nulldev,		/* devo_probe */
208 	bl_attach,		/* devo_attach */
209 	bl_detach,		/* devo_detach */
210 	nodev,			/* devo_reset */
211 	&bl_cb_ops,		/* devo_cb_ops */
212 	(struct bus_ops *)0,	/* devo_bus_ops */
213 	NULL,			/* devo_power */
214 	ddi_quiesce_not_needed,		/* devo_quiesce */
215 };
216 
217 static struct modldrv modldrv = {
218 	&mod_driverops, "blacklist driver", &bl_ops,
219 };
220 
221 static struct modlinkage modlinkage = {
222 	MODREV_1, &modldrv, NULL
223 };
224 
225 int
226 _init(void)
227 {
228 	return (mod_install(&modlinkage));
229 }
230 
231 int
232 _info(struct modinfo *modinfop)
233 {
234 	return (mod_info(&modlinkage, modinfop));
235 }
236 
237 int
238 _fini(void)
239 {
240 	return (mod_remove(&modlinkage));
241 }
242