Home | History | Annotate | Line # | Download | only in dev
clockctl.c revision 1.35.14.10
      1  1.35.14.10  pgoyette /*      $NetBSD: clockctl.c,v 1.35.14.10 2019/01/14 13:34:27 pgoyette Exp $ */
      2         1.1      manu 
      3         1.1      manu /*-
      4         1.1      manu  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5         1.1      manu  * All rights reserved.
      6         1.1      manu  *
      7         1.1      manu  * This code is derived from software contributed to The NetBSD Foundation
      8         1.1      manu  * by Emmanuel Dreyfus.
      9         1.1      manu  *
     10         1.1      manu  * Redistribution and use in source and binary forms, with or without
     11         1.1      manu  * modification, are permitted provided that the following conditions
     12         1.1      manu  * are met:
     13         1.1      manu  * 1. Redistributions of source code must retain the above copyright
     14         1.1      manu  *    notice, this list of conditions and the following disclaimer.
     15         1.1      manu  * 2. Redistributions in binary form must reproduce the above copyright
     16         1.1      manu  *    notice, this list of conditions and the following disclaimer in the
     17         1.1      manu  *    documentation and/or other materials provided with the distribution.
     18         1.1      manu  * 3. The name of the author may not be used to endorse or promote products
     19         1.1      manu  *    derived from this software without specific prior written permission.
     20         1.1      manu  *
     21         1.1      manu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22         1.1      manu  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23         1.1      manu  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24         1.1      manu  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25         1.1      manu  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26         1.1      manu  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27         1.1      manu  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28         1.1      manu  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29         1.1      manu  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30         1.1      manu  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31         1.1      manu  */
     32         1.2     lukem 
     33         1.2     lukem #include <sys/cdefs.h>
     34  1.35.14.10  pgoyette __KERNEL_RCSID(0, "$NetBSD: clockctl.c,v 1.35.14.10 2019/01/14 13:34:27 pgoyette Exp $");
     35         1.5      manu 
     36        1.33  pgoyette #ifdef _KERNEL_OPT
     37         1.5      manu #include "opt_ntp.h"
     38        1.24  christos #include "opt_compat_netbsd.h"
     39        1.33  pgoyette #endif
     40         1.1      manu 
     41         1.1      manu #include <sys/param.h>
     42         1.1      manu #include <sys/systm.h>
     43         1.1      manu #include <sys/proc.h>
     44         1.1      manu #include <sys/errno.h>
     45         1.1      manu #include <sys/ioctl.h>
     46         1.1      manu #include <sys/device.h>
     47         1.1      manu #include <sys/time.h>
     48         1.7   gehenna #include <sys/conf.h>
     49         1.1      manu #include <sys/timex.h>
     50        1.28      elad #include <sys/kauth.h>
     51        1.33  pgoyette #include <sys/module.h>
     52        1.33  pgoyette #include <sys/mutex.h>
     53   1.35.14.1  pgoyette #include <sys/compat_stub.h>
     54         1.1      manu 
     55         1.1      manu #include <sys/clockctl.h>
     56        1.24  christos #include <compat/sys/clockctl.h>
     57        1.33  pgoyette #include <compat/sys/time_types.h>
     58   1.35.14.1  pgoyette 
     59         1.1      manu 
     60        1.33  pgoyette kmutex_t clockctl_mtx;
     61        1.33  pgoyette int clockctl_refcnt;
     62        1.33  pgoyette 
     63        1.33  pgoyette #include "ioconf.h"
     64        1.33  pgoyette 
     65         1.7   gehenna dev_type_ioctl(clockctlioctl);
     66         1.7   gehenna 
     67         1.7   gehenna const struct cdevsw clockctl_cdevsw = {
     68        1.33  pgoyette 	.d_open = clockctlopen,
     69        1.33  pgoyette 	.d_close = clockctlclose,
     70        1.31  dholland 	.d_read = noread,
     71        1.31  dholland 	.d_write = nowrite,
     72        1.31  dholland 	.d_ioctl = clockctlioctl,
     73        1.31  dholland 	.d_stop = nostop,
     74        1.31  dholland 	.d_tty = notty,
     75        1.31  dholland 	.d_poll = nopoll,
     76        1.31  dholland 	.d_mmap = nommap,
     77        1.31  dholland 	.d_kqfilter = nokqfilter,
     78        1.32  dholland 	.d_discard = nodiscard,
     79        1.31  dholland 	.d_flag = D_OTHER,
     80         1.7   gehenna };
     81         1.1      manu 
     82        1.28      elad static kauth_listener_t clockctl_listener;
     83        1.28      elad 
     84        1.28      elad static int
     85        1.28      elad clockctl_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
     86        1.28      elad     void *arg0, void *arg1, void *arg2, void *arg3)
     87        1.28      elad {
     88        1.28      elad 	int result;
     89        1.28      elad 	enum kauth_system_req req;
     90        1.28      elad 	bool device_context;
     91        1.28      elad 
     92        1.28      elad 	result = KAUTH_RESULT_DEFER;
     93        1.28      elad 	req = (enum kauth_system_req)arg0;
     94        1.28      elad 
     95        1.28      elad 	if ((action != KAUTH_SYSTEM_TIME) ||
     96        1.28      elad 	    (req != KAUTH_REQ_SYSTEM_TIME_SYSTEM))
     97        1.28      elad 		return result;
     98        1.28      elad 
     99        1.28      elad 	device_context = (bool)arg3;
    100        1.28      elad 
    101        1.28      elad 	/* Device is controlled by permissions, so allow. */
    102        1.28      elad 	if (device_context)
    103        1.28      elad 		result = KAUTH_RESULT_ALLOW;
    104        1.28      elad 
    105        1.28      elad 	return result;
    106        1.28      elad }
    107        1.28      elad 
    108        1.10     perry /*ARGSUSED*/
    109         1.1      manu void
    110        1.20  christos clockctlattach(int num)
    111         1.1      manu {
    112        1.28      elad 
    113        1.33  pgoyette /*
    114        1.33  pgoyette  * Don't initialize the listener here - it will get handled as part
    115        1.33  pgoyette  * of module initialization.
    116        1.33  pgoyette  */
    117        1.33  pgoyette #if 0
    118        1.28      elad 	clockctl_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
    119        1.28      elad 	    clockctl_listener_cb, NULL);
    120        1.33  pgoyette #endif
    121        1.33  pgoyette }
    122        1.33  pgoyette 
    123        1.33  pgoyette /*
    124        1.33  pgoyette  * Maintain a refcount for each open/close, so we know when it is
    125        1.33  pgoyette  * safe to call devsw_detach()
    126        1.33  pgoyette  */
    127        1.33  pgoyette int
    128        1.33  pgoyette clockctlopen(dev_t dev, int flag, int mode, struct lwp *l)
    129        1.33  pgoyette {
    130        1.33  pgoyette 
    131        1.33  pgoyette 	mutex_enter(&clockctl_mtx);
    132        1.33  pgoyette 	clockctl_refcnt++;
    133        1.33  pgoyette 	mutex_exit(&clockctl_mtx);
    134        1.33  pgoyette 
    135        1.33  pgoyette 	return 0;
    136        1.33  pgoyette }
    137        1.33  pgoyette 
    138        1.33  pgoyette int
    139        1.33  pgoyette clockctlclose(dev_t dev, int flag, int mode, struct lwp *l)
    140        1.33  pgoyette {
    141        1.33  pgoyette 
    142        1.33  pgoyette 	mutex_enter(&clockctl_mtx);
    143        1.33  pgoyette 	clockctl_refcnt--;
    144        1.33  pgoyette 	mutex_exit(&clockctl_mtx);
    145        1.33  pgoyette 
    146        1.33  pgoyette 	return 0;
    147        1.33  pgoyette }
    148        1.33  pgoyette 
    149        1.33  pgoyette MODULE(MODULE_CLASS_DRIVER, clockctl, NULL);
    150        1.33  pgoyette 
    151        1.33  pgoyette int
    152        1.33  pgoyette clockctl_modcmd(modcmd_t cmd, void *data)
    153        1.33  pgoyette {
    154        1.33  pgoyette 	int error;
    155        1.33  pgoyette #ifdef _MODULE
    156        1.33  pgoyette 	int bmajor, cmajor;
    157        1.33  pgoyette #endif
    158        1.33  pgoyette 
    159        1.33  pgoyette 	error = 0;
    160        1.33  pgoyette 
    161        1.33  pgoyette 	switch (cmd) {
    162        1.33  pgoyette 	case MODULE_CMD_INIT:
    163        1.34  christos 		mutex_init(&clockctl_mtx, MUTEX_DEFAULT, IPL_NONE);
    164        1.33  pgoyette 
    165        1.33  pgoyette 		clockctl_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
    166        1.33  pgoyette 		    clockctl_listener_cb, NULL);
    167        1.33  pgoyette 
    168        1.33  pgoyette #ifdef _MODULE
    169        1.33  pgoyette 		bmajor = cmajor = -1;
    170        1.33  pgoyette 		error = devsw_attach("clockctl", NULL, &bmajor,
    171        1.33  pgoyette 		    &clockctl_cdevsw, &cmajor);
    172        1.33  pgoyette 		if (error != 0)
    173        1.33  pgoyette 			kauth_unlisten_scope(clockctl_listener);
    174        1.33  pgoyette #endif
    175        1.33  pgoyette 
    176        1.33  pgoyette 		break;
    177        1.33  pgoyette 
    178        1.33  pgoyette 	case MODULE_CMD_FINI:
    179        1.33  pgoyette 		mutex_enter(&clockctl_mtx);
    180        1.33  pgoyette 		if (clockctl_refcnt != 0) {
    181        1.33  pgoyette 			mutex_exit(&clockctl_mtx);
    182        1.33  pgoyette 			return EBUSY;
    183        1.33  pgoyette 		}
    184        1.33  pgoyette #ifdef _MODULE
    185        1.33  pgoyette 		error = devsw_detach(NULL, &clockctl_cdevsw);
    186        1.33  pgoyette #endif
    187        1.33  pgoyette 		mutex_exit(&clockctl_mtx);
    188        1.33  pgoyette 
    189        1.34  christos 		if (error == 0) {
    190        1.33  pgoyette 			kauth_unlisten_scope(clockctl_listener);
    191        1.34  christos 			mutex_destroy(&clockctl_mtx);
    192        1.34  christos 		}
    193        1.33  pgoyette 		break;
    194        1.33  pgoyette 
    195        1.33  pgoyette 	default:
    196        1.33  pgoyette 		error = ENOTTY;
    197        1.33  pgoyette 		break;
    198        1.33  pgoyette 	}
    199        1.33  pgoyette 
    200        1.33  pgoyette 	return error;
    201         1.1      manu }
    202         1.1      manu 
    203   1.35.14.2  pgoyette /* Hook the compat_50 stuff */
    204  1.35.14.10  pgoyette MODULE_CALL_INT_HOOK_DECL(clockctl_ioctl_50_hook,
    205   1.35.14.8  pgoyette     (dev_t dev, u_long cmd, void *data, int flags, struct lwp *l));
    206  1.35.14.10  pgoyette MODULE_CALL_INT_HOOK(clockctl_ioctl_50_hook,
    207   1.35.14.2  pgoyette     (dev_t dev, u_long cmd, void *data, int flags, struct lwp *l),
    208   1.35.14.2  pgoyette     (dev, cmd, data, flags, l), enosys());
    209   1.35.14.2  pgoyette 
    210         1.1      manu int
    211        1.19  christos clockctlioctl(
    212        1.20  christos     dev_t dev,
    213        1.19  christos     u_long cmd,
    214        1.21  christos     void *data,
    215        1.20  christos     int flags,
    216        1.19  christos     struct lwp *l)
    217         1.1      manu {
    218         1.1      manu 	int error = 0;
    219        1.13     perry 
    220         1.1      manu 	switch (cmd) {
    221        1.24  christos 	case CLOCKCTL_SETTIMEOFDAY: {
    222        1.24  christos 		struct clockctl_settimeofday *args = data;
    223         1.1      manu 
    224        1.24  christos 		error = settimeofday1(args->tv, true, args->tzp, l, false);
    225        1.24  christos 		break;
    226        1.24  christos 	}
    227        1.24  christos 	case CLOCKCTL_ADJTIME: {
    228        1.24  christos 		struct timeval atv, oldatv;
    229        1.24  christos 		struct clockctl_adjtime *args = data;
    230         1.1      manu 
    231        1.24  christos 		if (args->delta) {
    232        1.27  nakayama 			error = copyin(args->delta, &atv, sizeof(atv));
    233         1.1      manu 			if (error)
    234        1.13     perry 				return (error);
    235         1.1      manu 		}
    236        1.24  christos 		adjtime1(args->delta ? &atv : NULL,
    237        1.24  christos 		    args->olddelta ? &oldatv : NULL, l->l_proc);
    238        1.24  christos 		if (args->olddelta)
    239        1.24  christos 			error = copyout(&oldatv, args->olddelta,
    240        1.27  nakayama 			    sizeof(oldatv));
    241        1.24  christos 		break;
    242        1.24  christos 	}
    243        1.24  christos 	case CLOCKCTL_CLOCK_SETTIME: {
    244        1.24  christos 		struct clockctl_clock_settime *args = data;
    245        1.25       mrg 		struct timespec ts;
    246         1.1      manu 
    247        1.26       mrg 		error = copyin(args->tp, &ts, sizeof ts);
    248        1.26       mrg 		if (error)
    249        1.26       mrg 			return (error);
    250        1.26       mrg 		error = clock_settime1(l->l_proc, args->clock_id, &ts, false);
    251        1.24  christos 		break;
    252        1.24  christos 	}
    253        1.24  christos 	case CLOCKCTL_NTP_ADJTIME: {
    254        1.24  christos 		struct clockctl_ntp_adjtime *args = data;
    255        1.24  christos 		struct timex ntv;
    256         1.1      manu 
    257   1.35.14.2  pgoyette 		if (vec_ntp_timestatus == NULL) {
    258   1.35.14.2  pgoyette 			error = ENOTTY;
    259   1.35.14.2  pgoyette 			break;
    260   1.35.14.2  pgoyette 		}
    261        1.24  christos 		error = copyin(args->tp, &ntv, sizeof(ntv));
    262        1.24  christos 		if (error)
    263        1.24  christos 			return (error);
    264         1.6      manu 
    265   1.35.14.7  pgoyette 		(*vec_ntp_adjtime1)(&ntv);
    266        1.17    kardel 
    267        1.24  christos 		error = copyout(&ntv, args->tp, sizeof(ntv));
    268        1.24  christos 		if (error == 0)
    269   1.35.14.7  pgoyette 			args->retval = (*vec_ntp_timestatus)();
    270        1.27  nakayama 		break;
    271        1.24  christos 	}
    272        1.24  christos 	default:
    273   1.35.14.9  pgoyette 		error = clockctl_ioctl_50_hook_call(dev, cmd, data, flags, l);
    274   1.35.14.1  pgoyette 		if (error == ENOSYS)
    275   1.35.14.1  pgoyette 			error = ENOTTY;
    276        1.33  pgoyette 	}
    277        1.33  pgoyette 
    278        1.33  pgoyette 	return (error);
    279        1.33  pgoyette }
    280