|  | /* | 
|  | * Copyright (C) 1993-2001 by Darren Reed. | 
|  | * | 
|  | * See the IPFILTER.LICENCE file for details on licencing. | 
|  | */ | 
|  | #if !defined(lint) | 
|  | static const char rcsid[] = "@(#)$Id$"; | 
|  | #endif | 
|  | #include <sys/types.h> | 
|  | #include <sys/conf.h> | 
|  | #include <sys/sysconfig.h> | 
|  | #include <machine/machlimits.h> | 
|  | #include <net/net_globals.h> | 
|  | #include <io/common/iotypes.h> | 
|  | #include <sys/errno.h> | 
|  | #include <sys/buf.h> | 
|  | #include <sys/secdefines.h> | 
|  | #include <sys/malloc.h> | 
|  | #include <sys/mbuf.h> | 
|  | #include <sys/fcntl.h> | 
|  | #include <sys/ioctl.h> | 
|  | #include <sys/disklabel.h> | 
|  | #include <sys/user.h> | 
|  | #include <sys/socket.h> | 
|  | #include <sys/sysmacros.h> | 
|  | #include <sys/syslog.h> | 
|  | #include <io/common/pt.h> | 
|  | #include <io/common/devdriver.h> | 
|  | #include <io/common/devio.h> | 
|  | #include <io/common/devgetinfo.h> | 
|  |  | 
|  | #include <net/if.h> | 
|  | #include <netinet/ip.h> | 
|  | #include <netinet/ip_stat.h> | 
|  | #include <netinet/in.h> | 
|  | #include <netinet/firewall.h> | 
|  |  | 
|  | #include <netinet/if_ether.h> | 
|  | #include <net/ether_driver.h> | 
|  |  | 
|  | #include "ip_compat.h" | 
|  | #include "ip_fil.h" | 
|  | #include "ip_nat.h" | 
|  | #include "ip_state.h" | 
|  | #include "ip_frag.h" | 
|  | #include "ip_auth.h" | 
|  | #include "ip_compat.h" | 
|  | #include "ip_fil.h" | 
|  |  | 
|  | /* #undef	IPFDEBUG	*/ | 
|  |  | 
|  | /* function prototypes */ | 
|  | int	ipfilter_attach(void); | 
|  | int	ipfilter_detach(void); | 
|  | void	ipfilter_ifattach(void); | 
|  | void	ipfilter_ifdetach(void); | 
|  | int	ipfilter_ifioctl(struct ifnet *, unsigned int, caddr_t); | 
|  | #if TRU64 >= 1885 | 
|  | int	ipfilter_ifoutput(struct ifnet *, struct mbuf *, struct sockaddr *, | 
|  | struct rtentry *, char *); | 
|  | #else | 
|  | int	ipfilter_ifoutput(struct ifnet *, struct mbuf *, struct sockaddr *, | 
|  | struct rtentry *); | 
|  | #endif | 
|  | void	ipfilter_in_control(struct socket *, u_int, caddr_t *, struct ifnet *); | 
|  | void	ipfilter_ip_input(struct mbuf *m); | 
|  | int	ipfilter_ip_output(struct ifnet *, struct mbuf *, struct in_route *, | 
|  | int, struct ip_moptions *); | 
|  | void	ipfilter_configure_callback __P((int, int, int, int)); | 
|  | void	ipfilter_timer(void); | 
|  | void	ipfilter_clock(void *arg); | 
|  | int	ipfilteropen(dev_t, int, int); | 
|  | int	ipfilterread(dev_t, struct uio *, int); | 
|  | int	ipfilterclose(dev_t, int, int); | 
|  | int	ipfilterwrite(dev_t, int, int); | 
|  | int	ipfilterioctl(dev_t, u_int, caddr_t, int); | 
|  |  | 
|  | extern	int	nodev(), nulldev(); | 
|  | extern	task_t	first_task; | 
|  | extern	ipfrwlock_t	ipf_tru64; | 
|  |  | 
|  | struct	dsent	ipfilter_devsw_entry = { | 
|  | ipfilteropen, | 
|  | ipfilterclose, | 
|  | nodev,		/* d_strategy */ | 
|  | ipfilterread, | 
|  | #ifdef	IPFILTER_SYNC | 
|  | ipfilterwrite, | 
|  | #else | 
|  | nulldev,	/* d_write */ | 
|  | #endif | 
|  | ipfilterioctl, | 
|  | nodev,		/* d_dump */ | 
|  | nodev,		/* d_psize */ | 
|  | nulldev,	/* d_stop */ | 
|  | nulldev,	/* d_reset */ | 
|  | nulldev,	/* d_select */ | 
|  | 0,		/* d_mmap */ | 
|  | 0,		/* d_segmap */ | 
|  | NULL,		/* d_ttys */ | 
|  | DEV_FUNNEL_NULL,/* SMP-safe */ | 
|  | 0,		/* d_bflags */ | 
|  | 0		/* d_cflags */ | 
|  | }; | 
|  |  | 
|  | struct controller *ipfilter_info[IPL_LOGSIZE]; | 
|  | static char ipfilter_name[] = "ipfilter"; | 
|  |  | 
|  | struct	driver	ipfdriver = { | 
|  | NULL,		/* probe  */ | 
|  | NULL,		/* slave */ | 
|  | NULL,		/* cattach */ | 
|  | NULL,		/* dattach */ | 
|  | 0,		/* go */ | 
|  | 0,		/* addr_list */ | 
|  | 0,		/* dev_name */ | 
|  | 0,		/* dev_list */ | 
|  | ipfilter_name,	/* ctlr_name */ | 
|  | ipfilter_info,	/* ctlr_list */ | 
|  | 0,		/* Want exclusive use of bdp's flag */ | 
|  | 0,		/* Size of first csr area */ | 
|  | 0,		/* Address space of first csr area */ | 
|  | 0,		/* Size of second csr area */ | 
|  | 0,		/* Address space of second csr area */ | 
|  | NULL,		/* controller unattach routine */ | 
|  |  | 
|  | NULL,		/* dev_unattach */ | 
|  | }; | 
|  |  | 
|  | #define NO_DEV -1 | 
|  | #define MAJOR_INSTANCE 1 | 
|  | #define IPF_NAME "ipf" | 
|  |  | 
|  | int ipfilter_config = FALSE; | 
|  | int ipfilter_devno = NO_DEV; | 
|  | int ipfilter_num_units=1; | 
|  | int ipfilter_dev_number = NO_DEV; | 
|  | int callback_return_status = ESUCCESS; | 
|  | int driver_cfg_state; | 
|  | int ipfilter_is_dynamic; | 
|  |  | 
|  | /* Variables referenced by attributes. 'majnum' must | 
|  | * be present to inform cfgmgr that this is a 5.0A | 
|  | * driver. 'ipfilter_version' is used to keep track of the version | 
|  | * numbers during development. It is printed out after | 
|  | * configure to indicate which version is being loaded. | 
|  | */ | 
|  | static int majnum = NO_DEV; | 
|  | static int ipfilter_num_installed = 1; | 
|  | static u_char ipfilter_desc[100] = "IPFilter firewall"; | 
|  | static u_char ipfilter_unused[300] = ""; | 
|  | static thread_t ipf_timeout = 0; | 
|  |  | 
|  | /* protos for functions used in configuration */ | 
|  | void ipfilter_print_attr_error __P((cfg_attr_t *)); | 
|  | void ipfilter_preconfig_callback __P((int, int, ulong, ulong)); | 
|  | void ipfilter_postconfig_callback __P((int, int, ulong, ulong)); | 
|  |  | 
|  |  | 
|  | struct firewall_stat { | 
|  | u_long	in_control_called; | 
|  | u_long	ip_input_mbufs; | 
|  | u_long	ip_input_accept; | 
|  | u_long	ip_input_reject; | 
|  | u_long	ip_input_tooshort; | 
|  | u_long	ip_input_toosmall; | 
|  | u_long	ip_input_badlen; | 
|  | u_long	ip_input_badhlen; | 
|  | u_long	ip_input_badvers; | 
|  | u_long	ip_input_badsum; | 
|  | u_long	ip_output_mbufs; | 
|  | u_long	ip_output_accept; | 
|  | u_long	ip_output_reject; | 
|  | }; | 
|  | struct firewall_stat ipfilter_stat; | 
|  | static	int	ipfilter_registered = 0; | 
|  | static	int	ipftru64_inited = 0; | 
|  | static	char	ipfname[CFG_ATTR_NAME_SZ] = "ipfilter"; | 
|  |  | 
|  |  | 
|  | cfg_subsys_attr_t ipfilter_attributes[] = { | 
|  |  | 
|  | { "Subsystem_Description",CFG_ATTR_STRTYPE, CFG_OP_CONFIGURE | CFG_OP_QUERY, | 
|  | (caddr_t)ipfilter_desc, 2, 300, 0 }, | 
|  | { "Module_Config_Name",	CFG_ATTR_STRTYPE, CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfname, 2, CFG_ATTR_NAME_SZ, 0 }, | 
|  | { "majnum",		CFG_ATTR_INTTYPE, CFG_OP_QUERY, | 
|  | (caddr_t)&majnum, 0, 512, 0 }, | 
|  | { "Num_Installed",	CFG_ATTR_INTTYPE, CFG_OP_QUERY, | 
|  | (caddr_t)&ipfilter_num_installed, 1, 1, 1 }, | 
|  | { "Num_Units",		CFG_ATTR_INTTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)&ipfilter_num_units, | 
|  | 1, IPL_LOGSIZE, 0 }, | 
|  | { "Module_Type",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 2, CFG_ATTR_NAME_SZ, 0 }, | 
|  | { "Device_User",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Group",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Mode",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Major_Req",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Char_Major",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Char_Files",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, | 
|  | 0, sizeof(ipfilter_unused), 0 }, | 
|  | { "Device_Char_Minor",	CFG_ATTR_STRTYPE, CFG_OP_QUERY | CFG_OP_CONFIGURE, | 
|  | (caddr_t)ipfilter_unused, 0, | 
|  | sizeof(ipfilter_unused), 0 }, | 
|  | { "version",		CFG_ATTR_STRTYPE, CFG_OP_QUERY, | 
|  | (caddr_t)ipfilter_version, 0, 5, 0 }, | 
|  | { "fr_chksrc",		CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t)&fr_chksrc, 0, 1, 0 }, | 
|  | { "fr_minttl",		CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t)&fr_minttl, 0, 255, 0 }, | 
|  | { "fr_pass",		CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t)&fr_minttl, 0, 0xffffffff, 0 }, | 
|  | { "fr_flags",		CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t)&fr_minttl, 0, 0xffffffff, 0 }, | 
|  | { "fr_active",		CFG_ATTR_INTTYPE, CFG_OP_QUERY, | 
|  | (caddr_t)&fr_minttl, 0, 1, 0 }, | 
|  | { "fr_running",		CFG_ATTR_INTTYPE, CFG_OP_QUERY, | 
|  | (caddr_t)&fr_minttl, 0, 1, 0 }, | 
|  | { "fr_control_forwarding", | 
|  | CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t) &fr_control_forwarding, 0, 1, 0 }, | 
|  | { "fr_update_ipid",	CFG_ATTR_INTTYPE, CFG_OP_QUERY | | 
|  | CFG_OP_CONFIGURE | CFG_OP_RECONFIGURE, | 
|  | (caddr_t) &fr_update_ipid, 0, 1, 0 }, | 
|  | { "",			0, 0, 0, 0, 0, 0 } | 
|  | }; | 
|  |  | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * Configure interface | 
|  | * 1 - Handle attribute verification. | 
|  | * 2 - Handle the differences between static and dynamic | 
|  | *     configuration. | 
|  | * Returns: EBUSY,EINVAL,ENOTSUP,ESRCH for fail, | 
|  | *          ESUCCESS for success | 
|  | *--------------------------------------------------------*/ | 
|  | cfg_status_t ipfilter_configure(op, indata, indata_size, outdata, outdata_size) | 
|  | cfg_op_t op; | 
|  | caddr_t indata; | 
|  | ulong indata_size; | 
|  | caddr_t outdata; | 
|  | ulong outdata_size; | 
|  | { | 
|  | int ipfilter_cfg_state; | 
|  | cfg_attr_t *attr_ptr; | 
|  | int status, i; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_configure(%x,%x,%d,%x,%d)\n", | 
|  | op, indata, indata_size, outdata, outdata_size); | 
|  | #endif | 
|  |  | 
|  | status = ESUCCESS; | 
|  |  | 
|  | if (cfgmgr_get_state("ipfilter", &ipfilter_cfg_state) != ESUCCESS) { | 
|  | printf("ipfilter cfgmgr_get_state failed\n"); | 
|  | return EINVAL; | 
|  | } | 
|  |  | 
|  | switch (op) | 
|  | { | 
|  | case CFG_OP_CONFIGURE : | 
|  | #ifdef IPFDEBUG | 
|  | printf("ipfilter_config=%d\n",ipfilter_config); | 
|  | printf("driver_cfg_state=%d\n",driver_cfg_state); | 
|  | #endif | 
|  | if (ipfilter_config == TRUE) { | 
|  | /* | 
|  | * We have already been configured | 
|  | */ | 
|  | return EINVAL; | 
|  | } | 
|  | /* | 
|  | * cfgmgr takes care of error checking, but we have to | 
|  | * investigate what happened and report to user. | 
|  | */ | 
|  | attr_ptr = (cfg_attr_t *)indata; | 
|  | for(i = 0; i < indata_size; i++) { | 
|  | switch(attr_ptr->type) | 
|  | { | 
|  | case CFG_ATTR_STRTYPE: | 
|  | break; | 
|  | default: | 
|  | switch(attr_ptr->status) | 
|  | { | 
|  | case CFG_FRAME_SUCCESS: | 
|  | break; | 
|  | default: | 
|  | ipfilter_print_attr_error(attr_ptr); | 
|  | break; | 
|  | } | 
|  | } | 
|  | attr_ptr++; | 
|  | } | 
|  |  | 
|  | if (cfgmgr_get_state((char *)ipfilter_name, | 
|  | &driver_cfg_state) != ESUCCESS) { | 
|  | printf("ipfilter_conf:Error determining state of ipf subsystem\n"); | 
|  | /* | 
|  | * Error determining state of the "ipf" subs.. | 
|  | */ | 
|  | return(EINVAL); | 
|  | } | 
|  |  | 
|  | if (driver_cfg_state == SUBSYSTEM_STATICALLY_CONFIGURED)  { | 
|  | callback_return_status = ESUCCESS; | 
|  | ipfilter_is_dynamic = 0; | 
|  | status = register_callback(ipfilter_configure_callback, | 
|  | CFG_PT_OLD_CONF_ALL, | 
|  | CFG_ORD_DONTCARE, 0L); | 
|  | if (status != ESUCCESS) | 
|  | break; | 
|  | status = register_callback(ipfilter_preconfig_callback, | 
|  | CFG_PT_PRECONFIG, | 
|  | CFG_ORD_NOMINAL, 0L); | 
|  | if (status != ESUCCESS) | 
|  | break; | 
|  | status = register_callback(ipfilter_postconfig_callback, | 
|  | CFG_PT_POSTCONFIG, | 
|  | CFG_ORD_NOMINAL, 0L); | 
|  | } else { | 
|  | /* | 
|  | * ipf.mod is getting loaded dynamically. | 
|  | */ | 
|  | ipfilter_is_dynamic = 1; | 
|  | status = ipfilter_preconfig(); | 
|  | if (status != ESUCCESS) { | 
|  | printf("ipfilter_conf:preconfig failed\n"); | 
|  | return (status); | 
|  | } | 
|  |  | 
|  | status = ipfilter_postconfig(); | 
|  | if (status != ESUCCESS) { | 
|  | printf("ipfilter_conf:postconfig failed\n"); | 
|  | return (status); | 
|  | } | 
|  | status = ipfilter_attach(); | 
|  | #ifdef IPFDEBUG | 
|  | printf("ipfilter_attach=%d\n",status); | 
|  | #endif | 
|  | } | 
|  | break; | 
|  |  | 
|  | case CFG_OP_QUERY : | 
|  | break; | 
|  |  | 
|  | case CFG_OP_RECONFIGURE : | 
|  | break; | 
|  |  | 
|  | case CFG_OP_UNCONFIGURE : | 
|  | if (ipfilter_is_dynamic) { | 
|  |  | 
|  | status = devsw_del(ipfilter_name, MAJOR_INSTANCE); | 
|  | if (status == NO_DEV) { | 
|  | printf("ipfilter_configure: call to devsw_del failed\n"); | 
|  | return ESRCH; | 
|  | } | 
|  |  | 
|  | ipfilter_is_dynamic = 0; | 
|  | ipfilter_config = FALSE; | 
|  |  | 
|  | printf("ipfilter_configure: dynamic module unconfigured\n"); | 
|  | } else { | 
|  | /* static configuration */ | 
|  | printf("ipfilter_configure: Can't unconfigure a static mod\n"); | 
|  | return ESUCCESS; | 
|  | } | 
|  | if (ipfilter_cfg_state & SUBSYSTEM_STATICALLY_CONFIGURED) { | 
|  | status = EINVAL; | 
|  | break; | 
|  | } | 
|  | status = ipfilter_detach(); | 
|  | break; | 
|  |  | 
|  | default : | 
|  | status = ENOTSUP; | 
|  | break; | 
|  | } | 
|  |  | 
|  | #ifdef IPFDEBUG | 
|  | printf("ipfilter_configure(%d)=%d\n",op,status); | 
|  | #endif | 
|  | return status; | 
|  | } | 
|  |  | 
|  |  | 
|  | void ipfilter_configure_callback(conf, order, arg, evarg) | 
|  | int conf, order, arg, evarg; | 
|  | { | 
|  | int status; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_configure_callback(%x,%x,%x,%x)\n", | 
|  | conf, order, arg, evarg); | 
|  | #endif | 
|  |  | 
|  | status = ipfilter_attach(); | 
|  |  | 
|  | if (status != ESUCCESS) { | 
|  | cfgmgr_set_status("ipfilter"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * This hook intercepts mbufs directly off the IP input | 
|  | * queue(s) and gives them to the routine at (*ip_input_hook)(m). | 
|  | * The hook must either free the mbuf, or enqueue it back to | 
|  | * an IP input queue by calling ip_continue_input(m). It is | 
|  | * assumed that the hook returns to the caller in a timely | 
|  | * manner, enqueuing the mbuf on its own list for further | 
|  | * processing at a later time (if necesary). | 
|  | */ | 
|  | void ipfilter_ip_input(m) | 
|  | struct mbuf *m; | 
|  | { | 
|  | struct mbuf *m0; | 
|  | struct ip *ip; | 
|  | int hlen, len; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_ip_input(%x)\n", m); | 
|  | #endif | 
|  | READ_ENTER(&ipf_tru64); | 
|  | if (ipfilter_registered < 1 || ipftru64_inited == 0) { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | ip_continue_input(m); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ipfilter_stat.ip_input_mbufs++; | 
|  |  | 
|  | ip = mtod(m, struct ip *); | 
|  |  | 
|  | /* | 
|  | * Because this gets packets directly off the IP input queue, we need | 
|  | * to do all of the input packet checking.  This is IPv4 only. | 
|  | */ | 
|  | if (m->m_len < sizeof(struct ip) && | 
|  | (m = m_pullup(m, sizeof (struct ip))) == 0) { | 
|  | ipfilter_stat.ip_input_toosmall++; | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (IP_V(ip) != IPVERSION) { | 
|  | ipfilter_stat.ip_input_badvers++; | 
|  | goto bad; | 
|  | } | 
|  |  | 
|  | hlen = IP_HL(ip) << 2; | 
|  | if (hlen < sizeof(*ip)) { | 
|  | ipfilter_stat.ip_input_badhlen++; | 
|  | goto bad; | 
|  | } | 
|  |  | 
|  | if (hlen > m->m_len) { | 
|  | if ((m = m_pullup(m, hlen)) == 0) { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return; | 
|  | } | 
|  | ip = mtod(m, struct ip *); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * If header checksum verification fails, do no more. | 
|  | */ | 
|  | if (in_cksum(m, hlen) != 0) { | 
|  | ipfilter_stat.ip_input_badsum++; | 
|  | goto bad; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Convert fields to host representation. | 
|  | */ | 
|  | ip->ip_len = ntohs(ip->ip_len); | 
|  | len = ip->ip_len; | 
|  | if (len < hlen) { | 
|  | ipfilter_stat.ip_input_badlen++; | 
|  | goto bad; | 
|  | } | 
|  | if (m->m_pkthdr.len < len) { | 
|  | ipfilter_stat.ip_input_tooshort++; | 
|  | goto bad; | 
|  | } | 
|  | if (m->m_pkthdr.len > len) { | 
|  | if (m->m_len == m->m_pkthdr.len) { | 
|  | m->m_len = len; | 
|  | m->m_pkthdr.len = len; | 
|  | } else | 
|  | m_adj(m, len - m->m_pkthdr.len); | 
|  | } | 
|  | ip->ip_off = ntohs(ip->ip_off); | 
|  |  | 
|  | if (fr_check(ip, hlen, m->m_pkthdr.rcvif, 0, &m) == 0) { | 
|  | if (m != NULL) { | 
|  | m->m_flags &= ~M_PROTOCOL_SUM|M_NOCHECKSUM|M_CHECKSUM; | 
|  | /* | 
|  | * Convert back to network byte order. | 
|  | */ | 
|  | ip->ip_len = htons(ip->ip_len); | 
|  | ip->ip_off = htons(ip->ip_off); | 
|  |  | 
|  | ipfilter_stat.ip_input_accept++; | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | ip_continue_input(m); | 
|  | return; | 
|  | } | 
|  | } | 
|  | bad: | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | if (m != NULL) | 
|  | m_freem(m); | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * This hook intercepts mbufs directly from the IP output | 
|  | * routine and gives them to the routine at | 
|  | * (*ip_output_hook)(ifp, m, in_ro, flags, imo).  The | 
|  | * hook must either free the mbuf, or set an mbuf flag | 
|  | * (m->m_flags |= M_OUTPUT_PROCESSING_DONE) and call | 
|  | * ip_output() again to transmit it.  It is assumed that | 
|  | * the hook returns to the caller in a timely manner, enqueuing | 
|  | * the mbuf on its own list for further processing at a later | 
|  | * time (if necesary). | 
|  | */ | 
|  | int ipfilter_ip_output(ifp, m, in_ro, flags, imo) | 
|  | struct ifnet *ifp; | 
|  | struct mbuf *m; | 
|  | struct in_route *in_ro; | 
|  | int flags; | 
|  | struct ip_moptions *imo; | 
|  | { | 
|  | struct ip *ip; | 
|  | int hlen; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_ip_output(%x,%x,%x,%x,%x)\n", | 
|  | ifp, m, in_ro, flags, imo); | 
|  | #endif | 
|  | READ_ENTER(&ipf_tru64); | 
|  | if (ipfilter_registered < 1 || ipftru64_inited == 0) { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return (ip_output(m, NULL, in_ro, flags, imo)); | 
|  | } | 
|  |  | 
|  | ipfilter_stat.ip_output_mbufs++; | 
|  |  | 
|  | ip = mtod(m, struct ip *); | 
|  | hlen = IP_HL(ip); | 
|  | hlen <<= 2; | 
|  |  | 
|  | if (fr_check(ip, hlen, ifp, 1, &m) == 0) { | 
|  | if (m != NULL) { | 
|  | m->m_flags |= M_OUTPUT_PROCESSING_DONE; | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return (ip_output(m, NULL, in_ro, flags, imo)); | 
|  | } | 
|  | } | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * This is a passive routine.  It does not implement any ioctl's, just merely | 
|  | * "snoops" ioctls being sent so that we can be aware of things like address | 
|  | * changes on the interfaces. | 
|  | */ | 
|  | void ipfilter_in_control(so, cmd, data, ifp) | 
|  | struct socket *so; | 
|  | u_int cmd; | 
|  | caddr_t *data; | 
|  | struct ifnet *ifp; | 
|  | { | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_in_control(%x,%x,%x,%x)\n", so, cmd, data, ifp); | 
|  | #endif | 
|  |  | 
|  | ipfilter_stat.in_control_called++; | 
|  |  | 
|  | READ_ENTER(&ipf_tru64); | 
|  | if (ipfilter_registered < 1 || ipftru64_inited == 0) { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cmd == (ioctlcmd_t)SIOCAIFADDR) | 
|  | frsync(NULL); | 
|  |  | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* "protocol" ifnet structure for accessing ipf statistics */ | 
|  | static struct { | 
|  | struct ifnet	ifnet; | 
|  | char		pad[sizeof(struct ether_driver) - sizeof(ifnet)]; | 
|  | } ipfilter_if; | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routine to attach ipf module | 
|  | */ | 
|  | int | 
|  | ipfilter_attach(void) | 
|  | { | 
|  | struct firewall ipf; | 
|  | int status; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_attach(void)\n"); | 
|  | #endif | 
|  |  | 
|  | RWLOCK_INIT(&ipf_tru64, 1); | 
|  | RWLOCK_INIT(&ipf_global, 1); | 
|  | RWLOCK_INIT(&ipf_mutex, 1); | 
|  | RWLOCK_INIT(&ipf_frcache, 1); | 
|  | ipftru64_inited = 1; | 
|  |  | 
|  | status = ipfattach(); | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfattach() = %d\n", status); | 
|  | #endif | 
|  | if (status != ESUCCESS) { | 
|  | (void) ipfdetach(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | ipfilter_registered = 1; | 
|  |  | 
|  | /* | 
|  | * Initialize the struct, else the kernel might interpret | 
|  | * a field as being valid when it's not, which would probably | 
|  | * be fatal. | 
|  | */ | 
|  | bzero(&ipf, sizeof(struct firewall)); | 
|  |  | 
|  | /* | 
|  | * Tell which version of the ipf structure we are passing-in. | 
|  | * The only currently supported version is #1. | 
|  | */ | 
|  | ipf.version = FIREWALL_VERSION1; | 
|  |  | 
|  | /* | 
|  | * Tell which protocol family we wish to register. | 
|  | * The only currently supported family is PF_INET. | 
|  | */ | 
|  | ipf.pf = PF_INET; | 
|  |  | 
|  | /* | 
|  | * Tell the kernel to disable the RPC/NFS "fastpath" code and | 
|  | * send all NFS output packets through the "slow" IP output code. | 
|  | */ | 
|  | ipf.flags = FW_DISABLE_RPC_FASTPATH; | 
|  |  | 
|  | /* | 
|  | * Fill-in the hooks we wish to register.  At a minumum there | 
|  | * must be an input and output hook. | 
|  | */ | 
|  | ipf.in_control_hook = ipfilter_in_control; | 
|  | ipf.fw_ip_input_hook = ipfilter_ip_input; | 
|  | ipf.fw_ip_output_hook = ipfilter_ip_output; | 
|  |  | 
|  | /* make the call */ | 
|  | status = register_firewall(&ipf); | 
|  |  | 
|  | /* | 
|  | * Additionally, if we wish to attach a protocol statistics structure, | 
|  | * do it now.  We will only attach to counter ioctls on success. | 
|  | */ | 
|  | if (status == ESUCCESS) { | 
|  | char *defpass; | 
|  |  | 
|  | ipfilter_registered = 2; | 
|  | ipfilter_ifattach(); | 
|  | fr_running = 1; | 
|  |  | 
|  | /* | 
|  | * Start timeout thread | 
|  | */ | 
|  | ipf_timeout = kernel_thread_w_arg(first_task, ipfilter_timer, | 
|  | NULL); | 
|  | timeout(ipfilter_clock, NULL, | 
|  | (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); | 
|  |  | 
|  | if (FR_ISPASS(fr_pass)) | 
|  | defpass = "pass"; | 
|  | else if (FR_ISBLOCK(fr_pass)) | 
|  | defpass = "block"; | 
|  | else | 
|  | defpass = "no-match -> block"; | 
|  |  | 
|  | printf("%s initialized.  Default = %s all, Logging = %s%s\n", | 
|  | ipfilter_version, defpass, | 
|  | #ifdef  IPFILTER_LOG | 
|  | "enabled", | 
|  | #else | 
|  | "disabled", | 
|  | #endif | 
|  | #ifdef  IPFILTER_COMPILED | 
|  | " (COMPILED)" | 
|  | #else | 
|  | "" | 
|  | #endif | 
|  | ); | 
|  | } | 
|  |  | 
|  | return (status); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routine to detach ipf module | 
|  | */ | 
|  | int | 
|  | ipfilter_detach(void) | 
|  | { | 
|  | int status; | 
|  | struct firewall ipf; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_detach(void)\n"); | 
|  | #endif | 
|  |  | 
|  | WRITE_ENTER(&ipf_tru64); | 
|  | /* | 
|  | * Initialize the struct, else the kernel might interpret | 
|  | * a field as being valid when it's not, which would probably | 
|  | * be fatal. | 
|  | */ | 
|  | bzero(&ipf, sizeof(struct firewall)); | 
|  |  | 
|  | /* | 
|  | * If we had attached a protocol statistics structure, detach it now. | 
|  | * We do this before un-registering our hooks. | 
|  | */ | 
|  | ipfilter_ifdetach(); | 
|  |  | 
|  | /* | 
|  | * Tell which version of the ipf structure we are passing-in. | 
|  | * The only currently supported version is #1. | 
|  | */ | 
|  | ipf.version = FIREWALL_VERSION1; | 
|  |  | 
|  | /* | 
|  | * Tell which protocol family we wish to register. | 
|  | * The only currently supported family is PF_INET. | 
|  | */ | 
|  | ipf.pf = PF_INET; | 
|  |  | 
|  | /* | 
|  | * Tell the kernel to re-enable the RPC/NFS "fastpath" code and stop | 
|  | * sending all NFS output packets through the "slow" IP output code. | 
|  | */ | 
|  | ipf.flags = FW_ENABLE_RPC_FASTPATH; | 
|  |  | 
|  | /* | 
|  | * We don't need to fill-in the hook pointers as they | 
|  | * are not used in the unregister_ipf() routine. | 
|  | */ | 
|  |  | 
|  | /* make the call */ | 
|  | status = ESUCCESS; | 
|  | if (ipfilter_registered > 1) { | 
|  | status = unregister_firewall(&ipf); | 
|  | ipfilter_registered = 1; | 
|  | } | 
|  |  | 
|  | if ((status == ESUCCESS) && (ipfilter_registered > 0)) { | 
|  | status = ipfdetach(); | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfdetach() = %d\n", status); | 
|  | #endif | 
|  | ipfilter_registered = 0; | 
|  | } | 
|  |  | 
|  | if (status == ESUCCESS) { | 
|  | fr_running = 0; | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | if (ipftru64_inited == 1) { | 
|  | RW_DESTROY(&ipf_tru64); | 
|  | RW_DESTROY(&ipf_global); | 
|  | RW_DESTROY(&ipf_frcache); | 
|  | RW_DESTROY(&ipf_mutex); | 
|  | ipftru64_inited = 0; | 
|  | } | 
|  | #if 0 | 
|  | if (ipf_timeout != 0) { | 
|  | thread_terminate(ipf_timeout); | 
|  | ipf_timeout = 0; | 
|  | } | 
|  | #else | 
|  | /* | 
|  | * Deschedule the timeout, kill the thread that is wiating on | 
|  | * it and then wait one second for that thread to die. | 
|  | */ | 
|  | untimeout(ipfilter_clock, NULL); | 
|  | thread_wakeup_one((vm_offset_t)&ipf_timeout); | 
|  |  | 
|  | while (ipf_timeout != 0) { | 
|  | assert_wait_mesg((vm_offset_t)&ipf_timeout, | 
|  | TRUE, "ipftimeout"); | 
|  | thread_set_timeout(hz); | 
|  | thread_block(); | 
|  | } | 
|  | #endif | 
|  | printf("%s unloaded\n", ipfilter_version); | 
|  | } else { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | } | 
|  |  | 
|  | return (status); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routine to attach protocol statistics structure | 
|  | */ | 
|  | void ipfilter_ifattach(void) | 
|  | { | 
|  | struct ifnet *ifp = &(ipfilter_if.ifnet); | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_ifattach(void)\n"); | 
|  | #endif | 
|  |  | 
|  | ifp->if_name = "ipf"; | 
|  | ifp->if_version = "Network Packet Filter"; | 
|  | ifp->if_mtu = IP_MAXPACKET; | 
|  | ifp->if_flags = IFF_UP; | 
|  | ifp->if_ioctl = ipfilter_ifioctl; | 
|  | ifp->if_output = ipfilter_ifoutput; | 
|  | ifp->if_type = IFT_OTHER; | 
|  | ifp->if_hdrlen = 8; | 
|  | ifp->if_affinity = NETALLCPU; | 
|  | ifp->if_addrlen = 0; | 
|  |  | 
|  | if_proto_attach(ifp); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routine to detach protocol statistics structure | 
|  | */ | 
|  | void ipfilter_ifdetach(void) | 
|  | { | 
|  | struct ifnet *ifp = &(ipfilter_if.ifnet); | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilter_ifdetach(void)\n"); | 
|  | #endif | 
|  |  | 
|  | if_proto_detach(ifp); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routine to handle protocol ioctls | 
|  | */ | 
|  | int ipfilter_ifioctl(ifp, cmd, data) | 
|  | register struct ifnet *ifp; | 
|  | unsigned int cmd; | 
|  | caddr_t data; | 
|  | { | 
|  | return(EOPNOTSUPP); | 
|  | } | 
|  |  | 
|  | /* Stub output routine.  Should never be called, but just in case... */ | 
|  | #if TRU64 >= 1885 | 
|  | int ipfilter_ifoutput(ifp, m0, dst, rt, cp) | 
|  | char *cp; | 
|  | #else | 
|  | int ipfilter_ifoutput(ifp, m0, dst, rt) | 
|  | #endif | 
|  | struct ifnet *ifp; | 
|  | struct mbuf *m0; | 
|  | struct sockaddr *dst; | 
|  | struct rtentry *rt; | 
|  | { | 
|  | return(EOPNOTSUPP); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* called from ipfilter_configure(CFG_OP_CONFIGURE,...) */ | 
|  | void ipfilter_print_attr_error(cfg_attr_t *attr_ptr) | 
|  | { | 
|  | printf("%s:", attr_ptr->name); | 
|  |  | 
|  | switch(attr_ptr->status) | 
|  | { | 
|  | case CFG_ATTR_EEXISTS: | 
|  | printf("Attribute does not exist\n"); | 
|  | break; | 
|  | case CFG_ATTR_EOP: | 
|  | printf("Attribute does not support operation\n"); | 
|  | break; | 
|  | case CFG_ATTR_ESUBSYS: | 
|  | printf("Subsystem Failure\n"); | 
|  | break; | 
|  | case CFG_ATTR_ESMALL: | 
|  | printf("Attribute size/value too small\n"); | 
|  | break; | 
|  | case CFG_ATTR_ELARGE: | 
|  | printf("Attribute size/value too large\n"); | 
|  | break; | 
|  | case CFG_ATTR_ETYPE: | 
|  | printf("Attribute invalid type\n"); | 
|  | break; | 
|  | case CFG_ATTR_EINDEX: | 
|  | printf("Attribute invalid index\n"); | 
|  | break; | 
|  | case CFG_ATTR_EMEM: | 
|  | printf("Attribute memory allocation error\n"); | 
|  | break; | 
|  | default: | 
|  | printf("**Unknown attribute: "); | 
|  | printf("%x\n", attr_ptr->status); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * pre-configuration | 
|  | * Returns: ENOMEM for fail. | 
|  | *          ESUCCESS for success. | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilter_preconfig() | 
|  | { | 
|  | int status; | 
|  |  | 
|  | return ESUCCESS; | 
|  | } | 
|  |  | 
|  | void | 
|  | ipfilter_preconfig_callback(int point, int order, ulong argument, ulong event_arg) | 
|  | { | 
|  | int status; | 
|  | struct hwconfig *hwc; | 
|  | hwc = create_hwconfig_struct(); | 
|  |  | 
|  | if (hwc == NULL) | 
|  | return; | 
|  |  | 
|  | /* | 
|  | * Add ourselves to the switch table. | 
|  | */ | 
|  | majnum = devsw_add(ipfilter_name, MAJOR_INSTANCE, NO_DEV, &ipfilter_devsw_entry); | 
|  | if (majnum == NO_DEV) { | 
|  | printf("devsw_add_failed\n"); | 
|  | (void)cfgmgr_set_status(ipfilter_name); | 
|  | callback_return_status = ENODEV; | 
|  | return; | 
|  | } | 
|  | printf("devsw_add_majnum=%d\n", majnum); | 
|  |  | 
|  | hwc->type = HWCONFIG_CONTROLLER_ALL | HWCONFIG_CONFIGURE_REQUEST; | 
|  |  | 
|  | hwc->parent_bus = HWCONFIG_ALL; | 
|  | hwc->parent_bus_instance = DRIVER_WILDNUM; | 
|  | hwc->driver_name = ipfilter_name; | 
|  | hwc->driver_struct = &ipfdriver; | 
|  | hwc->instance_info = -1; | 
|  |  | 
|  | status = driver_framework(hwc); | 
|  | free_hwconfig_struct(hwc); | 
|  |  | 
|  | if (status != ESUCCESS) { | 
|  | printf("Cannot configure driver %s-- status = %d\n", | 
|  | ipfilter_name, status); | 
|  | return; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * post configure | 
|  | * Return: ENODEV on fail. | 
|  | *         ESUCCESS on success. | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilter_postconfig() | 
|  | { | 
|  |  | 
|  | majnum = devsw_add(ipfilter_name,MAJOR_INSTANCE, majnum, &ipfilter_devsw_entry); | 
|  |  | 
|  | if (majnum == ENODEV) { | 
|  | printf("ipfilter_postconfig: call to devsw_add failed\n"); | 
|  | return ENODEV; | 
|  | } | 
|  |  | 
|  | printf("ipfilter_postconfig:major # = %d\n",majnum); | 
|  |  | 
|  | ipfilter_devno = majnum; | 
|  | ipfilter_config = TRUE; | 
|  |  | 
|  | printf("%s configured\n", ipfilter_version); | 
|  |  | 
|  | return ESUCCESS; | 
|  | } | 
|  |  | 
|  | void | 
|  | ipfilter_postconfig_callback(int point, int order, ulong argument, ulong event_arg) | 
|  | { | 
|  | int status; | 
|  |  | 
|  | if (callback_return_status != ESUCCESS) | 
|  | return; | 
|  |  | 
|  | status  = ipfilter_postconfig(); | 
|  | if (status != ESUCCESS) { | 
|  | cfgmgr_set_status(ipfilter_name); | 
|  | callback_return_status = status; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * Open | 
|  | * Return: ENXIO on fail. | 
|  | *         ESUCCESS on success. | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilteropen(dev_t dev, int flag, int format) | 
|  | { | 
|  | int unit; | 
|  |  | 
|  | unit = minor(dev); | 
|  |  | 
|  | if ((IPL_LOGMAX < unit) || (unit < 0)) | 
|  | unit = ENXIO; | 
|  | else | 
|  | unit = ESUCCESS; | 
|  |  | 
|  | return unit; | 
|  | } | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * Close | 
|  | * Return: ESUCCESS on success. | 
|  | *         ENXIO on fail. | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilterclose(dev_t dev, int flag, int format) | 
|  | { | 
|  | int unit; | 
|  |  | 
|  | #ifdef  IPFDEBUG | 
|  | printf("ipfilter_close(%x,%x,%x)\n", dev, flag, format); | 
|  | #endif | 
|  |  | 
|  | unit = minor(dev); | 
|  |  | 
|  | if ((IPL_LOGMAX < unit) || (unit < 0)) | 
|  | unit = ENXIO; | 
|  | else | 
|  | unit = ESUCCESS; | 
|  |  | 
|  | return unit; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * Read - | 
|  | * return: ESUCCESS on success. | 
|  | *         fail: An error number from errno.h | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilterread(dev_t dev, struct uio *uio, int flag) | 
|  | { | 
|  | #ifdef	IPFILTER_LOG | 
|  | int unit, status; | 
|  |  | 
|  | unit = minor(dev); | 
|  |  | 
|  | # ifdef  IPFDEBUG | 
|  | printf("ipfread(%x,%lx,%x)\n", dev, uio, flag); | 
|  | # endif | 
|  | status = ipflog_read(unit, uio); | 
|  |  | 
|  | return status; | 
|  | #else | 
|  | return ENXIO; | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * Write - | 
|  | * return: ESUCCESS on success. | 
|  | *         fail: An error number from errno.h | 
|  | *--------------------------------------------------------*/ | 
|  | #ifdef	IPFILTER_SYNC | 
|  | int | 
|  | ipfilterwrite(dev_t dev, struct uio *uio) | 
|  | { | 
|  | int unit; | 
|  |  | 
|  | # ifdef  IPFDEBUG | 
|  | printf("ipfilter_write(%x,%lx)\n", dev, uio); | 
|  | # endif | 
|  | if (getminor(dev) != IPL_LOGSYNC) | 
|  | return ENXIO; | 
|  | return ipfsync_write(uio); | 
|  |  | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /*--------------------------------------------------------- | 
|  | * IOCTL | 
|  | * Return: ESUCCESS on success. | 
|  | *         fail: An error number from errno.h | 
|  | *--------------------------------------------------------*/ | 
|  | int ipfilterioctl(dev_t dev, unsigned int cmd, caddr_t data, int flag) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | #ifdef	IPFDEBUG | 
|  | printf("ipfilterioctl(%d(%d),%x,%lx,%x)\n", dev, | 
|  | getminor(dev), cmd, data, flag); | 
|  | #endif | 
|  | READ_ENTER(&ipf_tru64); | 
|  | if (ipfilter_registered < 1 || ipftru64_inited == 0) { | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | #ifdef IPFDEBUG | 
|  | printf("ipfilter_registered %d ipftru64_inited %d\n", | 
|  | ipfilter_registered, ipftru64_inited); | 
|  | #endif | 
|  | return EIO; | 
|  | } | 
|  | err = iplioctl(dev, cmd, data, flag); | 
|  | RWLOCK_EXIT(&ipf_tru64); | 
|  | return err; | 
|  | } | 
|  |  | 
|  |  | 
|  | void ipfilter_clock(void *arg) | 
|  | { | 
|  | thread_wakeup_one((vm_offset_t)&ipf_timeout); | 
|  | if (fr_running != 0) { | 
|  | timeout(ipfilter_clock, NULL, | 
|  | (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void ipfilter_timer() | 
|  | { | 
|  | #if 0 | 
|  | lock_data_t ipfdelaylock; | 
|  |  | 
|  | lock_init(&ipfdelaylock, TRUE); | 
|  | #else | 
|  | simple_lock_data_t ipfdelaylock; | 
|  |  | 
|  | simple_lock_init(&ipfdelaylock); | 
|  | simple_lock(&ipfdelaylock); | 
|  | #endif | 
|  |  | 
|  | while (1) { | 
|  | #if 0 | 
|  | lock_write(&ipfdelaylock); | 
|  | assert_wait_mesg((vm_offset_t)&ipfdelaylock, TRUE, "ipftimer"); | 
|  | lock_done(&ipfdelaylock); | 
|  |  | 
|  | thread_set_timeout((hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); | 
|  |  | 
|  | thread_block(); | 
|  | #else | 
|  | if (fr_running == 0) | 
|  | break; | 
|  | mpsleep((vm_offset_t)&ipf_timeout, PCATCH, | 
|  | "ipftimer", 0, &ipfdelaylock, | 
|  | MS_LOCK_SIMPLE | MS_LOCK_ON_ERROR); | 
|  | #endif | 
|  |  | 
|  | if (fr_running == 0) | 
|  | break; | 
|  | simple_unlock(&ipfdelaylock); | 
|  | fr_slowtimer(NULL); | 
|  | simple_lock(&ipfdelaylock); | 
|  | } | 
|  |  | 
|  | simple_unlock(&ipfdelaylock); | 
|  | simple_lock_terminate(&ipfdelaylock); | 
|  |  | 
|  | if (ipf_timeout != 0) { | 
|  | thread_terminate(ipf_timeout); | 
|  | ipf_timeout = 0; | 
|  | } | 
|  | thread_halt_self(); | 
|  | } |