]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_control.c
xnu-6153.81.5.tar.gz
[apple/xnu.git] / bsd / kern / kern_control.c
CommitLineData
9bccf70c 1/*
5c9f4661 2 * Copyright (c) 1999-2017 Apple Inc. All rights reserved.
9bccf70c 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
fe8ab488 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.
fe8ab488 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.
fe8ab488 17 *
2d21ac55
A
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.
fe8ab488 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>
fe8ab488 52#include <sys/sysctl.h>
3e170ce0 53#include <sys/proc_info.h>
9bccf70c
A
54#include <net/if_var.h>
55
56#include <mach/vm_types.h>
9bccf70c
A
57
58#include <kern/thread.h>
59
3e170ce0 60struct kctl {
0a7de745
A
61 TAILQ_ENTRY(kctl) next; /* controller chain */
62 kern_ctl_ref kctlref;
3e170ce0
A
63
64 /* controller information provided when registering */
0a7de745
A
65 char name[MAX_KCTL_NAME]; /* unique identifier */
66 u_int32_t id;
67 u_int32_t reg_unit;
3e170ce0
A
68
69 /* misc communication information */
0a7de745
A
70 u_int32_t flags; /* support flags */
71 u_int32_t recvbufsize; /* request more than the default buffer size */
72 u_int32_t sendbufsize; /* request more than the default buffer size */
3e170ce0
A
73
74 /* Dispatch functions */
0a7de745
A
75 ctl_bind_func bind; /* Prepare contact */
76 ctl_connect_func connect; /* Make contact */
77 ctl_disconnect_func disconnect; /* Break contact */
78 ctl_send_func send; /* Send data to nke */
79 ctl_send_list_func send_list; /* Send list of packets */
80 ctl_setopt_func setopt; /* set kctl configuration */
81 ctl_getopt_func getopt; /* get kctl configuration */
82 ctl_rcvd_func rcvd; /* Notify nke when client reads data */
83
84 TAILQ_HEAD(, ctl_cb) kcb_head;
85 u_int32_t lastunit;
3e170ce0
A
86};
87
4ba76501
A
88#if DEVELOPMENT || DEBUG
89enum ctl_status {
90 KCTL_DISCONNECTED = 0,
91 KCTL_CONNECTING = 1,
92 KCTL_CONNECTED = 2
93};
94#endif /* DEVELOPMENT || DEBUG */
95
3e170ce0 96struct ctl_cb {
0a7de745
A
97 TAILQ_ENTRY(ctl_cb) next; /* controller chain */
98 lck_mtx_t *mtx;
99 struct socket *so; /* controlling socket */
100 struct kctl *kctl; /* back pointer to controller */
101 void *userdata;
102 struct sockaddr_ctl sac;
103 u_int32_t usecount;
94ff46dc 104 u_int32_t kcb_usecount;
4ba76501
A
105#if DEVELOPMENT || DEBUG
106 enum ctl_status status;
107#endif /* DEVELOPMENT || DEBUG */
3e170ce0
A
108};
109
fe8ab488 110#ifndef ROUNDUP64
0a7de745 111#define ROUNDUP64(x) P2ROUNDUP((x), sizeof (u_int64_t))
fe8ab488
A
112#endif
113
114#ifndef ADVANCE64
0a7de745 115#define ADVANCE64(p, n) (void*)((char *)(p) + ROUNDUP64(n))
fe8ab488
A
116#endif
117
9bccf70c
A
118/*
119 * Definitions and vars for we support
120 */
121
0a7de745
A
122#define CTL_SENDSIZE (2 * 1024) /* default buffer size */
123#define CTL_RECVSIZE (8 * 1024) /* default buffer size */
9bccf70c
A
124
125/*
91447636
A
126 * Definitions and vars for we support
127 */
9bccf70c 128
0a7de745
A
129static u_int32_t ctl_maxunit = 65536;
130static lck_grp_attr_t *ctl_lck_grp_attr = 0;
131static lck_attr_t *ctl_lck_attr = 0;
132static lck_grp_t *ctl_lck_grp = 0;
133static lck_mtx_t *ctl_mtx;
9bccf70c
A
134
135/* all the controllers are chained */
0a7de745 136TAILQ_HEAD(kctl_list, kctl) ctl_head;
91447636
A
137
138static int ctl_attach(struct socket *, int, struct proc *);
139static int ctl_detach(struct socket *);
140static int ctl_sofreelastref(struct socket *so);
5c9f4661 141static int ctl_bind(struct socket *, struct sockaddr *, struct proc *);
91447636
A
142static int ctl_connect(struct socket *, struct sockaddr *, struct proc *);
143static int ctl_disconnect(struct socket *);
144static int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
0a7de745 145 struct ifnet *ifp, struct proc *p);
91447636 146static int ctl_send(struct socket *, int, struct mbuf *,
0a7de745 147 struct sockaddr *, struct mbuf *, struct proc *);
fe8ab488 148static int ctl_send_list(struct socket *, int, struct mbuf *,
0a7de745 149 struct sockaddr *, struct mbuf *, struct proc *);
91447636
A
150static int ctl_ctloutput(struct socket *, struct sockopt *);
151static int ctl_peeraddr(struct socket *so, struct sockaddr **nam);
39236c6e 152static int ctl_usr_rcvd(struct socket *so, int flags);
91447636 153
91447636
A
154static struct kctl *ctl_find_by_name(const char *);
155static struct kctl *ctl_find_by_id_unit(u_int32_t id, u_int32_t unit);
9bccf70c 156
3e170ce0 157static struct socket *kcb_find_socket(kern_ctl_ref kctlref, u_int32_t unit,
0a7de745 158 u_int32_t *);
91447636 159static struct ctl_cb *kcb_find(struct kctl *, u_int32_t unit);
b0d623f7 160static void ctl_post_msg(u_int32_t event_code, u_int32_t id);
9bccf70c 161
b0d623f7
A
162static int ctl_lock(struct socket *, int, void *);
163static int ctl_unlock(struct socket *, int, void *);
91447636 164static lck_mtx_t * ctl_getlock(struct socket *, int);
9bccf70c 165
39236c6e 166static struct pr_usrreqs ctl_usrreqs = {
0a7de745
A
167 .pru_attach = ctl_attach,
168 .pru_bind = ctl_bind,
169 .pru_connect = ctl_connect,
170 .pru_control = ctl_ioctl,
171 .pru_detach = ctl_detach,
172 .pru_disconnect = ctl_disconnect,
173 .pru_peeraddr = ctl_peeraddr,
174 .pru_rcvd = ctl_usr_rcvd,
175 .pru_send = ctl_send,
176 .pru_send_list = ctl_send_list,
177 .pru_sosend = sosend,
178 .pru_sosend_list = sosend_list,
179 .pru_soreceive = soreceive,
180 .pru_soreceive_list = soreceive_list,
91447636
A
181};
182
39236c6e 183static struct protosw kctlsw[] = {
0a7de745
A
184 {
185 .pr_type = SOCK_DGRAM,
186 .pr_protocol = SYSPROTO_CONTROL,
187 .pr_flags = PR_ATOMIC | PR_CONNREQUIRED | PR_PCBLOCK | PR_WANTRCVD,
188 .pr_ctloutput = ctl_ctloutput,
189 .pr_usrreqs = &ctl_usrreqs,
190 .pr_lock = ctl_lock,
191 .pr_unlock = ctl_unlock,
192 .pr_getlock = ctl_getlock,
193 },
194 {
195 .pr_type = SOCK_STREAM,
196 .pr_protocol = SYSPROTO_CONTROL,
197 .pr_flags = PR_CONNREQUIRED | PR_PCBLOCK | PR_WANTRCVD,
198 .pr_ctloutput = ctl_ctloutput,
199 .pr_usrreqs = &ctl_usrreqs,
200 .pr_lock = ctl_lock,
201 .pr_unlock = ctl_unlock,
202 .pr_getlock = ctl_getlock,
203 }
9bccf70c
A
204};
205
fe8ab488
A
206__private_extern__ int kctl_reg_list SYSCTL_HANDLER_ARGS;
207__private_extern__ int kctl_pcblist SYSCTL_HANDLER_ARGS;
208__private_extern__ int kctl_getstat SYSCTL_HANDLER_ARGS;
209
91447636 210
fe8ab488 211SYSCTL_NODE(_net_systm, OID_AUTO, kctl,
0a7de745 212 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "Kernel control family");
fe8ab488
A
213
214struct kctlstat kctlstat;
215SYSCTL_PROC(_net_systm_kctl, OID_AUTO, stats,
216 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
217 kctl_getstat, "S,kctlstat", "");
218
219SYSCTL_PROC(_net_systm_kctl, OID_AUTO, reg_list,
0a7de745
A
220 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
221 kctl_reg_list, "S,xkctl_reg", "");
fe8ab488
A
222
223SYSCTL_PROC(_net_systm_kctl, OID_AUTO, pcblist,
0a7de745
A
224 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
225 kctl_pcblist, "S,xkctlpcb", "");
fe8ab488
A
226
227u_int32_t ctl_autorcvbuf_max = 256 * 1024;
228SYSCTL_INT(_net_systm_kctl, OID_AUTO, autorcvbufmax,
0a7de745 229 CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_autorcvbuf_max, 0, "");
fe8ab488
A
230
231u_int32_t ctl_autorcvbuf_high = 0;
232SYSCTL_INT(_net_systm_kctl, OID_AUTO, autorcvbufhigh,
0a7de745 233 CTLFLAG_RD | CTLFLAG_LOCKED, &ctl_autorcvbuf_high, 0, "");
fe8ab488
A
234
235u_int32_t ctl_debug = 0;
236SYSCTL_INT(_net_systm_kctl, OID_AUTO, debug,
0a7de745 237 CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_debug, 0, "");
fe8ab488 238
4ba76501
A
239#if DEVELOPMENT || DEBUG
240u_int32_t ctl_panic_debug = 0;
241SYSCTL_INT(_net_systm_kctl, OID_AUTO, panicdebug,
242 CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_panic_debug, 0, "");
243#endif /* DEVELOPMENT || DEBUG */
244
0a7de745 245#define KCTL_TBL_INC 16
3e170ce0
A
246
247static uintptr_t kctl_tbl_size = 0;
248static u_int32_t kctl_tbl_growing = 0;
39037602 249static u_int32_t kctl_tbl_growing_waiting = 0;
3e170ce0
A
250static uintptr_t kctl_tbl_count = 0;
251static struct kctl **kctl_table = NULL;
252static uintptr_t kctl_ref_gencnt = 0;
253
254static void kctl_tbl_grow(void);
255static kern_ctl_ref kctl_make_ref(struct kctl *kctl);
256static void kctl_delete_ref(kern_ctl_ref);
257static struct kctl *kctl_from_ref(kern_ctl_ref);
258
9bccf70c 259/*
91447636 260 * Install the protosw's for the Kernel Control manager.
9bccf70c 261 */
39236c6e
A
262__private_extern__ void
263kern_control_init(struct domain *dp)
9bccf70c 264{
39236c6e
A
265 struct protosw *pr;
266 int i;
0a7de745 267 int kctl_proto_count = (sizeof(kctlsw) / sizeof(struct protosw));
39236c6e
A
268
269 VERIFY(!(dp->dom_flags & DOM_INITIALIZED));
270 VERIFY(dp == systemdomain);
271
91447636 272 ctl_lck_grp_attr = lck_grp_attr_alloc_init();
39236c6e
A
273 if (ctl_lck_grp_attr == NULL) {
274 panic("%s: lck_grp_attr_alloc_init failed\n", __func__);
275 /* NOTREACHED */
91447636 276 }
39236c6e
A
277
278 ctl_lck_grp = lck_grp_alloc_init("Kernel Control Protocol",
279 ctl_lck_grp_attr);
280 if (ctl_lck_grp == NULL) {
281 panic("%s: lck_grp_alloc_init failed\n", __func__);
282 /* NOTREACHED */
91447636 283 }
39236c6e 284
91447636 285 ctl_lck_attr = lck_attr_alloc_init();
39236c6e
A
286 if (ctl_lck_attr == NULL) {
287 panic("%s: lck_attr_alloc_init failed\n", __func__);
288 /* NOTREACHED */
91447636 289 }
39236c6e 290
91447636 291 ctl_mtx = lck_mtx_alloc_init(ctl_lck_grp, ctl_lck_attr);
39236c6e
A
292 if (ctl_mtx == NULL) {
293 panic("%s: lck_mtx_alloc_init failed\n", __func__);
294 /* NOTREACHED */
91447636
A
295 }
296 TAILQ_INIT(&ctl_head);
39236c6e 297
0a7de745 298 for (i = 0, pr = &kctlsw[0]; i < kctl_proto_count; i++, pr++) {
39236c6e 299 net_add_proto(pr, dp, 1);
0a7de745 300 }
91447636 301}
9bccf70c 302
91447636
A
303static void
304kcb_delete(struct ctl_cb *kcb)
305{
306 if (kcb != 0) {
0a7de745 307 if (kcb->mtx != 0) {
91447636 308 lck_mtx_free(kcb->mtx, ctl_lck_grp);
0a7de745 309 }
91447636
A
310 FREE(kcb, M_TEMP);
311 }
9bccf70c
A
312}
313
9bccf70c
A
314/*
315 * Kernel Controller user-request functions
fe8ab488
A
316 * attach function must exist and succeed
317 * detach not necessary
91447636 318 * we need a pcb for the per socket mutex
9bccf70c 319 */
91447636 320static int
fe8ab488
A
321ctl_attach(struct socket *so, int proto, struct proc *p)
322{
323#pragma unused(proto, p)
91447636 324 int error = 0;
0a7de745 325 struct ctl_cb *kcb = 0;
91447636
A
326
327 MALLOC(kcb, struct ctl_cb *, sizeof(struct ctl_cb), M_TEMP, M_WAITOK);
328 if (kcb == NULL) {
329 error = ENOMEM;
330 goto quit;
331 }
332 bzero(kcb, sizeof(struct ctl_cb));
fe8ab488 333
91447636
A
334 kcb->mtx = lck_mtx_alloc_init(ctl_lck_grp, ctl_lck_attr);
335 if (kcb->mtx == NULL) {
336 error = ENOMEM;
337 goto quit;
338 }
339 kcb->so = so;
340 so->so_pcb = (caddr_t)kcb;
fe8ab488 341
91447636
A
342quit:
343 if (error != 0) {
344 kcb_delete(kcb);
345 kcb = 0;
346 }
0a7de745 347 return error;
91447636
A
348}
349
350static int
351ctl_sofreelastref(struct socket *so)
352{
0a7de745 353 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
fe8ab488
A
354
355 so->so_pcb = 0;
356
357 if (kcb != 0) {
0a7de745 358 struct kctl *kctl;
fe8ab488
A
359 if ((kctl = kcb->kctl) != 0) {
360 lck_mtx_lock(ctl_mtx);
361 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
362 kctlstat.kcs_pcbcount--;
363 kctlstat.kcs_gencnt++;
364 lck_mtx_unlock(ctl_mtx);
365 }
366 kcb_delete(kcb);
367 }
368 sofreelastref(so, 1);
0a7de745 369 return 0;
91447636
A
370}
371
94ff46dc
A
372/*
373 * Use this function to serialize calls into the kctl subsystem
374 */
375static void
376ctl_kcb_increment_use_count(struct ctl_cb *kcb, lck_mtx_t *mutex_held)
377{
378 LCK_MTX_ASSERT(mutex_held, LCK_MTX_ASSERT_OWNED);
379 while (kcb->kcb_usecount > 0) {
380 msleep(&kcb->kcb_usecount, mutex_held, PSOCK | PCATCH, "kcb_usecount", NULL);
381 }
382 kcb->kcb_usecount++;
383}
384
385static void
386clt_kcb_decrement_use_count(struct ctl_cb *kcb)
387{
388 assert(kcb->kcb_usecount != 0);
389 kcb->kcb_usecount--;
390 wakeup_one((caddr_t)&kcb->kcb_usecount);
391}
392
91447636
A
393static int
394ctl_detach(struct socket *so)
395{
0a7de745 396 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
fe8ab488 397
0a7de745
A
398 if (kcb == 0) {
399 return 0;
400 }
fe8ab488 401
94ff46dc
A
402 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
403 ctl_kcb_increment_use_count(kcb, mtx_held);
404
5c9f4661
A
405 if (kcb->kctl != NULL && kcb->kctl->bind != NULL &&
406 kcb->userdata != NULL && !(so->so_state & SS_ISCONNECTED)) {
407 // The unit was bound, but not connected
408 // Invoke the disconnected call to cleanup
409 if (kcb->kctl->disconnect != NULL) {
410 socket_unlock(so, 0);
411 (*kcb->kctl->disconnect)(kcb->kctl->kctlref,
412 kcb->sac.sc_unit, kcb->userdata);
413 socket_lock(so, 0);
414 }
415 }
416
fe8ab488 417 soisdisconnected(so);
4ba76501
A
418#if DEVELOPMENT || DEBUG
419 kcb->status = KCTL_DISCONNECTED;
420#endif /* DEVELOPMENT || DEBUG */
fe8ab488 421 so->so_flags |= SOF_PCBCLEARING;
94ff46dc 422 clt_kcb_decrement_use_count(kcb);
0a7de745 423 return 0;
9bccf70c
A
424}
425
91447636 426static int
5c9f4661 427ctl_setup_kctl(struct socket *so, struct sockaddr *nam, struct proc *p)
fe8ab488 428{
5c9f4661
A
429 struct kctl *kctl = NULL;
430 int error = 0;
0a7de745 431 struct sockaddr_ctl sa;
5c9f4661
A
432 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
433 struct ctl_cb *kcb_next = NULL;
434 u_quad_t sbmaxsize;
435 u_int32_t recvbufsize, sendbufsize;
fe8ab488 436
5c9f4661
A
437 if (kcb == 0) {
438 panic("ctl_setup_kctl so_pcb null\n");
439 }
440
441 if (kcb->kctl != NULL) {
442 // Already set up, skip
0a7de745 443 return 0;
5c9f4661 444 }
fe8ab488 445
5c9f4661 446 if (nam->sa_len != sizeof(struct sockaddr_ctl)) {
0a7de745 447 return EINVAL;
5c9f4661 448 }
fe8ab488
A
449
450 bcopy(nam, &sa, sizeof(struct sockaddr_ctl));
451
452 lck_mtx_lock(ctl_mtx);
453 kctl = ctl_find_by_id_unit(sa.sc_id, sa.sc_unit);
454 if (kctl == NULL) {
455 lck_mtx_unlock(ctl_mtx);
0a7de745 456 return ENOENT;
fe8ab488
A
457 }
458
459 if (((kctl->flags & CTL_FLAG_REG_SOCK_STREAM) &&
0a7de745
A
460 (so->so_type != SOCK_STREAM)) ||
461 (!(kctl->flags & CTL_FLAG_REG_SOCK_STREAM) &&
462 (so->so_type != SOCK_DGRAM))) {
463 lck_mtx_unlock(ctl_mtx);
464 return EPROTOTYPE;
465 }
fe8ab488
A
466
467 if (kctl->flags & CTL_FLAG_PRIVILEGED) {
468 if (p == 0) {
469 lck_mtx_unlock(ctl_mtx);
0a7de745 470 return EINVAL;
fe8ab488
A
471 }
472 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
473 lck_mtx_unlock(ctl_mtx);
0a7de745 474 return EPERM;
fe8ab488
A
475 }
476 }
91447636
A
477
478 if ((kctl->flags & CTL_FLAG_REG_ID_UNIT) || sa.sc_unit != 0) {
479 if (kcb_find(kctl, sa.sc_unit) != NULL) {
480 lck_mtx_unlock(ctl_mtx);
0a7de745 481 return EBUSY;
91447636
A
482 }
483 } else {
fe8ab488 484 /* Find an unused ID, assumes control IDs are in order */
5c9f4661 485 u_int32_t unit = 1;
fe8ab488
A
486
487 TAILQ_FOREACH(kcb_next, &kctl->kcb_head, next) {
5c9f4661 488 if (kcb_next->sac.sc_unit > unit) {
fe8ab488
A
489 /* Found a gap, lets fill it in */
490 break;
491 }
5c9f4661
A
492 unit = kcb_next->sac.sc_unit + 1;
493 if (unit == ctl_maxunit) {
fe8ab488 494 break;
5c9f4661 495 }
fe8ab488
A
496 }
497
2d21ac55
A
498 if (unit == ctl_maxunit) {
499 lck_mtx_unlock(ctl_mtx);
0a7de745 500 return EBUSY;
2d21ac55 501 }
fe8ab488 502
2d21ac55 503 sa.sc_unit = unit;
fe8ab488 504 }
55e303ae 505
5c9f4661 506 bcopy(&sa, &kcb->sac, sizeof(struct sockaddr_ctl));
fe8ab488
A
507 kcb->kctl = kctl;
508 if (kcb_next != NULL) {
509 TAILQ_INSERT_BEFORE(kcb_next, kcb, next);
510 } else {
2d21ac55
A
511 TAILQ_INSERT_TAIL(&kctl->kcb_head, kcb, next);
512 }
fe8ab488
A
513 kctlstat.kcs_pcbcount++;
514 kctlstat.kcs_gencnt++;
515 kctlstat.kcs_connections++;
516 lck_mtx_unlock(ctl_mtx);
9bccf70c 517
04b8595b
A
518 /*
519 * rdar://15526688: Limit the send and receive sizes to sb_max
520 * by using the same scaling as sbreserve()
521 */
522 sbmaxsize = (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES);
523
5c9f4661 524 if (kctl->sendbufsize > sbmaxsize) {
04b8595b 525 sendbufsize = sbmaxsize;
5c9f4661 526 } else {
04b8595b 527 sendbufsize = kctl->sendbufsize;
5c9f4661 528 }
04b8595b 529
5c9f4661 530 if (kctl->recvbufsize > sbmaxsize) {
04b8595b 531 recvbufsize = sbmaxsize;
5c9f4661 532 } else {
04b8595b 533 recvbufsize = kctl->recvbufsize;
5c9f4661 534 }
04b8595b
A
535
536 error = soreserve(so, sendbufsize, recvbufsize);
fe8ab488 537 if (error) {
0a7de745 538 if (ctl_debug) {
39037602 539 printf("%s - soreserve(%llx, %u, %u) error %d\n",
0a7de745
A
540 __func__, (uint64_t)VM_KERNEL_ADDRPERM(so),
541 sendbufsize, recvbufsize, error);
542 }
91447636 543 goto done;
fe8ab488 544 }
5c9f4661
A
545
546done:
547 if (error) {
548 soisdisconnected(so);
4ba76501
A
549#if DEVELOPMENT || DEBUG
550 kcb->status = KCTL_DISCONNECTED;
551#endif /* DEVELOPMENT || DEBUG */
5c9f4661
A
552 lck_mtx_lock(ctl_mtx);
553 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
554 kcb->kctl = NULL;
555 kcb->sac.sc_unit = 0;
556 kctlstat.kcs_pcbcount--;
557 kctlstat.kcs_gencnt++;
558 kctlstat.kcs_conn_fail++;
559 lck_mtx_unlock(ctl_mtx);
560 }
0a7de745 561 return error;
5c9f4661
A
562}
563
564static int
565ctl_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
566{
567 int error = 0;
568 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
569
570 if (kcb == NULL) {
571 panic("ctl_bind so_pcb null\n");
572 }
573
94ff46dc
A
574 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
575 ctl_kcb_increment_use_count(kcb, mtx_held);
576
5c9f4661
A
577 error = ctl_setup_kctl(so, nam, p);
578 if (error) {
94ff46dc 579 goto out;
5c9f4661
A
580 }
581
582 if (kcb->kctl == NULL) {
583 panic("ctl_bind kctl null\n");
584 }
585
586 if (kcb->kctl->bind == NULL) {
94ff46dc
A
587 error = EINVAL;
588 goto out;
5c9f4661 589 }
fe8ab488 590
91447636 591 socket_unlock(so, 0);
5c9f4661 592 error = (*kcb->kctl->bind)(kcb->kctl->kctlref, &kcb->sac, &kcb->userdata);
91447636 593 socket_lock(so, 0);
fe8ab488 594
94ff46dc
A
595out:
596 clt_kcb_decrement_use_count(kcb);
0a7de745 597 return error;
5c9f4661
A
598}
599
600static int
601ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
602{
603 int error = 0;
604 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
605
606 if (kcb == NULL) {
607 panic("ctl_connect so_pcb null\n");
608 }
609
94ff46dc
A
610 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
611 ctl_kcb_increment_use_count(kcb, mtx_held);
612
4ba76501
A
613#if DEVELOPMENT || DEBUG
614 if (kcb->status != KCTL_DISCONNECTED && ctl_panic_debug) {
615 panic("kctl already connecting/connected");
616 }
617 kcb->status = KCTL_CONNECTING;
618#endif /* DEVELOPMENT || DEBUG */
619
5c9f4661
A
620 error = ctl_setup_kctl(so, nam, p);
621 if (error) {
94ff46dc 622 goto out;
5c9f4661
A
623 }
624
625 if (kcb->kctl == NULL) {
626 panic("ctl_connect kctl null\n");
627 }
628
629 soisconnecting(so);
630 socket_unlock(so, 0);
631 error = (*kcb->kctl->connect)(kcb->kctl->kctlref, &kcb->sac, &kcb->userdata);
632 socket_lock(so, 0);
633 if (error) {
634 goto end;
635 }
fe8ab488 636 soisconnected(so);
4ba76501
A
637#if DEVELOPMENT || DEBUG
638 kcb->status = KCTL_CONNECTED;
639#endif /* DEVELOPMENT || DEBUG */
91447636 640
6d2010ae 641end:
5c9f4661 642 if (error && kcb->kctl->disconnect) {
39037602
A
643 /*
644 * XXX Make sure we Don't check the return value
645 * of disconnect here.
646 * ipsec/utun_ctl_disconnect will return error when
647 * disconnect gets called after connect failure.
648 * However if we decide to check for disconnect return
649 * value here. Please make sure to revisit
650 * ipsec/utun_ctl_disconnect.
651 */
6d2010ae 652 socket_unlock(so, 0);
5c9f4661 653 (*kcb->kctl->disconnect)(kcb->kctl->kctlref, kcb->sac.sc_unit, kcb->userdata);
6d2010ae
A
654 socket_lock(so, 0);
655 }
fe8ab488
A
656 if (error) {
657 soisdisconnected(so);
4ba76501
A
658#if DEVELOPMENT || DEBUG
659 kcb->status = KCTL_DISCONNECTED;
660#endif /* DEVELOPMENT || DEBUG */
fe8ab488 661 lck_mtx_lock(ctl_mtx);
5c9f4661
A
662 TAILQ_REMOVE(&kcb->kctl->kcb_head, kcb, next);
663 kcb->kctl = NULL;
664 kcb->sac.sc_unit = 0;
fe8ab488
A
665 kctlstat.kcs_pcbcount--;
666 kctlstat.kcs_gencnt++;
667 kctlstat.kcs_conn_fail++;
668 lck_mtx_unlock(ctl_mtx);
669 }
94ff46dc
A
670out:
671 clt_kcb_decrement_use_count(kcb);
0a7de745 672 return error;
9bccf70c
A
673}
674
91447636 675static int
9bccf70c
A
676ctl_disconnect(struct socket *so)
677{
0a7de745 678 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
fe8ab488
A
679
680 if ((kcb = (struct ctl_cb *)so->so_pcb)) {
94ff46dc
A
681 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
682 ctl_kcb_increment_use_count(kcb, mtx_held);
0a7de745 683 struct kctl *kctl = kcb->kctl;
fe8ab488
A
684
685 if (kctl && kctl->disconnect) {
686 socket_unlock(so, 0);
5c9f4661 687 (*kctl->disconnect)(kctl->kctlref, kcb->sac.sc_unit,
3e170ce0 688 kcb->userdata);
fe8ab488
A
689 socket_lock(so, 0);
690 }
691
692 soisdisconnected(so);
4ba76501
A
693#if DEVELOPMENT || DEBUG
694 kcb->status = KCTL_DISCONNECTED;
695#endif /* DEVELOPMENT || DEBUG */
fe8ab488 696
6d2010ae 697 socket_unlock(so, 0);
fe8ab488
A
698 lck_mtx_lock(ctl_mtx);
699 kcb->kctl = 0;
5c9f4661 700 kcb->sac.sc_unit = 0;
fe8ab488
A
701 while (kcb->usecount != 0) {
702 msleep(&kcb->usecount, ctl_mtx, 0, "kcb->usecount", 0);
703 }
704 TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
705 kctlstat.kcs_pcbcount--;
706 kctlstat.kcs_gencnt++;
707 lck_mtx_unlock(ctl_mtx);
6d2010ae 708 socket_lock(so, 0);
94ff46dc 709 clt_kcb_decrement_use_count(kcb);
fe8ab488 710 }
0a7de745 711 return 0;
9bccf70c
A
712}
713
91447636
A
714static int
715ctl_peeraddr(struct socket *so, struct sockaddr **nam)
9bccf70c 716{
0a7de745
A
717 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
718 struct kctl *kctl;
719 struct sockaddr_ctl sc;
fe8ab488 720
0a7de745
A
721 if (kcb == NULL) { /* sanity check */
722 return ENOTCONN;
723 }
fe8ab488 724
0a7de745
A
725 if ((kctl = kcb->kctl) == NULL) {
726 return EINVAL;
727 }
fe8ab488 728
91447636
A
729 bzero(&sc, sizeof(struct sockaddr_ctl));
730 sc.sc_len = sizeof(struct sockaddr_ctl);
731 sc.sc_family = AF_SYSTEM;
732 sc.ss_sysaddr = AF_SYS_CONTROL;
733 sc.sc_id = kctl->id;
5c9f4661 734 sc.sc_unit = kcb->sac.sc_unit;
fe8ab488 735
91447636 736 *nam = dup_sockaddr((struct sockaddr *)&sc, 1);
fe8ab488 737
0a7de745 738 return 0;
fe8ab488
A
739}
740
741static void
742ctl_sbrcv_trim(struct socket *so)
743{
744 struct sockbuf *sb = &so->so_rcv;
745
746 if (sb->sb_hiwat > sb->sb_idealsize) {
747 u_int32_t diff;
748 int32_t trim;
749
750 /*
751 * The difference between the ideal size and the
752 * current size is the upper bound of the trimage
753 */
754 diff = sb->sb_hiwat - sb->sb_idealsize;
755 /*
756 * We cannot trim below the outstanding data
757 */
758 trim = sb->sb_hiwat - sb->sb_cc;
759
760 trim = imin(trim, (int32_t)diff);
761
762 if (trim > 0) {
763 sbreserve(sb, (sb->sb_hiwat - trim));
764
0a7de745 765 if (ctl_debug) {
fe8ab488
A
766 printf("%s - shrunk to %d\n",
767 __func__, sb->sb_hiwat);
0a7de745 768 }
fe8ab488
A
769 }
770 }
9bccf70c
A
771}
772
39236c6e
A
773static int
774ctl_usr_rcvd(struct socket *so, int flags)
775{
94ff46dc 776 int error = 0;
0a7de745
A
777 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
778 struct kctl *kctl;
39236c6e 779
94ff46dc
A
780 if (kcb == NULL) {
781 return ENOTCONN;
782 }
783
784 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
785 ctl_kcb_increment_use_count(kcb, mtx_held);
786
39236c6e 787 if ((kctl = kcb->kctl) == NULL) {
94ff46dc
A
788 error = EINVAL;
789 goto out;
39236c6e
A
790 }
791
792 if (kctl->rcvd) {
793 socket_unlock(so, 0);
5c9f4661 794 (*kctl->rcvd)(kctl->kctlref, kcb->sac.sc_unit, kcb->userdata, flags);
39236c6e
A
795 socket_lock(so, 0);
796 }
797
fe8ab488
A
798 ctl_sbrcv_trim(so);
799
94ff46dc
A
800out:
801 clt_kcb_decrement_use_count(kcb);
802 return error;
39236c6e
A
803}
804
91447636
A
805static int
806ctl_send(struct socket *so, int flags, struct mbuf *m,
0a7de745
A
807 struct sockaddr *addr, struct mbuf *control,
808 struct proc *p)
9bccf70c 809{
fe8ab488 810#pragma unused(addr, p)
0a7de745
A
811 int error = 0;
812 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
813 struct kctl *kctl;
fe8ab488 814
0a7de745 815 if (control) {
fe8ab488 816 m_freem(control);
0a7de745 817 }
fe8ab488 818
0a7de745 819 if (kcb == NULL) { /* sanity check */
6d2010ae 820 error = ENOTCONN;
0a7de745 821 }
fe8ab488 822
94ff46dc
A
823 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
824 ctl_kcb_increment_use_count(kcb, mtx_held);
825
0a7de745 826 if (error == 0 && (kctl = kcb->kctl) == NULL) {
6d2010ae 827 error = EINVAL;
0a7de745 828 }
fe8ab488 829
6d2010ae 830 if (error == 0 && kctl->send) {
fe8ab488 831 so_tc_update_stats(m, so, m_get_service_class(m));
91447636 832 socket_unlock(so, 0);
5c9f4661 833 error = (*kctl->send)(kctl->kctlref, kcb->sac.sc_unit, kcb->userdata,
3e170ce0 834 m, flags);
91447636 835 socket_lock(so, 0);
6d2010ae
A
836 } else {
837 m_freem(m);
0a7de745 838 if (error == 0) {
6d2010ae 839 error = ENOTSUP;
0a7de745 840 }
91447636 841 }
0a7de745 842 if (error != 0) {
fe8ab488 843 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_send_fail);
0a7de745 844 }
94ff46dc
A
845 clt_kcb_decrement_use_count(kcb);
846
0a7de745 847 return error;
fe8ab488
A
848}
849
850static int
851ctl_send_list(struct socket *so, int flags, struct mbuf *m,
0a7de745
A
852 __unused struct sockaddr *addr, struct mbuf *control,
853 __unused struct proc *p)
fe8ab488 854{
0a7de745
A
855 int error = 0;
856 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
857 struct kctl *kctl;
fe8ab488 858
0a7de745 859 if (control) {
fe8ab488 860 m_freem_list(control);
0a7de745 861 }
fe8ab488 862
0a7de745 863 if (kcb == NULL) { /* sanity check */
fe8ab488 864 error = ENOTCONN;
0a7de745 865 }
fe8ab488 866
94ff46dc
A
867 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
868 ctl_kcb_increment_use_count(kcb, mtx_held);
869
0a7de745 870 if (error == 0 && (kctl = kcb->kctl) == NULL) {
fe8ab488 871 error = EINVAL;
0a7de745 872 }
fe8ab488
A
873
874 if (error == 0 && kctl->send_list) {
875 struct mbuf *nxt;
876
0a7de745 877 for (nxt = m; nxt != NULL; nxt = nxt->m_nextpkt) {
fe8ab488 878 so_tc_update_stats(nxt, so, m_get_service_class(nxt));
0a7de745 879 }
fe8ab488
A
880
881 socket_unlock(so, 0);
5c9f4661 882 error = (*kctl->send_list)(kctl->kctlref, kcb->sac.sc_unit,
3e170ce0 883 kcb->userdata, m, flags);
fe8ab488
A
884 socket_lock(so, 0);
885 } else if (error == 0 && kctl->send) {
886 while (m != NULL && error == 0) {
887 struct mbuf *nextpkt = m->m_nextpkt;
888
889 m->m_nextpkt = NULL;
890 so_tc_update_stats(m, so, m_get_service_class(m));
891 socket_unlock(so, 0);
5c9f4661 892 error = (*kctl->send)(kctl->kctlref, kcb->sac.sc_unit,
3e170ce0 893 kcb->userdata, m, flags);
fe8ab488
A
894 socket_lock(so, 0);
895 m = nextpkt;
896 }
0a7de745 897 if (m != NULL) {
fe8ab488 898 m_freem_list(m);
0a7de745 899 }
fe8ab488
A
900 } else {
901 m_freem_list(m);
0a7de745 902 if (error == 0) {
fe8ab488 903 error = ENOTSUP;
0a7de745 904 }
fe8ab488 905 }
0a7de745 906 if (error != 0) {
fe8ab488 907 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_send_list_fail);
0a7de745 908 }
94ff46dc
A
909 clt_kcb_decrement_use_count(kcb);
910
0a7de745 911 return error;
fe8ab488
A
912}
913
914static errno_t
3e170ce0 915ctl_rcvbspace(struct socket *so, u_int32_t datasize,
0a7de745 916 u_int32_t kctlflags, u_int32_t flags)
fe8ab488
A
917{
918 struct sockbuf *sb = &so->so_rcv;
919 u_int32_t space = sbspace(sb);
920 errno_t error;
04b8595b 921
3e170ce0 922 if ((kctlflags & CTL_FLAG_REG_CRIT) == 0) {
0a7de745 923 if ((u_int32_t) space >= datasize) {
fe8ab488 924 error = 0;
0a7de745 925 } else {
fe8ab488 926 error = ENOBUFS;
0a7de745 927 }
fe8ab488 928 } else if ((flags & CTL_DATA_CRIT) == 0) {
3e170ce0
A
929 /*
930 * Reserve 25% for critical messages
931 */
932 if (space < (sb->sb_hiwat >> 2) ||
0a7de745 933 space < datasize) {
3e170ce0 934 error = ENOBUFS;
0a7de745 935 } else {
3e170ce0 936 error = 0;
0a7de745 937 }
fe8ab488
A
938 } else {
939 u_int32_t autorcvbuf_max;
940
941 /*
942 * Allow overcommit of 25%
943 */
944 autorcvbuf_max = min(sb->sb_idealsize + (sb->sb_idealsize >> 2),
0a7de745 945 ctl_autorcvbuf_max);
fe8ab488
A
946
947 if ((u_int32_t) space >= datasize) {
948 error = 0;
949 } else if (tcp_cansbgrow(sb) &&
950 sb->sb_hiwat < autorcvbuf_max) {
951 /*
952 * Grow with a little bit of leeway
953 */
954 u_int32_t grow = datasize - space + MSIZE;
955
956 if (sbreserve(sb,
957 min((sb->sb_hiwat + grow), autorcvbuf_max)) == 1) {
0a7de745 958 if (sb->sb_hiwat > ctl_autorcvbuf_high) {
fe8ab488 959 ctl_autorcvbuf_high = sb->sb_hiwat;
0a7de745 960 }
fe8ab488 961
3e170ce0
A
962 /*
963 * A final check
964 */
965 if ((u_int32_t) sbspace(sb) >= datasize) {
966 error = 0;
967 } else {
968 error = ENOBUFS;
969 }
970
0a7de745 971 if (ctl_debug) {
3e170ce0
A
972 printf("%s - grown to %d error %d\n",
973 __func__, sb->sb_hiwat, error);
0a7de745 974 }
fe8ab488
A
975 } else {
976 error = ENOBUFS;
977 }
978 } else {
979 error = ENOBUFS;
980 }
981 }
0a7de745 982 return error;
9bccf70c
A
983}
984
91447636 985errno_t
3e170ce0
A
986ctl_enqueuembuf(kern_ctl_ref kctlref, u_int32_t unit, struct mbuf *m,
987 u_int32_t flags)
9bccf70c 988{
0a7de745
A
989 struct socket *so;
990 errno_t error = 0;
991 int len = m->m_pkthdr.len;
992 u_int32_t kctlflags;
fe8ab488 993
3e170ce0
A
994 so = kcb_find_socket(kctlref, unit, &kctlflags);
995 if (so == NULL) {
0a7de745 996 return EINVAL;
3e170ce0 997 }
fe8ab488 998
3e170ce0 999 if (ctl_rcvbspace(so, len, kctlflags, flags) != 0) {
91447636 1000 error = ENOBUFS;
fe8ab488 1001 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fullsock);
91447636
A
1002 goto bye;
1003 }
0a7de745 1004 if ((flags & CTL_DATA_EOR)) {
91447636 1005 m->m_flags |= M_EOR;
0a7de745 1006 }
fe8ab488
A
1007
1008 so_recv_data_stat(so, m, 0);
1009 if (sbappend(&so->so_rcv, m) != 0) {
0a7de745 1010 if ((flags & CTL_DATA_NOWAKEUP) == 0) {
fe8ab488 1011 sorwakeup(so);
0a7de745 1012 }
fe8ab488
A
1013 } else {
1014 error = ENOBUFS;
1015 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fullsock);
1016 }
91447636 1017bye:
0a7de745 1018 if (ctl_debug && error != 0 && (flags & CTL_DATA_CRIT)) {
fe8ab488 1019 printf("%s - crit data err %d len %d hiwat %d cc: %d\n",
0a7de745
A
1020 __func__, error, len,
1021 so->so_rcv.sb_hiwat, so->so_rcv.sb_cc);
1022 }
fe8ab488 1023
91447636 1024 socket_unlock(so, 1);
0a7de745 1025 if (error != 0) {
fe8ab488 1026 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fail);
0a7de745 1027 }
fe8ab488 1028
0a7de745 1029 return error;
fe8ab488
A
1030}
1031
1032/*
1033 * Compute space occupied by mbuf like sbappendrecord
1034 */
1035static int
1036m_space(struct mbuf *m)
1037{
1038 int space = 0;
1039 struct mbuf *nxt;
1040
0a7de745 1041 for (nxt = m; nxt != NULL; nxt = nxt->m_next) {
fe8ab488 1042 space += nxt->m_len;
0a7de745 1043 }
fe8ab488 1044
0a7de745 1045 return space;
fe8ab488
A
1046}
1047
1048errno_t
1049ctl_enqueuembuf_list(void *kctlref, u_int32_t unit, struct mbuf *m_list,
0a7de745 1050 u_int32_t flags, struct mbuf **m_remain)
fe8ab488
A
1051{
1052 struct socket *so = NULL;
1053 errno_t error = 0;
fe8ab488
A
1054 struct mbuf *m, *nextpkt;
1055 int needwakeup = 0;
5ba3f43e 1056 int len = 0;
3e170ce0 1057 u_int32_t kctlflags;
fe8ab488
A
1058
1059 /*
1060 * Need to point the beginning of the list in case of early exit
1061 */
1062 m = m_list;
1063
3e170ce0
A
1064 /*
1065 * kcb_find_socket takes the socket lock with a reference
1066 */
1067 so = kcb_find_socket(kctlref, unit, &kctlflags);
1068 if (so == NULL) {
fe8ab488
A
1069 error = EINVAL;
1070 goto done;
1071 }
3e170ce0
A
1072
1073 if (kctlflags & CTL_FLAG_REG_SOCK_STREAM) {
fe8ab488
A
1074 error = EOPNOTSUPP;
1075 goto done;
1076 }
1077 if (flags & CTL_DATA_EOR) {
1078 error = EINVAL;
1079 goto done;
1080 }
fe8ab488
A
1081
1082 for (m = m_list; m != NULL; m = nextpkt) {
1083 nextpkt = m->m_nextpkt;
1084
0a7de745 1085 if (m->m_pkthdr.len == 0 && ctl_debug) {
fe8ab488 1086 printf("%s: %llx m_pkthdr.len is 0",
0a7de745
A
1087 __func__, (uint64_t)VM_KERNEL_ADDRPERM(m));
1088 }
fe8ab488
A
1089
1090 /*
1091 * The mbuf is either appended or freed by sbappendrecord()
1092 * so it's not reliable from a data standpoint
1093 */
1094 len = m_space(m);
3e170ce0 1095 if (ctl_rcvbspace(so, len, kctlflags, flags) != 0) {
fe8ab488
A
1096 error = ENOBUFS;
1097 OSIncrementAtomic64(
0a7de745 1098 (SInt64 *)&kctlstat.kcs_enqueue_fullsock);
fe8ab488
A
1099 break;
1100 } else {
1101 /*
1102 * Unlink from the list, m is on its own
1103 */
1104 m->m_nextpkt = NULL;
1105 so_recv_data_stat(so, m, 0);
1106 if (sbappendrecord(&so->so_rcv, m) != 0) {
1107 needwakeup = 1;
1108 } else {
1109 /*
1110 * We free or return the remaining
1111 * mbufs in the list
1112 */
1113 m = nextpkt;
1114 error = ENOBUFS;
1115 OSIncrementAtomic64(
0a7de745 1116 (SInt64 *)&kctlstat.kcs_enqueue_fullsock);
fe8ab488
A
1117 break;
1118 }
1119 }
1120 }
0a7de745 1121 if (needwakeup && (flags & CTL_DATA_NOWAKEUP) == 0) {
fe8ab488 1122 sorwakeup(so);
0a7de745 1123 }
fe8ab488
A
1124
1125done:
1126 if (so != NULL) {
0a7de745 1127 if (ctl_debug && error != 0 && (flags & CTL_DATA_CRIT)) {
fe8ab488 1128 printf("%s - crit data err %d len %d hiwat %d cc: %d\n",
0a7de745
A
1129 __func__, error, len,
1130 so->so_rcv.sb_hiwat, so->so_rcv.sb_cc);
1131 }
fe8ab488
A
1132
1133 socket_unlock(so, 1);
1134 }
1135 if (m_remain) {
1136 *m_remain = m;
1137
1138 if (m != NULL && socket_debug && so != NULL &&
1139 (so->so_options & SO_DEBUG)) {
1140 struct mbuf *n;
1141
1142 printf("%s m_list %llx\n", __func__,
1143 (uint64_t) VM_KERNEL_ADDRPERM(m_list));
0a7de745 1144 for (n = m; n != NULL; n = n->m_nextpkt) {
fe8ab488
A
1145 printf(" remain %llx m_next %llx\n",
1146 (uint64_t) VM_KERNEL_ADDRPERM(n),
1147 (uint64_t) VM_KERNEL_ADDRPERM(n->m_next));
0a7de745 1148 }
fe8ab488
A
1149 }
1150 } else {
0a7de745 1151 if (m != NULL) {
fe8ab488 1152 m_freem_list(m);
0a7de745 1153 }
fe8ab488 1154 }
0a7de745 1155 if (error != 0) {
fe8ab488 1156 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fail);
0a7de745
A
1157 }
1158 return error;
91447636 1159}
9bccf70c 1160
91447636 1161errno_t
fe8ab488
A
1162ctl_enqueuedata(void *kctlref, u_int32_t unit, void *data, size_t len,
1163 u_int32_t flags)
91447636 1164{
0a7de745
A
1165 struct socket *so;
1166 struct mbuf *m;
1167 errno_t error = 0;
1168 unsigned int num_needed;
1169 struct mbuf *n;
1170 size_t curlen = 0;
1171 u_int32_t kctlflags;
fe8ab488 1172
3e170ce0
A
1173 so = kcb_find_socket(kctlref, unit, &kctlflags);
1174 if (so == NULL) {
0a7de745 1175 return EINVAL;
3e170ce0 1176 }
fe8ab488 1177
3e170ce0 1178 if (ctl_rcvbspace(so, len, kctlflags, flags) != 0) {
91447636 1179 error = ENOBUFS;
fe8ab488 1180 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fullsock);
91447636
A
1181 goto bye;
1182 }
1183
1184 num_needed = 1;
1185 m = m_allocpacket_internal(&num_needed, len, NULL, M_NOWAIT, 1, 0);
1186 if (m == NULL) {
39037602 1187 kctlstat.kcs_enqdata_mb_alloc_fail++;
0a7de745 1188 if (ctl_debug) {
39037602
A
1189 printf("%s: m_allocpacket_internal(%lu) failed\n",
1190 __func__, len);
0a7de745 1191 }
fe8ab488 1192 error = ENOMEM;
91447636
A
1193 goto bye;
1194 }
fe8ab488 1195
91447636
A
1196 for (n = m; n != NULL; n = n->m_next) {
1197 size_t mlen = mbuf_maxlen(n);
fe8ab488 1198
0a7de745 1199 if (mlen + curlen > len) {
91447636 1200 mlen = len - curlen;
0a7de745 1201 }
91447636
A
1202 n->m_len = mlen;
1203 bcopy((char *)data + curlen, n->m_data, mlen);
1204 curlen += mlen;
1205 }
1206 mbuf_pkthdr_setlen(m, curlen);
1207
0a7de745 1208 if ((flags & CTL_DATA_EOR)) {
91447636 1209 m->m_flags |= M_EOR;
0a7de745 1210 }
fe8ab488
A
1211 so_recv_data_stat(so, m, 0);
1212 if (sbappend(&so->so_rcv, m) != 0) {
0a7de745 1213 if ((flags & CTL_DATA_NOWAKEUP) == 0) {
fe8ab488 1214 sorwakeup(so);
0a7de745 1215 }
fe8ab488 1216 } else {
39037602 1217 kctlstat.kcs_enqdata_sbappend_fail++;
fe8ab488
A
1218 error = ENOBUFS;
1219 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fullsock);
1220 }
1221
91447636 1222bye:
0a7de745 1223 if (ctl_debug && error != 0 && (flags & CTL_DATA_CRIT)) {
fe8ab488 1224 printf("%s - crit data err %d len %d hiwat %d cc: %d\n",
0a7de745
A
1225 __func__, error, (int)len,
1226 so->so_rcv.sb_hiwat, so->so_rcv.sb_cc);
1227 }
fe8ab488 1228
91447636 1229 socket_unlock(so, 1);
0a7de745 1230 if (error != 0) {
fe8ab488 1231 OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_enqueue_fail);
0a7de745
A
1232 }
1233 return error;
91447636 1234}
9bccf70c 1235
3e170ce0
A
1236errno_t
1237ctl_getenqueuepacketcount(kern_ctl_ref kctlref, u_int32_t unit, u_int32_t *pcnt)
1238{
0a7de745 1239 struct socket *so;
3e170ce0
A
1240 u_int32_t cnt;
1241 struct mbuf *m1;
1242
0a7de745
A
1243 if (pcnt == NULL) {
1244 return EINVAL;
1245 }
3e170ce0
A
1246
1247 so = kcb_find_socket(kctlref, unit, NULL);
1248 if (so == NULL) {
0a7de745 1249 return EINVAL;
3e170ce0
A
1250 }
1251
1252 cnt = 0;
1253 m1 = so->so_rcv.sb_mb;
1254 while (m1 != NULL) {
1255 if (m1->m_type == MT_DATA ||
1256 m1->m_type == MT_HEADER ||
0a7de745 1257 m1->m_type == MT_OOBDATA) {
3e170ce0 1258 cnt += 1;
0a7de745 1259 }
3e170ce0
A
1260 m1 = m1->m_nextpkt;
1261 }
1262 *pcnt = cnt;
1263
1264 socket_unlock(so, 1);
1265
0a7de745 1266 return 0;
3e170ce0 1267}
55e303ae 1268
fe8ab488 1269errno_t
91447636
A
1270ctl_getenqueuespace(kern_ctl_ref kctlref, u_int32_t unit, size_t *space)
1271{
0a7de745 1272 struct socket *so;
2d21ac55 1273 long avail;
fe8ab488 1274
0a7de745
A
1275 if (space == NULL) {
1276 return EINVAL;
1277 }
fe8ab488 1278
3e170ce0
A
1279 so = kcb_find_socket(kctlref, unit, NULL);
1280 if (so == NULL) {
0a7de745 1281 return EINVAL;
3e170ce0 1282 }
fe8ab488 1283
2d21ac55
A
1284 avail = sbspace(&so->so_rcv);
1285 *space = (avail < 0) ? 0 : avail;
91447636 1286 socket_unlock(so, 1);
fe8ab488 1287
0a7de745 1288 return 0;
fe8ab488
A
1289}
1290
1291errno_t
1292ctl_getenqueuereadable(kern_ctl_ref kctlref, u_int32_t unit,
1293 u_int32_t *difference)
1294{
0a7de745 1295 struct socket *so;
fe8ab488 1296
0a7de745
A
1297 if (difference == NULL) {
1298 return EINVAL;
1299 }
fe8ab488 1300
3e170ce0
A
1301 so = kcb_find_socket(kctlref, unit, NULL);
1302 if (so == NULL) {
0a7de745 1303 return EINVAL;
3e170ce0 1304 }
fe8ab488
A
1305
1306 if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat) {
1307 *difference = 0;
1308 } else {
1309 *difference = (so->so_rcv.sb_lowat - so->so_rcv.sb_cc);
1310 }
1311 socket_unlock(so, 1);
1312
0a7de745 1313 return 0;
9bccf70c
A
1314}
1315
91447636 1316static int
9bccf70c
A
1317ctl_ctloutput(struct socket *so, struct sockopt *sopt)
1318{
0a7de745
A
1319 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
1320 struct kctl *kctl;
1321 int error = 0;
1322 void *data = NULL;
1323 size_t len;
fe8ab488 1324
91447636 1325 if (sopt->sopt_level != SYSPROTO_CONTROL) {
0a7de745 1326 return EINVAL;
91447636 1327 }
fe8ab488 1328
0a7de745
A
1329 if (kcb == NULL) { /* sanity check */
1330 return ENOTCONN;
1331 }
fe8ab488 1332
0a7de745
A
1333 if ((kctl = kcb->kctl) == NULL) {
1334 return EINVAL;
1335 }
fe8ab488 1336
94ff46dc
A
1337 lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
1338 ctl_kcb_increment_use_count(kcb, mtx_held);
1339
91447636 1340 switch (sopt->sopt_dir) {
0a7de745
A
1341 case SOPT_SET:
1342 if (kctl->setopt == NULL) {
94ff46dc
A
1343 error = ENOTSUP;
1344 goto out;
0a7de745
A
1345 }
1346 if (sopt->sopt_valsize != 0) {
1347 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP,
1348 M_WAITOK | M_ZERO);
1349 if (data == NULL) {
94ff46dc
A
1350 error = ENOMEM;
1351 goto out;
91447636 1352 }
0a7de745
A
1353 error = sooptcopyin(sopt, data,
1354 sopt->sopt_valsize, sopt->sopt_valsize);
1355 }
1356 if (error == 0) {
1357 socket_unlock(so, 0);
1358 error = (*kctl->setopt)(kctl->kctlref,
1359 kcb->sac.sc_unit, kcb->userdata, sopt->sopt_name,
1360 data, sopt->sopt_valsize);
1361 socket_lock(so, 0);
1362 }
5c9f4661 1363
0a7de745
A
1364 if (data != NULL) {
1365 FREE(data, M_TEMP);
1366 }
1367 break;
fe8ab488 1368
0a7de745
A
1369 case SOPT_GET:
1370 if (kctl->getopt == NULL) {
94ff46dc
A
1371 error = ENOTSUP;
1372 goto out;
0a7de745 1373 }
5c9f4661 1374
0a7de745
A
1375 if (sopt->sopt_valsize && sopt->sopt_val) {
1376 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP,
1377 M_WAITOK | M_ZERO);
1378 if (data == NULL) {
94ff46dc
A
1379 error = ENOMEM;
1380 goto out;
91447636 1381 }
0a7de745
A
1382 /*
1383 * 4108337 - copy user data in case the
1384 * kernel control needs it
1385 */
1386 error = sooptcopyin(sopt, data,
1387 sopt->sopt_valsize, sopt->sopt_valsize);
1388 }
5c9f4661 1389
0a7de745
A
1390 if (error == 0) {
1391 len = sopt->sopt_valsize;
1392 socket_unlock(so, 0);
1393 error = (*kctl->getopt)(kctl->kctlref, kcb->sac.sc_unit,
1394 kcb->userdata, sopt->sopt_name,
1395 data, &len);
1396 if (data != NULL && len > sopt->sopt_valsize) {
1397 panic_plain("ctl_ctloutput: ctl %s returned "
1398 "len (%lu) > sopt_valsize (%lu)\n",
1399 kcb->kctl->name, len,
1400 sopt->sopt_valsize);
1401 }
1402 socket_lock(so, 0);
91447636 1403 if (error == 0) {
0a7de745
A
1404 if (data != NULL) {
1405 error = sooptcopyout(sopt, data, len);
1406 } else {
1407 sopt->sopt_valsize = len;
5c9f4661 1408 }
91447636 1409 }
0a7de745
A
1410 }
1411 if (data != NULL) {
1412 FREE(data, M_TEMP);
1413 }
1414 break;
91447636 1415 }
94ff46dc
A
1416
1417out:
1418 clt_kcb_decrement_use_count(kcb);
0a7de745 1419 return error;
91447636 1420}
9bccf70c 1421
fe8ab488
A
1422static int
1423ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
0a7de745 1424 struct ifnet *ifp, struct proc *p)
91447636 1425{
fe8ab488 1426#pragma unused(so, ifp, p)
0a7de745 1427 int error = ENOTSUP;
fe8ab488 1428
91447636 1429 switch (cmd) {
0a7de745
A
1430 /* get the number of controllers */
1431 case CTLIOCGCOUNT: {
1432 struct kctl *kctl;
1433 u_int32_t n = 0;
91447636 1434
0a7de745
A
1435 lck_mtx_lock(ctl_mtx);
1436 TAILQ_FOREACH(kctl, &ctl_head, next)
1437 n++;
1438 lck_mtx_unlock(ctl_mtx);
fe8ab488 1439
0a7de745
A
1440 bcopy(&n, data, sizeof(n));
1441 error = 0;
1442 break;
1443 }
1444 case CTLIOCGINFO: {
1445 struct ctl_info ctl_info;
1446 struct kctl *kctl = 0;
1447 size_t name_len;
316670eb 1448
0a7de745
A
1449 bcopy(data, &ctl_info, sizeof(ctl_info));
1450 name_len = strnlen(ctl_info.ctl_name, MAX_KCTL_NAME);
316670eb 1451
0a7de745
A
1452 if (name_len == 0 || name_len + 1 > MAX_KCTL_NAME) {
1453 error = EINVAL;
91447636
A
1454 break;
1455 }
0a7de745
A
1456 lck_mtx_lock(ctl_mtx);
1457 kctl = ctl_find_by_name(ctl_info.ctl_name);
1458 lck_mtx_unlock(ctl_mtx);
1459 if (kctl == 0) {
1460 error = ENOENT;
1461 break;
1462 }
1463 ctl_info.ctl_id = kctl->id;
1464 bcopy(&ctl_info, data, sizeof(ctl_info));
1465 error = 0;
1466 break;
1467 }
fe8ab488 1468
91447636 1469 /* add controls to get list of NKEs */
91447636 1470 }
fe8ab488 1471
0a7de745 1472 return error;
91447636 1473}
9bccf70c 1474
3e170ce0
A
1475static void
1476kctl_tbl_grow()
1477{
1478 struct kctl **new_table;
1479 uintptr_t new_size;
1480
1481 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
1482
39037602 1483 if (kctl_tbl_growing) {
3e170ce0 1484 /* Another thread is allocating */
39037602
A
1485 kctl_tbl_growing_waiting++;
1486
1487 do {
1488 (void) msleep((caddr_t) &kctl_tbl_growing, ctl_mtx,
0a7de745 1489 PSOCK | PCATCH, "kctl_tbl_growing", 0);
39037602
A
1490 } while (kctl_tbl_growing);
1491 kctl_tbl_growing_waiting--;
3e170ce0
A
1492 }
1493 /* Another thread grew the table */
0a7de745 1494 if (kctl_table != NULL && kctl_tbl_count < kctl_tbl_size) {
3e170ce0 1495 return;
0a7de745 1496 }
3e170ce0
A
1497
1498 /* Verify we have a sane size */
1499 if (kctl_tbl_size + KCTL_TBL_INC >= UINT16_MAX) {
39037602 1500 kctlstat.kcs_tbl_size_too_big++;
0a7de745 1501 if (ctl_debug) {
39037602
A
1502 printf("%s kctl_tbl_size %lu too big\n",
1503 __func__, kctl_tbl_size);
0a7de745 1504 }
3e170ce0
A
1505 return;
1506 }
1507 kctl_tbl_growing = 1;
1508
1509 new_size = kctl_tbl_size + KCTL_TBL_INC;
1510
1511 lck_mtx_unlock(ctl_mtx);
1512 new_table = _MALLOC(sizeof(struct kctl *) * new_size,
1513 M_TEMP, M_WAIT | M_ZERO);
1514 lck_mtx_lock(ctl_mtx);
1515
1516 if (new_table != NULL) {
1517 if (kctl_table != NULL) {
1518 bcopy(kctl_table, new_table,
1519 kctl_tbl_size * sizeof(struct kctl *));
1520
1521 _FREE(kctl_table, M_TEMP);
1522 }
1523 kctl_table = new_table;
1524 kctl_tbl_size = new_size;
1525 }
1526
1527 kctl_tbl_growing = 0;
39037602
A
1528
1529 if (kctl_tbl_growing_waiting) {
1530 wakeup(&kctl_tbl_growing);
1531 }
3e170ce0
A
1532}
1533
1534#define KCTLREF_INDEX_MASK 0x0000FFFF
1535#define KCTLREF_GENCNT_MASK 0xFFFF0000
1536#define KCTLREF_GENCNT_SHIFT 16
1537
1538static kern_ctl_ref
1539kctl_make_ref(struct kctl *kctl)
1540{
1541 uintptr_t i;
1542
1543 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
1544
0a7de745 1545 if (kctl_tbl_count >= kctl_tbl_size) {
3e170ce0 1546 kctl_tbl_grow();
0a7de745 1547 }
3e170ce0
A
1548
1549 kctl->kctlref = NULL;
1550 for (i = 0; i < kctl_tbl_size; i++) {
1551 if (kctl_table[i] == NULL) {
1552 uintptr_t ref;
1553
1554 /*
1555 * Reference is index plus one
1556 */
1557 kctl_ref_gencnt += 1;
1558
1559 /*
1560 * Add generation count as salt to reference to prevent
1561 * use after deregister
1562 */
0a7de745 1563 ref = ((kctl_ref_gencnt << KCTLREF_GENCNT_SHIFT) &
3e170ce0
A
1564 KCTLREF_GENCNT_MASK) +
1565 ((i + 1) & KCTLREF_INDEX_MASK);
1566
1567 kctl->kctlref = (void *)(ref);
1568 kctl_table[i] = kctl;
1569 kctl_tbl_count++;
1570 break;
1571 }
1572 }
1573
0a7de745 1574 if (kctl->kctlref == NULL) {
3e170ce0 1575 panic("%s no space in table", __func__);
0a7de745 1576 }
3e170ce0 1577
0a7de745 1578 if (ctl_debug > 0) {
3e170ce0 1579 printf("%s %p for %p\n",
0a7de745
A
1580 __func__, kctl->kctlref, kctl);
1581 }
3e170ce0 1582
0a7de745 1583 return kctl->kctlref;
3e170ce0
A
1584}
1585
1586static void
1587kctl_delete_ref(kern_ctl_ref kctlref)
1588{
1589 /*
1590 * Reference is index plus one
1591 */
1592 uintptr_t i = (((uintptr_t)kctlref) & KCTLREF_INDEX_MASK) - 1;
1593
1594 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
1595
1596 if (i < kctl_tbl_size) {
1597 struct kctl *kctl = kctl_table[i];
1598
1599 if (kctl->kctlref == kctlref) {
1600 kctl_table[i] = NULL;
1601 kctl_tbl_count--;
1602 } else {
1603 kctlstat.kcs_bad_kctlref++;
1604 }
1605 } else {
1606 kctlstat.kcs_bad_kctlref++;
1607 }
1608}
1609
1610static struct kctl *
1611kctl_from_ref(kern_ctl_ref kctlref)
1612{
1613 /*
1614 * Reference is index plus one
1615 */
1616 uintptr_t i = (((uintptr_t)kctlref) & KCTLREF_INDEX_MASK) - 1;
1617 struct kctl *kctl = NULL;
1618
1619 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
1620
1621 if (i >= kctl_tbl_size) {
1622 kctlstat.kcs_bad_kctlref++;
0a7de745 1623 return NULL;
3e170ce0
A
1624 }
1625 kctl = kctl_table[i];
1626 if (kctl->kctlref != kctlref) {
1627 kctlstat.kcs_bad_kctlref++;
0a7de745 1628 return NULL;
3e170ce0 1629 }
0a7de745 1630 return kctl;
3e170ce0
A
1631}
1632
91447636
A
1633/*
1634 * Register/unregister a NKE
1635 */
1636errno_t
1637ctl_register(struct kern_ctl_reg *userkctl, kern_ctl_ref *kctlref)
2d21ac55 1638{
0a7de745
A
1639 struct kctl *kctl = NULL;
1640 struct kctl *kctl_next = NULL;
1641 u_int32_t id = 1;
1642 size_t name_len;
1643 int is_extended = 0;
1644
1645 if (userkctl == NULL) { /* sanity check */
1646 return EINVAL;
1647 }
1648 if (userkctl->ctl_connect == NULL) {
1649 return EINVAL;
1650 }
91447636 1651 name_len = strlen(userkctl->ctl_name);
0a7de745
A
1652 if (name_len == 0 || name_len + 1 > MAX_KCTL_NAME) {
1653 return EINVAL;
1654 }
fe8ab488 1655
91447636 1656 MALLOC(kctl, struct kctl *, sizeof(*kctl), M_TEMP, M_WAITOK);
0a7de745
A
1657 if (kctl == NULL) {
1658 return ENOMEM;
1659 }
91447636 1660 bzero((char *)kctl, sizeof(*kctl));
fe8ab488 1661
91447636 1662 lck_mtx_lock(ctl_mtx);
fe8ab488 1663
3e170ce0
A
1664 if (kctl_make_ref(kctl) == NULL) {
1665 lck_mtx_unlock(ctl_mtx);
1666 FREE(kctl, M_TEMP);
0a7de745 1667 return ENOMEM;
3e170ce0
A
1668 }
1669
2d21ac55
A
1670 /*
1671 * Kernel Control IDs
1672 *
1673 * CTL_FLAG_REG_ID_UNIT indicates the control ID and unit number are
1674 * static. If they do not exist, add them to the list in order. If the
1675 * flag is not set, we must find a new unique value. We assume the
1676 * list is in order. We find the last item in the list and add one. If
1677 * this leads to wrapping the id around, we start at the front of the
1678 * list and look for a gap.
1679 */
fe8ab488 1680
2d21ac55
A
1681 if ((userkctl->ctl_flags & CTL_FLAG_REG_ID_UNIT) == 0) {
1682 /* Must dynamically assign an unused ID */
fe8ab488 1683
2d21ac55 1684 /* Verify the same name isn't already registered */
91447636 1685 if (ctl_find_by_name(userkctl->ctl_name) != NULL) {
3e170ce0 1686 kctl_delete_ref(kctl->kctlref);
91447636
A
1687 lck_mtx_unlock(ctl_mtx);
1688 FREE(kctl, M_TEMP);
0a7de745 1689 return EEXIST;
91447636 1690 }
fe8ab488 1691
2d21ac55
A
1692 /* Start with 1 in case the list is empty */
1693 id = 1;
1694 kctl_next = TAILQ_LAST(&ctl_head, kctl_list);
fe8ab488 1695
2d21ac55 1696 if (kctl_next != NULL) {
fe8ab488 1697 /* List was not empty, add one to the last item */
2d21ac55
A
1698 id = kctl_next->id + 1;
1699 kctl_next = NULL;
fe8ab488 1700
2d21ac55 1701 /*
fe8ab488
A
1702 * If this wrapped the id number, start looking at
1703 * the front of the list for an unused id.
2d21ac55 1704 */
91447636 1705 if (id == 0) {
2d21ac55
A
1706 /* Find the next unused ID */
1707 id = 1;
fe8ab488 1708
2d21ac55
A
1709 TAILQ_FOREACH(kctl_next, &ctl_head, next) {
1710 if (kctl_next->id > id) {
1711 /* We found a gap */
1712 break;
1713 }
fe8ab488 1714
2d21ac55
A
1715 id = kctl_next->id + 1;
1716 }
91447636 1717 }
91447636 1718 }
fe8ab488 1719
2d21ac55 1720 userkctl->ctl_id = id;
91447636
A
1721 kctl->id = id;
1722 kctl->reg_unit = -1;
1723 } else {
2d21ac55 1724 TAILQ_FOREACH(kctl_next, &ctl_head, next) {
0a7de745 1725 if (kctl_next->id > userkctl->ctl_id) {
2d21ac55 1726 break;
0a7de745 1727 }
2d21ac55 1728 }
fe8ab488
A
1729
1730 if (ctl_find_by_id_unit(userkctl->ctl_id, userkctl->ctl_unit)) {
3e170ce0 1731 kctl_delete_ref(kctl->kctlref);
91447636
A
1732 lck_mtx_unlock(ctl_mtx);
1733 FREE(kctl, M_TEMP);
0a7de745 1734 return EEXIST;
91447636
A
1735 }
1736 kctl->id = userkctl->ctl_id;
1737 kctl->reg_unit = userkctl->ctl_unit;
1738 }
39236c6e
A
1739
1740 is_extended = (userkctl->ctl_flags & CTL_FLAG_REG_EXTENDED);
1741
2d21ac55 1742 strlcpy(kctl->name, userkctl->ctl_name, MAX_KCTL_NAME);
91447636
A
1743 kctl->flags = userkctl->ctl_flags;
1744
fe8ab488
A
1745 /*
1746 * Let the caller know the default send and receive sizes
fe8ab488 1747 */
04b8595b 1748 if (userkctl->ctl_sendsize == 0) {
fe8ab488 1749 kctl->sendbufsize = CTL_SENDSIZE;
04b8595b
A
1750 userkctl->ctl_sendsize = kctl->sendbufsize;
1751 } else {
1752 kctl->sendbufsize = userkctl->ctl_sendsize;
1753 }
1754 if (userkctl->ctl_recvsize == 0) {
fe8ab488 1755 kctl->recvbufsize = CTL_RECVSIZE;
04b8595b
A
1756 userkctl->ctl_recvsize = kctl->recvbufsize;
1757 } else {
1758 kctl->recvbufsize = userkctl->ctl_recvsize;
1759 }
91447636 1760
5c9f4661 1761 kctl->bind = userkctl->ctl_bind;
91447636
A
1762 kctl->connect = userkctl->ctl_connect;
1763 kctl->disconnect = userkctl->ctl_disconnect;
1764 kctl->send = userkctl->ctl_send;
1765 kctl->setopt = userkctl->ctl_setopt;
1766 kctl->getopt = userkctl->ctl_getopt;
39236c6e
A
1767 if (is_extended) {
1768 kctl->rcvd = userkctl->ctl_rcvd;
fe8ab488 1769 kctl->send_list = userkctl->ctl_send_list;
39236c6e 1770 }
fe8ab488 1771
91447636 1772 TAILQ_INIT(&kctl->kcb_head);
fe8ab488 1773
0a7de745 1774 if (kctl_next) {
2d21ac55 1775 TAILQ_INSERT_BEFORE(kctl_next, kctl, next);
0a7de745 1776 } else {
2d21ac55 1777 TAILQ_INSERT_TAIL(&ctl_head, kctl, next);
0a7de745 1778 }
fe8ab488
A
1779
1780 kctlstat.kcs_reg_count++;
1781 kctlstat.kcs_gencnt++;
1782
91447636 1783 lck_mtx_unlock(ctl_mtx);
fe8ab488 1784
3e170ce0 1785 *kctlref = kctl->kctlref;
fe8ab488 1786
91447636 1787 ctl_post_msg(KEV_CTL_REGISTERED, kctl->id);
0a7de745 1788 return 0;
9bccf70c
A
1789}
1790
91447636
A
1791errno_t
1792ctl_deregister(void *kctlref)
fe8ab488 1793{
0a7de745 1794 struct kctl *kctl;
fe8ab488 1795
fe8ab488 1796 lck_mtx_lock(ctl_mtx);
3e170ce0
A
1797 if ((kctl = kctl_from_ref(kctlref)) == NULL) {
1798 kctlstat.kcs_bad_kctlref++;
fe8ab488 1799 lck_mtx_unlock(ctl_mtx);
0a7de745 1800 if (ctl_debug != 0) {
3e170ce0 1801 printf("%s invalid kctlref %p\n",
0a7de745
A
1802 __func__, kctlref);
1803 }
1804 return EINVAL;
fe8ab488 1805 }
3e170ce0 1806
91447636 1807 if (!TAILQ_EMPTY(&kctl->kcb_head)) {
fe8ab488 1808 lck_mtx_unlock(ctl_mtx);
0a7de745 1809 return EBUSY;
91447636
A
1810 }
1811
fe8ab488
A
1812 TAILQ_REMOVE(&ctl_head, kctl, next);
1813
1814 kctlstat.kcs_reg_count--;
1815 kctlstat.kcs_gencnt++;
91447636 1816
3e170ce0 1817 kctl_delete_ref(kctl->kctlref);
fe8ab488
A
1818 lck_mtx_unlock(ctl_mtx);
1819
1820 ctl_post_msg(KEV_CTL_DEREGISTERED, kctl->id);
1821 FREE(kctl, M_TEMP);
0a7de745 1822 return 0;
9bccf70c
A
1823}
1824
91447636
A
1825/*
1826 * Must be called with global ctl_mtx lock taked
1827 */
1828static struct kctl *
1829ctl_find_by_name(const char *name)
fe8ab488 1830{
0a7de745 1831 struct kctl *kctl;
fe8ab488
A
1832
1833 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
9bccf70c 1834
fe8ab488 1835 TAILQ_FOREACH(kctl, &ctl_head, next)
0a7de745
A
1836 if (strncmp(kctl->name, name, sizeof(kctl->name)) == 0) {
1837 return kctl;
1838 }
9bccf70c 1839
0a7de745 1840 return NULL;
91447636 1841}
9bccf70c 1842
6d2010ae
A
1843u_int32_t
1844ctl_id_by_name(const char *name)
1845{
0a7de745
A
1846 u_int32_t ctl_id = 0;
1847 struct kctl *kctl;
fe8ab488 1848
6d2010ae 1849 lck_mtx_lock(ctl_mtx);
fe8ab488 1850 kctl = ctl_find_by_name(name);
0a7de745 1851 if (kctl) {
fe8ab488 1852 ctl_id = kctl->id;
0a7de745 1853 }
6d2010ae 1854 lck_mtx_unlock(ctl_mtx);
fe8ab488 1855
0a7de745 1856 return ctl_id;
6d2010ae
A
1857}
1858
1859errno_t
fe8ab488 1860ctl_name_by_id(u_int32_t id, char *out_name, size_t maxsize)
6d2010ae 1861{
0a7de745 1862 int found = 0;
6d2010ae 1863 struct kctl *kctl;
fe8ab488
A
1864
1865 lck_mtx_lock(ctl_mtx);
1866 TAILQ_FOREACH(kctl, &ctl_head, next) {
0a7de745 1867 if (kctl->id == id) {
fe8ab488 1868 break;
0a7de745 1869 }
fe8ab488
A
1870 }
1871
3e170ce0 1872 if (kctl) {
0a7de745 1873 if (maxsize > MAX_KCTL_NAME) {
fe8ab488 1874 maxsize = MAX_KCTL_NAME;
0a7de745 1875 }
fe8ab488
A
1876 strlcpy(out_name, kctl->name, maxsize);
1877 found = 1;
1878 }
6d2010ae 1879 lck_mtx_unlock(ctl_mtx);
fe8ab488 1880
0a7de745 1881 return found ? 0 : ENOENT;
6d2010ae
A
1882}
1883
91447636
A
1884/*
1885 * Must be called with global ctl_mtx lock taked
1886 *
1887 */
1888static struct kctl *
1889ctl_find_by_id_unit(u_int32_t id, u_int32_t unit)
fe8ab488 1890{
0a7de745 1891 struct kctl *kctl;
fe8ab488
A
1892
1893 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
1894
1895 TAILQ_FOREACH(kctl, &ctl_head, next) {
0a7de745
A
1896 if (kctl->id == id && (kctl->flags & CTL_FLAG_REG_ID_UNIT) == 0) {
1897 return kctl;
1898 } else if (kctl->id == id && kctl->reg_unit == unit) {
1899 return kctl;
1900 }
fe8ab488 1901 }
0a7de745 1902 return NULL;
9bccf70c
A
1903}
1904
1905/*
91447636 1906 * Must be called with kernel controller lock taken
9bccf70c 1907 */
91447636
A
1908static struct ctl_cb *
1909kcb_find(struct kctl *kctl, u_int32_t unit)
fe8ab488 1910{
0a7de745 1911 struct ctl_cb *kcb;
9bccf70c 1912
fe8ab488 1913 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_OWNED);
9bccf70c 1914
fe8ab488 1915 TAILQ_FOREACH(kcb, &kctl->kcb_head, next)
0a7de745
A
1916 if (kcb->sac.sc_unit == unit) {
1917 return kcb;
1918 }
fe8ab488 1919
0a7de745 1920 return NULL;
9bccf70c
A
1921}
1922
6d2010ae 1923static struct socket *
3e170ce0 1924kcb_find_socket(kern_ctl_ref kctlref, u_int32_t unit, u_int32_t *kctlflags)
6d2010ae
A
1925{
1926 struct socket *so = NULL;
0a7de745 1927 struct ctl_cb *kcb;
fe8ab488 1928 void *lr_saved;
3e170ce0
A
1929 struct kctl *kctl;
1930 int i;
fe8ab488
A
1931
1932 lr_saved = __builtin_return_address(0);
1933
6d2010ae 1934 lck_mtx_lock(ctl_mtx);
3e170ce0
A
1935 /*
1936 * First validate the kctlref
1937 */
1938 if ((kctl = kctl_from_ref(kctlref)) == NULL) {
1939 kctlstat.kcs_bad_kctlref++;
1940 lck_mtx_unlock(ctl_mtx);
0a7de745 1941 if (ctl_debug != 0) {
3e170ce0 1942 printf("%s invalid kctlref %p\n",
0a7de745
A
1943 __func__, kctlref);
1944 }
1945 return NULL;
6d2010ae 1946 }
fe8ab488 1947
3e170ce0
A
1948 kcb = kcb_find(kctl, unit);
1949 if (kcb == NULL || kcb->kctl != kctl || (so = kcb->so) == NULL) {
1950 lck_mtx_unlock(ctl_mtx);
0a7de745 1951 return NULL;
6d2010ae 1952 }
3e170ce0
A
1953 /*
1954 * This prevents the socket from being closed
1955 */
1956 kcb->usecount++;
1957 /*
1958 * Respect lock ordering: socket before ctl_mtx
1959 */
1960 lck_mtx_unlock(ctl_mtx);
fe8ab488 1961
6d2010ae 1962 socket_lock(so, 1);
3e170ce0
A
1963 /*
1964 * The socket lock history is more useful if we store
1965 * the address of the caller.
1966 */
1967 i = (so->next_lock_lr + SO_LCKDBG_MAX - 1) % SO_LCKDBG_MAX;
1968 so->lock_lr[i] = lr_saved;
fe8ab488 1969
6d2010ae 1970 lck_mtx_lock(ctl_mtx);
3e170ce0
A
1971
1972 if ((kctl = kctl_from_ref(kctlref)) == NULL || kcb->kctl == NULL) {
6d2010ae
A
1973 lck_mtx_unlock(ctl_mtx);
1974 socket_unlock(so, 1);
1975 so = NULL;
1976 lck_mtx_lock(ctl_mtx);
3e170ce0
A
1977 } else if (kctlflags != NULL) {
1978 *kctlflags = kctl->flags;
6d2010ae 1979 }
3e170ce0 1980
6d2010ae 1981 kcb->usecount--;
0a7de745 1982 if (kcb->usecount == 0) {
6d2010ae 1983 wakeup((event_t)&kcb->usecount);
0a7de745 1984 }
3e170ce0 1985
6d2010ae 1986 lck_mtx_unlock(ctl_mtx);
fe8ab488 1987
0a7de745 1988 return so;
6d2010ae
A
1989}
1990
fe8ab488
A
1991static void
1992ctl_post_msg(u_int32_t event_code, u_int32_t id)
9bccf70c 1993{
0a7de745
A
1994 struct ctl_event_data ctl_ev_data;
1995 struct kev_msg ev_msg;
fe8ab488
A
1996
1997 lck_mtx_assert(ctl_mtx, LCK_MTX_ASSERT_NOTOWNED);
1998
1999 bzero(&ev_msg, sizeof(struct kev_msg));
2000 ev_msg.vendor_code = KEV_VENDOR_APPLE;
2001
2002 ev_msg.kev_class = KEV_SYSTEM_CLASS;
2003 ev_msg.kev_subclass = KEV_CTL_SUBCLASS;
2004 ev_msg.event_code = event_code;
2005
2006 /* common nke subclass data */
2007 bzero(&ctl_ev_data, sizeof(ctl_ev_data));
2008 ctl_ev_data.ctl_id = id;
2009 ev_msg.dv[0].data_ptr = &ctl_ev_data;
2010 ev_msg.dv[0].data_length = sizeof(ctl_ev_data);
2011
2012 ev_msg.dv[1].data_length = 0;
2013
2014 kev_post_msg(&ev_msg);
9bccf70c
A
2015}
2016
91447636 2017static int
b0d623f7
A
2018ctl_lock(struct socket *so, int refcount, void *lr)
2019{
2020 void *lr_saved;
2021
0a7de745 2022 if (lr == NULL) {
b0d623f7 2023 lr_saved = __builtin_return_address(0);
0a7de745 2024 } else {
b0d623f7 2025 lr_saved = lr;
0a7de745 2026 }
b0d623f7
A
2027
2028 if (so->so_pcb != NULL) {
91447636 2029 lck_mtx_lock(((struct ctl_cb *)so->so_pcb)->mtx);
0a7de745 2030 } else {
fe8ab488 2031 panic("ctl_lock: so=%p NO PCB! lr=%p lrh= %s\n",
b0d623f7
A
2032 so, lr_saved, solockhistory_nr(so));
2033 /* NOTREACHED */
91447636 2034 }
b0d623f7
A
2035
2036 if (so->so_usecount < 0) {
2037 panic("ctl_lock: so=%p so_pcb=%p lr=%p ref=%x lrh= %s\n",
0a7de745
A
2038 so, so->so_pcb, lr_saved, so->so_usecount,
2039 solockhistory_nr(so));
b0d623f7
A
2040 /* NOTREACHED */
2041 }
2042
0a7de745 2043 if (refcount) {
91447636 2044 so->so_usecount++;
0a7de745 2045 }
0c530ab8 2046
2d21ac55 2047 so->lock_lr[so->next_lock_lr] = lr_saved;
0a7de745
A
2048 so->next_lock_lr = (so->next_lock_lr + 1) % SO_LCKDBG_MAX;
2049 return 0;
91447636
A
2050}
2051
2052static int
b0d623f7 2053ctl_unlock(struct socket *so, int refcount, void *lr)
91447636 2054{
b0d623f7
A
2055 void *lr_saved;
2056 lck_mtx_t *mutex_held;
2057
0a7de745 2058 if (lr == NULL) {
b0d623f7 2059 lr_saved = __builtin_return_address(0);
0a7de745 2060 } else {
b0d623f7 2061 lr_saved = lr;
0a7de745 2062 }
b0d623f7 2063
39037602 2064#if (MORE_KCTLLOCK_DEBUG && (DEVELOPMENT || DEBUG))
fe8ab488
A
2065 printf("ctl_unlock: so=%llx sopcb=%x lock=%llx ref=%u lr=%llx\n",
2066 (uint64_t)VM_KERNEL_ADDRPERM(so),
2067 (uint64_t)VM_KERNEL_ADDRPERM(so->so_pcb,
2068 (uint64_t)VM_KERNEL_ADDRPERM(((struct ctl_cb *)so->so_pcb)->mtx),
2069 so->so_usecount, (uint64_t)VM_KERNEL_ADDRPERM(lr_saved));
39037602 2070#endif /* (MORE_KCTLLOCK_DEBUG && (DEVELOPMENT || DEBUG)) */
0a7de745 2071 if (refcount) {
91447636 2072 so->so_usecount--;
0a7de745 2073 }
b0d623f7
A
2074
2075 if (so->so_usecount < 0) {
fe8ab488 2076 panic("ctl_unlock: so=%p usecount=%x lrh= %s\n",
b0d623f7
A
2077 so, so->so_usecount, solockhistory_nr(so));
2078 /* NOTREACHED */
2079 }
91447636 2080 if (so->so_pcb == NULL) {
fe8ab488 2081 panic("ctl_unlock: so=%p NO PCB usecount=%x lr=%p lrh= %s\n",
0a7de745
A
2082 so, so->so_usecount, (void *)lr_saved,
2083 solockhistory_nr(so));
b0d623f7 2084 /* NOTREACHED */
91447636 2085 }
b0d623f7
A
2086 mutex_held = ((struct ctl_cb *)so->so_pcb)->mtx;
2087
0a7de745
A
2088 lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
2089 so->unlock_lr[so->next_unlock_lr] = lr_saved;
2090 so->next_unlock_lr = (so->next_unlock_lr + 1) % SO_LCKDBG_MAX;
2091 lck_mtx_unlock(mutex_held);
b0d623f7 2092
0a7de745 2093 if (so->so_usecount == 0) {
91447636 2094 ctl_sofreelastref(so);
0a7de745 2095 }
b0d623f7 2096
0a7de745 2097 return 0;
91447636
A
2098}
2099
2100static lck_mtx_t *
5ba3f43e 2101ctl_getlock(struct socket *so, int flags)
91447636 2102{
5ba3f43e 2103#pragma unused(flags)
0a7de745 2104 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
fe8ab488 2105
0a7de745
A
2106 if (so->so_pcb) {
2107 if (so->so_usecount < 0) {
2108 panic("ctl_getlock: so=%p usecount=%x lrh= %s\n",
2109 so, so->so_usecount, solockhistory_nr(so));
2110 }
2111 return kcb->mtx;
91447636 2112 } else {
0a7de745
A
2113 panic("ctl_getlock: so=%p NULL NO so_pcb %s\n",
2114 so, solockhistory_nr(so));
2115 return so->so_proto->pr_domain->dom_mtx;
91447636
A
2116 }
2117}
fe8ab488
A
2118
2119__private_extern__ int
2120kctl_reg_list SYSCTL_HANDLER_ARGS
2121{
2122#pragma unused(oidp, arg1, arg2)
0a7de745
A
2123 int error = 0;
2124 int n, i;
2125 struct xsystmgen xsg;
2126 void *buf = NULL;
2127 struct kctl *kctl;
2128 size_t item_size = ROUNDUP64(sizeof(struct xkctl_reg));
2129
2130 buf = _MALLOC(item_size, M_TEMP, M_WAITOK | M_ZERO);
2131 if (buf == NULL) {
2132 return ENOMEM;
2133 }
2134
2135 lck_mtx_lock(ctl_mtx);
2136
2137 n = kctlstat.kcs_reg_count;
2138
2139 if (req->oldptr == USER_ADDR_NULL) {
2140 req->oldidx = (n + n / 8) * sizeof(struct xkctl_reg);
2141 goto done;
2142 }
2143 if (req->newptr != USER_ADDR_NULL) {
2144 error = EPERM;
2145 goto done;
2146 }
2147 bzero(&xsg, sizeof(xsg));
2148 xsg.xg_len = sizeof(xsg);
2149 xsg.xg_count = n;
2150 xsg.xg_gen = kctlstat.kcs_gencnt;
2151 xsg.xg_sogen = so_gencnt;
2152 error = SYSCTL_OUT(req, &xsg, sizeof(xsg));
2153 if (error) {
2154 goto done;
2155 }
2156 /*
2157 * We are done if there is no pcb
2158 */
2159 if (n == 0) {
2160 goto done;
2161 }
2162
2163 i = 0;
2164 for (i = 0, kctl = TAILQ_FIRST(&ctl_head);
2165 i < n && kctl != NULL;
2166 i++, kctl = TAILQ_NEXT(kctl, next)) {
2167 struct xkctl_reg *xkr = (struct xkctl_reg *)buf;
2168 struct ctl_cb *kcb;
2169 u_int32_t pcbcount = 0;
2170
2171 TAILQ_FOREACH(kcb, &kctl->kcb_head, next)
2172 pcbcount++;
2173
2174 bzero(buf, item_size);
2175
2176 xkr->xkr_len = sizeof(struct xkctl_reg);
2177 xkr->xkr_kind = XSO_KCREG;
2178 xkr->xkr_id = kctl->id;
2179 xkr->xkr_reg_unit = kctl->reg_unit;
2180 xkr->xkr_flags = kctl->flags;
2181 xkr->xkr_kctlref = (uint64_t)(kctl->kctlref);
2182 xkr->xkr_recvbufsize = kctl->recvbufsize;
2183 xkr->xkr_sendbufsize = kctl->sendbufsize;
2184 xkr->xkr_lastunit = kctl->lastunit;
2185 xkr->xkr_pcbcount = pcbcount;
2186 xkr->xkr_connect = (uint64_t)VM_KERNEL_UNSLIDE(kctl->connect);
2187 xkr->xkr_disconnect =
2188 (uint64_t)VM_KERNEL_UNSLIDE(kctl->disconnect);
2189 xkr->xkr_send = (uint64_t)VM_KERNEL_UNSLIDE(kctl->send);
2190 xkr->xkr_send_list =
2191 (uint64_t)VM_KERNEL_UNSLIDE(kctl->send_list);
2192 xkr->xkr_setopt = (uint64_t)VM_KERNEL_UNSLIDE(kctl->setopt);
2193 xkr->xkr_getopt = (uint64_t)VM_KERNEL_UNSLIDE(kctl->getopt);
2194 xkr->xkr_rcvd = (uint64_t)VM_KERNEL_UNSLIDE(kctl->rcvd);
2195 strlcpy(xkr->xkr_name, kctl->name, sizeof(xkr->xkr_name));
2196
2197 error = SYSCTL_OUT(req, buf, item_size);
2198 }
2199
2200 if (error == 0) {
2201 /*
2202 * Give the user an updated idea of our state.
2203 * If the generation differs from what we told
2204 * her before, she knows that something happened
2205 * while we were processing this request, and it
2206 * might be necessary to retry.
2207 */
2208 bzero(&xsg, sizeof(xsg));
2209 xsg.xg_len = sizeof(xsg);
2210 xsg.xg_count = n;
2211 xsg.xg_gen = kctlstat.kcs_gencnt;
2212 xsg.xg_sogen = so_gencnt;
2213 error = SYSCTL_OUT(req, &xsg, sizeof(xsg));
2214 if (error) {
2215 goto done;
fe8ab488
A
2216 }
2217 }
2218
2219done:
0a7de745 2220 lck_mtx_unlock(ctl_mtx);
fe8ab488 2221
0a7de745
A
2222 if (buf != NULL) {
2223 FREE(buf, M_TEMP);
2224 }
fe8ab488 2225
0a7de745 2226 return error;
fe8ab488
A
2227}
2228
2229__private_extern__ int
2230kctl_pcblist SYSCTL_HANDLER_ARGS
2231{
2232#pragma unused(oidp, arg1, arg2)
0a7de745
A
2233 int error = 0;
2234 int n, i;
2235 struct xsystmgen xsg;
2236 void *buf = NULL;
2237 struct kctl *kctl;
2238 size_t item_size = ROUNDUP64(sizeof(struct xkctlpcb)) +
2239 ROUNDUP64(sizeof(struct xsocket_n)) +
2240 2 * ROUNDUP64(sizeof(struct xsockbuf_n)) +
2241 ROUNDUP64(sizeof(struct xsockstat_n));
2242
2243 buf = _MALLOC(item_size, M_TEMP, M_WAITOK | M_ZERO);
2244 if (buf == NULL) {
2245 return ENOMEM;
2246 }
2247
2248 lck_mtx_lock(ctl_mtx);
2249
2250 n = kctlstat.kcs_pcbcount;
2251
2252 if (req->oldptr == USER_ADDR_NULL) {
2253 req->oldidx = (n + n / 8) * item_size;
2254 goto done;
2255 }
2256 if (req->newptr != USER_ADDR_NULL) {
2257 error = EPERM;
2258 goto done;
2259 }
2260 bzero(&xsg, sizeof(xsg));
2261 xsg.xg_len = sizeof(xsg);
2262 xsg.xg_count = n;
2263 xsg.xg_gen = kctlstat.kcs_gencnt;
2264 xsg.xg_sogen = so_gencnt;
2265 error = SYSCTL_OUT(req, &xsg, sizeof(xsg));
2266 if (error) {
2267 goto done;
2268 }
2269 /*
2270 * We are done if there is no pcb
2271 */
2272 if (n == 0) {
2273 goto done;
2274 }
2275
2276 i = 0;
2277 for (i = 0, kctl = TAILQ_FIRST(&ctl_head);
2278 i < n && kctl != NULL;
2279 kctl = TAILQ_NEXT(kctl, next)) {
2280 struct ctl_cb *kcb;
2281
2282 for (kcb = TAILQ_FIRST(&kctl->kcb_head);
2283 i < n && kcb != NULL;
2284 i++, kcb = TAILQ_NEXT(kcb, next)) {
2285 struct xkctlpcb *xk = (struct xkctlpcb *)buf;
2286 struct xsocket_n *xso = (struct xsocket_n *)
2287 ADVANCE64(xk, sizeof(*xk));
2288 struct xsockbuf_n *xsbrcv = (struct xsockbuf_n *)
2289 ADVANCE64(xso, sizeof(*xso));
2290 struct xsockbuf_n *xsbsnd = (struct xsockbuf_n *)
2291 ADVANCE64(xsbrcv, sizeof(*xsbrcv));
2292 struct xsockstat_n *xsostats = (struct xsockstat_n *)
2293 ADVANCE64(xsbsnd, sizeof(*xsbsnd));
2294
2295 bzero(buf, item_size);
2296
2297 xk->xkp_len = sizeof(struct xkctlpcb);
2298 xk->xkp_kind = XSO_KCB;
2299 xk->xkp_unit = kcb->sac.sc_unit;
2300 xk->xkp_kctpcb = (uint64_t)VM_KERNEL_ADDRPERM(kcb);
2301 xk->xkp_kctlref = (uint64_t)VM_KERNEL_ADDRPERM(kctl);
2302 xk->xkp_kctlid = kctl->id;
2303 strlcpy(xk->xkp_kctlname, kctl->name,
2304 sizeof(xk->xkp_kctlname));
2305
2306 sotoxsocket_n(kcb->so, xso);
2307 sbtoxsockbuf_n(kcb->so ?
2308 &kcb->so->so_rcv : NULL, xsbrcv);
2309 sbtoxsockbuf_n(kcb->so ?
2310 &kcb->so->so_snd : NULL, xsbsnd);
2311 sbtoxsockstat_n(kcb->so, xsostats);
2312
2313 error = SYSCTL_OUT(req, buf, item_size);
fe8ab488
A
2314 }
2315 }
2316
0a7de745
A
2317 if (error == 0) {
2318 /*
2319 * Give the user an updated idea of our state.
2320 * If the generation differs from what we told
2321 * her before, she knows that something happened
2322 * while we were processing this request, and it
2323 * might be necessary to retry.
2324 */
2325 bzero(&xsg, sizeof(xsg));
2326 xsg.xg_len = sizeof(xsg);
2327 xsg.xg_count = n;
2328 xsg.xg_gen = kctlstat.kcs_gencnt;
2329 xsg.xg_sogen = so_gencnt;
2330 error = SYSCTL_OUT(req, &xsg, sizeof(xsg));
2331 if (error) {
2332 goto done;
fe8ab488
A
2333 }
2334 }
2335
2336done:
0a7de745 2337 lck_mtx_unlock(ctl_mtx);
fe8ab488 2338
0a7de745 2339 return error;
fe8ab488
A
2340}
2341
2342int
2343kctl_getstat SYSCTL_HANDLER_ARGS
2344{
2345#pragma unused(oidp, arg1, arg2)
0a7de745 2346 int error = 0;
fe8ab488 2347
0a7de745 2348 lck_mtx_lock(ctl_mtx);
fe8ab488 2349
0a7de745
A
2350 if (req->newptr != USER_ADDR_NULL) {
2351 error = EPERM;
2352 goto done;
fe8ab488 2353 }
0a7de745
A
2354 if (req->oldptr == USER_ADDR_NULL) {
2355 req->oldidx = sizeof(struct kctlstat);
2356 goto done;
fe8ab488
A
2357 }
2358
0a7de745
A
2359 error = SYSCTL_OUT(req, &kctlstat,
2360 MIN(sizeof(struct kctlstat), req->oldlen));
fe8ab488 2361done:
0a7de745
A
2362 lck_mtx_unlock(ctl_mtx);
2363 return error;
fe8ab488 2364}
3e170ce0
A
2365
2366void
2367kctl_fill_socketinfo(struct socket *so, struct socket_info *si)
2368{
0a7de745
A
2369 struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
2370 struct kern_ctl_info *kcsi =
2371 &si->soi_proto.pri_kern_ctl;
2372 struct kctl *kctl = kcb->kctl;
3e170ce0 2373
0a7de745 2374 si->soi_kind = SOCKINFO_KERN_CTL;
3e170ce0 2375
0a7de745
A
2376 if (kctl == 0) {
2377 return;
2378 }
3e170ce0 2379
0a7de745
A
2380 kcsi->kcsi_id = kctl->id;
2381 kcsi->kcsi_reg_unit = kctl->reg_unit;
2382 kcsi->kcsi_flags = kctl->flags;
2383 kcsi->kcsi_recvbufsize = kctl->recvbufsize;
2384 kcsi->kcsi_sendbufsize = kctl->sendbufsize;
2385 kcsi->kcsi_unit = kcb->sac.sc_unit;
2386 strlcpy(kcsi->kcsi_name, kctl->name, MAX_KCTL_NAME);
3e170ce0 2387}