Subject: Full story on PFIL_HOOKS rearrangement
To: None <tech-net@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-net
Date: 11/09/2000 23:55:36
The diff below includes some things I previously talked about -- the
placement of the PFIL_HOOKS calls.  Here is also changes to make the
mechanism more generic -- you can have multiple hook heads -- they're
registered with a "key" and "dlt" pair.

Key is a void * (so it could be e.g. a network interface structure; this
gets into my classification engine, which I'll describe in more detail
later).  DLT is a BPF DLT constant that indicates what kind of link
level header is present.

For INET and INET6, the keys are ((void *) AF_INET) and ((void *) AF_INET6),
and the DLT is DLT_RAW (since there is no link level header present when
the packets are handed off to the filter).

The interface to the pfil_* functions have changed, as has the interface
to the hooks themselves.  I have compsenated with wrappers for IP Filter.

Below is my proposed patch.

Feedback ASAP appreciated.

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>

Index: net/bpf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/bpf.h,v
retrieving revision 1.26
diff -c -r1.26 bpf.h
*** net/bpf.h	2000/11/02 16:14:05	1.26
--- net/bpf.h	2000/11/10 07:45:08
***************
*** 44,49 ****
--- 44,51 ----
  #ifndef _NET_BPF_H_
  #define _NET_BPF_H_
  
+ #include <sys/time.h>
+ 
  /* BSD style release date */
  #define BPF_RELEASE 199606
  
Index: net/pfil.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/pfil.c,v
retrieving revision 1.15
diff -c -r1.15 pfil.c
*** net/pfil.c	2000/02/23 02:35:42	1.15
--- net/pfil.c	2000/11/10 07:45:10
***************
*** 40,62 ****
  #include <net/if.h>
  #include <net/pfil.h>
  
- static void pfil_init __P((struct pfil_head *));
  static int pfil_list_add(pfil_list_t *,
!     int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)), int);
  static int pfil_list_remove(pfil_list_t *,
!     int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)));
  
! static void
! pfil_init(ph)
! 	 struct pfil_head *ph;
  {
  
! 	TAILQ_INIT(&ph->ph_in);
  	TAILQ_INIT(&ph->ph_out);
! 	ph->ph_init = 1;
  }
  
  /*
   * pfil_add_hook() adds a function to the packet filter hook.  the
   * flags are:
   *	PFIL_IN		call me on incoming packets
--- 40,132 ----
  #include <net/if.h>
  #include <net/pfil.h>
  
  static int pfil_list_add(pfil_list_t *,
!     int (*)(void *, struct mbuf **, struct ifnet *, int), void *, int);
! 
  static int pfil_list_remove(pfil_list_t *,
!     int (*)(void *, struct mbuf **, struct ifnet *, int), void *);
! 
! LIST_HEAD(, pfil_head) pfil_head_list =
!     LIST_HEAD_INITIALIZER(&pfil_head_list);
! 
! /*
!  * pfil_run_hooks() runs the specified packet filter hooks.
!  */
! int
! pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
!     int dir)
! {
! 	struct packet_filter_hook *pfh;
! 	struct mbuf *m = *mp;
! 	int rv = 0;
! 
! 	for (pfh = pfil_hook_get(dir, ph); pfh != NULL;
! 	     pfh = TAILQ_NEXT(pfh, pfil_link)) {
! 		if (pfh->pfil_func != NULL) {
! 			rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir);
! 			if (rv != 0 || m == NULL)
! 				break;
! 		}
! 	}
! 
! 	*mp = m;
! 	return (rv);
! }
  
! /*
!  * pfil_head_register() registers a pfil_head with the packet filter
!  * hook mechanism.
!  */
! int
! pfil_head_register(struct pfil_head *ph)
  {
+ 	struct pfil_head *lph;
  
! 	for (lph = LIST_FIRST(&pfil_head_list); lph != NULL;
! 	     lph = LIST_NEXT(lph, ph_list)) {
! 		if (lph->ph_key == ph->ph_key &&
! 		    lph->ph_dlt == ph->ph_dlt)
! 			return EEXIST;
! 	}
! 
! 	TAILQ_INIT(&ph->ph_in); 
  	TAILQ_INIT(&ph->ph_out);
! 
! 	LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list);
! 
! 	return (0);
  }
  
  /*
+  * pfil_head_unregister() removes a pfil_head from the packet filter
+  * hook mechanism.
+  */
+ int
+ pfil_head_unregister(struct pfil_head *pfh)
+ {
+ 
+ 	LIST_REMOVE(pfh, ph_list);
+ 	return (0);
+ }
+ 
+ /*
+  * pfil_head_get() returns the pfil_head for a given key/dlt.
+  */
+ struct pfil_head *
+ pfil_head_get(void *key, int dlt)
+ {
+ 	struct pfil_head *ph;
+ 
+ 	for (ph = LIST_FIRST(&pfil_head_list); ph != NULL;
+ 	     ph = LIST_NEXT(ph, ph_list)) {
+ 		if (ph->ph_key == key && ph->ph_dlt == dlt)
+ 			break;
+ 	}
+ 
+ 	return (ph);
+ }
+ 
+ /*
   * pfil_add_hook() adds a function to the packet filter hook.  the
   * flags are:
   *	PFIL_IN		call me on incoming packets
***************
*** 65,118 ****
   *	PFIL_WAITOK	OK to call malloc with M_WAITOK.
   */
  int
! pfil_add_hook(func, flags, ph)
! 	int	(*func) __P((void *, int, struct ifnet *, int,
! 			     struct mbuf **));
! 	int	flags;
! 	struct	pfil_head	*ph;
  {
  	int err = 0;
- 
- 	if (ph->ph_init == 0)
- 		pfil_init(ph);
  
! 	if (flags & PFIL_IN)
! 		err = pfil_list_add(&ph->ph_in, func, flags & ~PFIL_OUT);
! 	if (err)
! 		return err;
! 	if (flags & PFIL_OUT)
! 		err = pfil_list_add(&ph->ph_out, func, flags & ~PFIL_IN);
! 	if (err) {
! 		if (flags & PFIL_IN)
! 			pfil_list_remove(&ph->ph_in, func);
! 		return err;
  	}
  	return 0;
  }
  
  static int
! pfil_list_add(list, func, flags)
! 	pfil_list_t *list;
! 	int	(*func) __P((void *, int, struct ifnet *, int,
! 			     struct mbuf **));
! 	int flags;
  {
  	struct packet_filter_hook *pfh;
  
  	pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR,
! 	    flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT);
  	if (pfh == NULL)
  		return ENOMEM;
  	pfh->pfil_func = func;
  	/*
  	 * insert the input list in reverse order of the output list
  	 * so that the same path is followed in or out of the kernel.
  	 */
- 	
  	if (flags & PFIL_IN)
  		TAILQ_INSERT_HEAD(list, pfh, pfil_link);
  	else
  		TAILQ_INSERT_TAIL(list, pfh, pfil_link);
  	return 0;
  }
  
--- 135,195 ----
   *	PFIL_WAITOK	OK to call malloc with M_WAITOK.
   */
  int
! pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int),
!     void *arg, int flags, struct pfil_head *ph)
  {
  	int err = 0;
  
! 	if (flags & PFIL_IN) {
! 		err = pfil_list_add(&ph->ph_in, func, arg, flags & ~PFIL_OUT);
! 		if (err)
! 			return err;
! 	}
! 	if (flags & PFIL_OUT) {
! 		err = pfil_list_add(&ph->ph_out, func, arg, flags & ~PFIL_IN);
! 		if (err) {
! 			if (flags & PFIL_IN)
! 				pfil_list_remove(&ph->ph_in, func, arg);
! 			return err;
! 		}
  	}
  	return 0;
  }
  
  static int
! pfil_list_add(pfil_list_t *list,
!     int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg,
!     int flags)
  {
  	struct packet_filter_hook *pfh;
  
+ 	/*
+ 	 * First make sure the hook is not already there.
+ 	 */
+ 	for (pfh = TAILQ_FIRST(list); pfh != NULL;
+ 	     pfh = TAILQ_NEXT(pfh, pfil_link)) {
+ 		if (pfh->pfil_func == func &&
+ 		    pfh->pfil_arg == arg)
+ 			return EEXIST;
+ 	}
+ 
  	pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR,
! 	    (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
  	if (pfh == NULL)
  		return ENOMEM;
+ 
  	pfh->pfil_func = func;
+ 	pfh->pfil_arg  = arg;
+ 
  	/*
  	 * insert the input list in reverse order of the output list
  	 * so that the same path is followed in or out of the kernel.
  	 */
  	if (flags & PFIL_IN)
  		TAILQ_INSERT_HEAD(list, pfh, pfil_link);
  	else
  		TAILQ_INSERT_TAIL(list, pfh, pfil_link);
+ 
  	return 0;
  }
  
***************
*** 121,141 ****
   * hook list.
   */
  int
! pfil_remove_hook(func, flags, ph)
! 	int	(*func) __P((void *, int, struct ifnet *, int,
! 			     struct mbuf **));
! 	int	flags;
! 	struct	pfil_head	*ph;
  {
  	int err = 0;
  
- 	if (ph->ph_init == 0)
- 		pfil_init(ph);
- 
  	if (flags & PFIL_IN)
! 		err = pfil_list_remove(&ph->ph_in, func);
  	if ((err == 0) && (flags & PFIL_OUT))
! 		err = pfil_list_remove(&ph->ph_out, func);
  	return err;
  }
  
--- 198,212 ----
   * hook list.
   */
  int
! pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int),
!     void *arg, int flags, struct pfil_head *ph)
  {
  	int err = 0;
  
  	if (flags & PFIL_IN)
! 		err = pfil_list_remove(&ph->ph_in, func, arg);
  	if ((err == 0) && (flags & PFIL_OUT))
! 		err = pfil_list_remove(&ph->ph_out, func, arg);
  	return err;
  }
  
***************
*** 144,176 ****
   * specified list.
   */
  static int
! pfil_list_remove(list, func)
! 	pfil_list_t *list;
! 	int	(*func) __P((void *, int, struct ifnet *, int,
! 			     struct mbuf **));
  {
  	struct packet_filter_hook *pfh;
  
! 	for (pfh = list->tqh_first; pfh; pfh = pfh->pfil_link.tqe_next)
! 		if (pfh->pfil_func == func) {
  			TAILQ_REMOVE(list, pfh, pfil_link);
  			free(pfh, M_IFADDR);
  			return 0;
  		}
  	return ENOENT;
- }
- 
- struct packet_filter_hook *
- pfil_hook_get(flag, ph)
- 	int flag;
- 	struct	pfil_head	*ph;
- {
- 	if (ph->ph_init != 0)
- 		switch (flag) {
- 		case PFIL_IN:
- 			return (ph->ph_in.tqh_first);
- 		case PFIL_OUT:
- 			return (ph->ph_out.tqh_first);
- 		}
- 	return NULL;
  }
--- 215,232 ----
   * specified list.
   */
  static int
! pfil_list_remove(pfil_list_t *list,
!     int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg)
  {
  	struct packet_filter_hook *pfh;
  
! 	for (pfh = TAILQ_FIRST(list); pfh != NULL;
! 	     pfh = TAILQ_NEXT(pfh, pfil_link)) {
! 		if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
  			TAILQ_REMOVE(list, pfh, pfil_link);
  			free(pfh, M_IFADDR);
  			return 0;
  		}
+ 	}
  	return ENOENT;
  }
Index: net/pfil.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/pfil.h,v
retrieving revision 1.13
diff -c -r1.13 pfil.h
*** net/pfil.h	2000/04/19 04:46:23	1.13
--- net/pfil.h	2000/11/10 07:45:10
***************
*** 32,37 ****
--- 32,38 ----
  #define _NET_PFIL_H_
  
  #include <sys/queue.h>
+ #include <net/bpf.h>
  
  struct mbuf;
  struct ifnet;
***************
*** 42,49 ****
   */
  struct packet_filter_hook {
          TAILQ_ENTRY(packet_filter_hook) pfil_link;
!         int	(*pfil_func) __P((void *, int, struct ifnet *, int,
! 				  struct mbuf **));
  	int	pfil_flags;
  };
  
--- 43,50 ----
   */
  struct packet_filter_hook {
          TAILQ_ENTRY(packet_filter_hook) pfil_link;
! 	int	(*pfil_func)(void *, struct mbuf **, struct ifnet *, int);
! 	void	*pfil_arg;
  	int	pfil_flags;
  };
  
***************
*** 57,71 ****
  struct pfil_head {
  	pfil_list_t	ph_in;
  	pfil_list_t	ph_out;
! 	int		ph_init;
  };
  typedef struct pfil_head pfil_head_t;
  
! struct packet_filter_hook *pfil_hook_get __P((int, struct pfil_head *));
! int	pfil_add_hook __P((int (*func) __P((void *, int,
! 	    struct ifnet *, int, struct mbuf **)), int, struct pfil_head *));
! int	pfil_remove_hook __P((int (*func) __P((void *, int,
! 	    struct ifnet *, int, struct mbuf **)), int, struct pfil_head *));
  
  /* XXX */
  #if defined(_KERNEL) && !defined(_LKM)
--- 58,93 ----
  struct pfil_head {
  	pfil_list_t	ph_in;
  	pfil_list_t	ph_out;
! 	void		*ph_key;
! 	int		ph_dlt;
! 	LIST_ENTRY(pfil_head) ph_list;
  };
  typedef struct pfil_head pfil_head_t;
  
! int	pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
! 	    int);
! 
! int	pfil_add_hook(int (*func)(void *, struct mbuf **,
! 	    struct ifnet *, int), void *, int, struct pfil_head *);
! int	pfil_remove_hook(int (*func)(void *, struct mbuf **,
! 	    struct ifnet *, int), void *, int, struct pfil_head *);
! 
! int	pfil_head_register(struct pfil_head *);
! int	pfil_head_unregister(struct pfil_head *);
! 
! struct pfil_head *pfil_head_get(void *, int);
! 
! static __inline struct packet_filter_hook *
! pfil_hook_get(int dir, struct pfil_head *ph)
! {
! 
! 	if (dir == PFIL_IN)
! 		return (TAILQ_FIRST(&ph->ph_in));
! 	else if (dir == PFIL_OUT)
! 		return (TAILQ_FIRST(&ph->ph_out));
! 	else
! 		return (NULL);
! }
  
  /* XXX */
  #if defined(_KERNEL) && !defined(_LKM)
Index: netinet/fil.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/fil.c,v
retrieving revision 1.40
diff -c -r1.40 fil.c
*** netinet/fil.c	2000/10/08 13:01:30	1.40
--- netinet/fil.c	2000/11/10 07:45:11
***************
*** 713,718 ****
--- 713,760 ----
  	return pass;
  }
  
+ #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) && \
+     defined(_KERNEL)
+ #include <net/pfil.h>
+ 
+ int
+ fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ {
+ 	struct ip *ip = mtod(*mp, struct ip *);
+ 	int rv, hlen = ip->ip_hl << 2;
+ 
+ 	/*
+ 	 * We get the packet with all fields in network byte
+ 	 * order.  We expect ip_len and ip_off to be in host
+ 	 * order.  We frob them, call the filter, then frob
+ 	 * them back.
+ 	 *
+ 	 * Note, we don't need to update the checksum, because
+ 	 * it has already been verified.
+ 	 */
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
+ 
+ 	rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp);
+ 
+ 	HTONS(ip->ip_len);
+ 	HTONS(ip->ip_off);
+ 
+ 	return (rv);
+ }
+ 
+ #ifdef USE_INET6
+ #include <netinet/ip6.h>
+ 
+ int
+ fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ {
+ 	
+ 	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
+ 	    ifp, (dir == PFIL_OUT), mp));
+ }
+ #endif
+ #endif /* __NetBSD_Version >= 105110000 && _KERNEL */
  
  /*
   * frcheck - filter check
Index: netinet/ip_fil.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_fil.c,v
retrieving revision 1.59
diff -c -r1.59 ip_fil.c
*** netinet/ip_fil.c	2000/08/22 16:02:16	1.59
--- netinet/ip_fil.c	2000/11/10 07:45:13
***************
*** 245,250 ****
--- 245,256 ----
  # if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000))
  	int error = 0;
  # endif
+ #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
+ 	struct pfil_head *ph_inet;
+ #ifdef USE_INET6
+ 	struct pfil_head *ph_inet6;
+ #endif
+ #endif
  
  	SPL_NET(s);
  	if (fr_running || (fr_checkp == fr_check)) {
***************
*** 264,272 ****
  		return EIO;
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error) {
  #   ifdef USE_INET6
  		goto pfil_error;
--- 270,298 ----
  		return EIO;
  
  # ifdef NETBSD_PF
+ #  if __NetBSD_Version__ >= 105110000
+ 	ph_inet = pfil_head_get((void *)(u_long) AF_INET, DLT_RAW);
+ #ifdef USE_INET6
+ 	ph_inet6 = pfil_head_get((void *)(u_long) AF_INET6, DLT_RAW);
+ #endif
+ 	if (ph_inet == NULL
+ #ifdef USE_INET6
+ 	    && ph_inet6 == NULL
+ #endif
+ 	   )
+ 		return ENODEV;
+ #  endif
  #  if __NetBSD_Version__ >= 104200000
! #   if __NetBSD_Version__ >= 105110000
! 	if (ph_inet != NULL)
! 		error = pfil_add_hook((void *)fr_check_wrapper, NULL,
! 		    PFIL_IN|PFIL_OUT, ph_inet);
! 	else
! 		error = 0;
! #   else
! 	error = pfil_add_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+ #   endif
  	if (error) {
  #   ifdef USE_INET6
  		goto pfil_error;
***************
*** 281,291 ****
  	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! 	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error) {
! 		pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  pfil_error:
  		appr_unload();
  		ip_natunload();
--- 307,330 ----
  	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! #   if __NetBSD_Version__ >= 105110000
! 	if (ph_inet6 != NULL)
! 		error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
! 		    PFIL_IN|PFIL_OUT, ph_inet6);
! 	else
! 		error = 0;
! #   else
! 	error = pfil_add_hook((void *)fr_check_wrapper6, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
+ #   endif
  	if (error) {
! #   if __NetBSD_Version__ >= 105110000
! 		pfil_remove_hook((void *)fr_check_wrapper, NULL,
! 		    PFIL_IN|PFIL_OUT, ph_inet);
! #   else
! 		pfil_remove_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+ #   endif
  pfil_error:
  		appr_unload();
  		ip_natunload();
***************
*** 354,359 ****
--- 393,406 ----
  {
  	int s, i = FR_INQUE|FR_OUTQUE;
  #if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)
+ # if __NetBSD_Version__ >= 105110000
+ 	struct pfil_head *ph_inet = pfil_head_get((void *)(u_long) AF_INET,
+ 	    DLT_RAW);
+ #ifdef USE_INET6
+ 	struct pfil_head *ph_inet6 = pfil_head_get((void *)(u_long) AF_INET6,
+ 	    DLT_RAW);
+ #endif
+ # endif
  	int error = 0;
  #endif
  
***************
*** 388,403 ****
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error)
  		return error;
  #  else
  	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! 	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error)
  		return error;
  #  endif
--- 435,466 ----
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! #   if __NetBSD_Version__ >= 105110000
! 	if (ph_inet != NULL)
! 		error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
! 		    PFIL_IN|PFIL_OUT, ph_inet);
! 	else
! 		error = 0;
! #   else
! 	error = pfil_remove_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+ #   endif
  	if (error)
  		return error;
  #  else
  	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! #   if __NetBSD_Version__ >= 105110000
! 	if (ph_inet6 != NULL)
! 		error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
! 		    PFIL_IN|PFIL_OUT, ph_inet6);
! 	else
! 		error = 0;
! #   else
! 	error = pfil_remove_hook((void *)fr_check_wrapper6, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
+ #   endif
  	if (error)
  		return error;
  #  endif
Index: netinet/ip_fil.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_fil.h,v
retrieving revision 1.37
diff -c -r1.37 ip_fil.h
*** netinet/ip_fil.h	2000/06/12 10:28:21	1.37
--- netinet/ip_fil.h	2000/11/10 07:45:13
***************
*** 531,536 ****
--- 531,542 ----
  extern	int	fr_qout __P((queue_t *, mblk_t *));
  extern	int	iplread __P((dev_t, struct uio *, cred_t *));
  # else /* SOLARIS */
+ #if defined(__NetBSD__)
+ extern	int	fr_check_wrapper __P((void *, struct mbuf **,
+ 		    struct ifnet *, int));
+ extern	int	fr_check_wrapper6 __P((void *, struct mbuf **,
+ 		    struct ifnet *, int));
+ #endif
  extern	int	fr_check __P((ip_t *, int, void *, int, mb_t **));
  extern	int	(*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
  extern	int	ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *));
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.120
diff -c -r1.120 ip_input.c
*** netinet/ip_input.c	2000/11/08 14:28:15	1.120
--- netinet/ip_input.c	2000/11/10 07:45:14
***************
*** 205,210 ****
--- 205,214 ----
  struct	ipstat	ipstat;
  u_int16_t	ip_id;
  
+ #ifdef PFIL_HOOKS
+ struct pfil_head inet_pfil_hook;
+ #endif
+ 
  struct ipqhead ipq;
  int	ipq_locked;
  
***************
*** 312,317 ****
--- 316,331 ----
  #ifdef GATEWAY
  	ipflow_init();
  #endif
+ 
+ #ifdef PFIL_HOOKS
+ 	/* Register our Packet Filter hook. */
+ 	inet_pfil_hook.ph_key = (void *)(u_long) AF_INET;
+ 	inet_pfil_hook.ph_dlt = DLT_RAW;
+ 	i = pfil_head_register(&inet_pfil_hook);
+ 	if (i != 0)
+ 		printf("ip_init: WARNING: unable to register pfil hook, "
+ 		    "error %d\n", i);
+ #endif /* PFIL_HOOKS */
  }
  
  struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
***************
*** 350,360 ****
  	struct ipqent *ipqe;
  	int hlen = 0, mff, len;
  	int downmatch;
- #ifdef PFIL_HOOKS
- 	struct packet_filter_hook *pfh;
- 	struct mbuf *m0;
- 	int rv;
- #endif /* PFIL_HOOKS */
  
  #ifdef	DIAGNOSTIC
  	if ((m->m_flags & M_PKTHDR) == 0)
--- 364,369 ----
***************
*** 414,425 ****
  		goto bad;
  	}
  
! 	/*
! 	 * Convert fields to host representation.
! 	 */
! 	NTOHS(ip->ip_len);
! 	NTOHS(ip->ip_off);
! 	len = ip->ip_len;
  
  	/*
  	 * Check for additional length bogosity
--- 423,430 ----
  		goto bad;
  	}
  
! 	/* Retrieve the packet length. */
! 	len = ntohs(ip->ip_len);
  
  	/*
  	 * Check for additional length bogosity
***************
*** 466,485 ****
  	 * Note that filters must _never_ set this flag, as another filter
  	 * in the list may have previously cleared it.
  	 */
! 	m0 = m;
! 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
! 	for (; pfh; pfh = pfh->pfil_link.tqe_next)
! 		if (pfh->pfil_func) {
! 			rv = pfh->pfil_func(ip, hlen,
! 					    m->m_pkthdr.rcvif, 0, &m0);
! 			if (rv)
! 				return;
! 			m = m0;
! 			if (m == NULL)
! 				return;
! 			ip = mtod(m, struct ip *);
! 		}
  #endif /* PFIL_HOOKS */
  
  	/*
  	 * Process options and, if not destined for us,
--- 471,489 ----
  	 * Note that filters must _never_ set this flag, as another filter
  	 * in the list may have previously cleared it.
  	 */
! 	if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
! 			   PFIL_IN) != 0)
! 		return;
! 	if (m == NULL)
! 		return;
! 	ip = mtod(m, struct ip *);
  #endif /* PFIL_HOOKS */
+ 
+ 	/*
+ 	 * Convert fields to host representation.
+ 	 */
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
  
  	/*
  	 * Process options and, if not destined for us,
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_output.c,v
retrieving revision 1.77
diff -c -r1.77 ip_output.c
*** netinet/ip_output.c	2000/10/23 03:42:18	1.77
--- netinet/ip_output.c	2000/11/10 07:45:16
***************
*** 146,151 ****
--- 146,155 ----
  static void ip_mloopback
  	__P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
  
+ #ifdef PFIL_HOOKS
+ extern struct pfil_head inet_pfil_hook;			/* XXX */
+ #endif
+ 
  /*
   * IP output.  The packet in mbuf chain m contains a skeletal IP
   * header (with len, off, ttl, proto, tos, src, dst).
***************
*** 176,190 ****
  	int mtu;
  	struct ip_moptions *imo;
  	va_list ap;
- #ifdef PFIL_HOOKS
- 	struct packet_filter_hook *pfh;
- 	struct mbuf *m1;
- 	int rv;
- #endif /* PFIL_HOOKS */
  #ifdef IPSEC
  	struct socket *so;
  	struct secpolicy *sp = NULL;
  #endif /*IPSEC*/
  
  	va_start(ap, m0);
  	opt = va_arg(ap, struct mbuf *);
--- 180,190 ----
  	int mtu;
  	struct ip_moptions *imo;
  	va_list ap;
  #ifdef IPSEC
  	struct socket *so;
  	struct secpolicy *sp = NULL;
  #endif /*IPSEC*/
+ 	u_int16_t ip_len, ip_off;
  
  	va_start(ap, m0);
  	opt = va_arg(ap, struct mbuf *);
***************
*** 420,443 ****
  	    (ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
  		ip->ip_off |= IP_DF;
  
  #ifdef PFIL_HOOKS
  	/*
  	 * Run through list of hooks for output packets.
  	 */
! 	m1 = m;
! 	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
! 	for (; pfh; pfh = pfh->pfil_link.tqe_next)
! 		if (pfh->pfil_func) {
! 		    	rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
! 			if (rv) {
! 				error = EHOSTUNREACH;
! 				goto done;
! 			}
! 			m = m1;
! 			if (m == NULL)
! 				goto done;
! 			ip = mtod(m, struct ip *);
! 		}
  #endif /* PFIL_HOOKS */
  
  #ifdef IPSEC
--- 420,446 ----
  	    (ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
  		ip->ip_off |= IP_DF;
  
+ 	/*
+ 	 * Remember the current ip_len and ip_off, and swap them into
+ 	 * network order.
+ 	 */
+ 	ip_len = ip->ip_len;
+ 	ip_off = ip->ip_off;
+ 
+ 	HTONS(ip->ip_len);
+ 	HTONS(ip->ip_off);
+ 
  #ifdef PFIL_HOOKS
  	/*
  	 * Run through list of hooks for output packets.
  	 */
! 	if ((error = pfil_run_hooks(&inet_pfil_hook, &m, ifp,
! 				    PFIL_OUT)) != 0)
! 		goto done;
! 	if (m == NULL)
! 		goto done;
! 
! 	ip = mtod(m, struct ip *);
  #endif /* PFIL_HOOKS */
  
  #ifdef IPSEC
***************
*** 482,490 ****
  		printf("ip_output: Invalid policy found. %d\n", sp->policy);
  	}
  
! 	ip->ip_len = htons((u_short)ip->ip_len);
! 	ip->ip_off = htons((u_short)ip->ip_off);
! 	ip->ip_sum = 0;
  
      {
  	struct ipsec_output_state state;
--- 485,494 ----
  		printf("ip_output: Invalid policy found. %d\n", sp->policy);
  	}
  
! 	/*
! 	 * ipsec4_output() expects ip_len and ip_off in network
! 	 * order.  They have been set to network order above.
! 	 */
  
      {
  	struct ipsec_output_state state;
***************
*** 541,546 ****
--- 545,553 ----
  #else
  	hlen = ip->ip_hl << 2;
  #endif
+ 	ip_len = ntohs(ip->ip_len);
+ 	ip_off = ntohs(ip->ip_off);
+ 
  	if (ro->ro_rt == NULL) {
  		if ((flags & IP_ROUTETOIF) == 0) {
  			printf("ip_output: "
***************
*** 553,568 ****
  		ifp = ro->ro_rt->rt_ifp;
  	}
  
- 	/* make it flipped, again. */
- 	ip->ip_len = ntohs((u_short)ip->ip_len);
- 	ip->ip_off = ntohs((u_short)ip->ip_off);
  skip_ipsec:
  #endif /*IPSEC*/
  
  	/*
  	 * If small enough for mtu of path, can just send directly.
  	 */
! 	if ((u_int16_t)ip->ip_len <= mtu) {
  #if IFA_STATS
  		/*
  		 * search for the source address structure to
--- 560,572 ----
  		ifp = ro->ro_rt->rt_ifp;
  	}
  
  skip_ipsec:
  #endif /*IPSEC*/
  
  	/*
  	 * If small enough for mtu of path, can just send directly.
  	 */
! 	if (ip_len <= mtu) {
  #if IFA_STATS
  		/*
  		 * search for the source address structure to
***************
*** 570,579 ****
  		 */
  		INADDR_TO_IA(ip->ip_src, ia);
  		if (ia)
! 			ia->ia_ifa.ifa_data.ifad_outbytes += ip->ip_len;
  #endif
- 		HTONS(ip->ip_len);
- 		HTONS(ip->ip_off);
  		ip->ip_sum = 0;
  		ip->ip_sum = in_cksum(m, hlen);
  		error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
--- 574,581 ----
  		 */
  		INADDR_TO_IA(ip->ip_src, ia);
  		if (ia)
! 			ia->ia_ifa.ifa_data.ifad_outbytes += ip_len;
  #endif
  		ip->ip_sum = 0;
  		ip->ip_sum = in_cksum(m, hlen);
  		error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
***************
*** 583,589 ****
--- 585,598 ----
  	/*
  	 * Too large for interface; fragment if possible.
  	 * Must be able to put at least 8 bytes per fragment.
+ 	 *
+ 	 * Note we swap ip_len and ip_off into host order to make
+ 	 * the logic below a little simpler.
  	 */
+ 
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
+ 
  #if 0
  	/*
  	 * If IPsec packet is too big for the interface, try fragment it.
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_input.c,v
retrieving revision 1.28
diff -c -r1.28 ip6_input.c
*** netinet6/ip6_input.c	2000/10/23 03:45:25	1.28
--- netinet6/ip6_input.c	2000/11/10 07:45:17
***************
*** 140,145 ****
--- 140,149 ----
  ip6_fw_ctl_t *ip6_fw_ctl_ptr;
  #endif
  
+ #ifdef PFIL_HOOKS
+ struct pfil_head inet6_pfil_hook;
+ #endif
+ 
  struct ip6stat ip6stat;
  
  static void ip6_init2 __P((void *));
***************
*** 181,186 ****
--- 185,200 ----
  	ip6_flow_seq = random() ^ tv.tv_usec;
  
  	ip6_init2((void *)0);
+ 
+ #ifdef PFIL_HOOKS
+ 	/* Register our Packet Filter hook. */
+ 	inet6_pfil_hook.ph_key = (void *)(u_long) AF_INET6;
+ 	inet6_pfil_hook.ph_dlt = DLT_RAW;
+ 	i = pfil_head_register(&inet6_pfil_hook);
+ 	if (i != 0)
+ 		printf("ip6_init: WARNING: unable to register pfil hook, "
+ 		    "error %d\n", i);
+ #endif /* PFIL_HOOKS */
  }
  
  static void
***************
*** 232,242 ****
  	u_int32_t rtalert = ~0;
  	int nxt, ours = 0;
  	struct ifnet *deliverifp = NULL;
- #ifdef	PFIL_HOOKS
- 	struct packet_filter_hook *pfh;
- 	struct mbuf *m0;
- 	int rv;
- #endif	/* PFIL_HOOKS */
  
  #ifdef IPSEC
  	/*
--- 246,251 ----
***************
*** 303,321 ****
  	 * Note that filters must _never_ set this flag, as another filter
  	 * in the list may have previously cleared it.
  	 */
! 	m0 = m;
! 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
! 	for (; pfh; pfh = pfh->pfil_link.tqe_next)
! 		if (pfh->pfil_func) {
! 			rv = pfh->pfil_func(ip6, sizeof(*ip6),
! 					    m->m_pkthdr.rcvif, 0, &m0);
! 			if (rv)
! 				return;
! 			m = m0;
! 			if (m == NULL)
! 				return;
! 			ip6 = mtod(m, struct ip6_hdr *);
! 		}
  #endif /* PFIL_HOOKS */
  
  
--- 312,323 ----
  	 * Note that filters must _never_ set this flag, as another filter
  	 * in the list may have previously cleared it.
  	 */
! 	if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif,
! 			   PFIL_IN) != 0)
! 		return;
! 	if (m == NULL)
! 		return;
! 	ip6 = mtod(m, struct ip6_hdr *);
  #endif /* PFIL_HOOKS */
  
  
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_output.c,v
retrieving revision 1.26
diff -c -r1.26 ip6_output.c
*** netinet6/ip6_output.c	2000/10/23 03:45:25	1.26
--- netinet6/ip6_output.c	2000/11/10 07:45:18
***************
*** 106,111 ****
--- 106,115 ----
  #include <netinet6/ip6_fw.h>
  #endif
  
+ #ifdef PFIL_HOOKS
+ extern struct pfil_head inet6_pfil_hook;	/* XXX */
+ #endif
+ 
  struct ip6_exthdrs {
  	struct mbuf *ip6e_ip6;
  	struct mbuf *ip6e_hbh;
***************
*** 157,167 ****
  	struct route_in6 *ro_pmtu = NULL;
  	int hdrsplit = 0;
  	int needipsec = 0;
- #ifdef PFIL_HOOKS
- 	struct packet_filter_hook *pfh;
- 	struct mbuf *m1;
- 	int rv;
- #endif /* PFIL_HOOKS */
  #ifdef IPSEC
  	int needipsectun = 0;
  	struct socket *so;
--- 161,166 ----
***************
*** 826,845 ****
  	/*
  	 * Run through list of hooks for output packets.
  	 */
! 	m1 = m;
! 	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
! 	for (; pfh; pfh = pfh->pfil_link.tqe_next)
! 		if (pfh->pfil_func) {
! 		    	rv = pfh->pfil_func(ip6, sizeof(*ip6), ifp, 1, &m1);
! 			if (rv) {
! 				error = EHOSTUNREACH;
! 				goto done;
! 			}
! 			m = m1;
! 			if (m == NULL)
! 				goto done;
! 			ip6 = mtod(m, struct ip6_hdr *);
! 		}
  #endif /* PFIL_HOOKS */
  	/*
  	 * Send the packet to the outgoing interface.
--- 825,836 ----
  	/*
  	 * Run through list of hooks for output packets.
  	 */
! 	if ((error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp,
! 				    PFIL_OUT)) != 0)
! 		goto done;
! 	if (m == NULL)
! 		goto done;
! 	ip6 = mtod(m, struct ip6_hdr *);
  #endif /* PFIL_HOOKS */
  	/*
  	 * Send the packet to the outgoing interface.
Index: netinet6/ip6protosw.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6protosw.h,v
retrieving revision 1.7
diff -c -r1.7 ip6protosw.h
*** netinet6/ip6protosw.h	2000/10/18 21:14:16	1.7
--- netinet6/ip6protosw.h	2000/11/10 07:45:18
***************
*** 75,81 ****
   * Protocol switch table for IPv6.
   * All other definitions should refer to sys/protosw.h
   */
- #include <net/pfil.h>
  
  struct mbuf;
  struct sockaddr;
--- 75,80 ----
***************
*** 141,147 ****
  			__P((void));
  	int	(*pr_sysctl)		/* sysctl for protocol */
  			__P((int *, u_int, void *, size_t *, void *, size_t));
- 	struct	pfil_head	pr_pfh;
  };
  
  extern	struct	ip6protosw	inet6sw[];
--- 140,145 ----
Index: sys/param.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/param.h,v
retrieving revision 1.110
diff -c -r1.110 param.h
*** sys/param.h	2000/11/08 14:53:23	1.110
--- sys/param.h	2000/11/10 07:45:18
***************
*** 65,71 ****
   *
   */
  
! #define __NetBSD_Version__  105100000	/* NetBSD 1.5J */
  
  /*
   * Historical NetBSD #define
--- 65,71 ----
   *
   */
  
! #define __NetBSD_Version__  105110000	/* NetBSD 1.5K */
  
  /*
   * Historical NetBSD #define
Index: sys/protosw.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/protosw.h,v
retrieving revision 1.22
diff -c -r1.22 protosw.h
*** sys/protosw.h	2000/02/17 10:59:41	1.22
--- sys/protosw.h	2000/11/10 07:45:19
***************
*** 61,71 ****
   * described below.
   */
  
- /*
-  * For pfil_head structure.
-  */
- #include <net/pfil.h>
- 
  struct mbuf;
  struct sockaddr;
  struct socket;
--- 61,66 ----
***************
*** 105,111 ****
  			__P((void));
  	int	(*pr_sysctl)		/* sysctl for protocol */
  			__P((int *, u_int, void *, size_t *, void *, size_t));
- 	struct	pfil_head	pr_pfh;
  };
  
  #define	PR_SLOWHZ	2		/* 2 slow timeouts per second */
--- 100,105 ----