#include <sys/types.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <machine/spl.h>
#include "kext_net.h"
struct nf_list nf_list;
static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc);
int
register_sockfilter(struct NFDescriptor *nfp, struct NFDescriptor *nfp1,
struct protosw *pr, int flags)
{ int s;
static int NF_initted = 0;
if (nfp == NULL)
return(EINVAL);
if (nfp->nf_handle == 0xf1ab02de) {
int err = sockfilter_fix_symantec_bug(nfp);
if (err != 0)
return err;
}
s = splhigh();
if (!NF_initted)
{ NF_initted = 1;
TAILQ_INIT(&nf_list);
}
TAILQ_INSERT_TAIL(&nf_list, nfp, nf_list);
if (nfp->nf_flags & NFD_GLOBAL)
{ if (flags & NFF_BEFORE)
{ if (nfp1 == NULL)
{ TAILQ_INSERT_HEAD(&pr->pr_sfilter,
nfp, nf_next);
} else
TAILQ_INSERT_BEFORE(nfp1, nfp, nf_next);
} else
{ if (nfp1 == NULL)
{ TAILQ_INSERT_TAIL(&pr->pr_sfilter,
nfp, nf_next);
} else
TAILQ_INSERT_AFTER(&pr->pr_sfilter, nfp1,
nfp, nf_next);
}
}
splx(s);
return(0);
}
int
unregister_sockfilter(struct NFDescriptor *nfp, struct protosw *pr, __unused int flags)
{ int s;
s = splhigh();
TAILQ_REMOVE(&nf_list, nfp, nf_list);
if (nfp->nf_flags & NFD_GLOBAL)
TAILQ_REMOVE(&pr->pr_sfilter, nfp, nf_next);
splx(s);
return(0);
}
struct NFDescriptor *
find_nke(unsigned int handle)
{ struct NFDescriptor *nfp;
nfp = nf_list.tqh_first;
while (nfp)
{ if (nfp->nf_handle == handle)
return(nfp);
nfp = nfp->nf_list.tqe_next;
}
return(NULL);
}
int
nke_insert(struct socket *so, struct so_nke *np)
{
struct kextcb *kp, *kp1;
struct NFDescriptor *nf1, *nf2 = NULL;
if (np->nke_where != NULL)
{ if ((nf2 = find_nke(np->nke_where)) == NULL)
{
return(ENXIO);
}
}
if ((nf1 = find_nke(np->nke_handle)) == NULL)
{
return(ENXIO);
}
kp = so->so_ext;
kp1 = NULL;
if (np->nke_flags & NFF_BEFORE)
{ if (nf2)
{ while (kp)
{ if (kp->e_nfd == nf2)
break;
kp1 = kp;
kp = kp->e_next;
}
if (kp == NULL)
return(ENXIO);
}
} else
{ if (nf2)
{ while (kp)
{ if (kp->e_nfd == nf2)
break;
kp1 = kp;
kp = kp->e_next;
}
if (kp == NULL)
return(ENXIO);
}
kp1 = kp;
}
MALLOC(kp, struct kextcb *, sizeof(*kp), M_TEMP, M_WAITOK);
if (kp == NULL)
return(ENOBUFS);
bzero(kp, sizeof (*kp));
if (kp1 == NULL)
{ kp->e_next = so->so_ext;
so->so_ext = kp;
} else
{ kp->e_next = kp1->e_next;
kp1->e_next = kp;
}
kp->e_fcb = NULL;
kp->e_nfd = nf1;
kp->e_soif = nf1->nf_soif;
kp->e_sout = nf1->nf_soutil;
if (kp->e_soif && kp->e_soif->sf_socreate)
(*kp->e_soif->sf_socreate)(so, so->so_proto, kp);
return(0);
}
static struct sockif* g_symantec_if_funcs = NULL;
static struct sockutil* g_symantec_util_funcs = NULL;
static int sym_fix_sbflush(struct sockbuf *, struct kextcb *);
static int sym_fix_sbappend(struct sockbuf *, struct mbuf *, struct kextcb *);
static int sym_fix_soclose(struct socket *, struct kextcb *);
static int sym_fix_sofree(struct socket *, struct kextcb *);
static int sym_fix_soconnect(struct socket *, struct sockaddr *, struct kextcb *);
static int sym_fix_soisconnected(struct socket *, struct kextcb *);
static int sym_fix_sosend(struct socket *, struct sockaddr **, struct uio **, struct mbuf **,
struct mbuf **, int *, struct kextcb *);
static int sym_fix_socantrcvmore(struct socket *, struct kextcb *);
static int sym_fix_socontrol(struct socket *, struct sockopt *, struct kextcb *);
static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc)
{
if (!g_symantec_if_funcs ) {
MALLOC(g_symantec_if_funcs, struct sockif*, sizeof(*g_symantec_if_funcs), M_TEMP, M_WAITOK);
if (!g_symantec_if_funcs)
return ENOMEM;
*g_symantec_if_funcs = *theirDesc->nf_soif;
}
if (!g_symantec_util_funcs) {
MALLOC(g_symantec_util_funcs, struct sockutil*, sizeof(*g_symantec_util_funcs), M_TEMP, M_WAITOK);
if (!g_symantec_util_funcs)
return ENOMEM;
*g_symantec_util_funcs = *theirDesc->nf_soutil;
}
if (theirDesc->nf_soutil->su_sbflush)
theirDesc->nf_soutil->su_sbflush = sym_fix_sbflush;
if (theirDesc->nf_soutil->su_sbappend)
theirDesc->nf_soutil->su_sbappend = sym_fix_sbappend;
if (theirDesc->nf_soif->sf_soclose)
theirDesc->nf_soif->sf_soclose = sym_fix_soclose;
if (theirDesc->nf_soif->sf_sofree)
theirDesc->nf_soif->sf_sofree = sym_fix_sofree;
if (theirDesc->nf_soif->sf_soconnect)
theirDesc->nf_soif->sf_soconnect = sym_fix_soconnect;
if (theirDesc->nf_soif->sf_soisconnected)
theirDesc->nf_soif->sf_soisconnected = sym_fix_soisconnected;
if (theirDesc->nf_soif->sf_sosend)
theirDesc->nf_soif->sf_sosend = sym_fix_sosend;
if (theirDesc->nf_soif->sf_socantrcvmore)
theirDesc->nf_soif->sf_socantrcvmore = sym_fix_socantrcvmore;
if (theirDesc->nf_soif->sf_socontrol)
theirDesc->nf_soif->sf_socontrol = sym_fix_socontrol;
return 0;
}
static int sym_fix_sbflush(struct sockbuf *p1, struct kextcb *p2)
{
if (p2->e_fcb != NULL && g_symantec_util_funcs)
return g_symantec_util_funcs->su_sbflush(p1, p2);
else
return 0;
}
static int sym_fix_sbappend(struct sockbuf *p1, struct mbuf *p2, struct kextcb *p3)
{
if (p3->e_fcb != NULL && g_symantec_util_funcs)
return g_symantec_util_funcs->su_sbappend(p1, p2, p3);
else
return 0;
}
static int sym_fix_soclose(struct socket *p1, struct kextcb *p2)
{
if (p2->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_soclose(p1, p2);
else
return 0;
}
static int sym_fix_sofree(struct socket *p1, struct kextcb *p2)
{
if (p2->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_sofree(p1, p2);
else
return 0;
}
static int sym_fix_soconnect(struct socket *p1, struct sockaddr *p2, struct kextcb *p3)
{
if (p3->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_soconnect(p1, p2, p3);
else
return 0;
}
static int sym_fix_soisconnected(struct socket *p1, struct kextcb *p2)
{
if (p2->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_soisconnected(p1, p2);
else
return 0;
}
static int sym_fix_sosend(struct socket *p1, struct sockaddr **p2, struct uio **p3, struct mbuf **p4,
struct mbuf **p5, int *p6, struct kextcb *p7)
{
if (p7->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_sosend(p1, p2, p3, p4, p5, p6, p7);
else
return 0;
}
static int sym_fix_socantrcvmore(struct socket *p1, struct kextcb *p2)
{
if (p2->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_socantrcvmore(p1, p2);
else
return 0;
}
static int sym_fix_socontrol(struct socket *p1, struct sockopt *p2, struct kextcb *p3)
{
if (p3->e_fcb != NULL && g_symantec_if_funcs)
return g_symantec_if_funcs->sf_socontrol(p1, p2, p3);
else
return 0;
}