]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_control.c
xnu-344.49.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->skt != NULL)
172 return(EBUSY);
173
174 error = soreserve(so,
175 ctl->sendbufsize ? ctl->sendbufsize : CTL_SENDSIZE,
176 ctl->recvbufsize ? ctl->recvbufsize : CTL_RECVSIZE);
177 if (error)
178 return error;
179
180 ctl->skt = so;
181
182 if (ctl->flags & CTL_FLAG_PRIVILEGED) {
183 if (p == 0)
184 return(EPERM);
185 if (error = suser(p->p_ucred, &p->p_acflag))
186 return error;
187 }
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
288 sbappend(&so->so_rcv, m);
289 if ((flags & CTL_DATA_NOWAKEUP) == 0)
290 sorwakeup(so);
291 return 0;
292 }
293
294 int
295 ctl_ctloutput(struct socket *so, struct sockopt *sopt)
296 {
297 struct ctl *ctl = (struct ctl *)so->so_pcb;
298 int error = 0, s;
299 void *data;
300 size_t len;
301
302 if (sopt->sopt_level != SYSPROTO_CONTROL) {
303 return(EINVAL);
304 }
305
306 if (ctl == NULL)
307 return(ENOTCONN);
308
309 switch (sopt->sopt_dir) {
310 case SOPT_SET:
311 if (ctl->set == NULL)
312 return(ENOTSUP);
313 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
314 if (data == NULL)
315 return(ENOMEM);
316 error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize);
317 if (error == 0)
318 error = (*ctl->set)(ctl, ctl->userdata, sopt->sopt_name, data, sopt->sopt_valsize);
319 FREE(data, M_TEMP);
320 break;
321
322 case SOPT_GET:
323 if (ctl->get == NULL)
324 return(ENOTSUP);
325 data = NULL;
326 if (sopt->sopt_valsize && sopt->sopt_val) {
327 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
328 if (data == NULL)
329 return(ENOMEM);
330 }
331 len = sopt->sopt_valsize;
332 error = (*ctl->get)(ctl, ctl->userdata, sopt->sopt_name, data, &len);
333 if (error == 0) {
334 if (data != NULL)
335 error = sooptcopyout(sopt, data, len);
336 else
337 sopt->sopt_valsize = len;
338 }
339 if (data != NULL)
340 FREE(data, M_TEMP);
341 break;
342 }
343 return error;
344 }
345
346 int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
347 struct ifnet *ifp, struct proc *p)
348 {
349 int error = ENOTSUP, s, n;
350 struct ctl *ctl = (struct ctl *)so->so_pcb;
351
352 switch (cmd) {
353 /* get the number of controllers */
354 case CTLIOCGCOUNT:
355 n = 0;
356 TAILQ_FOREACH(ctl, &ctl_head, next)
357 n++;
358 *(u_int32_t *)data = n;
359 error = 0;
360 break;
361
362
363 /* add controls to get list of NKEs */
364
365 }
366
367 return error;
368 }
369
370 /*
371 * Register/unregister a NKE
372 */
373 int
374 ctl_register(struct kern_ctl_reg *userctl, void *userdata, kern_ctl_ref *ctlref)
375 {
376 struct ctl *ctl;
377
378 if (userctl == NULL) /* sanity check */
379 return(EINVAL);
380
381 ctl = ctl_find(userctl->ctl_id, userctl->ctl_unit);
382 if (ctl != NULL)
383 return(EEXIST);
384
385 MALLOC(ctl, struct ctl *, sizeof(*ctl), M_TEMP, M_WAITOK);
386 if (ctl == NULL)
387 return(ENOMEM);
388
389 bzero((char *)ctl, sizeof(*ctl));
390
391 ctl->id = userctl->ctl_id;
392 ctl->unit = userctl->ctl_unit;
393 ctl->flags = userctl->ctl_flags;
394 ctl->sendbufsize = userctl->ctl_sendsize;
395 ctl->recvbufsize = userctl->ctl_recvsize;
396 ctl->userdata = userdata;
397 ctl->connect = userctl->ctl_connect;
398 ctl->disconnect = userctl->ctl_disconnect;
399 ctl->write = userctl->ctl_write;
400 ctl->set = userctl->ctl_set;
401 ctl->get = userctl->ctl_get;
402
403 TAILQ_INSERT_TAIL(&ctl_head, ctl, next);
404
405 *ctlref = ctl;
406
407 ctl_post_msg(KEV_CTL_REGISTERED, ctl->id, ctl->unit);
408 return(0);
409 }
410
411 int
412 ctl_deregister(void *ctlref)
413 {
414 struct ctl *ctl = (struct ctl *)ctlref;
415 struct socket *so;
416
417 if (ctl == NULL) /* sanity check */
418 return(EINVAL);
419
420 TAILQ_REMOVE(&ctl_head, ctl, next);
421
422 if (ctl->skt) {
423 ctl->skt->so_pcb = 0;
424 soisdisconnected(ctl->skt);
425 }
426
427 ctl_post_msg(KEV_CTL_DEREGISTERED, ctl->id, ctl->unit);
428 FREE(ctl, M_TEMP);
429 return(0);
430 }
431
432 /*
433 * Locate a NKE
434 */
435 struct ctl *
436 ctl_find(u_int32_t id, u_int32_t unit)
437 {
438 struct ctl *ctl;
439
440 TAILQ_FOREACH(ctl, &ctl_head, next)
441 if ((ctl->id == id) && (ctl->unit == unit))
442 return ctl;
443
444 return NULL;
445 }
446
447 void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit)
448 {
449 struct ctl_event_data ctl_ev_data;
450 struct kev_msg ev_msg;
451
452 ev_msg.vendor_code = KEV_VENDOR_APPLE;
453
454 ev_msg.kev_class = KEV_SYSTEM_CLASS;
455 ev_msg.kev_subclass = KEV_CTL_SUBCLASS;
456 ev_msg.event_code = event_code;
457
458 /* common nke subclass data */
459 bzero(&ctl_ev_data, sizeof(ctl_ev_data));
460 ctl_ev_data.ctl_id = id;
461 ctl_ev_data.ctl_unit = unit;
462 ev_msg.dv[0].data_ptr = &ctl_ev_data;
463 ev_msg.dv[0].data_length = sizeof(ctl_ev_data);
464
465 ev_msg.dv[1].data_length = 0;
466
467 kev_post_msg(&ev_msg);
468 }
469