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