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