#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/ucred.h>
#include <sys/lock.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/ifq_var.h>
#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/bpf.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp_var.h>
#include <netinet/udp.h>
#include <net/ipfw3/ip_fw.h>
#include <net/ipfw3_basic/ip_fw3_log.h>
extern int sysctl_var_fw3_verbose;
extern struct if_clone *if_clone_lookup(const char *, int *);
static const char ipfw3_log_ifname[] = "ipfw";
static int log_if_count;
struct ifnet *log_if_table[LOG_IF_MAX];
struct lock log_if_lock;
u_char fake_eh[14] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x08, 0x00};
static const u_char ipfwbroadcastaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#define LOGIF_LOCK_INIT(x) lockinit(&log_if_lock, "fw3log_lk", 0, LK_CANRECURSE)
#define LOGIF_LOCK_DESTROY(x) lockuninit(&log_if_lock)
#define LOGIF_RLOCK(x) lockmgr(&log_if_lock, LK_SHARED)
#define LOGIF_RUNLOCK(x) lockmgr(&log_if_lock, LK_RELEASE)
#define LOGIF_WLOCK(x) lockmgr(&log_if_lock, LK_EXCLUSIVE)
#define LOGIF_WUNLOCK(x) lockmgr(&log_if_lock, LK_RELEASE)
static int
ip_fw3_log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr, struct ucred *uc)
{
return EINVAL;
}
static int
ip_fw3_log_output(struct ifnet *ifp, struct mbuf *m,
struct sockaddr *dst, struct rtentry *rtent)
{
if (m != NULL) {
m_freem(m);
}
return EINVAL;
}
static void
ip_fw3_log_start(struct ifnet* ifp, struct ifaltq_subque *subque)
{
}
void
ip_fw3_log(struct mbuf *m, struct ether_header *eh, uint16_t id)
{
struct ifnet *the_if = NULL;
if (sysctl_var_fw3_verbose) {
#ifndef WITHOUT_BPF
LOGIF_RLOCK();
the_if = log_if_table[id];
if (the_if == NULL || the_if->if_bpf == NULL) {
LOGIF_RUNLOCK();
return;
}
if (eh != NULL) {
bpf_gettoken();
bpf_mtap_hdr(the_if->if_bpf, (caddr_t)eh,
ETHER_HDR_LEN, m, 0);
bpf_reltoken();
} else {
bpf_gettoken();
bpf_mtap_hdr(the_if->if_bpf, (caddr_t)fake_eh,
ETHER_HDR_LEN, m, 0);
bpf_reltoken();
}
LOGIF_RUNLOCK();
#endif
}
}
static int
ip_fw3_log_clone_create(struct if_clone *ifc, int unit,
caddr_t params __unused, caddr_t data __unused)
{
struct ifnet *ifp;
if (unit < 0 || unit >= LOG_IF_MAX) {
return EINVAL;
}
if (log_if_table[unit] != NULL) {
return EINVAL;
}
ifp = if_alloc(IFT_PFLOG);
if_initname(ifp, ipfw3_log_ifname, unit);
ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
ifq_set_ready(&ifp->if_snd);
ifp->if_mtu = 65536;
ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_init = (void *)ip_fw3_log_dummy;
ifp->if_ioctl = ip_fw3_log_dummy;
ifp->if_start = ip_fw3_log_start;
ifp->if_output = ip_fw3_log_output;
ifp->if_addrlen = 6;
ifp->if_hdrlen = 14;
ifp->if_broadcastaddr = ipfwbroadcastaddr;
ifp->if_baudrate = IF_Mbps(10);
LOGIF_WLOCK();
log_if_table[unit] = ifp;
log_if_count++;
if_attach(ifp, NULL);
bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
LOGIF_WUNLOCK();
return (0);
}
static int
ip_fw3_log_clone_destroy(struct ifnet *ifp)
{
int unit;
if (ifp == NULL)
return (0);
unit = ifp->if_dunit;
if (unit < 0 || unit >= LOG_IF_MAX) {
return EINVAL;
}
if (log_if_table[unit] == NULL) {
return EINVAL;
}
LOGIF_WLOCK();
log_if_table[unit] = NULL;
bpfdetach(ifp);
if_detach(ifp);
if_free(ifp);
log_if_count--;
LOGIF_WUNLOCK();
return (0);
}
static eventhandler_tag ip_fw3_log_ifdetach_cookie;
static struct if_clone ipfw3_log_cloner = IF_CLONE_INITIALIZER(ipfw3_log_ifname,
ip_fw3_log_clone_create, ip_fw3_log_clone_destroy, 0, 9);
void ip_fw3_log_modevent(int type){
struct ifnet *tmpif;
int i;
switch (type) {
case MOD_LOAD:
LOGIF_LOCK_INIT();
log_if_count = 0;
if_clone_attach(&ipfw3_log_cloner);
ip_fw3_log_ifdetach_cookie =
EVENTHANDLER_REGISTER(ifnet_detach_event,
ip_fw3_log_clone_destroy, &ipfw3_log_cloner,
EVENTHANDLER_PRI_ANY);
break;
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(ifnet_detach_event,
ip_fw3_log_ifdetach_cookie);
if_clone_detach(&ipfw3_log_cloner);
for(i = 0; log_if_count > 0 && i < LOG_IF_MAX; i++){
tmpif = log_if_table[i];
if (tmpif != NULL) {
ip_fw3_log_clone_destroy(tmpif);
}
}
LOGIF_LOCK_DESTROY();
break;
default:
break;
}
}