#include <mach/mach_types.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <net/kext_net.h>
#include <machine/spl.h>
#include "sipfw.h"
extern struct NFDescriptor *find_nke(unsigned int handle);
extern int nke_insert(struct socket *so, struct so_nke *np);
static int sipfwldr_sobind(struct socket *so, struct sockaddr *sa, struct kextcb *kp);
static int sipfwldr_socreate(struct socket *so, struct protosw *proto, struct kextcb *kp);
static int sipfwldr_sofree(struct socket *so, struct kextcb *kp);
static TAILQ_HEAD(sipfwldr_so_head, sipfwldr_so_entry) sipfwldr_so_head = TAILQ_HEAD_INITIALIZER(sipfwldr_so_head);
struct sipfwldr_so_entry {
TAILQ_ENTRY(sipfwldr_so_entry) link;
struct socket *so;
};
static int ipfwldr_use_count = 0;
static int sipfwldr_inited = 0;
SYSCTL_DECL(_net_inet_ip_fw_classic);
SYSCTL_INT(_net_inet_ip_fw_classic, OID_AUTO, ldrusecount, CTLFLAG_RW, &ipfwldr_use_count, 0, "");
static struct sockif sipfwldr_sockif = {
NULL,
NULL,
sipfwldr_sobind,
NULL,
NULL,
NULL,
NULL,
sipfwldr_socreate,
NULL,
sipfwldr_sofree,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static struct sockutil sipfwldr_sockutil = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static struct NFDescriptor sipfwldr_nfd =
{
{NULL, NULL},
{NULL, NULL},
SIPFWLDR_NFHANDLE,
NFD_GLOBAL|NFD_VISIBLE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&sipfwldr_sockif,
&sipfwldr_sockutil
};
int sipfwldr_sobind(struct socket *so, struct sockaddr *sa, struct kextcb *kp)
{
struct NFDescriptor *sipfw_nfd;
int error;
printf("sipfwldr_sobind: so=%x sa=%x kp=%x\n", so, sa, kp);
sipfw_nfd = find_nke(SIPFW_NFHANDLE);
if (sipfw_nfd) {
struct so_nke sipfw_nke;
sipfw_nke.nke_handle = SIPFW_NFHANDLE;
sipfw_nke.nke_where = 0;
sipfw_nke.nke_flags = NFF_BEFORE;
if ((error = nke_insert(so, &sipfw_nke))) {
printf("sipfwldr_socreate nke_insert failed %d\n", error);
}
} else
printf("sipfw nfd not found\n");
return 0;
}
int sipfwldr_socreate(struct socket *so, struct protosw *proto, struct kextcb *kp)
{
int err = 0;
struct sipfwldr_so_entry *entry;
printf("sipfwldr_socreate: so=%x protp=%x kp=%x\n", so, proto, kp);
if ((entry = _MALLOC(sizeof (struct sipfwldr_so_entry), M_TEMP, M_WAITOK)) == NULL) {
err = ENOBUFS;
goto done;
}
entry->so = so;
TAILQ_INSERT_TAIL(&sipfwldr_so_head, entry, link);
ipfwldr_use_count++;
done:
return 0;
}
int sipfwldr_sofree(struct socket *so, struct kextcb *kp)
{
int err = 0;
struct sipfwldr_so_entry *entry;
printf("sipfwldr_sofree: so=%x kp=%x\n", so, kp);
for (entry = sipfwldr_so_head.tqh_first; entry != NULL; entry = entry->link.tqe_next) {
if (entry->so == so) {
TAILQ_REMOVE(&sipfwldr_so_head, entry, link);
FREE(entry, M_TEMP);
ipfwldr_use_count--;
}
}
return err;
}
kern_return_t sipfwldr_load()
{
kern_return_t err = KERN_FAILURE;
struct protosw *pp;
spl_t spl;
spl = splnet();
if ((pp = pffindproto(PF_NDRV, 0, SOCK_RAW)) == NULL)
{
goto done;
}
if (register_sockfilter(&sipfwldr_nfd, NULL, pp, 0))
{
goto done;
}
sysctl_register_oid(&sysctl__net_inet_ip_fw_classic_ldrusecount);
sipfwldr_inited = 1;
err = KERN_SUCCESS;
done:
splx(spl);
return err;
}
kern_return_t sipfwldr_unload()
{
kern_return_t err = KERN_FAILURE;
struct protosw *pp;
spl_t spl;
spl = splnet();
sysctl_unregister_oid(&sysctl__net_inet_ip_fw_classic_ldrusecount);
if ((pp = pffindproto(PF_NDRV, 0, SOCK_RAW)) == NULL)
{
goto done;
}
if (unregister_sockfilter(&sipfwldr_nfd, pp, 0))
{
goto done;
}
err = KERN_SUCCESS;
sipfwldr_inited = 0;
done:
splx(spl);
return err;
}