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