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