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