Merge branch 'vendor/FILE'
[dragonfly.git] / sys / libprop / prop_kern.c
1 /*      $NetBSD: prop_kern.c,v 1.15 2011/01/19 20:34:23 bouyer Exp $    */
2
3 /*-
4  * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/types.h>
33
34 #include <libprop/proplib.h>
35
36 #if !defined(_KERNEL) && !defined(_STANDALONE)
37 #include <sys/mman.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <sys/ioctl.h>
43
44 static int
45 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref, char **bufp)
46 {
47         char *buf;
48
49         switch (prop_object_type(obj)) {
50         case PROP_TYPE_DICTIONARY:
51                 buf = prop_dictionary_externalize(obj);
52                 break;
53         case PROP_TYPE_ARRAY:
54                 buf = prop_array_externalize(obj);
55                 break;
56         default:
57                 return (ENOTSUP);
58         }
59         if (buf == NULL) {
60                 /* Assume we ran out of memory. */
61                 return (ENOMEM);
62         }
63         pref->pref_plist = buf;
64         pref->pref_len = strlen(buf) + 1;
65
66         *bufp = buf;
67
68         return (0);
69 }
70
71 /*
72  * prop_array_externalize_to_pref --
73  *      Externalize an array into a plistref for sending to the kernel.
74  */
75 bool
76 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
77 {
78         char *buf;
79         int rv;
80
81         rv = _prop_object_externalize_to_pref(array, prefp, &buf);
82         if (rv != 0)
83                 errno = rv;     /* pass up error value in errno */
84         return (rv == 0);
85 }
86 __strong_reference(prop_array_externalize_to_pref, prop_array_send_syscall)
87
88 /*
89  * prop_dictionary_externalize_to_pref --
90  *      Externalize an dictionary into a plistref for sending to the kernel.
91  */
92 bool
93 prop_dictionary_externalize_to_pref(prop_dictionary_t dict, struct plistref *prefp)
94 {
95         char *buf;
96         int rv;
97
98         rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
99         if (rv != 0)
100                 errno = rv;     /* pass up error value in errno */
101         return (rv == 0);
102 }
103 __strong_reference(prop_dictionary_externalize_to_pref,
104     prop_dictionary_send_syscall)
105
106 static int
107 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
108 {
109         struct plistref pref;
110         char *buf;
111         int error;
112
113         error = _prop_object_externalize_to_pref(obj, &pref, &buf);
114         if (error)
115                 return (error);
116
117         if (ioctl(fd, cmd, &pref) == -1)
118                 error = errno;
119         else
120                 error = 0;
121         
122         free(buf);
123
124         return (error);
125 }
126
127 /*
128  * prop_array_send_ioctl --
129  *      Send an array to the kernel using the specified ioctl.
130  */
131 int
132 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
133 {
134
135         return (_prop_object_send_ioctl(array, fd, cmd));
136 }
137
138 /*
139  * prop_dictionary_send_ioctl --
140  *      Send a dictionary to the kernel using the specified ioctl.
141  */
142 int
143 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
144 {
145
146         return (_prop_object_send_ioctl(dict, fd, cmd));
147 }
148
149 static int
150 _prop_object_internalize_from_pref(const struct plistref *pref, prop_type_t type,
151                          prop_object_t *objp)
152 {
153         prop_object_t obj = NULL;
154         char *buf;
155         int error = 0;
156
157         if (pref->pref_len == 0) {
158                 /*
159                  * This should never happen; we should always get the XML
160                  * for an empty dictionary if it's really empty.
161                  */
162                 error = EIO;
163                 goto out;
164         } else {
165                 buf = pref->pref_plist;
166                 buf[pref->pref_len - 1] = '\0'; /* extra insurance */
167                 switch (type) {
168                 case PROP_TYPE_DICTIONARY:
169                         obj = prop_dictionary_internalize(buf);
170                         break;
171                 case PROP_TYPE_ARRAY:
172                         obj = prop_array_internalize(buf);
173                         break;
174                 default:
175                         error = ENOTSUP;
176                 }
177                 (void) munmap(buf, pref->pref_len);
178                 if (obj == NULL && error == 0)
179                         error = EIO;
180         }
181
182  out:
183         if (error == 0)
184                 *objp = obj;
185         return (error);
186 }
187
188 /*
189  * prop_array_recv_ioctl --
190  *      Receive an array from the kernel using the specified ioctl.
191  */
192 int
193 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
194 {
195         struct plistref pref;
196
197         if (ioctl(fd, cmd, &pref) == -1)
198                 return (errno);
199         
200         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
201                                          (prop_object_t *)arrayp));
202 }
203
204 /*
205  * prop_dictionary_recv_ioctl --
206  *      Receive a dictionary from the kernel using the specified ioctl.
207  */
208 int
209 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
210 {
211         struct plistref pref;
212
213         if (ioctl(fd, cmd, &pref) == -1)
214                 return (errno);
215
216         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
217                                          (prop_object_t *)dictp));
218 }
219
220 /*
221  * prop_array_recv_syscall --
222  *      Receive an array from the kernel as pref.
223  *      Pref's buf is freed on exit
224  */
225 bool
226 prop_array_recv_syscall(const struct plistref *pref, prop_array_t *arrayp)
227 {
228         return (_prop_object_internalize_from_pref(pref, PROP_TYPE_ARRAY,
229                                          (prop_object_t *)arrayp));
230 }
231
232 /*
233  * prop_dictionary_recv_syscall --
234  *      Receive a dictionary from the kernel as pref.
235  *      Pref's buf is freed on exit
236  */
237 bool
238 prop_dictionary_recv_syscall(const struct plistref *pref,
239     prop_dictionary_t *dictp)
240 {
241         return (_prop_object_internalize_from_pref(pref, PROP_TYPE_DICTIONARY,
242                                          (prop_object_t *)dictp));
243 }
244
245 /*
246  * prop_dictionary_sendrecv_ioctl --
247  *      Combination send/receive a dictionary to/from the kernel using
248  *      the specified ioctl.
249  */
250 int
251 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
252                                unsigned long cmd, prop_dictionary_t *dictp)
253 {
254         struct plistref pref;
255         char *buf;
256         int error;
257
258         error = _prop_object_externalize_to_pref(dict, &pref, &buf);
259         if (error)
260                 return (error);
261
262         if (ioctl(fd, cmd, &pref) == -1)
263                 error = errno;
264         else
265                 error = 0;
266         
267         free(buf);
268
269         if (error)
270                 return (error);
271
272         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
273                             (prop_object_t *)dictp));
274 }
275 #endif /* !_KERNEL && !_STANDALONE */
276
277 #if defined(_KERNEL)
278 #include <sys/param.h>
279 #include <sys/mman.h>
280 #include <sys/errno.h>
281 #include <sys/malloc.h>
282 #include <sys/systm.h>
283 #include <sys/proc.h>
284 #include <sys/resource.h>
285 #include <sys/objcache.h>
286 #include <sys/ioccom.h>
287 #include <vm/vm.h>
288 #include <vm/vm_extern.h>
289 #include <vm/vm_param.h>
290
291 #include "prop_object_impl.h"
292
293 /* Arbitrary limit ioctl input to 64KB */
294 unsigned int prop_object_copyin_limit = 65536;
295
296 static int
297 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
298                           prop_object_t *objp)
299 {
300         prop_object_t obj = NULL;
301         char *buf;
302         int error;
303
304         /*
305          * Allocate an extra byte so we can guarantee NUL-termination.
306          *
307          * Allow malloc to fail in case pmap would be exhausted.
308          */
309         buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
310         if (buf == NULL)
311                 return (ENOMEM);
312         error = copyin(pref->pref_plist, buf, pref->pref_len);
313         if (error) {
314                 kfree(buf, M_TEMP);
315                 return (error);
316         }
317         buf[pref->pref_len] = '\0';
318
319         switch (type) {
320         case PROP_TYPE_ARRAY:
321                 obj = prop_array_internalize(buf);
322                 break;
323         case PROP_TYPE_DICTIONARY:
324                 obj = prop_dictionary_internalize(buf);
325                 break;
326         default:
327                 error = ENOTSUP;
328         }
329
330         kfree(buf, M_TEMP);
331         if (obj == NULL) {
332                 if (error == 0)
333                         error = EIO;
334         } else {
335                 *objp = obj;
336         }
337         return (error);
338 }
339
340
341 static int
342 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
343                           const u_long cmd, prop_object_t *objp)
344 {
345         if ((cmd & IOC_IN) == 0)
346                 return (EFAULT);
347
348         return _prop_object_copyin(pref, type, objp);
349 }
350
351 /*
352  * prop_array_copyin --
353  *      Copy in an array passed as a syscall arg.
354  */
355 int
356 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
357 {
358         return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
359                                           (prop_object_t *)arrayp));
360 }
361
362 /*
363  * prop_dictionary_copyin --
364  *      Copy in a dictionary passed as a syscall arg.
365  */
366 int
367 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
368 {
369         return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
370                                           (prop_object_t *)dictp));
371 }
372
373
374 /*
375  * prop_array_copyin_ioctl --
376  *      Copy in an array send with an ioctl.
377  */
378 int
379 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
380                         prop_array_t *arrayp)
381 {
382         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
383                                           cmd, (prop_object_t *)arrayp));
384 }
385
386 /*
387  * prop_dictionary_copyin_ioctl --
388  *      Copy in a dictionary sent with an ioctl.
389  */
390 int
391 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
392                              prop_dictionary_t *dictp)
393 {
394         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
395                                           cmd, (prop_object_t *)dictp));
396 }
397
398 static int
399 _prop_object_copyout(struct plistref *pref, prop_object_t obj)
400 {
401         struct proc *p = curproc;
402         char *buf;
403         size_t len, rlen;
404         int error = 0;
405         vm_offset_t uaddr;
406
407         switch (prop_object_type(obj)) {
408         case PROP_TYPE_ARRAY:
409                 buf = prop_array_externalize(obj);
410                 break;
411         case PROP_TYPE_DICTIONARY:
412                 buf = prop_dictionary_externalize(obj);
413                 break;
414         default:
415                 return (ENOTSUP);
416         }
417         if (buf == NULL)
418                 return (ENOMEM);
419
420         len = strlen(buf) + 1;
421         rlen = round_page(len);
422
423         /*
424          * See sys_mmap() in sys/uvm/uvm_mmap.c.
425          * Let's act as if we were calling mmap(0, ...)
426          */
427 #if 0
428         uaddr = p->p_emul->e_vm_default_addr(p,
429             (vaddr_t)p->p_vmspace->vm_daddr, rlen);
430 #endif
431         uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz);
432
433         error = vm_mmap(&p->p_vmspace->vm_map,
434                          &uaddr, rlen,
435                          VM_PROT_READ|VM_PROT_WRITE,
436                          VM_PROT_READ|VM_PROT_WRITE,
437                          MAP_PRIVATE|MAP_ANON,
438                          NULL, 0);
439         if (error == 0) {
440                 error = copyout(buf, (char *)uaddr, len);
441                 if (error == 0) {
442                         pref->pref_plist = (char *)uaddr;
443                         pref->pref_len   = len;
444                 }
445         }
446
447         kfree(buf, M_TEMP);
448
449         return (error);
450 }
451
452 /*
453  * prop_array_copyout --
454  *      Copy out an array to a syscall arg.
455  */
456 int
457 prop_array_copyout(struct plistref *pref, prop_array_t array)
458 {
459         return (_prop_object_copyout(pref, array));
460 }
461
462 /*
463  * prop_dictionary_copyout --
464  *      Copy out a dictionary to a syscall arg.
465  */
466 int
467 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
468 {
469         return (_prop_object_copyout(pref, dict));
470 }
471
472 static int
473 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
474                            prop_object_t obj)
475 {
476         if ((cmd & IOC_OUT) == 0)
477                 return (EFAULT);
478         return _prop_object_copyout(pref, obj);
479 }
480
481
482 /*
483  * prop_array_copyout_ioctl --
484  *      Copy out an array being received with an ioctl.
485  */
486 int
487 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
488                          prop_array_t array)
489 {
490         return (_prop_object_copyout_ioctl(pref, cmd, array));
491 }
492
493 /*
494  * prop_dictionary_copyout_ioctl --
495  *      Copy out a dictionary being received with an ioctl.
496  */
497 int
498 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
499                               prop_dictionary_t dict)
500 {
501         return (
502             _prop_object_copyout_ioctl(pref, cmd, dict));
503 }
504 #endif /* _KERNEL */