]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_control.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / bsd / kern / kern_control.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* Copyright (C) 1999 Apple Computer, Inc. */
26
27 /*
28 * NKE management domain - allows control connections to
29 * an NKE and to read/write data.
30 *
31 * Christophe Allie, 010928
32 * Justin C. Walker, 990319
33 */
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/syslog.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/protosw.h>
42 #include <sys/domain.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <net/kext_net.h>
46 #include <sys/sys_domain.h>
47 #include <sys/kern_event.h>
48 #include <sys/kern_control.h>
49 #include <net/if_var.h>
50
51 #include <mach/vm_types.h>
52 #include <mach/kmod.h>
53
54 #include <kern/thread.h>
55
56
57 /*
58 * Definitions and vars for we support
59 */
60
61 #define CTL_SENDSIZE (2 * 1024) /* default buffer size */
62 #define CTL_RECVSIZE (8 * 1024) /* default buffer size */
63
64 /*
65 internal structure maintained for each register controller
66 */
67 struct ctl
68 {
69 TAILQ_ENTRY(ctl) next; /* controller chain */
70 struct socket *skt; /* current controlling socket */
71
72 /* controller information provided when registering */
73 u_int32_t id; /* unique nke identifier, provided by DTS */
74 u_int32_t unit; /* unit number for use by the nke */
75 void *userdata; /* for private use by nke */
76
77 /* misc communication information */
78 u_int32_t flags; /* support flags */
79 u_int32_t recvbufsize; /* request more than the default buffer size */
80 u_int32_t sendbufsize; /* request more than the default buffer size */
81
82 /* Dispatch functions */
83 int (*connect)(kern_ctl_ref, void *); /* Make contact */
84 void (*disconnect)(kern_ctl_ref, void *); /* Break contact */
85 int (*write) (kern_ctl_ref, void *, struct mbuf *); /* Send data to nke */
86 int (*set)(kern_ctl_ref, void *, int, void *, size_t ); /* set ctl configuration */
87 int (*get)(kern_ctl_ref, void *, int, void *, size_t *); /* get ctl configuration */
88 };
89
90
91 /* all the controllers are chained */
92 TAILQ_HEAD(, ctl) ctl_head;
93
94 int ctl_attach(struct socket *, int, struct proc *);
95 int ctl_connect(struct socket *, struct sockaddr *, struct proc *);
96 int ctl_disconnect(struct socket *);
97 int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
98 struct ifnet *ifp, struct proc *p);
99 int ctl_send(struct socket *, int, struct mbuf *,
100 struct sockaddr *, struct mbuf *, struct proc *);
101 int ctl_ctloutput(struct socket *, struct sockopt *);
102
103 struct ctl *ctl_find(u_int32_t, u_int32_t unit);
104 void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit);
105
106
107 struct pr_usrreqs ctl_usrreqs =
108 {
109 pru_abort_notsupp, pru_accept_notsupp, ctl_attach, pru_bind_notsupp,
110 ctl_connect, pru_connect2_notsupp, ctl_ioctl, pru_detach_notsupp,
111 ctl_disconnect, pru_listen_notsupp, pru_peeraddr_notsupp,
112 pru_rcvd_notsupp, pru_rcvoob_notsupp, ctl_send,
113 pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
114 sosend, soreceive, sopoll
115 };
116
117 struct protosw ctlsw =
118 {
119 SOCK_DGRAM, &systemdomain, SYSPROTO_CONTROL, PR_ATOMIC|PR_CONNREQUIRED,
120 NULL, NULL, NULL, ctl_ctloutput,
121 NULL, NULL,
122 NULL, NULL, NULL, NULL, &ctl_usrreqs
123 };
124
125 /*
126 * Install the protosw's for the NKE manager.
127 */
128 int
129 kern_control_init(void)
130 {
131 int retval;
132
133 retval = net_add_proto(&ctlsw, &systemdomain);
134 if (retval) {
135 log(LOG_WARNING, "Can't install Kernel Controller Manager (%d)\n", retval);
136 return retval;
137 }
138
139 TAILQ_INIT(&ctl_head);
140
141 return(KERN_SUCCESS);
142 }
143
144
145 /*
146 * Kernel Controller user-request functions
147 */
148 int
149 ctl_attach (struct socket *so, int proto, struct proc *p)
150 {
151 /*
152 * attach function must exist and succeed
153 * detach not necessary since we use
154 * connect/disconnect to handle so_pcb
155 */
156
157 return 0;
158 }
159
160 int
161 ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
162 {
163 struct ctl *ctl;
164 int error = 0;
165 struct sockaddr_ctl *sa = (struct sockaddr_ctl *)nam;
166
167 ctl = ctl_find(sa->sc_id, sa->sc_unit);
168 if (ctl == NULL)
169 return(EADDRNOTAVAIL);
170
171 if (ctl->flags & CTL_FLAG_PRIVILEGED) {
172 if (p == 0)
173 return(EINVAL);
174 if (error = suser(p->p_ucred, &p->p_acflag))
175 return error;
176 }
177
178 if (ctl->skt != NULL)
179 return(EBUSY);
180
181 error = soreserve(so,
182 ctl->sendbufsize ? ctl->sendbufsize : CTL_SENDSIZE,
183 ctl->recvbufsize ? ctl->recvbufsize : CTL_RECVSIZE);
184 if (error)
185 return error;
186
187 ctl->skt = so;
188
189 if (ctl->connect)
190 error = (*ctl->connect)(ctl, ctl->userdata);
191 if (error) {
192 ctl->skt = NULL;
193 return error;
194 }
195
196 so->so_pcb = (caddr_t)ctl;
197 soisconnected(so);
198
199 return error;
200 }
201
202 int
203 ctl_disconnect(struct socket *so)
204 {
205 struct ctl *ctl;
206
207 if ((ctl = (struct ctl *)so->so_pcb))
208 {
209 if (ctl->disconnect)
210 (*ctl->disconnect)(ctl, ctl->userdata);
211 ctl->skt = NULL;
212 so->so_pcb = NULL;
213 soisdisconnected(so);
214 }
215 return 0;
216 }
217
218 int
219 ctl_send(struct socket *so, int flags, struct mbuf *m,
220 struct sockaddr *addr, struct mbuf *control,
221 struct proc *p)
222 {
223 struct ctl *ctl = (struct ctl *)so->so_pcb;
224 int error = 0;
225
226 if (ctl == NULL)
227 return(ENOTCONN);
228
229 if (ctl->write)
230 error = (*ctl->write)(ctl, ctl->userdata, m);
231
232 return error;
233 }
234
235 int
236 ctl_enqueuembuf(void *ctlref, struct mbuf *m, u_int32_t flags)
237 {
238 struct ctl *ctl = (struct ctl *)ctlref;
239 struct socket *so = (struct socket *)ctl->skt;
240
241 if (ctl == NULL) /* sanity check */
242 return(EINVAL);
243
244 if (so == NULL)
245 return(ENOTCONN);
246
247 if (sbspace(&so->so_rcv) < m->m_pkthdr.len)
248 return(ENOBUFS);
249
250 sbappend(&so->so_rcv, m);
251 if ((flags & CTL_DATA_NOWAKEUP) == 0)
252 sorwakeup(so);
253 return 0;
254 }
255
256 int
257 ctl_enqueuedata(void *ctlref, void *data, size_t len, u_int32_t flags)
258 {
259 struct ctl *ctl = (struct ctl *)ctlref;
260 struct socket *so = (struct socket *)ctl->skt;
261 struct mbuf *m;
262
263 if (ctl == NULL) /* sanity check */
264 return(EINVAL);
265
266 if (so == NULL)
267 return(ENOTCONN);
268
269 if (len > MCLBYTES)
270 return(EMSGSIZE);
271
272 if (sbspace(&so->so_rcv) < len)
273 return(ENOBUFS);
274
275 if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
276 return (ENOBUFS);
277
278 if (len > MHLEN) {
279 MCLGET(m, M_NOWAIT);
280 if (!(m->m_flags & M_EXT)) {
281 m_freem(m);
282 return(ENOBUFS);
283 }
284 }
285
286 bcopy(data, mtod(m, void *), len);
287 m->m_pkthdr.len = m->m_len = len;
288
289 sbappend(&so->so_rcv, m);
290 if ((flags & CTL_DATA_NOWAKEUP) == 0)
291 sorwakeup(so);
292 return 0;
293 }
294
295 int
296 ctl_ctloutput(struct socket *so, struct sockopt *sopt)
297 {
298 struct ctl *ctl = (struct ctl *)so->so_pcb;
299 int error = 0, s;
300 void *data;
301 size_t len;
302
303 if (sopt->sopt_level != SYSPROTO_CONTROL) {
304 return(EINVAL);
305 }
306
307 if (ctl == NULL)
308 return(ENOTCONN);
309
310 switch (sopt->sopt_dir) {
311 case SOPT_SET:
312 if (ctl->set == NULL)
313 return(ENOTSUP);
314 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
315 if (data == NULL)
316 return(ENOMEM);
317 error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize);
318 if (error == 0)
319 error = (*ctl->set)(ctl, ctl->userdata, sopt->sopt_name, data, sopt->sopt_valsize);
320 FREE(data, M_TEMP);
321 break;
322
323 case SOPT_GET:
324 if (ctl->get == NULL)
325 return(ENOTSUP);
326 data = NULL;
327 if (sopt->sopt_valsize && sopt->sopt_val) {
328 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
329 if (data == NULL)
330 return(ENOMEM);
331 }
332 len = sopt->sopt_valsize;
333 error = (*ctl->get)(ctl, ctl->userdata, sopt->sopt_name, data, &len);
334 if (error == 0) {
335 if (data != NULL)
336 error = sooptcopyout(sopt, data, len);
337 else
338 sopt->sopt_valsize = len;
339 }
340 if (data != NULL)
341 FREE(data, M_TEMP);
342 break;
343 }
344 return error;
345 }
346
347 int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
348 struct ifnet *ifp, struct proc *p)
349 {
350 int error = ENOTSUP, s, n;
351 struct ctl *ctl = (struct ctl *)so->so_pcb;
352
353 switch (cmd) {
354 /* get the number of controllers */
355 case CTLIOCGCOUNT:
356 n = 0;
357 TAILQ_FOREACH(ctl, &ctl_head, next)
358 n++;
359 *(u_int32_t *)data = n;
360 error = 0;
361 break;
362
363
364 /* add controls to get list of NKEs */
365
366 }
367
368 return error;
369 }
370
371 /*
372 * Register/unregister a NKE
373 */
374 int
375 ctl_register(struct kern_ctl_reg *userctl, void *userdata, kern_ctl_ref *ctlref)
376 {
377 struct ctl *ctl;
378
379 if (userctl == NULL) /* sanity check */
380 return(EINVAL);
381
382 ctl = ctl_find(userctl->ctl_id, userctl->ctl_unit);
383 if (ctl != NULL)
384 return(EEXIST);
385
386 MALLOC(ctl, struct ctl *, sizeof(*ctl), M_TEMP, M_WAITOK);
387 if (ctl == NULL)
388 return(ENOMEM);
389
390 bzero((char *)ctl, sizeof(*ctl));
391
392 ctl->id = userctl->ctl_id;
393 ctl->unit = userctl->ctl_unit;
394 ctl->flags = userctl->ctl_flags;
395 ctl->sendbufsize = userctl->ctl_sendsize;
396 ctl->recvbufsize = userctl->ctl_recvsize;
397 ctl->userdata = userdata;
398 ctl->connect = userctl->ctl_connect;
399 ctl->disconnect = userctl->ctl_disconnect;
400 ctl->write = userctl->ctl_write;
401 ctl->set = userctl->ctl_set;
402 ctl->get = userctl->ctl_get;
403
404 TAILQ_INSERT_TAIL(&ctl_head, ctl, next);
405
406 *ctlref = ctl;
407
408 ctl_post_msg(KEV_CTL_REGISTERED, ctl->id, ctl->unit);
409 return(0);
410 }
411
412 int
413 ctl_deregister(void *ctlref)
414 {
415 struct ctl *ctl = (struct ctl *)ctlref;
416 struct socket *so;
417
418 if (ctl == NULL) /* sanity check */
419 return(EINVAL);
420
421 TAILQ_REMOVE(&ctl_head, ctl, next);
422
423 if (ctl->skt) {
424 ctl->skt->so_pcb = 0;
425 soisdisconnected(ctl->skt);
426 }
427
428 ctl_post_msg(KEV_CTL_DEREGISTERED, ctl->id, ctl->unit);
429 FREE(ctl, M_TEMP);
430 return(0);
431 }
432
433 /*
434 * Locate a NKE
435 */
436 struct ctl *
437 ctl_find(u_int32_t id, u_int32_t unit)
438 {
439 struct ctl *ctl;
440
441 TAILQ_FOREACH(ctl, &ctl_head, next)
442 if ((ctl->id == id) && (ctl->unit == unit))
443 return ctl;
444
445 return NULL;
446 }
447
448 void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit)
449 {
450 struct ctl_event_data ctl_ev_data;
451 struct kev_msg ev_msg;
452
453 ev_msg.vendor_code = KEV_VENDOR_APPLE;
454
455 ev_msg.kev_class = KEV_SYSTEM_CLASS;
456 ev_msg.kev_subclass = KEV_CTL_SUBCLASS;
457 ev_msg.event_code = event_code;
458
459 /* common nke subclass data */
460 bzero(&ctl_ev_data, sizeof(ctl_ev_data));
461 ctl_ev_data.ctl_id = id;
462 ctl_ev_data.ctl_unit = unit;
463 ev_msg.dv[0].data_ptr = &ctl_ev_data;
464 ev_msg.dv[0].data_length = sizeof(ctl_ev_data);
465
466 ev_msg.dv[1].data_length = 0;
467
468 kev_post_msg(&ev_msg);
469 }
470