#include <sys/param.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/kern_event.h>
#include <sys/malloc.h>
#include <sys/sys_domain.h>
#include <sys/syslog.h>
int raw_usrreq();
struct pr_usrreqs event_usrreqs;
struct protosw eventsw[] = {
{
SOCK_RAW, &systemdomain, SYSPROTO_EVENT, PR_ATOMIC,
0, 0, 0, 0,
0,
0, 0, 0, 0,
0, &event_usrreqs
}
};
static
struct kern_event_head kern_event_head;
static u_long static_event_id = 0;
int
kern_event_init(void)
{
int retval;
if ((retval = net_add_proto(eventsw, &systemdomain)) == 0)
return(KERN_SUCCESS);
log(LOG_WARNING, "Can't install kernel events protocol (%d)\n", retval);
return(retval);
}
int kev_attach(struct socket *so, int proto, struct proc *p)
{
int error;
struct kern_event_pcb *ev_pcb;
ev_pcb = _MALLOC(sizeof(struct kern_event_pcb), M_PCB, M_WAITOK);
if (ev_pcb == 0)
return ENOBUFS;
ev_pcb->ev_socket = so;
ev_pcb->vendor_code_filter = 0xffffffff;
so->so_pcb = (caddr_t) ev_pcb;
LIST_INSERT_HEAD(&kern_event_head, ev_pcb, ev_link);
error = soreserve(so, KEV_SNDSPACE, KEV_RECVSPACE);
if (error)
return error;
return 0;
}
int kev_detach(struct socket *so)
{
struct kern_event_pcb *ev_pcb = (struct kern_event_pcb *) so->so_pcb;
LIST_REMOVE(ev_pcb, ev_link);
if (ev_pcb)
FREE(ev_pcb, M_PCB);
return 0;
}
int kev_post_msg(struct kev_msg *event_msg)
{
struct mbuf *m, *m2;
struct kern_event_pcb *ev_pcb;
struct kern_event_msg *ev;
char *tmp;
int total_size;
int i;
m = m_get(M_DONTWAIT, MT_DATA);
if (m == 0)
return ENOBUFS;
ev = mtod(m, struct kern_event_msg *);
total_size = KEV_MSG_HEADER_SIZE;
tmp = (char *) &ev->event_data[0];
for (i = 0; i < 5; i++) {
if (event_msg->dv[i].data_length == 0)
break;
total_size += event_msg->dv[i].data_length;
bcopy(event_msg->dv[i].data_ptr, tmp,
event_msg->dv[i].data_length);
tmp += event_msg->dv[i].data_length;
}
ev->id = ++static_event_id;
ev->total_size = total_size;
ev->vendor_code = event_msg->vendor_code;
ev->kev_class = event_msg->kev_class;
ev->kev_subclass = event_msg->kev_subclass;
ev->event_code = event_msg->event_code;
m->m_len = total_size;
for (ev_pcb = LIST_FIRST(&kern_event_head);
ev_pcb;
ev_pcb = LIST_NEXT(ev_pcb, ev_link)) {
if (ev_pcb->vendor_code_filter != KEV_ANY_VENDOR) {
if (ev_pcb->vendor_code_filter != ev->vendor_code)
continue;
if (ev_pcb->class_filter != KEV_ANY_CLASS) {
if (ev_pcb->class_filter != ev->kev_class)
continue;
if ((ev_pcb->subclass_filter != KEV_ANY_SUBCLASS) &&
(ev_pcb->subclass_filter != ev->kev_subclass))
continue;
}
}
m2 = m_copym(m, 0, m->m_len, M_NOWAIT);
if (m2 == 0) {
m_free(m);
return ENOBUFS;
}
sbappendrecord(&ev_pcb->ev_socket->so_rcv, m2);
sorwakeup(ev_pcb->ev_socket);
}
m_free(m);
return 0;
}
int kev_control(so, cmd, data, ifp, p)
struct socket *so;
u_long cmd;
caddr_t data;
register struct ifnet *ifp;
struct proc *p;
{
struct kev_request *kev_req = (struct kev_request *) data;
int stat = 0;
struct kern_event_pcb *ev_pcb;
u_long *id_value = (u_long *) data;
switch (cmd) {
case SIOCGKEVID:
*id_value = static_event_id;
break;
case SIOCSKEVFILT:
ev_pcb = (struct kern_event_pcb *) so->so_pcb;
ev_pcb->vendor_code_filter = kev_req->vendor_code;
ev_pcb->class_filter = kev_req->kev_class;
ev_pcb->subclass_filter = kev_req->kev_subclass;
break;
case SIOCGKEVFILT:
ev_pcb = (struct kern_event_pcb *) so->so_pcb;
kev_req->vendor_code = ev_pcb->vendor_code_filter;
kev_req->kev_class = ev_pcb->class_filter;
kev_req->kev_subclass = ev_pcb->subclass_filter;
break;
default:
return EOPNOTSUPP;
}
return 0;
}
struct pr_usrreqs event_usrreqs = {
pru_abort_notsupp, pru_accept_notsupp, kev_attach, pru_bind_notsupp, pru_connect_notsupp,
pru_connect2_notsupp, kev_control, kev_detach, pru_disconnect_notsupp,
pru_listen_notsupp, pru_peeraddr_notsupp, pru_rcvd_notsupp, pru_rcvoob_notsupp,
pru_send_notsupp, pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
pru_sosend_notsupp, soreceive, sopoll
};