]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_control.c
xnu-1228.0.2.tar.gz
[apple/xnu.git] / bsd / kern / kern_control.c
CommitLineData
9bccf70c 1/*
2d21ac55 2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
9bccf70c 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
9bccf70c 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
9bccf70c 27 */
9bccf70c
A
28
29/*
91447636
A
30 * Kernel Control domain - allows control connections to
31 * and to read/write data.
9bccf70c 32 *
91447636 33 * Vincent Lubet, 040506
9bccf70c
A
34 * Christophe Allie, 010928
35 * Justin C. Walker, 990319
36 */
37
38#include <sys/types.h>
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/syslog.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/protosw.h>
45#include <sys/domain.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
9bccf70c
A
48#include <sys/sys_domain.h>
49#include <sys/kern_event.h>
50#include <sys/kern_control.h>
2d21ac55 51#include <sys/kauth.h>
9bccf70c
A
52#include <net/if_var.h>
53
54#include <mach/vm_types.h>
55#include <mach/kmod.h>
56
57#include <kern/thread.h>
58
9bccf70c
A
59/*
60 * Definitions and vars for we support
61 */
62
63#define CTL_SENDSIZE (2 * 1024) /* default buffer size */
64#define CTL_RECVSIZE (8 * 1024) /* default buffer size */
65
66/*
91447636
A
67 * Definitions and vars for we support
68 */
9bccf70c 69
91447636
A
70static u_int32_t ctl_maxunit = 65536;
71static lck_grp_attr_t *ctl_lck_grp_attr = 0;
72static lck_attr_t *ctl_lck_attr = 0;
73static lck_grp_t *ctl_lck_grp = 0;
74static lck_mtx_t *ctl_mtx;
75
9bccf70c
A
76
77/* all the controllers are chained */
2d21ac55 78TAILQ_HEAD(kctl_list, kctl) ctl_head;
91447636
A
79
80static int ctl_attach(struct socket *, int, struct proc *);
81static int ctl_detach(struct socket *);
82static int ctl_sofreelastref(struct socket *so);
83static int ctl_connect(struct socket *, struct sockaddr *, struct proc *);
84static int ctl_disconnect(struct socket *);
85static int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
9bccf70c 86 struct ifnet *ifp, struct proc *p);
91447636 87static int ctl_send(struct socket *, int, struct mbuf *,
9bccf70c 88 struct sockaddr *, struct mbuf *, struct proc *);
91447636
A
89static int ctl_ctloutput(struct socket *, struct sockopt *);
90static int ctl_peeraddr(struct socket *so, struct sockaddr **nam);
91
91447636
A
92static struct kctl *ctl_find_by_name(const char *);
93static struct kctl *ctl_find_by_id_unit(u_int32_t id, u_int32_t unit);
9bccf70c 94
91447636
A
95static struct ctl_cb *kcb_find(struct kctl *, u_int32_t unit);
96static void ctl_post_msg(u_long event_code, u_int32_t id);
9bccf70c 97
91447636
A
98static int ctl_lock(struct socket *, int, int);
99static int ctl_unlock(struct socket *, int, int);
100static lck_mtx_t * ctl_getlock(struct socket *, int);
9bccf70c 101
91447636 102static struct pr_usrreqs ctl_usrreqs =
9bccf70c
A
103{
104 pru_abort_notsupp, pru_accept_notsupp, ctl_attach, pru_bind_notsupp,
91447636
A
105 ctl_connect, pru_connect2_notsupp, ctl_ioctl, ctl_detach,
106 ctl_disconnect, pru_listen_notsupp, ctl_peeraddr,
9bccf70c
A
107 pru_rcvd_notsupp, pru_rcvoob_notsupp, ctl_send,
108 pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
91447636
A
109 sosend, soreceive, pru_sopoll_notsupp
110};
111
112static struct protosw kctlswk_dgram =
113{
114 SOCK_DGRAM, &systemdomain, SYSPROTO_CONTROL,
115 PR_ATOMIC|PR_CONNREQUIRED|PR_PCBLOCK,
116 NULL, NULL, NULL, ctl_ctloutput,
117 NULL, NULL,
118 NULL, NULL, NULL, NULL, &ctl_usrreqs,
119 ctl_lock, ctl_unlock, ctl_getlock, { 0, 0 } , 0, { 0 }
9bccf70c
A
120};
121
91447636 122static struct protosw kctlswk_stream =
9bccf70c 123{
91447636
A
124 SOCK_STREAM, &systemdomain, SYSPROTO_CONTROL,
125 PR_CONNREQUIRED|PR_PCBLOCK,
9bccf70c
A
126 NULL, NULL, NULL, ctl_ctloutput,
127 NULL, NULL,
91447636
A
128 NULL, NULL, NULL, NULL, &ctl_usrreqs,
129 ctl_lock, ctl_unlock, ctl_getlock, { 0, 0 } , 0, { 0 }
9bccf70c
A
130};
131
91447636 132
9bccf70c 133/*
91447636 134 * Install the protosw's for the Kernel Control manager.
9bccf70c 135 */
91447636 136__private_extern__ int
9bccf70c
A
137kern_control_init(void)
138{
91447636
A
139 int error = 0;
140
141 ctl_lck_grp_attr = lck_grp_attr_alloc_init();
142 if (ctl_lck_grp_attr == 0) {
143 printf(": lck_grp_attr_alloc_init failed\n");
144 error = ENOMEM;
145 goto done;
146 }
91447636
A
147
148 ctl_lck_grp = lck_grp_alloc_init("Kernel Control Protocol", ctl_lck_grp_attr);
149 if (ctl_lck_grp == 0) {
150 printf("kern_control_init: lck_grp_alloc_init failed\n");
151 error = ENOMEM;
152 goto done;
153 }
154
155 ctl_lck_attr = lck_attr_alloc_init();
156 if (ctl_lck_attr == 0) {
157 printf("kern_control_init: lck_attr_alloc_init failed\n");
158 error = ENOMEM;
159 goto done;
160 }
91447636
A
161
162 ctl_mtx = lck_mtx_alloc_init(ctl_lck_grp, ctl_lck_attr);
163 if (ctl_mtx == 0) {
164 printf("kern_control_init: lck_mtx_alloc_init failed\n");
165 error = ENOMEM;
166 goto done;
167 }
168 TAILQ_INIT(&ctl_head);
169
170 error = net_add_proto(&kctlswk_dgram, &systemdomain);
171 if (error) {
172 log(LOG_WARNING, "kern_control_init: net_add_proto dgram failed (%d)\n", error);
173 }
174 error = net_add_proto(&kctlswk_stream, &systemdomain);
175 if (error) {
176 log(LOG_WARNING, "kern_control_init: net_add_proto stream failed (%d)\n", error);
177 }
178
179 done:
180 if (error != 0) {
181 if (ctl_mtx) {
182 lck_mtx_free(ctl_mtx, ctl_lck_grp);
183 ctl_mtx = 0;
184 }
185 if (ctl_lck_grp) {
186 lck_grp_free(ctl_lck_grp);
187 ctl_lck_grp = 0;
188 }
189 if (ctl_lck_grp_attr) {
190 lck_grp_attr_free(ctl_lck_grp_attr);
191 ctl_lck_grp_attr = 0;
192 }
193 if (ctl_lck_attr) {
194 lck_attr_free(ctl_lck_attr);
195 ctl_lck_attr = 0;
196 }
197 }
198 return error;
199}
9bccf70c 200
91447636
A
201static void
202kcb_delete(struct ctl_cb *kcb)
203{
204 if (kcb != 0) {
205 if (kcb->mtx != 0)
206 lck_mtx_free(kcb->mtx, ctl_lck_grp);
207 FREE(kcb, M_TEMP);
208 }
9bccf70c
A
209}
210
211
212/*
213 * Kernel Controller user-request functions
91447636
A
214 * attach function must exist and succeed
215 * detach not necessary
216 * we need a pcb for the per socket mutex
9bccf70c 217 */
91447636
A
218static int
219ctl_attach(__unused struct socket *so, __unused int proto, __unused struct proc *p)
9bccf70c 220{
91447636
A
221 int error = 0;
222 struct ctl_cb *kcb = 0;
223
224 MALLOC(kcb, struct ctl_cb *, sizeof(struct ctl_cb), M_TEMP, M_WAITOK);
225 if (kcb == NULL) {
226 error = ENOMEM;
227 goto quit;
228 }
229 bzero(kcb, sizeof(struct ctl_cb));
230
231 kcb->mtx = lck_mtx_alloc_init(ctl_lck_grp, ctl_lck_attr);
232 if (kcb->mtx == NULL) {
233 error = ENOMEM;
234 goto quit;
235 }
236 kcb->so = so;
237 so->so_pcb = (caddr_t)kcb;
238
239quit:
240 if (error != 0) {
241 kcb_delete(kcb);
242 kcb = 0;
243 }
244 return error;
245}
246
247static int
248ctl_sofreelastref(struct socket *so)
249{
250 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
251
252 so->so_pcb = 0;
253
254 if (kcb != 0) {
255 struct kctl *kctl;
256 if ((kctl = kcb->kctl) != 0) {
257 lck_mtx_lock(ctl_mtx);
258 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
259 lck_mtx_lock(ctl_mtx);
260 }
261 kcb_delete(kcb);
262 }
0c530ab8 263 sofreelastref(so, 1);
91447636
A
264 return 0;
265}
266
267static int
268ctl_detach(struct socket *so)
269{
270 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
9bccf70c 271
91447636
A
272 if (kcb == 0)
273 return 0;
274
275 soisdisconnected(so);
276 so->so_flags |= SOF_PCBCLEARING;
9bccf70c
A
277 return 0;
278}
279
91447636
A
280
281static int
282ctl_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
9bccf70c 283{
91447636
A
284 struct kctl *kctl;
285 int error = 0;
286 struct sockaddr_ctl sa;
287 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
2d21ac55 288 struct ctl_cb *kcb_next = NULL;
91447636
A
289
290 if (kcb == 0)
291 panic("ctl_connect so_pcb null\n");
292
293 if (nam->sa_len != sizeof(struct sockaddr_ctl))
294 return(EINVAL);
295
296 bcopy(nam, &sa, sizeof(struct sockaddr_ctl));
297
298 lck_mtx_lock(ctl_mtx);
299 kctl = ctl_find_by_id_unit(sa.sc_id, sa.sc_unit);
300 if (kctl == NULL) {
301 lck_mtx_unlock(ctl_mtx);
302 return ENOENT;
303 }
9bccf70c 304
91447636
A
305 if (((kctl->flags & CTL_FLAG_REG_SOCK_STREAM) && (so->so_type != SOCK_STREAM)) ||
306 (!(kctl->flags & CTL_FLAG_REG_SOCK_STREAM) && (so->so_type != SOCK_DGRAM))) {
307 lck_mtx_unlock(ctl_mtx);
308 return EPROTOTYPE;
309 }
9bccf70c 310
91447636
A
311 if (kctl->flags & CTL_FLAG_PRIVILEGED) {
312 if (p == 0) {
313 lck_mtx_unlock(ctl_mtx);
55e303ae 314 return(EINVAL);
91447636 315 }
2d21ac55 316 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
91447636 317 lck_mtx_unlock(ctl_mtx);
2d21ac55 318 return EPERM;
91447636
A
319 }
320 }
321
322 if ((kctl->flags & CTL_FLAG_REG_ID_UNIT) || sa.sc_unit != 0) {
323 if (kcb_find(kctl, sa.sc_unit) != NULL) {
324 lck_mtx_unlock(ctl_mtx);
325 return EBUSY;
326 }
327 } else {
2d21ac55
A
328 /* Find an unused ID, assumes control IDs are listed in order */
329 u_int32_t unit = 1;
330
331 TAILQ_FOREACH(kcb_next, &kctl->kcb_head, next) {
332 if (kcb_next->unit > unit) {
333 /* Found a gap, lets fill it in */
334 break;
335 }
336 unit = kcb_next->unit + 1;
337 if (unit == ctl_maxunit)
338 break;
339 }
91447636 340
2d21ac55
A
341 if (unit == ctl_maxunit) {
342 lck_mtx_unlock(ctl_mtx);
343 return EBUSY;
344 }
345
346 sa.sc_unit = unit;
55e303ae
A
347 }
348
91447636
A
349 kcb->unit = sa.sc_unit;
350 kcb->kctl = kctl;
2d21ac55
A
351 if (kcb_next != NULL) {
352 TAILQ_INSERT_BEFORE(kcb_next, kcb, next);
353 }
354 else {
355 TAILQ_INSERT_TAIL(&kctl->kcb_head, kcb, next);
356 }
91447636 357 lck_mtx_unlock(ctl_mtx);
9bccf70c 358
91447636 359 error = soreserve(so, kctl->sendbufsize, kctl->recvbufsize);
9bccf70c 360 if (error)
91447636
A
361 goto done;
362 soisconnecting(so);
9bccf70c 363
91447636
A
364 socket_unlock(so, 0);
365 error = (*kctl->connect)(kctl, &sa, &kcb->userdata);
366 socket_lock(so, 0);
367 if (error)
368 goto done;
9bccf70c 369
91447636
A
370 soisconnected(so);
371
372done:
9bccf70c 373 if (error) {
91447636
A
374 soisdisconnected(so);
375 lck_mtx_lock(ctl_mtx);
376 kcb->kctl = 0;
377 kcb->unit = 0;
378 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
379 lck_mtx_unlock(ctl_mtx);
9bccf70c 380 }
9bccf70c
A
381 return error;
382}
383
91447636 384static int
9bccf70c
A
385ctl_disconnect(struct socket *so)
386{
91447636
A
387 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
388
389 if ((kcb = (struct ctl_cb *)so->so_pcb)) {
390 struct kctl *kctl = kcb->kctl;
391
392 if (kctl && kctl->disconnect) {
393 socket_unlock(so, 0);
394 (*kctl->disconnect)(kctl, kcb->unit, kcb->userdata);
395 socket_lock(so, 0);
396 }
397 lck_mtx_lock(ctl_mtx);
398 kcb->kctl = 0;
399 kcb->unit = 0;
400 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
9bccf70c 401 soisdisconnected(so);
91447636 402 lck_mtx_unlock(ctl_mtx);
9bccf70c
A
403 }
404 return 0;
405}
406
91447636
A
407static int
408ctl_peeraddr(struct socket *so, struct sockaddr **nam)
9bccf70c 409{
91447636
A
410 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
411 struct kctl *kctl;
412 struct sockaddr_ctl sc;
413
414 if (kcb == NULL) /* sanity check */
415 return(ENOTCONN);
416
417 if ((kctl = kcb->kctl) == NULL)
418 return(EINVAL);
419
420 bzero(&sc, sizeof(struct sockaddr_ctl));
421 sc.sc_len = sizeof(struct sockaddr_ctl);
422 sc.sc_family = AF_SYSTEM;
423 sc.ss_sysaddr = AF_SYS_CONTROL;
424 sc.sc_id = kctl->id;
425 sc.sc_unit = kcb->unit;
426
427 *nam = dup_sockaddr((struct sockaddr *)&sc, 1);
428
429 return 0;
9bccf70c
A
430}
431
91447636
A
432static int
433ctl_send(struct socket *so, int flags, struct mbuf *m,
434 __unused struct sockaddr *addr, __unused struct mbuf *control,
435 __unused struct proc *p)
9bccf70c 436{
91447636
A
437 int error = 0;
438 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
439 struct kctl *kctl;
440
441 if (kcb == NULL) /* sanity check */
442 return(ENOTCONN);
443
444 if ((kctl = kcb->kctl) == NULL)
445 return(EINVAL);
446
447 if (kctl->send) {
448 socket_unlock(so, 0);
449 error = (*kctl->send)(kctl, kcb->unit, kcb->userdata, m, flags);
450 socket_lock(so, 0);
451 }
452 return error;
9bccf70c
A
453}
454
91447636
A
455errno_t
456ctl_enqueuembuf(void *kctlref, u_int32_t unit, struct mbuf *m, u_int32_t flags)
9bccf70c 457{
91447636
A
458 struct ctl_cb *kcb;
459 struct socket *so;
460 errno_t error = 0;
461 struct kctl *kctl = (struct kctl *)kctlref;
462
463 if (kctl == NULL)
464 return EINVAL;
465
466 kcb = kcb_find(kctl, unit);
467 if (kcb == NULL)
468 return EINVAL;
469
470 so = (struct socket *)kcb->so;
471 if (so == NULL)
472 return EINVAL;
473
474 socket_lock(so, 1);
475 if (sbspace(&so->so_rcv) < m->m_pkthdr.len) {
476 error = ENOBUFS;
477 goto bye;
478 }
479 if ((flags & CTL_DATA_EOR))
480 m->m_flags |= M_EOR;
481 if (sbappend(&so->so_rcv, m) && (flags & CTL_DATA_NOWAKEUP) == 0)
482 sorwakeup(so);
483bye:
484 socket_unlock(so, 1);
485 return error;
486}
9bccf70c 487
91447636
A
488errno_t
489ctl_enqueuedata(void *kctlref, u_int32_t unit, void *data, size_t len, u_int32_t flags)
490{
491 struct ctl_cb *kcb;
492 struct socket *so;
493 struct mbuf *m;
494 errno_t error = 0;
495 struct kctl *kctl = (struct kctl *)kctlref;
496 unsigned int num_needed;
497 struct mbuf *n;
498 size_t curlen = 0;
499
500 if (kctlref == NULL)
501 return EINVAL;
502
503 kcb = kcb_find(kctl, unit);
504 if (kcb == NULL)
505 return EINVAL;
506
507 so = (struct socket *)kcb->so;
508 if (so == NULL)
509 return EINVAL;
510
511 socket_lock(so, 1);
2d21ac55 512 if (sbspace(&so->so_rcv) < (long)len) {
91447636
A
513 error = ENOBUFS;
514 goto bye;
515 }
516
517 num_needed = 1;
518 m = m_allocpacket_internal(&num_needed, len, NULL, M_NOWAIT, 1, 0);
519 if (m == NULL) {
520 printf("ctl_enqueuedata: m_allocpacket_internal(%lu) failed\n", len);
521 error = ENOBUFS;
522 goto bye;
523 }
524
525 for (n = m; n != NULL; n = n->m_next) {
526 size_t mlen = mbuf_maxlen(n);
527
528 if (mlen + curlen > len)
529 mlen = len - curlen;
530 n->m_len = mlen;
531 bcopy((char *)data + curlen, n->m_data, mlen);
532 curlen += mlen;
533 }
534 mbuf_pkthdr_setlen(m, curlen);
535
536 if ((flags & CTL_DATA_EOR))
537 m->m_flags |= M_EOR;
538 if (sbappend(&so->so_rcv, m) && (flags & CTL_DATA_NOWAKEUP) == 0)
539 sorwakeup(so);
540bye:
541 socket_unlock(so, 1);
542 return error;
543}
9bccf70c 544
55e303ae 545
91447636
A
546errno_t
547ctl_getenqueuespace(kern_ctl_ref kctlref, u_int32_t unit, size_t *space)
548{
549 struct ctl_cb *kcb;
550 struct kctl *kctl = (struct kctl *)kctlref;
551 struct socket *so;
2d21ac55 552 long avail;
91447636
A
553
554 if (kctlref == NULL || space == NULL)
555 return EINVAL;
556
557 kcb = kcb_find(kctl, unit);
558 if (kcb == NULL)
559 return EINVAL;
560
561 so = (struct socket *)kcb->so;
562 if (so == NULL)
563 return EINVAL;
564
565 socket_lock(so, 1);
2d21ac55
A
566 avail = sbspace(&so->so_rcv);
567 *space = (avail < 0) ? 0 : avail;
91447636
A
568 socket_unlock(so, 1);
569
570 return 0;
9bccf70c
A
571}
572
91447636 573static int
9bccf70c
A
574ctl_ctloutput(struct socket *so, struct sockopt *sopt)
575{
91447636
A
576 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
577 struct kctl *kctl;
578 int error = 0;
579 void *data;
580 size_t len;
581
582 if (sopt->sopt_level != SYSPROTO_CONTROL) {
583 return(EINVAL);
584 }
585
586 if (kcb == NULL) /* sanity check */
587 return(ENOTCONN);
588
589 if ((kctl = kcb->kctl) == NULL)
590 return(EINVAL);
591
592 switch (sopt->sopt_dir) {
593 case SOPT_SET:
594 if (kctl->setopt == NULL)
595 return(ENOTSUP);
2d21ac55
A
596 if (sopt->sopt_valsize == 0) {
597 data = NULL;
598 } else {
599 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
600 if (data == NULL)
601 return(ENOMEM);
602 error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize);
603 }
91447636
A
604 if (error == 0) {
605 socket_unlock(so, 0);
606 error = (*kctl->setopt)(kcb->kctl, kcb->unit, kcb->userdata, sopt->sopt_name,
607 data, sopt->sopt_valsize);
608 socket_lock(so, 0);
609 }
610 FREE(data, M_TEMP);
611 break;
612
613 case SOPT_GET:
614 if (kctl->getopt == NULL)
615 return(ENOTSUP);
616 data = NULL;
617 if (sopt->sopt_valsize && sopt->sopt_val) {
618 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
619 if (data == NULL)
620 return(ENOMEM);
cc9f6e38
A
621 /* 4108337 - copy in data for get socket option */
622 error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize);
91447636
A
623 }
624 len = sopt->sopt_valsize;
625 socket_unlock(so, 0);
626 error = (*kctl->getopt)(kcb->kctl, kcb->unit, kcb->userdata, sopt->sopt_name,
627 data, &len);
628 socket_lock(so, 0);
629 if (error == 0) {
630 if (data != NULL)
631 error = sooptcopyout(sopt, data, len);
632 else
633 sopt->sopt_valsize = len;
634 }
635 if (data != NULL)
636 FREE(data, M_TEMP);
637 break;
638 }
639 return error;
640}
9bccf70c 641
91447636
A
642static int
643ctl_ioctl(__unused struct socket *so, u_long cmd, caddr_t data,
644 __unused struct ifnet *ifp, __unused struct proc *p)
645{
646 int error = ENOTSUP;
647
648 switch (cmd) {
649 /* get the number of controllers */
650 case CTLIOCGCOUNT: {
651 struct kctl *kctl;
652 int n = 0;
653
654 lck_mtx_lock(ctl_mtx);
655 TAILQ_FOREACH(kctl, &ctl_head, next)
656 n++;
657 lck_mtx_unlock(ctl_mtx);
658
659 *(u_int32_t *)data = n;
660 error = 0;
661 break;
662 }
663 case CTLIOCGINFO: {
664 struct ctl_info *ctl_info = (struct ctl_info *)data;
665 struct kctl *kctl = 0;
666 size_t name_len = strlen(ctl_info->ctl_name);
667
668 if (name_len == 0 || name_len + 1 > MAX_KCTL_NAME) {
669 error = EINVAL;
670 break;
671 }
672 lck_mtx_lock(ctl_mtx);
673 kctl = ctl_find_by_name(ctl_info->ctl_name);
674 lck_mtx_unlock(ctl_mtx);
675 if (kctl == 0) {
676 error = ENOENT;
677 break;
678 }
679 ctl_info->ctl_id = kctl->id;
680 error = 0;
681 break;
682 }
683
684 /* add controls to get list of NKEs */
685
686 }
687
688 return error;
689}
9bccf70c 690
91447636
A
691/*
692 * Register/unregister a NKE
693 */
694errno_t
695ctl_register(struct kern_ctl_reg *userkctl, kern_ctl_ref *kctlref)
2d21ac55
A
696{
697 struct kctl *kctl = NULL;
698 struct kctl *kctl_next = NULL;
699 u_int32_t id = 1;
91447636
A
700 size_t name_len;
701
702 if (userkctl == NULL) /* sanity check */
703 return(EINVAL);
704 if (userkctl->ctl_connect == NULL)
705 return(EINVAL);
706 name_len = strlen(userkctl->ctl_name);
707 if (name_len == 0 || name_len + 1 > MAX_KCTL_NAME)
708 return(EINVAL);
709
710 MALLOC(kctl, struct kctl *, sizeof(*kctl), M_TEMP, M_WAITOK);
711 if (kctl == NULL)
712 return(ENOMEM);
713 bzero((char *)kctl, sizeof(*kctl));
714
715 lck_mtx_lock(ctl_mtx);
716
2d21ac55
A
717 /*
718 * Kernel Control IDs
719 *
720 * CTL_FLAG_REG_ID_UNIT indicates the control ID and unit number are
721 * static. If they do not exist, add them to the list in order. If the
722 * flag is not set, we must find a new unique value. We assume the
723 * list is in order. We find the last item in the list and add one. If
724 * this leads to wrapping the id around, we start at the front of the
725 * list and look for a gap.
726 */
727
728 if ((userkctl->ctl_flags & CTL_FLAG_REG_ID_UNIT) == 0) {
729 /* Must dynamically assign an unused ID */
730
731 /* Verify the same name isn't already registered */
91447636
A
732 if (ctl_find_by_name(userkctl->ctl_name) != NULL) {
733 lck_mtx_unlock(ctl_mtx);
734 FREE(kctl, M_TEMP);
735 return(EEXIST);
736 }
2d21ac55
A
737
738 /* Start with 1 in case the list is empty */
739 id = 1;
740 kctl_next = TAILQ_LAST(&ctl_head, kctl_list);
741
742 if (kctl_next != NULL) {
743 /* List was not empty, add one to the last item in the list */
744 id = kctl_next->id + 1;
745 kctl_next = NULL;
746
747 /*
748 * If this wrapped the id number, start looking at the front
749 * of the list for an unused id.
750 */
91447636 751 if (id == 0) {
2d21ac55
A
752 /* Find the next unused ID */
753 id = 1;
754
755 TAILQ_FOREACH(kctl_next, &ctl_head, next) {
756 if (kctl_next->id > id) {
757 /* We found a gap */
758 break;
759 }
760
761 id = kctl_next->id + 1;
762 }
91447636 763 }
91447636 764 }
2d21ac55
A
765
766 userkctl->ctl_id = id;
91447636
A
767 kctl->id = id;
768 kctl->reg_unit = -1;
769 } else {
2d21ac55
A
770 TAILQ_FOREACH(kctl_next, &ctl_head, next) {
771 if (kctl_next->id > userkctl->ctl_id)
772 break;
773 }
774
91447636
A
775 if (ctl_find_by_id_unit(userkctl->ctl_id, userkctl->ctl_unit) != NULL) {
776 lck_mtx_unlock(ctl_mtx);
777 FREE(kctl, M_TEMP);
778 return(EEXIST);
779 }
780 kctl->id = userkctl->ctl_id;
781 kctl->reg_unit = userkctl->ctl_unit;
782 }
2d21ac55 783 strlcpy(kctl->name, userkctl->ctl_name, MAX_KCTL_NAME);
91447636
A
784 kctl->flags = userkctl->ctl_flags;
785
786 /* Let the caller know the default send and receive sizes */
787 if (userkctl->ctl_sendsize == 0)
788 userkctl->ctl_sendsize = CTL_SENDSIZE;
789 kctl->sendbufsize = userkctl->ctl_sendsize;
790
3a60a9f5 791 if (userkctl->ctl_recvsize == 0)
91447636
A
792 userkctl->ctl_recvsize = CTL_RECVSIZE;
793 kctl->recvbufsize = userkctl->ctl_recvsize;
794
795 kctl->connect = userkctl->ctl_connect;
796 kctl->disconnect = userkctl->ctl_disconnect;
797 kctl->send = userkctl->ctl_send;
798 kctl->setopt = userkctl->ctl_setopt;
799 kctl->getopt = userkctl->ctl_getopt;
800
801 TAILQ_INIT(&kctl->kcb_head);
802
2d21ac55
A
803 if (kctl_next)
804 TAILQ_INSERT_BEFORE(kctl_next, kctl, next);
805 else
806 TAILQ_INSERT_TAIL(&ctl_head, kctl, next);
91447636
A
807
808 lck_mtx_unlock(ctl_mtx);
809
810 *kctlref = kctl;
811
812 ctl_post_msg(KEV_CTL_REGISTERED, kctl->id);
813 return(0);
9bccf70c
A
814}
815
91447636
A
816errno_t
817ctl_deregister(void *kctlref)
818{
819 struct kctl *kctl;
9bccf70c 820
91447636
A
821 if (kctlref == NULL) /* sanity check */
822 return(EINVAL);
9bccf70c 823
91447636
A
824 lck_mtx_lock(ctl_mtx);
825 TAILQ_FOREACH(kctl, &ctl_head, next) {
826 if (kctl == (struct kctl *)kctlref)
827 break;
9bccf70c 828 }
91447636
A
829 if (kctl != (struct kctl *)kctlref) {
830 lck_mtx_unlock(ctl_mtx);
831 return EINVAL;
832 }
833 if (!TAILQ_EMPTY(&kctl->kcb_head)) {
834 lck_mtx_unlock(ctl_mtx);
835 return EBUSY;
836 }
837
838 TAILQ_REMOVE(&ctl_head, kctl, next);
91447636
A
839
840 lck_mtx_unlock(ctl_mtx);
9bccf70c 841
91447636
A
842 ctl_post_msg(KEV_CTL_DEREGISTERED, kctl->id);
843 FREE(kctl, M_TEMP);
844 return(0);
9bccf70c
A
845}
846
91447636
A
847/*
848 * Must be called with global ctl_mtx lock taked
849 */
850static struct kctl *
851ctl_find_by_name(const char *name)
9bccf70c 852{
91447636 853 struct kctl *kctl;
9bccf70c 854
91447636 855 TAILQ_FOREACH(kctl, &ctl_head, next)
2d21ac55 856 if (strncmp(kctl->name, name, sizeof(kctl->name)) == 0)
91447636 857 return kctl;
9bccf70c 858
91447636
A
859 return NULL;
860}
9bccf70c 861
91447636
A
862/*
863 * Must be called with global ctl_mtx lock taked
864 *
865 */
866static struct kctl *
867ctl_find_by_id_unit(u_int32_t id, u_int32_t unit)
868{
869 struct kctl *kctl;
870
871 TAILQ_FOREACH(kctl, &ctl_head, next) {
872 if (kctl->id == id && (kctl->flags & CTL_FLAG_REG_ID_UNIT) == 0)
873 return kctl;
874 else if (kctl->id == id && kctl->reg_unit == unit)
875 return kctl;
9bccf70c 876 }
91447636 877 return NULL;
9bccf70c
A
878}
879
880/*
91447636 881 * Must be called with kernel controller lock taken
9bccf70c 882 */
91447636
A
883static struct ctl_cb *
884kcb_find(struct kctl *kctl, u_int32_t unit)
9bccf70c 885{
91447636 886 struct ctl_cb *kcb;
9bccf70c 887
91447636
A
888 TAILQ_FOREACH(kcb, &kctl->kcb_head, next)
889 if ((kcb->unit == unit))
890 return kcb;
9bccf70c
A
891
892 return NULL;
893}
894
91447636
A
895/*
896 * Must be called witout lock
897 */
898static void
899ctl_post_msg(u_long event_code, u_int32_t id)
9bccf70c
A
900{
901 struct ctl_event_data ctl_ev_data;
902 struct kev_msg ev_msg;
903
904 ev_msg.vendor_code = KEV_VENDOR_APPLE;
905
906 ev_msg.kev_class = KEV_SYSTEM_CLASS;
907 ev_msg.kev_subclass = KEV_CTL_SUBCLASS;
908 ev_msg.event_code = event_code;
909
910 /* common nke subclass data */
911 bzero(&ctl_ev_data, sizeof(ctl_ev_data));
912 ctl_ev_data.ctl_id = id;
9bccf70c
A
913 ev_msg.dv[0].data_ptr = &ctl_ev_data;
914 ev_msg.dv[0].data_length = sizeof(ctl_ev_data);
915
916 ev_msg.dv[1].data_length = 0;
917
918 kev_post_msg(&ev_msg);
919}
920
91447636
A
921static int
922ctl_lock(struct socket *so, int refcount, int lr)
923 {
2d21ac55 924 uint32_t lr_saved;
0c530ab8
A
925 if (lr == 0)
926 lr_saved = (unsigned int) __builtin_return_address(0);
91447636 927 else lr_saved = lr;
91447636
A
928
929 if (so->so_pcb) {
930 lck_mtx_lock(((struct ctl_cb *)so->so_pcb)->mtx);
931 } else {
2d21ac55 932 panic("ctl_lock: so=%p NO PCB! lr=%x\n", so, lr_saved);
91447636
A
933 lck_mtx_lock(so->so_proto->pr_domain->dom_mtx);
934 }
935
936 if (so->so_usecount < 0)
2d21ac55 937 panic("ctl_lock: so=%p so_pcb=%p lr=%x ref=%x\n",
91447636
A
938 so, so->so_pcb, lr_saved, so->so_usecount);
939
940 if (refcount)
941 so->so_usecount++;
0c530ab8 942
2d21ac55 943 so->lock_lr[so->next_lock_lr] = lr_saved;
0c530ab8 944 so->next_lock_lr = (so->next_lock_lr+1) % SO_LCKDBG_MAX;
91447636
A
945 return (0);
946}
947
948static int
949ctl_unlock(struct socket *so, int refcount, int lr)
950{
2d21ac55 951 uint32_t lr_saved;
91447636
A
952 lck_mtx_t * mutex_held;
953
0c530ab8
A
954 if (lr == 0)
955 lr_saved = (unsigned int) __builtin_return_address(0);
91447636 956 else lr_saved = lr;
91447636
A
957
958#ifdef MORE_KCTLLOCK_DEBUG
959 printf("ctl_unlock: so=%x sopcb=%x lock=%x ref=%x lr=%x\n",
960 so, so->so_pcb, ((struct ctl_cb *)so->so_pcb)->mtx, so->so_usecount, lr_saved);
961#endif
962 if (refcount)
963 so->so_usecount--;
964
965 if (so->so_usecount < 0)
2d21ac55 966 panic("ctl_unlock: so=%p usecount=%x\n", so, so->so_usecount);
91447636 967 if (so->so_pcb == NULL) {
2d21ac55 968 panic("ctl_unlock: so=%p NO PCB usecount=%x lr=%x\n", so, so->so_usecount, lr_saved);
91447636
A
969 mutex_held = so->so_proto->pr_domain->dom_mtx;
970 } else {
971 mutex_held = ((struct ctl_cb *)so->so_pcb)->mtx;
972 }
973 lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
2d21ac55 974 so->unlock_lr[so->next_unlock_lr] = lr_saved;
0c530ab8 975 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
91447636 976 lck_mtx_unlock(mutex_held);
91447636
A
977
978 if (so->so_usecount == 0)
979 ctl_sofreelastref(so);
980
981 return (0);
982}
983
984static lck_mtx_t *
985ctl_getlock(struct socket *so, __unused int locktype)
986{
987 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
988
989 if (so->so_pcb) {
990 if (so->so_usecount < 0)
2d21ac55 991 panic("ctl_getlock: so=%p usecount=%x\n", so, so->so_usecount);
91447636
A
992 return(kcb->mtx);
993 } else {
2d21ac55 994 panic("ctl_getlock: so=%p NULL so_pcb\n", so);
91447636
A
995 return (so->so_proto->pr_domain->dom_mtx);
996 }
997}