diff -urN radiusd-cistron-1.6-dist/raddb/dictionary.ascend radiusd-cistron-1.6/raddb/dictionary.ascend
--- radiusd-cistron-1.6-dist/raddb/dictionary.ascend	2001-11-21 13:10:46.000000000 -0600
+++ radiusd-cistron-1.6/raddb/dictionary.ascend	2003-06-02 11:04:13.000000000 -0500
@@ -294,8 +294,8 @@
 ATTRIBUTE	Ascend-History-Weigh-Type	239	integer		Ascend
 ATTRIBUTE	Ascend-Add-Seconds		240	integer		Ascend
 ATTRIBUTE	Ascend-Remove-Seconds		241	integer		Ascend
-#ATTRIBUTE	Ascend-Data-Filter		242	abinary		Ascend
-#ATTRIBUTE	Ascend-Call-Filter		243	abinary		Ascend
+ATTRIBUTE	Ascend-Data-Filter		242	abinary		Ascend
+ATTRIBUTE	Ascend-Call-Filter		243	abinary		Ascend
 ATTRIBUTE	Ascend-Idle-Limit		244	integer		Ascend
 ATTRIBUTE	Ascend-Preempt-Limit		245	integer		Ascend
 ATTRIBUTE	Ascend-Callback			246	integer		Ascend
diff -urN radiusd-cistron-1.6-dist/src/Make.inc radiusd-cistron-1.6/src/Make.inc
--- radiusd-cistron-1.6-dist/src/Make.inc	2003-06-02 11:06:29.000000000 -0500
+++ radiusd-cistron-1.6/src/Make.inc	2003-06-02 11:04:49.000000000 -0500
@@ -15,7 +15,8 @@
 
 SERVER_OBJS   = radiusd.o files.o acct.o pam.o version.o proxy.o \
 			exec.o auth.o timestr.o cache.o readusers.o
-LIB_OBJS      = dict.o util.o md5.o attrprint.o radius.o log.o pair.o encrattr.o
+LIB_OBJS      = dict.o util.o md5.o attrprint.o radius.o log.o pair.o \
+			encrattr.o filters.o
 
 INCLUDES       = radius.h conf.h
 
@@ -53,6 +54,9 @@
 radius.o: radius.c $(INCLUDES)
 	$(CC) $(CFLAGS) $(DIRS) -c radius.c
 
+filters.o: filters.c $(INCLUDES)
+	$(CC) $(CFLAGS) $(DIRS) -c filters.c
+
 readusers.o: readusers.c $(INCLUDES)
 	$(CC) $(CFLAGS) $(DIRS) -c readusers.c
 
diff -urN radiusd-cistron-1.6-dist/src/attrprint.c radiusd-cistron-1.6/src/attrprint.c
--- radiusd-cistron-1.6-dist/src/attrprint.c	2003-04-03 11:23:17.000000000 -0600
+++ radiusd-cistron-1.6/src/attrprint.c	2003-06-02 11:04:13.000000000 -0500
@@ -195,7 +195,16 @@
 					localtime((time_t *)&pair->lvalue));
 		fprintf(fd, "\"%s\"", buffer);
 		break;
-
+	case PW_TYPE_FILTER_BINARY:
+		{
+			int ix;
+		
+			fprintf( fd, "%s = ", pair->name );
+			for ( ix = 0; ix < pair->length; ix += 1 ) {
+				 fprintf( fd, " %02x", (unsigned char)(pair->strvalue[ ix ]) );
+			}
+		}
+		break;
 	default:
 		fprintf(fd, "Unknown type %d", pair->type);
 		break;
diff -urN radiusd-cistron-1.6-dist/src/dict.c radiusd-cistron-1.6/src/dict.c
--- radiusd-cistron-1.6-dist/src/dict.c	2003-03-11 22:18:59.000000000 -0600
+++ radiusd-cistron-1.6/src/dict.c	2003-06-02 11:04:13.000000000 -0500
@@ -169,6 +169,9 @@
 	else if(strcmp(typestr, "date") == 0) {
 		type = PW_TYPE_DATE;
 	}
+	else if(strcmp(typestr, "abinary") == 0) {
+		type = PW_TYPE_FILTER_BINARY;
+	}
 	else {
 		log(L_ERR|L_CONS,
 	"dict_init: Invalid type on line %d of %s",
diff -urN radiusd-cistron-1.6-dist/src/filters.c radiusd-cistron-1.6/src/filters.c
--- radiusd-cistron-1.6-dist/src/filters.c	1969-12-31 18:00:00.000000000 -0600
+++ radiusd-cistron-1.6/src/filters.c	2003-06-02 11:04:13.000000000 -0500
@@ -0,0 +1,1088 @@
+/*
+ * ASCEND: @(#)filters.c	1.3 (95/07/25 00:55:30)
+ *
+ *      Copyright (c) 1994 Ascend Communications, Inc.
+ *      All rights reserved.
+ *
+ *	Permission to copy all or part of this material for any purpose is
+ *	granted provided that the above copyright notice and this paragraph
+ *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+ *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+ *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *	FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Id: filters.c,v 1.2 1996/12/11 23:17:08 baskar Exp $ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <sys/time.h>	/* gettimeofday() */
+
+#include "radiusd.h"
+
+VALUE_PAIR*	prevRadPair = 0;
+
+#undef DEBUG
+#if defined( DEBUG )
+#define PRINTF( x )	printf x
+#else
+#define PRINTF( x )
+#endif
+
+#define NO_TOKEN -1
+
+typedef struct {
+    const char*	name;
+    int 	value;
+} KeywordStruct;
+
+    /*
+     * FilterPortType:
+     *
+     * Ascii names of some well known tcp/udp services.
+     * Used for filtering on a port type.
+     *
+     */
+
+static KeywordStruct _filterPortType[] = {
+    { "ftp-data", 20 },
+    { "ftp", 21 },
+    { "telnet", 23 },
+    { "smtp", 25 },
+    { "nameserver", 42 },
+    { "domain", 53 },
+    { "tftp", 69 },
+    { "gopher", 70 },
+    { "finger", 79 },
+    { "www", 80 },
+    { "kerberos", 88 },
+    { "hostname", 101 },
+    { "nntp", 119 },
+    { "ntp", 123 },
+    { "exec", 512 },
+    { "login", 513 },
+    { "cmd", 514 },
+    { "talk", 517 },
+    {  NULL , NO_TOKEN },
+};
+
+typedef enum {
+    FILTER_IP_TYPE,
+    FILTER_GENERIC_TYPE,
+    FILTER_IN,
+    FILTER_OUT,
+    FILTER_FORWARD,
+    FILTER_DROP,
+    FILTER_GENERIC_OFFSET,
+    FILTER_GENERIC_MASK,
+    FILTER_GENERIC_VALUE,
+    FILTER_GENERIC_COMPNEQ,
+    FILTER_GENERIC_COMPEQ,
+    FILTER_MORE,
+    FILTER_IP_DST,
+    FILTER_IP_SRC,
+    FILTER_IP_PROTO,
+    FILTER_IP_DST_PORT,
+    FILTER_IP_SRC_PORT,
+    FILTER_EST,
+    FILTER_IPX_TYPE,
+    FILTER_IPX_DST_IPXNET,
+    FILTER_IPX_DST_IPXNODE,
+    FILTER_IPX_DST_IPXSOCK,
+    FILTER_IPX_SRC_IPXNET,
+    FILTER_IPX_SRC_IPXNODE,
+    FILTER_IPX_SRC_IPXSOCK
+} FilterTokens;
+
+
+static KeywordStruct _filterKeywords[] = {
+    { "ip", 	FILTER_IP_TYPE },
+    { "generic",FILTER_GENERIC_TYPE },
+    { "in", 	FILTER_IN },
+    { "out",	FILTER_OUT },
+    { "forward",FILTER_FORWARD },
+    { "drop",	FILTER_DROP },
+    { "dstip",  FILTER_IP_DST },
+    { "srcip",  FILTER_IP_SRC },
+    { "dstport",FILTER_IP_DST_PORT },
+    { "srcport",FILTER_IP_SRC_PORT },
+    { "est",	FILTER_EST },
+    { "more",	FILTER_MORE },
+    { "!=",	FILTER_GENERIC_COMPNEQ },
+    { "==",	FILTER_GENERIC_COMPEQ  },
+    { "ipx",	FILTER_IPX_TYPE  },
+    { "dstipxnet",	FILTER_IPX_DST_IPXNET  },
+    { "dstipxnode",	FILTER_IPX_DST_IPXNODE  },
+    { "dstipxsock",	FILTER_IPX_DST_IPXSOCK  },
+    { "srcipxnet",	FILTER_IPX_SRC_IPXNET  },
+    { "srcipxnode",	FILTER_IPX_SRC_IPXNODE  },
+    { "srcipxsock",	FILTER_IPX_SRC_IPXSOCK  },
+    {  NULL , NO_TOKEN },
+};
+
+#define FILTER_DIRECTION 	0
+#define FILTER_DISPOSITION	1
+#define IP_FILTER_COMPLETE  	0x3	/* bits shifted by FILTER_DIRECTION */
+					/* FILTER_DISPOSITION */
+
+#define IPX_FILTER_COMPLETE      0x3     /* bits shifted by FILTER_DIRECTION */
+                                        /* FILTER_DISPOSITION */
+
+#define GENERIC_FILTER_COMPLETE 0x1c3	/* bits shifted for FILTER_DIRECTION */
+					/* FILTER_DISPOSITION, FILTER_GENERIC_OFFSET*/
+					/* FILTER_GENERIC_MASK, FILTER_GENERIC_VALUE*/
+
+    /*
+     * FilterProtoName:
+     *
+     * Ascii name of protocols used for filtering.
+     *
+     */
+static KeywordStruct _filterProtoName[] = {
+    { "tcp",  6 },
+    { "udp",  17 },
+    { "ospf", 89 },
+    { "icmp", 1 },
+    {  NULL , NO_TOKEN },
+};
+
+static KeywordStruct _filterCompare[] = {
+    { ">", RAD_COMPARE_GREATER },
+    { "=", RAD_COMPARE_EQUAL },
+    { "<", RAD_COMPARE_LESS },
+    { "!=", RAD_COMPARE_NOT_EQUAL },
+    {  NULL , NO_TOKEN },
+};
+
+static char	_curString[512];
+
+int _findKey ( char *string, KeywordStruct *list );
+static int _isAllDigit ( char *token );
+static short _a2octet ( char *tok, char *retBuf );
+static char _defaultNetmask ( unsigned long address );
+static int _ipAddressStringToValue ( char *string, unsigned long *ipAddress,
+					 char *netmask);
+static int _parseIpFilter ( RadFilter *curEntry );
+static int _parseGenericFilter ( RadFilter *curEntry );
+static int _parseIpxFilter ( RadFilter *curEntry );
+static int _stringToNode   ( unsigned char* dest,  unsigned char* src );
+
+    /*
+     * _findKey:
+     *
+     * Given a table of keywords, it will try and match string to an
+     * entry. If it does it returns that keyword value. if no NO_TOKEN is
+     * returned. A sanity check is made for upper case characters.
+     *
+     *	string:			Pointer to the token to match.
+     *
+     *	list:			Point to the list of keywords.
+     *
+     *	returns:		Keyword value on a match or NO_TOKEN.
+     */
+int _findKey(char *string, KeywordStruct *list)
+{
+    short 	len;
+    KeywordStruct*  entry;
+    char	buf[80], *ptr;
+
+    len = strlen( (char *) string );
+    for( ptr = buf ; len; len--, string++ ) {
+	if( isupper( *string ) ) {
+	    *ptr++ = tolower( *string );
+	} else {
+	    *ptr++ = *string;
+	}
+    }
+    *ptr = 0;
+    entry = list;
+    while( entry->name ) {
+   	if( strcmp( entry->name, buf ) == 0 ) {
+	    break;
+	}
+	entry++;
+    }
+    return( entry->value );
+}
+
+    /*
+     * _isAllDigit:
+     *
+     * Routine checks a string to make sure all values are digits.
+     *
+     *	token:			Pointer to sting to check.
+     *
+     * 	returns:		TRUE if all digits, or FALSE.
+     *
+     */
+
+static int
+_isAllDigit(token)
+char	*token;
+{
+    int i;
+
+    i = strlen( (char *) token );
+    while( i-- ) {
+	if( isdigit( *token ) ) {
+	    token++;
+	} else {
+	    break;
+	}
+    }
+    if( i > 0 ) {
+	return( FALSE );
+    } 
+
+    return( TRUE );
+}
+
+    /*
+     * _a2octet:
+     *
+     * Converts the ascii mask and value for generic filters into octets.
+     * It also does a sanity check to see if the string is greater than
+     * MAX_FILTER_LEN. It assumes the sting is hex with NO leading "0x"
+     *
+     *	tok:			Pointer to the string.
+     *
+     *  retBuf:			Pointer to place the octets.
+     *
+     *	returns:		Number of octects or -1 for error.
+     * 
+     */
+static short
+_a2octet(tok, retBuf)
+char	*tok;
+char	*retBuf;
+{
+    short	rc, len, val, retLen, i;
+    char	buf[ RAD_MAX_FILTER_LEN *2 ];
+    char	*octet = buf;
+
+    rc = -1;
+    retLen = 0;
+
+    if( ( len = strlen( (char*) tok ) ) <= ( RAD_MAX_FILTER_LEN*2 ) ) {
+	retLen = len/2;
+	if( len % 2 ) {
+	    retLen++;
+	}
+	memset( buf, '\0', RAD_MAX_FILTER_LEN * 2 );
+	for( ; len; len-- ) {
+	    if( *tok <= '9' && *tok >= '0' ) {
+		val = '0';
+	        *octet++ = *tok++ - val;
+	    } else if( isxdigit( *tok ) ) {
+		if( *tok > 'Z' ) {
+		    val = 'a';
+		} else {
+		    val = 'A';
+		}
+	        *octet++ = ( *tok++ - val ) + 10;
+	    } else {
+		break;	
+	    }
+	}
+	if( !len ) {
+	    /* merge the values */
+	    for( i = 0; i < RAD_MAX_FILTER_LEN*2; i+=2 ) {
+		*retBuf++ = (buf[i] << 4) | buf[i+1];
+	    }
+	}
+    }
+
+    if( len ) {
+	rc = -1;
+    } else {
+	rc = retLen;
+    }
+    return( rc );
+}
+
+
+
+    /*
+     * _defaultNetMask:
+     *
+     *	Given an ip address this routine calculate a default netmask.
+     *
+     *	address:		Ip address.
+     *
+     *	returns:		Number of bits for the netmask
+     *
+     */
+static char
+_defaultNetmask(address)
+unsigned long	address;
+{
+    char netmask;
+
+    if ( ! address ) {
+	netmask = 0;
+    } else if (( address & htonl( 0x80000000 ) ) == 0 ) {
+	netmask = 8;
+    } else if (( address & htonl( 0xc0000000 ) ) == htonl( 0x80000000 ) ) {
+	netmask = 16;
+    } else if (( address & htonl( 0xe0000000 ) ) == htonl( 0xc0000000 ) ) {
+	netmask = 24;
+    } else {
+	netmask = 32;
+    }
+    return netmask;
+}
+
+		
+static char ipAddressDigits[] = "1234567890./";
+    /*
+     * This functions attempts to convert an IP address in ASCII dot
+     * with an optional netmask part to a pair of IpAddress.  Note:
+     * An IpAddress is always stored in network byte order.
+     *
+     * Parameters:
+     *
+     *  string:		Pointer to a NULL terminated IP address in dot 
+     *			notation followed by an optional /nn to indicate
+     *			the number leading of bits in the netmask.
+     * 
+     *  ipAddress:	Pointer to an IpAddress where the converted
+     *			address will be stored.
+     *
+     *	netmask:	Pointer to an IpAddress where the netmask
+     *			will be stored.  If no netmask is passed as
+     *			as part of the address the default netmask will
+     *			be stored here.
+     *
+     * Returns:
+     *	<>		TRUE if valid conversion, FALSE otherwise.
+     *
+     *	*ipAddress:	If function returns TRUE, the IP address in NBO.
+     *	*netmask:	If function returns TRUE, the netmask in NBO.
+     */
+
+static int
+_ipAddressStringToValue(char *string, unsigned long *ipAddress,
+	char *netmask)
+{
+    u_char*	dst;
+    char*	cp;
+    int		numDots;
+    int		i;
+    long	value;
+
+    if ( ! string ) {
+    	return(FALSE);
+    }
+
+    /* Allow an IP address to be blanked instead of forcing entry of
+       0.0.0.0 -- the user will like it. */
+
+    if ( *string == 0 ) {
+	*ipAddress = 0;
+	*netmask = 0;
+	return TRUE;
+    }
+
+    /* First just count the number of dots in the address.  If there
+       are more or less than three the address is invalid. */
+
+    cp = string;
+    numDots = 0;
+    while( *cp ) {
+	if( !strchr( ipAddressDigits, *cp) ) {
+	    return( FALSE );
+	}
+	if ( *cp == '.') {
+	    ++numDots;
+	}
+	++cp;
+    }
+    if ( numDots != 3 ) {
+	return( FALSE );
+    }
+
+    dst = (u_char *) ipAddress;
+    cp = string;
+
+    for ( i = 0; i < sizeof( *ipAddress ); i++ ) {
+	value = strtol( cp, (char**) &cp, 10 );
+	if (( value < 0 ) || ( value > 255 )) {
+	    return( FALSE );
+	}
+	*dst++ = (u_char) value;
+	if ( *cp == '.' ) {
+	    cp += 1;
+	}
+    }
+
+    /* If there is a netmask part, parse it, otherwise figure out the
+       default netmask for this class of address. */
+
+    if ( *cp == '/' ) {
+	value = strtol( cp + 1, (char**) &cp, 10 );
+	if (( *cp != 0 ) || ( value < 0 ) || ( value > 32 )) {
+	    return FALSE;
+	}
+	*netmask = (char) value;
+    } else {
+	*netmask = _defaultNetmask( *ipAddress );
+    }
+    return TRUE;
+}
+
+    /*
+     * Convert a 12 digit string representation of a hex data field to a
+     * value.
+     */
+static int
+_stringToNode(dest, src )
+unsigned char* 	dest;
+unsigned char*  src;
+{
+    int         srcIx = 0;
+    int         ix;
+    int         nibble1;
+    int         nibble2;
+    int		temp;
+    unsigned char *src1;
+
+    src1 = (unsigned char *) strchr(src, 'x');
+
+    if (src1 == NULL)
+	src1 = (unsigned char *) strchr(src,'X');
+
+    if (src1 == NULL)
+	src1 = src;
+    else
+	src1++;
+
+    /* skip any leading 0x or 0X 's */
+    temp = strlen( (char*) src1 );
+    if( strlen( (unsigned char*) src1 ) != ( IPX_NODE_ADDR_LEN * 2 ) ) {
+        return( FALSE );
+    }
+
+    for ( ix = 0; ix < IPX_NODE_ADDR_LEN; ++ix ) {
+        if ( src1[ srcIx ] <= '9' ) {
+            nibble1 = src1[ srcIx ] & 0x0f;
+        } else {
+            nibble1 = (src1[ srcIx ] & 0x0f) + 9;
+        }
+        srcIx += 1;
+        if ( src1[ srcIx ] <= '9' ) {
+            nibble2 = src1[ srcIx ] & 0x0f;
+        } else {
+            nibble2 = (src1[ srcIx ] & 0x0f) + 9;
+        }
+        srcIx += 1;
+        ((unsigned char *) dest)[ ix ] = (unsigned char) (nibble1 << 4) + nibble2;
+    }
+
+    return( TRUE );
+}
+
+
+    /*
+     * _parseIpxFilter:
+     *
+     * This routine parses an IPX filter string from a RADIUS
+     * reply. The format of the string is:
+     *
+     *	ipx dir action [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
+     * 	               [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
+     *
+     * Fields in [...] are optional.
+     *	where:
+     *
+     *  ipx:		Keyword to designate an IPX filter. Actually this
+     *			has been determined by _parseFilter.
+     *
+     *	dir:		Filter direction. "IN" or "OUT"
+     *
+     *	action:		Filter action. "FORWARD" or "DROP"
+     *
+     *  srcipxnet:      Keyword for source IPX address.
+     *                  nnnn = IPX Node address.
+     *
+     *  srcipxnode:     Keyword for source IPX Node address.
+     *                  mmmmm = IPX Node Address, could be FFFFFF.
+     *                  A vlid ipx node number should accompany ipx net number.
+     *
+     *  srcipxsoc:      Keyword for source IPX socket address.
+     *
+     *  cmd:            One of ">" or "<" or "=" or "!=".
+     *
+     *  value:          Socket value to be compared against, in hex. 
+     *			
+     *	dstipxnet:	Keyword for destination IPX address.
+     *			nnnn = IPX Node address. 
+     *			
+     *	dstipxnode:	Keyword for destination IPX Node address.
+     *  		mmmmm = IPX Node Address, could be FFFFFF.
+     *			A vlid ipx node number should accompany ipx net number.
+     *			
+     *	dstipxsoc:	Keyword for destination IPX socket address.
+     *			
+     *	cmd:		One of ">" or "<" or "=" or "!=".
+     *			
+     *	value:		Socket value to be compared against, in hex.		
+     *			
+     *			
+     * expects:
+     *
+     *	curEntry:	Pointer to place the filter structure
+     *
+     *	returns:	-1 for error or 0 for OK
+     *	
+     */
+
+static int 
+_parseIpxFilter(curEntry)
+RadFilter	*curEntry;
+{
+    unsigned long	elements = 0l;
+    int			tok; 
+    char*		token;
+    RadIpxFilter*	ipx;
+
+    token = (char *) strtok( NULL, " " ); 
+
+    memset( curEntry, '\0', sizeof( RadFilter ) );
+    curEntry->type = RAD_FILTER_IPX; 
+    ipx = &curEntry->u.ipx;
+ 
+    while( token ) {
+  	tok = _findKey( token, _filterKeywords );
+	switch( tok ) {
+	    case FILTER_IN:
+	    case FILTER_OUT:
+		curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
+		PRINTF((" got FILTER %s ", tok == FILTER_IN?"IN":"OUT"));
+	        elements |= (1 << FILTER_DIRECTION );
+		break;
+
+	    case FILTER_FORWARD:
+	    case FILTER_DROP:
+		PRINTF((" got FILTER %s ",
+			tok == FILTER_DROP? "DROP":"FORWARD"));
+
+	        elements |= (1 << FILTER_DISPOSITION );
+		if( tok == FILTER_FORWARD ) {
+		    curEntry->forward = TRUE;
+		} else {
+		    curEntry->forward = FALSE;
+		}
+		break;
+
+	    case FILTER_IPX_DST_IPXNET:
+	    case FILTER_IPX_SRC_IPXNET:
+                PRINTF((" got FILTER_IPX %s IPXNET ",
+                        tok == FILTER_IPX_DST_IPXNET ? "DST":"SRC"));
+		token = (char *) strtok( NULL, " " );
+
+		if ( token ) {
+		    if( tok == FILTER_IPX_DST_IPXNET ) {
+			ipx->dstIpxNet = ntohl( strtol( token, 0, 16 ));
+			PRINTF(("D.Net: %08lX  token: %s \n", htonl(ipx->dstIpxNet), token));
+		    } else {
+			ipx->srcIpxNet = ntohl( strtol( token, 0, 16 ));
+			PRINTF(("S Net: %08lX token: %s \n", htonl(ipx->srcIpxNet), token));
+		    }
+		    break;
+		} 
+		goto doneErr; 
+
+            case FILTER_IPX_DST_IPXNODE:
+            case FILTER_IPX_SRC_IPXNODE:
+                PRINTF((" got FILTER_IPX %s IPXNODE ",
+			tok == FILTER_IPX_DST_IPXNODE ? "DST":"SRC"));
+		token = (char *) strtok( NULL, " " );
+
+		if ( token ) {
+		    if ( tok == FILTER_IPX_DST_IPXNODE) {
+			_stringToNode( (unsigned char *)ipx->dstIpxNode, (unsigned char*)token );
+			PRINTF(("D. Node: %08lX%04X \n", 
+				htonl((*(int *)(ipx->dstIpxNode))),
+				htons((*(short *)(ipx->dstIpxNode+4)))));
+		    } else {
+			_stringToNode( (unsigned char *)ipx->srcIpxNode, (unsigned char*)token );
+			PRINTF(("S. Node: %08lX%04X \n", 
+				htonl((*(int *)(ipx->srcIpxNode))),
+				htons((*(short *)(ipx->srcIpxNode+4)))));
+		    }
+		    break;
+		}
+                goto doneErr;
+
+            case FILTER_IPX_DST_IPXSOCK:
+            case FILTER_IPX_SRC_IPXSOCK:
+	    {
+		RadFilterComparison cmp;
+
+                PRINTF((" got FILTER_IPX %s IPXSOCK",
+			tok == FILTER_IPX_DST_IPXSOCK ? "DST":"SRC"));
+                token = (char *) strtok( NULL, " " );
+
+		if ( token ) {
+		    cmp = _findKey( token, _filterCompare );
+		    PRINTF((" cmp value = %d \n", cmp ));
+		    if( cmp != NO_TOKEN ) {
+		    token = (char *) strtok( NULL, " " );
+			if ( token ) {
+			    if ( tok == FILTER_IPX_DST_IPXSOCK ) {
+				ipx->dstSocComp = cmp;
+				ipx->dstIpxSoc = 
+			    ntohs( (IpxSocket) strtol( token, NULL, 16 ));
+				PRINTF(("%X \n", htons(ipx->dstIpxSoc)));
+			    } else {
+				ipx->srcSocComp = cmp;
+				ipx->srcIpxSoc 
+				    = ntohs( (IpxSocket) strtol( token, NULL, 16 ));
+				PRINTF(("%X \n", htons(ipx->srcIpxSoc)));
+			    }
+			    break;
+			}
+		    }
+		}
+		goto doneErr;
+	     }
+
+	    default:
+		/* no keyword match */
+		goto doneErr;
+	}
+        token = (char *) strtok( NULL, " " ); 
+    } 
+
+    if( elements == IPX_FILTER_COMPLETE ) {
+	return( 0 );
+    }
+
+doneErr:
+    PRINTF(( "RADIF: IPX Filter syntax error %s \n", token ));
+    log(L_ERR, "ipx filter error: do not recognize %s in %s \n",
+	      token, _curString );
+    return( -1 );
+}
+
+    /*
+     * _parseIpFilter:
+     *
+     * This routine parses an IP filter string from a RADIUS
+     * reply. The format of the string is:
+     *
+     *	ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
+     *	    [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ] 
+     *
+     * Fields in [...] are optional.
+     *	where:
+     *
+     *  ip:		Keyword to designate an IP filter. Actually this
+     *			has been determined by _parseFilter.
+     *
+     *	dir:		Filter direction. "IN" or "OUT"
+     *
+     *	action:		Filter action. "FORWARD" or "DROP"
+     *
+     *	dstip:		Keyword for destination IP address.
+     *			n.n.n.n = IP address. /nn - netmask. 
+     *			
+     *	srcip:		Keyword for source IP address.
+     *			n.n.n.n = IP address. /nn - netmask. 
+     *			
+     *	proto:		Optional protocol field. Either a name or
+     *			number. Known names are in FilterProtoName[].
+     *			
+     *	dstpost:	Keyword for destination port. Only valid with tcp
+     *			or udp. 'cmp' are in FilterPortType[]. 'value' can be
+     *			a name or number.
+     *
+     *	srcpost:	Keyword for source port. Only valid with tcp
+     *			or udp. 'cmp' are in FilterPortType[]. 'value' can be
+     *			a name or number.
+     *			
+     *	est:		Keyword for TCP established. Valid only for tcp.
+     *			
+     * expects:
+     *
+     *	curEntry:	Pointer to place the filter structure
+     *
+     *	returns:	-1 for error or 0 for OK
+     *	
+     */
+
+static int 
+_parseIpFilter(curEntry)
+RadFilter	*curEntry;
+{
+ 
+    unsigned long	elements = 0l;
+    int			tok; 
+    char*		token;
+    RadIpFilter*	ip;
+
+    token = (char *) strtok( NULL, " " ); 
+
+    PRINTF((" in ip  filter \n")); 
+
+    memset( curEntry, '\0', sizeof( RadFilter ) );
+    curEntry->type = RAD_FILTER_IP; 
+    ip = &curEntry->u.ip;
+    ip->established = FALSE;
+ 
+    while( token ) {
+	PRINTF((" token %s ", token ));
+  	tok = _findKey( token, _filterKeywords );
+	switch( tok ) {
+	    case FILTER_IN:
+	    case FILTER_OUT:
+		curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
+		PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT"));
+	        elements |= (1 << FILTER_DIRECTION );
+		break;
+	    case FILTER_FORWARD:
+	    case FILTER_DROP:
+		PRINTF((" got %s ", tok == FILTER_DROP?
+			"FILTER_DROP":"FILTER_FORWARD"));
+	        elements |= (1 << FILTER_DISPOSITION );
+		if( tok == FILTER_FORWARD ) {
+		    curEntry->forward = TRUE;
+		} else {
+		    curEntry->forward = FALSE;
+		}
+		break;
+	    case FILTER_IP_DST:
+	    case FILTER_IP_SRC:
+		PRINTF((" got %s ", tok == FILTER_IP_DST?
+			"FILTER_IP_DST":"FILTER_IP_SRC"));
+		token = (char *) strtok( NULL, " " );
+		if ( token ) {
+		    if( tok == FILTER_IP_DST ) {
+			
+		        if( _ipAddressStringToValue( (char*)token, 
+				 &ip->dstip, (char *)&ip->dstmask ) ) {
+			    PRINTF((" ip %lx netmask %lx \n", ip->dstip, 
+				     ip->dstmask ));
+			    break;
+			}
+		    } else {
+		        if( _ipAddressStringToValue( (char *)token, 
+				&ip->srcip, (char *)&ip->srcmask ) ) {
+			    PRINTF((" ip %lx netmask %lx \n", ip->srcip,
+				     ip->srcmask ));
+			    break;
+			}
+		    }
+		} 
+
+		PRINTF(( "RADIF: IP Filter syntax error %s \n", token ));
+		log(L_ERR, "ip filter error: do not recognize %s in %s \n",
+			  token, _curString );
+		goto doneErr ;
+
+	    case FILTER_IP_DST_PORT:
+	    case FILTER_IP_SRC_PORT:
+	    {
+		RadFilterComparison cmp;
+		short		 port;
+
+		PRINTF((" got %s ", tok == FILTER_IP_DST_PORT?
+			"FILTER_IP_DST_PORT":"FILTER_IP_SRC_PORT"));
+		token = (char *) strtok( NULL, " " );
+		if ( token ) {
+  		    cmp = _findKey( token, _filterCompare );
+		    PRINTF((" cmp value = %d \n", cmp ));
+		    if( cmp != NO_TOKEN ) {
+			token = (char *) strtok( NULL, " " );
+			if ( token ) {
+			    if( _isAllDigit( token ) ) {
+				port = atoi( (char *) token );
+			    } else {
+  		    	        port = _findKey( token, _filterPortType );
+			    }
+			    if( port != (short) NO_TOKEN ) {
+		    	    	PRINTF((" port = %d \n", port ));
+				if( tok == FILTER_IP_DST_PORT ) {
+				    ip->dstPortComp = cmp;
+				    ip->dstport = htons( port );
+				} else {
+				    ip->srcPortComp = cmp;
+				    ip->srcport = htons( port );
+				}
+				break;
+			    }
+			}
+		    }
+		}
+		log( L_ERR, "ip filter error: do not recognize %s in %s \n",
+			  token, _curString );
+		PRINTF(( "RADIF: IP Filter syntax error %s \n", token ));
+		goto doneErr;
+		break;
+	    }
+	    case FILTER_EST:
+		PRINTF((" got est %s ", token ));
+		ip->established = TRUE;
+		break;
+	    default:
+		/* no keyword match but may match a protocol list */
+		if( _isAllDigit( token ) ) {
+		    tok = atoi( (char *) token );
+		} else {
+		    tok = _findKey( token, _filterProtoName );
+
+		    if( tok == NO_TOKEN ) {
+			PRINTF(( "RADIF: IP proto error %s \n", token ));
+			log(L_ERR, "ip filter error: do not recognize %s in %s \n",
+			     token, _curString );
+			goto doneErr;
+		    }
+		}
+		ip->proto = tok;
+		PRINTF(("ip proto cmd = %d ", tok));
+	}
+        token = (char *) strtok( NULL, " " ); 
+    } 
+
+    if( elements == IP_FILTER_COMPLETE ) {
+	return( 0 );
+    }
+
+doneErr:
+    PRINTF((" done err \n"));
+    return( -1 );
+}
+
+    /*
+     * _parseGenericFilter:
+     *
+     * This routine parses a Generic filter string from a RADIUS
+     * reply. The format of the string is:
+     *
+     *	GENERIC dir action offset mask value [== or != ] [more]
+     *
+     * Fields in [...] are optional.
+     *	where:
+     *
+     * 	generic:	Keyword to indicate a generic filter. This
+     *			has been determined by _parseFilter.
+     *
+     *	dir:		Filter direction. "IN" or "OUT"
+     *
+     *	action:		Filter action. "FORWARD" or "DROP"
+     *
+     *	offset:		A Number. Specifies an offset into a frame 
+     *			to start comparing.
+     *			
+     *	mask:		A hexadecimal mask of bits to compare.
+     *			
+     *	value:		A value to compare with the masked data.
+     *
+     *	compNeq:	Defines type of comparison. ( "==" or "!=")
+     *			Default is "==".
+     *			
+     *	more:		Optional keyword MORE, to represent the attachment
+     *			to the next entry.
+     *
+     * expects:
+     *
+     *	curEntry:	Pointer to place the filter structure
+     *
+     *	returns:	-1 for error or 0 for OK
+     *	
+     */
+
+static int
+_parseGenericFilter(curEntry)
+RadFilter	*curEntry;
+{
+    unsigned long	elements = 0l; 
+    int			tok; 
+    int			gstate = FILTER_GENERIC_OFFSET;
+    char*		token;
+    short		valLen, maskLen;
+    RadGenericFilter*	gen;
+
+    token = (char *) strtok( NULL, " " ); 
+
+    PRINTF((" in parse generic filter \n")); 
+
+    maskLen = 0;
+    memset( (char *)curEntry, '\0', sizeof( RadFilter ) );
+    curEntry->type = RAD_FILTER_GENERIC;
+    gen = &curEntry->u.generic;
+    gen->more = FALSE; 
+    gen->compNeq = FALSE;	
+
+    while( token ) {
+	PRINTF((" token %s ", token ));
+  	tok = _findKey( token, _filterKeywords );
+   	PRINTF(("tok %d ", tok));
+	switch( tok ) {
+	    case FILTER_IN:
+	    case FILTER_OUT:
+		curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
+	        elements |= (1 << FILTER_DIRECTION );
+		PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT"));
+		break;
+	    case FILTER_FORWARD:
+	    case FILTER_DROP:
+	        elements |= (1 << FILTER_DISPOSITION );
+		PRINTF((" got %s ", tok == FILTER_DROP?
+			"FILTER_DROP":"FILTER_FORWARD"));
+		if( tok == FILTER_FORWARD ) {
+		    curEntry->forward = TRUE;
+		} else {
+		    curEntry->forward = FALSE;
+		}
+		break;
+	    case FILTER_GENERIC_COMPNEQ:
+		gen->compNeq = TRUE;
+		PRINTF((" got compare %s ", token));
+		break;
+	    case FILTER_GENERIC_COMPEQ:
+		gen->compNeq = FALSE;
+		PRINTF((" got compare %s ", token));
+		break;
+	    case FILTER_MORE:
+		gen->more = htons( TRUE );
+		PRINTF((" got more %s ", token ));
+		break;
+	    default:
+	        elements |= ( 1 << gstate );
+		switch( gstate ) {
+		    case FILTER_GENERIC_OFFSET:
+			gstate = FILTER_GENERIC_MASK;
+			gen->offset = htons( atoi( (char *) token ) );
+			break;
+		    case FILTER_GENERIC_MASK:
+			gstate = FILTER_GENERIC_VALUE;
+			maskLen = _a2octet( token, (char *)gen->mask );
+			if( maskLen == (short) -1 ) {
+			    log(L_ERR, "filter mask error: %s \n", _curString );
+			    goto doneErr;
+			}
+#ifdef DEBUG
+			PRINTF((" octet retlen = %d ", maskLen ));
+			for( tok = 0; tok < maskLen; tok++) {
+        		    PRINTF(("%2x", gen->mask[tok]));
+		        }
+			PRINTF(("\n"));
+#endif
+
+			break;
+		    case FILTER_GENERIC_VALUE:
+			gstate ++;
+			valLen = _a2octet( token, (char *)gen->value );
+			if( valLen != maskLen ) {
+			    log(L_ERR, "filter value size is not the same size as the filter mask: %s \n", 
+				     _curString );
+			    goto doneErr;
+			}
+			gen->len = htons( valLen );
+#ifdef DEBUG
+			PRINTF((" octet retlen = %d ", maskLen ));
+			for( tok = 0; tok < maskLen; tok++) {
+        		    PRINTF(("%2x", gen->value[tok]));
+		        }
+			PRINTF(("\n"));
+#endif
+
+			break;
+		    default:
+			log(L_ERR, "filter: do not know %s in %s \n",
+				 token, _curString );
+			PRINTF(( "RADIF: Filter syntax error %s \n", token ));
+			goto doneErr;    
+		}
+	}
+        token = (char *) strtok( NULL, " " ); 
+    }
+
+    if( elements == GENERIC_FILTER_COMPLETE ) {
+	return( 0 );
+    }
+
+doneErr:
+    PRINTF((" done err \n"));
+    return( -1 );
+}
+		       
+    /*
+     * filterBinary:
+     *
+     * This routine will call routines to parse entries from an ASCII format
+     * to a binary format recognized by the Ascend boxes.
+     *
+     *	pair:			Pointer to value_pair to place return.
+     *
+     *	valstr:			The string to parse	
+     *
+     *	return:			-1 for error or 0.
+     */
+int 
+filterBinary(pair, valstr)
+VALUE_PAIR	*pair;
+char		*valstr;
+{
+
+    char*		token;
+    unsigned long	tok;
+    int			rc;
+    RadFilter		radFil, *filt;
+    RadGenericFilter*	gen;
+
+    rc = -1;
+    strcpy( _curString, valstr );
+
+    token = (char *) strtok( (char *)valstr, " " );
+    tok = _findKey( token, _filterKeywords );
+    pair->length = sizeof( RadFilter );
+    switch( tok ) {
+      case FILTER_IP_TYPE:
+	rc = _parseIpFilter( &radFil );
+	break;
+      case FILTER_GENERIC_TYPE:
+	rc = _parseGenericFilter( &radFil );
+	break;
+      case  FILTER_IPX_TYPE:
+	rc = _parseIpxFilter( &radFil );
+        break;
+    }
+
+    /*
+     * if more is set then this new entry must exist, be a 
+     * FILTER_GENERIC_TYPE, direction and disposition must match for 
+     * the previous more to be valid. If any should fail then TURN OFF 
+     * previos more
+     */
+    if( prevRadPair ) {
+	filt = ( RadFilter * )prevRadPair->strvalue;
+	if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
+	   ( prevRadPair->attribute != pair->attribute ) || 
+	   ( filt->indirection != radFil.indirection ) || 
+	   ( filt->forward != radFil.forward ) ) {
+	    gen = &filt->u.generic;
+	    gen->more = FALSE;
+	    log(L_ERR, "filterBinary:  'more' for previous entry doesn't match: %s.\n",
+		     _curString );
+	}
+    }
+    prevRadPair = NULL;
+    if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
+	if( radFil.u.generic.more ) {
+	    prevRadPair = pair;
+	} 
+    }
+
+    if( rc != -1 ) {
+	memcpy( pair->strvalue, (char *) &radFil, pair->length );
+    }
+    return(rc);
+}
+
diff -urN radiusd-cistron-1.6-dist/src/pair.c radiusd-cistron-1.6/src/pair.c
--- radiusd-cistron-1.6-dist/src/pair.c	2003-04-03 11:23:17.000000000 -0600
+++ radiusd-cistron-1.6/src/pair.c	2003-06-02 11:04:13.000000000 -0500
@@ -613,6 +613,16 @@
 
 			switch(pair->type) {
 
+			case PW_TYPE_FILTER_BINARY:
+				/*
+				 * special case to convert filter to binary
+				 */
+				if ( filterBinary( pair, valstr ) == -1 ) {
+					free(pair);
+					return(-1);
+				}
+				break;
+
 			case PW_TYPE_STRING:
 				/* Pair->strvalue has been set already */
 				pair->length = strlen(pair->strvalue);
diff -urN radiusd-cistron-1.6-dist/src/radius.c radiusd-cistron-1.6/src/radius.c
--- radiusd-cistron-1.6-dist/src/radius.c	2003-03-11 22:18:59.000000000 -0600
+++ radiusd-cistron-1.6/src/radius.c	2003-06-02 11:04:13.000000000 -0500
@@ -166,6 +166,7 @@
 
 		switch(vp->type) {
 
+		case PW_TYPE_FILTER_BINARY:
 		case PW_TYPE_STRING:
 			/*
 			 *	FIXME: this is just to make sure but
@@ -508,6 +509,7 @@
 
 	switch (pair->type) {
 
+		case PW_TYPE_FILTER_BINARY:
 		case PW_TYPE_STRING:
 			/* attrlen always < AUTH_STRING_LEN */
 			memset(pair->strvalue, 0, AUTH_STRING_LEN);
diff -urN radiusd-cistron-1.6-dist/src/radius.h radiusd-cistron-1.6/src/radius.h
--- radiusd-cistron-1.6-dist/src/radius.h	2003-04-03 11:23:17.000000000 -0600
+++ radiusd-cistron-1.6/src/radius.h	2003-06-02 11:05:33.000000000 -0500
@@ -57,6 +57,7 @@
 #define PW_TYPE_IPADDR			2
 #define PW_TYPE_DATE			3
 #define PW_TYPE_INTEGER8		4
+#define PW_TYPE_FILTER_BINARY		5	/* ASCEND extension */
 
 
 #define	PW_AUTHENTICATION_REQUEST	1
@@ -205,3 +206,193 @@
 #define PW_STATUS_ACCOUNTING_ON		7
 #define PW_STATUS_ACCOUNTING_OFF	8
 
+/*
+ * ASCEND extensions for ABINARY filters
+ */
+
+#define IPX_NODE_ADDR_LEN		6
+
+typedef UINT4			IpxNet;
+typedef char			IpxNode[ IPX_NODE_ADDR_LEN ];
+typedef unsigned short	IpxSocket;
+
+#if ! defined( FALSE )
+# define FALSE		0
+# define TRUE		(! FALSE)
+#endif
+
+/*
+ * Two types of filters are supported, GENERIC and IP.  The identifiers
+ * are:
+ */
+
+#define RAD_FILTER_GENERIC	0
+#define RAD_FILTER_IP		1
+#define RAD_FILTER_IPX		2
+
+/*
+ * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
+ * starting at some offset.  The length is:
+ */
+#define RAD_MAX_FILTER_LEN	6
+
+/*
+ * RadFilterComparison:
+ *
+ * An enumerated values for the IP filter port comparisons.
+ */
+typedef enum {
+	RAD_NO_COMPARE,
+	RAD_COMPARE_LESS,
+	RAD_COMPARE_EQUAL,
+	RAD_COMPARE_GREATER,
+	RAD_COMPARE_NOT_EQUAL
+} RadFilterComparison;
+
+    /*
+     * RadIpFilter:
+     *
+     * The binary format of an IP filter.  ALL fields are stored in
+     * network byte order.
+     *
+     *	srcip:		The source IP address.
+     *
+     *	dstip:		The destination IP address.
+     *
+     *	srcmask:	The number of leading one bits in the source address
+     *			mask.  Specifies the bits of interest.
+     *
+     *	dstmask:	The number of leading one bits in the destination
+     *			address mask. Specifies the bits of interest.
+     *
+     *	proto:		The IP protocol number
+     *
+     *	establised:	A boolean value.  TRUE when we care about the
+     *			established state of a TCP connection.  FALSE when
+     *			we dont care.
+     *
+     *	srcport:	TCP or UDP source port number.
+     *
+     *	dstport:	TCP or UDP destination port number.
+     *
+     *	srcPortCmp:	One of the values of the RadFilterComparison enumeration
+     *			specifying how to compare the srcport value.
+     *
+     *	dstPortCmp:	One of the values of the RadFilterComparison enumeration
+     *			specifying how to compare the dstport value.
+     *
+     *	fill:		Round things out to a dword boundary.
+     */
+typedef struct radip {
+    UINT4  		srcip;
+    UINT4  		dstip;
+    unsigned char 	srcmask;
+    unsigned char 	dstmask;
+    unsigned char	proto;
+    unsigned char	established;
+    unsigned short	srcport;
+    unsigned short	dstport;
+    unsigned char	srcPortComp;
+    unsigned char	dstPortComp;
+    unsigned char       fill[4];        /* used to be fill[2] */
+} RadIpFilter;
+
+    /*
+     * RadIpxFilter:
+     * The binary format of a GENERIC filter.  ALL fields are stored in
+     * network byte order.
+     *
+     *  srcIpxNet:      Source IPX Net address
+     *
+     *  srcIpxNode:     Source IPX Node address
+     *
+     *  srcIpxSoc:      Source IPX socket address
+     *
+     *  dstIpxNet:      Destination IPX Net address
+     *
+     *  dstIpxNode:     Destination IPX Node address
+     *
+     *  dstIpxSoc:      Destination IPX socket address
+     *
+     *  srcSocComp:     Source socket compare value
+     *
+     *  dstSocComp:     Destination socket compare value
+     *
+     */
+typedef struct radipx {                         
+    IpxNet              srcIpxNet;                      /* LongWord */
+    IpxNode             srcIpxNode;                     /* Byte[6] */
+    IpxSocket           srcIpxSoc;                      /* Word */
+    IpxNet              dstIpxNet;                      /* LongWord */
+    IpxNode             dstIpxNode;                     /* Byte[6] */
+    IpxSocket           dstIpxSoc;                      /* Word */
+    unsigned char       srcSocComp;
+    unsigned char       dstSocComp;
+} RadIpxFilter;
+
+    /*
+     * RadGenericFilter:
+     *
+     * The binary format of a GENERIC filter.  ALL fields are stored in
+     * network byte order.
+     *
+     *	offset:		Number of bytes into packet to start comparison.
+     *
+     *	len:		Number of bytes to mask and compare.  May not
+     *			exceed RAD_MAX_FILTER_LEN.
+     *
+     *	more:		Boolean.  If non-zero the next filter entry is
+     *			also to be applied to a packet.
+     *
+     *	mask:		A bit mask specifying the bits to compare.
+     *
+     *	value:		A value to compare against the masked bits at
+     *			offset in a users packet.
+     *			
+     *	compNeq:	Defines type of comarison (Equal or Notequal)
+     *			default is Equal.
+     *
+     *	fill:		Round things out to a dword boundary
+     */
+typedef struct radgeneric {
+    unsigned short	offset;
+    unsigned short	len;
+    unsigned short	more;
+    unsigned char	mask[ RAD_MAX_FILTER_LEN ];
+    unsigned char	value[ RAD_MAX_FILTER_LEN ];
+    unsigned char	compNeq;
+    unsigned char       fill[3];        /* used to be fill */
+} RadGenericFilter;
+
+    /*
+     * RadFilter:
+     *
+     * A binary filter element.  Contains either a RadIpFilter or a
+     * RadGenericFilter.  All fields are stored in network byte order.
+     *
+     *	type:		Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
+     *
+     *	forward:	TRUE if we should forward packets that match this
+     *			filter, FALSE if we should drop packets that match
+     *			this filter.
+     *
+     *	indirection:	TRUE if this is an input filter, FALSE if this is
+     *			an output filter.
+     *
+     *	fill:		Round things out to a dword boundary.
+     *
+     *	u:		A union of
+     *			ip:		An ip filter entry
+     *			generic:	A generic filter entry
+     */
+typedef struct filter {
+    unsigned char 	type;
+    unsigned char	forward;
+    unsigned char	indirection;
+    unsigned char	fill;
+    union {
+	RadIpFilter   	 ip;
+	RadIpxFilter   	 ipx;
+	RadGenericFilter generic;
+    } u;
+} RadFilter;
diff -urN radiusd-cistron-1.6-dist/src/radiusd.h radiusd-cistron-1.6/src/radiusd.h
--- radiusd-cistron-1.6-dist/src/radiusd.h	2003-03-11 22:18:59.000000000 -0600
+++ radiusd-cistron-1.6/src/radiusd.h	2003-06-02 11:04:13.000000000 -0500
@@ -326,6 +326,9 @@
 int		rad_dbm_open(void);
 #endif
 
+/* filters.c */
+int		filterBinary(VALUE_PAIR *pair, char *valstr);
+
 /* version.c */
 void		version();
 
