<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>raddb/attrs.access_challenge</filename>
    </added>
    <added>
      <filename>src/modules/frs_coa/Makefile</filename>
    </added>
    <added>
      <filename>src/modules/frs_coa/frs_coa.c</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -162,6 +162,13 @@ client localhost {
 	#  item, as in the example below.
 	#
 #	virtual_server = home1
+
+	#
+	#  A pointer to the &quot;home_server_pool&quot; OR a &quot;home_server&quot;
+	#  section that contains the CoA configuration for this
+	#  client.  For an example of a coa home server or pool,
+	#  see raddb/sites-available/originate-coa
+#	coa_server = coa
 }
 
 # IPv6 Client</diff>
      <filename>raddb/clients.conf</filename>
    </modified>
    <modified>
      <diff>@@ -39,14 +39,20 @@
 		mod_accounting = radiusd_test
 		func_accounting = accounting
 
-		mod_preproxy = radiusd_test
-		func_preproxy = preproxy
+		mod_pre_proxy = radiusd_test
+		func_pre_proxy = pre_proxy
 
-		mod_postproxy = radiusd_test
-		func_postproxy = postproxy
+		mod_post_proxy = radiusd_test
+		func_post_proxy = post_proxy
 
-		mod_postauth = radiusd_test
-		func_postauth = postauth
+		mod_post_auth = radiusd_test
+		func_post_auth = post_auth
+
+		mod_recv_coa = radiusd_test
+		func_recv_coa = recv_coa
+
+		mod_send_coa = radiusd_test
+		func_send_coa = send_coa
 
 		mod_detach = radiusd_test
 		func_detach = detach</diff>
      <filename>raddb/experimental.conf</filename>
    </modified>
    <modified>
      <diff>@@ -28,6 +28,16 @@ attr_filter attr_filter.access_reject {
 	attrsfile = ${confdir}/attrs.access_reject
 }
 
+# Enforce RFC requirements on the contents of Access-Reject
+# packets.  See the comments at the top of the file for
+# more details.
+#
+attr_filter attr_filter_access_challenge {
+	key = %{User-Name}
+	attrsfile = ${confdir}/attrs.access_challenge
+}
+
+
 #  Enforce RFC requirements on the contents of the
 #  Accounting-Response packets.  See the comments at the
 #  top of the file for more details.</diff>
      <filename>raddb/modules/attr_filter</filename>
    </modified>
    <modified>
      <diff>@@ -42,6 +42,8 @@ perl {
 	#func_pre_proxy = pre_proxy
 	#func_post_proxy = post_proxy
 	#func_post_auth = post_auth
+	#func_recv_coa = recv_coa
+	#func_send_coa = send_coa
 	#func_xlat = xlat
 	#func_detach = detach
 </diff>
      <filename>raddb/modules/perl</filename>
    </modified>
    <modified>
      <diff>@@ -192,6 +192,20 @@ home_server localhost {
 	#
 	############################################################
 
+	#
+	#  You can optionally specify the source IP address used when
+	#  proxying requests to this home server.  When the src_ipaddr
+	#  it set, the server will automatically create a proxy
+	#  listener for that IP address.
+	#
+	#  If you specify this field for one home server, you will
+	#  likely need to specify it for ALL home servers.
+	#
+	#  If you don't care about the source IP address, leave this
+	#  entry commented.
+	#
+#	src_ipaddr = 127.0.0.1
+
 	#  RFC 5080 suggests that all clients SHOULD include it in an
 	#  Access-Request.  The configuration item below tells the
 	#  proxying server (i.e. this one) whether or not the home</diff>
      <filename>raddb/proxy.conf</filename>
    </modified>
    <modified>
      <diff>@@ -247,16 +247,23 @@ listen {
 	#               raddb/sites-available/copy-acct-to-home-server
 	#	status  listen for Status-Server packets.  For examples,
 	#		see raddb/sites-available/status
+	#	coa     listen for CoA-Request and Disconnect-Request
+	#		packets.  For examples, see the file
+	#		raddb/sites-available/coa-server
 	#
 	type = auth
 
 	#  Note: &quot;type = proxy&quot; lets you control the source IP used for
 	#        proxying packets, with some limitations:
 	#
-	#    * Only ONE proxy listener can be defined.
 	#    * A proxy listener CANNOT be used in a virtual server section.
 	#    * You should probably set &quot;port = 0&quot;.
 	#    * Any &quot;clients&quot; configuration will be ignored.
+	#
+	#  See also proxy.conf, and the &quot;src_ipaddr&quot; configuration entry
+	#  in the sample &quot;home_server&quot; section.  When you specify the
+	#  source IP address for packets sent to a home server, the
+	#  proxy listeners are automatically created.
 
 	#  IP address on which to listen.
 	#  Allowed values are:</diff>
      <filename>raddb/radiusd.conf.in</filename>
    </modified>
    <modified>
      <diff>@@ -117,7 +117,7 @@ home_server localhost-coa {
 home_server_pool coa {
 	type = fail-over
 
-	# Point to the CoA server aboce.
+	# Point to the CoA server above.
 	home_server = localhost-coa
 
 	#  CoA requests are run through the pre-proxy section.</diff>
      <filename>raddb/sites-available/originate-coa</filename>
    </modified>
    <modified>
      <diff>@@ -59,7 +59,7 @@ CREATE TABLE radacct (
 CREATE TABLE radcheck (
   id int(11) unsigned NOT NULL auto_increment,
   username varchar(64) NOT NULL default '',
-  attribute varchar(32)  NOT NULL default '',
+  attribute varchar(64)  NOT NULL default '',
   op char(2) NOT NULL DEFAULT '==',
   value varchar(253) NOT NULL default '',
   PRIMARY KEY  (id),
@@ -73,7 +73,7 @@ CREATE TABLE radcheck (
 CREATE TABLE radgroupcheck (
   id int(11) unsigned NOT NULL auto_increment,
   groupname varchar(64) NOT NULL default '',
-  attribute varchar(32)  NOT NULL default '',
+  attribute varchar(64)  NOT NULL default '',
   op char(2) NOT NULL DEFAULT '==',
   value varchar(253)  NOT NULL default '',
   PRIMARY KEY  (id),
@@ -87,7 +87,7 @@ CREATE TABLE radgroupcheck (
 CREATE TABLE radgroupreply (
   id int(11) unsigned NOT NULL auto_increment,
   groupname varchar(64) NOT NULL default '',
-  attribute varchar(32)  NOT NULL default '',
+  attribute varchar(64)  NOT NULL default '',
   op char(2) NOT NULL DEFAULT '=',
   value varchar(253)  NOT NULL default '',
   PRIMARY KEY  (id),
@@ -101,7 +101,7 @@ CREATE TABLE radgroupreply (
 CREATE TABLE radreply (
   id int(11) unsigned NOT NULL auto_increment,
   username varchar(64) NOT NULL default '',
-  attribute varchar(32) NOT NULL default '',
+  attribute varchar(64) NOT NULL default '',
   op char(2) NOT NULL DEFAULT '=',
   value varchar(253) NOT NULL default '',
   PRIMARY KEY  (id),</diff>
      <filename>raddb/sql/mysql/schema.sql</filename>
    </modified>
    <modified>
      <diff>@@ -61,7 +61,7 @@ CREATE OR REPLACE TRIGGER radacct_serialnumber
 CREATE TABLE radcheck (
 	id 		INT PRIMARY KEY,
 	username	VARCHAR(30) NOT NULL,
-	attribute	VARCHAR(30),
+	attribute	VARCHAR(64),
 	op		VARCHAR(2) NOT NULL,
 	value		VARCHAR(40)
 );
@@ -84,7 +84,7 @@ CREATE OR REPLACE TRIGGER radcheck_serialnumber
 CREATE TABLE radgroupcheck (
 	id 		INT PRIMARY KEY,
 	groupname	VARCHAR(20) UNIQUE NOT NULL,
-	attribute	VARCHAR(40),
+	attribute	VARCHAR(64),
 	op		CHAR(2) NOT NULL,
 	value		VARCHAR(40)
 );
@@ -96,7 +96,7 @@ CREATE SEQUENCE radgroupcheck_seq START WITH 1 INCREMENT BY 1;
 CREATE TABLE radgroupreply (
 	id		INT PRIMARY KEY,
 	GroupName	VARCHAR(20) UNIQUE NOT NULL,
-	Attribute	VARCHAR(40),
+	Attribute	VARCHAR(64),
 	op		CHAR(2) NOT NULL,
 	Value		VARCHAR(40)
 );
@@ -108,7 +108,7 @@ CREATE SEQUENCE radgroupreply_seq START WITH 1 INCREMENT BY 1;
 CREATE TABLE radreply (
 	id		INT PRIMARY KEY,
 	UserName	VARCHAR(30) NOT NULL,
-	Attribute	VARCHAR(30),
+	Attribute	VARCHAR(64),
 	op		CHAR(2) NOT NULL,
 	Value		VARCHAR(40)
 );</diff>
      <filename>raddb/sql/oracle/schema.sql</filename>
    </modified>
    <modified>
      <diff>@@ -176,5 +176,5 @@ CREATE TABLE radpostauth (
 	reply			VARCHAR(32),
 	CalledStationId		VARCHAR(50),
 	CallingStationId	VARCHAR(50),
-	authdate		TIMESTAMP with time zone NOT NULL default 'now'
+	authdate		TIMESTAMP with time zone NOT NULL default 'now()'
 );</diff>
      <filename>raddb/sql/postgresql/schema.sql</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,9 @@ sqlippool {
 
  #########################################
  ## SQL instance to use (from sql.conf) ##
+ ##
+ ##  If you have multiple sql instances, such as &quot;sql sql1 {...}&quot;,
+ ##  use the *instance* name here: sql1.
  #########################################
  sql-instance-name = &quot;sql&quot;
 
@@ -27,20 +30,24 @@ sqlippool {
  # pool-key = &quot;%{Calling-Station-Id}&quot;
 
  ################################################################
- ## Uncomment the appropriate config file for your SQL dialect ##
  #
  #  WARNING: MySQL has certain limitations that means it can
  #           hand out the same IP address to 2 different users.
  #
  #           We suggest using an SQL DB with proper transaction
- #           support, such as PostgreSQL.
+ #           support, such as PostgreSQL, or using MySQL
+ #	     with InnoDB.
  #
  ################################################################
 
- # $INCLUDE sql/mysql/ippool.conf
- $INCLUDE sql/postgresql/ippool.conf
-
-
+ #
+ #  Use the same database as configured in the &quot;sql&quot; module, &quot;database&quot;
+ #  configuration item.  Change the &quot;postgresql&quot; name below to be the
+ #  same as the &quot;database&quot; field of the SQL module referred to in the
+ #  &quot;sql-instance-name&quot;, above.
+ #
+$INCLUDE sql/postgresql/ippool.conf
+ 
  ## Logging configuration. (Comment out to disable logging)
  sqlippool_log_exists = &quot;Existing IP: %{reply:Framed-IP-Address} \
   (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})&quot;</diff>
      <filename>raddb/sqlippool.conf</filename>
    </modified>
    <modified>
      <diff>@@ -207,6 +207,12 @@ ATTRIBUTE	EAP-MSK					1129	octets
 ATTRIBUTE	EAP-EMSK				1130	octets
 
 #
+#	For send/recv CoA packets (like Auth-Type, Acct-Type, etc.)
+#
+ATTRIBUTE	Recv-CoA-Type				1131	integer
+ATTRIBUTE	Send-CoA-Type				1132	integer
+
+#
 #	Range:	1200-1279
 #		EAP-SIM (and other EAP type) weirdness.
 #</diff>
      <filename>share/dictionary.freeradius.internal</filename>
    </modified>
    <modified>
      <diff>@@ -24,7 +24,11 @@ enum {
   RLM_COMPONENT_PRE_PROXY,	/* 5 */
   RLM_COMPONENT_POST_PROXY,	/* 6 */
   RLM_COMPONENT_POST_AUTH,	/* 7 */
-  RLM_COMPONENT_COUNT		/* 8: How many components are there */
+#ifdef WITH_COA
+  RLM_COMPONENT_RECV_COA,	/* 8 */
+  RLM_COMPONENT_SEND_COA,	/* 9 */
+#endif
+  RLM_COMPONENT_COUNT		/* 8 / 10: How many components are there */
 };
 
 #define RLM_TYPE_THREAD_SAFE		(0 &lt;&lt; 0)
@@ -68,6 +72,13 @@ int module_checksimul(int type, REQUEST *request, int maxsimul);
 int module_pre_proxy(int type, REQUEST *request);
 int module_post_proxy(int type, REQUEST *request);
 int module_post_auth(int type, REQUEST *request);
+#ifdef WITH_COA
+int module_recv_coa(int type, REQUEST *request);
+int module_send_coa(int type, REQUEST *request);
+#define MODULE_NULL_COA_FUNCS ,NULL,NULL
+#else
+#define MODULE_NULL_COA_FUNCS
+#endif
 int indexed_modcall(int comp, int idx, REQUEST *request);
 
 /*</diff>
      <filename>src/include/modules.h</filename>
    </modified>
    <modified>
      <diff>@@ -225,6 +225,8 @@
 #define PW_MODULE_RETURN_CODE		1108
 #define PW_PACKET_ORIGINAL_TIMESTAMP   	1109
 #define PW_HOME_SERVER_POOL		1111
+#define PW_RECV_COA_TYPE   		1131
+#define PW_SEND_COA_TYPE   		1132
 
 /*
  *	Integer Translations</diff>
      <filename>src/include/radius.h</filename>
    </modified>
    <modified>
      <diff>@@ -544,7 +544,7 @@ void fr_suid_down_permanent(void);
 /* listen.c */
 void listen_free(rad_listen_t **head);
 int listen_init(CONF_SECTION *cs, rad_listen_t **head);
-rad_listen_t *proxy_new_listener(void);
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists);
 RADCLIENT *client_listener_find(const rad_listen_t *listener,
 				const fr_ipaddr_t *ipaddr, int src_port);
 rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port);</diff>
      <filename>src/include/radiusd.h</filename>
    </modified>
    <modified>
      <diff>@@ -77,6 +77,8 @@ typedef struct home_server {
 #ifdef WITH_STATS
 	int		number;
 
+	fr_ipaddr_t	src_ipaddr; /* preferred source IP address */
+
 	fr_stats_t	stats;
 
 	fr_stats_ema_t  ema;
@@ -139,6 +141,7 @@ REALM *realm_find2(const char *name); /* ... with name taken from realm_find */
 fr_realm_status_t realm_status(const char *name, int flag);
 home_server *home_server_ldb(const char *realmname, home_pool_t *pool, REQUEST *request);
 home_server *home_server_find(fr_ipaddr_t *ipaddr, int port);
+int	home_server_create_listeners(void *head);
 #ifdef WITH_COA
 home_server *home_server_byname(const char *name);
 #endif</diff>
      <filename>src/include/realms.h</filename>
    </modified>
    <modified>
      <diff>@@ -47,6 +47,9 @@ typedef enum RAD_LISTEN_TYPE {
 #ifdef WITH_COMMAND_SOCKET
 	RAD_LISTEN_COMMAND,
 #endif
+#ifdef WITH_COA
+	RAD_LISTEN_COA,
+#endif
 	RAD_LISTEN_MAX
 } RAD_LISTEN_TYPE;
 </diff>
      <filename>src/include/smodule.h</filename>
    </modified>
    <modified>
      <diff>@@ -607,7 +607,7 @@ int fr_packet_list_num_elements(fr_packet_list_t *pl)
 int fr_packet_list_id_alloc(fr_packet_list_t *pl,
 			      RADIUS_PACKET *request)
 {
-	int i, id, start;
+	int i, id, start, fd;
 	uint32_t free_mask;
 	fr_packet_dst2id_t my_pd, *pd;
 	fr_packet_socket_t *ps;
@@ -647,6 +647,7 @@ int fr_packet_list_id_alloc(fr_packet_list_t *pl,
 	id = start = (int) fr_rand() &amp; 0xff;
 
 	while (pd-&gt;id[id] == pl-&gt;mask) { /* all sockets are using this ID */
+	redo:
 		id++;
 		id &amp;= 0xff;
 		if (id == start) return 0;
@@ -654,20 +655,48 @@ int fr_packet_list_id_alloc(fr_packet_list_t *pl,
 
 	free_mask = ~((~pd-&gt;id[id]) &amp; pl-&gt;mask);
 
-	start = -1;
+	/*
+	 *	This ID has at least one socket free.  Check the sockets
+	 *	to see if they are satisfactory for the caller.
+	 */
+	fd = -1;
 	for (i = 0; i &lt; MAX_SOCKETS; i++) {
 		if (pl-&gt;sockets[i].sockfd == -1) continue; /* paranoia */
 
-		if ((free_mask &amp; (1 &lt;&lt; i)) == 0) {
-			start = i;
-			break;
-		}
+		/*
+		 *	This ID is allocated.
+		 */
+		if ((free_mask &amp; (1 &lt;&lt; i)) != 0) continue;
+		
+		/*
+		 *	If the caller cares about the source address,
+		 *	try to re-use that.  This means that the
+		 *	requested source address is set, AND this
+		 *	socket wasn't bound to &quot;*&quot;, AND the requested
+		 *	source address is the same as this socket
+		 *	address.
+		 */
+		if ((request-&gt;src_ipaddr.af != AF_UNSPEC) &amp;&amp;
+		    !pl-&gt;sockets[i].inaddr_any &amp;&amp;
+		    (fr_ipaddr_cmp(&amp;request-&gt;src_ipaddr, &amp;pl-&gt;sockets[i].ipaddr) != 0)) continue;
+
+		/*
+		 *	They asked for a specific address, and this socket
+		 *	is bound to a wildcard address.  Ignore this one, too.
+		 */
+		if ((request-&gt;src_ipaddr.af != AF_UNSPEC) &amp;&amp;
+		    pl-&gt;sockets[i].inaddr_any) continue;
+		
+		fd = i;
+		break;
 	}
 
-	if (start &lt; 0) return 0; /* bad error */
+	if (fd &lt; 0) {
+		goto redo; /* keep searching IDs */
+	}
 
-	pd-&gt;id[id] |= (1 &lt;&lt; start);
-	ps = &amp;pl-&gt;sockets[start];
+	pd-&gt;id[id] |= (1 &lt;&lt; fd);
+	ps = &amp;pl-&gt;sockets[fd];
 
 	ps-&gt;num_outgoing++;
 	pl-&gt;num_outgoing++;</diff>
      <filename>src/lib/packet.c</filename>
    </modified>
    <modified>
      <diff>@@ -438,10 +438,15 @@ static void make_passwd(uint8_t *output, int *outlen,
 	 *	If the length is zero, round it up.
 	 */
 	len = inlen;
+
+	if (len &gt; MAX_PASS_LEN) len = MAX_PASS_LEN;
+
+	memcpy(passwd, input, len);
+	memset(passwd + len, 0, sizeof(passwd) - len);
+
 	if (len == 0) {
 		len = AUTH_PASS_LEN;
 	}
-	else if (len &gt; MAX_PASS_LEN) len = MAX_PASS_LEN;
 
 	else if ((len &amp; 0x0f) != 0) {
 		len += 0x0f;
@@ -449,9 +454,6 @@ static void make_passwd(uint8_t *output, int *outlen,
 	}
 	*outlen = len;
 
-	memcpy(passwd, input, len);
-	memset(passwd + len, 0, sizeof(passwd) - len);
-
 	fr_MD5Init(&amp;context);
 	fr_MD5Update(&amp;context, (const uint8_t *) secret, strlen(secret));
 	old = context;
@@ -1818,6 +1820,7 @@ int rad_packet_ok(RADIUS_PACKET *packet, int flags)
  */
 RADIUS_PACKET *rad_recv(int fd, int flags)
 {
+	int sock_flags = 0;
 	RADIUS_PACKET		*packet;
 
 	/*
@@ -1829,7 +1832,12 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
 	}
 	memset(packet, 0, sizeof(*packet));
 
-	packet-&gt;data_len = rad_recvfrom(fd, &amp;packet-&gt;data, 0,
+	if (flags &amp; 0x02) {
+		sock_flags = MSG_PEEK;
+		flags &amp;= ~0x02;
+	}
+
+	packet-&gt;data_len = rad_recvfrom(fd, &amp;packet-&gt;data, sock_flags,
 					&amp;packet-&gt;src_ipaddr, &amp;packet-&gt;src_port,
 					&amp;packet-&gt;dst_ipaddr, &amp;packet-&gt;dst_port);
 </diff>
      <filename>src/lib/radius.c</filename>
    </modified>
    <modified>
      <diff>@@ -587,6 +587,8 @@ static int WalkNodePostOrder(rbnode_t *X,
 int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
 		int (*callback)(void *, void *), void *context)
 {
+	if (tree-&gt;Root == NIL) return 0;
+
 	switch (order) {
 	case PreOrder:
 		return WalkNodePreOrder(tree-&gt;Root, callback, context);</diff>
      <filename>src/lib/rbtree.c</filename>
    </modified>
    <modified>
      <diff>@@ -282,7 +282,7 @@ static int proxy_id_alloc(REQUEST *request, RADIUS_PACKET *packet)
 	 *	it to the tail of the list of listeners.  With
 	 *	some care, this can be thread-safe.
 	 */
-	proxy_listener = proxy_new_listener();
+	proxy_listener = proxy_new_listener(&amp;packet-&gt;src_ipaddr, FALSE);
 	if (!proxy_listener) {
 		RDEBUG2(&quot;ERROR: Failed to create a new socket for proxying requests.&quot;);
 		return 0;
@@ -429,8 +429,9 @@ static void wait_for_proxy_id_to_expire(void *ctx)
 	request-&gt;when = request-&gt;proxy_when;
 
 #ifdef WITH_COA
-	if ((request-&gt;proxy-&gt;code == PW_COA_REQUEST) ||
-	    (request-&gt;proxy-&gt;code == PW_DISCONNECT_REQUEST)) {
+	if (((request-&gt;proxy-&gt;code == PW_COA_REQUEST) ||
+	     (request-&gt;proxy-&gt;code == PW_DISCONNECT_REQUEST)) &amp;&amp;
+	    (request-&gt;packet-&gt;code != request-&gt;proxy-&gt;code)) {
 		request-&gt;when.tv_sec += request-&gt;home_server-&gt;coa_mrd;
 	} else
 #endif
@@ -757,8 +758,8 @@ static void ping_home_server(void *ctx)
 	REQUEST *request;
 	VALUE_PAIR *vp;
 
-	if (home-&gt;state == HOME_STATE_ALIVE) {
-		radlog(L_INFO, &quot;Suspicious proxy state... continuing&quot;);
+	if ((home-&gt;state == HOME_STATE_ALIVE) ||
+	    (home-&gt;ping_check == HOME_PING_CHECK_NONE)) {
 		return;
 	}
 
@@ -1987,13 +1988,50 @@ static int successfully_proxied_request(REQUEST *request)
 	 *
 	 *	FIXME: This should really be a serious error.
 	 */
-	if (request-&gt;in_proxy_hash) {
+	if (request-&gt;in_proxy_hash ||
+	    (request-&gt;proxy_reply &amp;&amp; (request-&gt;proxy_reply-&gt;code != 0))) {
 		return 0;
 	}
 
 	realmpair = pairfind(request-&gt;config_items, PW_PROXY_TO_REALM);
 	if (!realmpair || (realmpair-&gt;length == 0)) {
-		return 0;
+		int pool_type;
+
+		vp = pairfind(request-&gt;config_items, PW_HOME_SERVER_POOL);
+		if (!vp) return 0;
+
+		switch (request-&gt;packet-&gt;code) {
+		case PW_AUTHENTICATION_REQUEST:
+			pool_type = HOME_TYPE_AUTH;
+			break;
+
+#ifdef WITH_ACCOUNTING
+		case PW_ACCOUNTING_REQUEST:
+			pool_type = HOME_TYPE_ACCT;
+			break;
+#endif
+
+#ifdef WITH_COA
+		case PW_COA_REQUEST:
+		case PW_DISCONNECT_REQUEST:
+			pool_type = HOME_TYPE_COA;
+			break;
+#endif
+
+		default:
+			return 0;
+		}
+
+		pool = home_pool_byname(vp-&gt;vp_strvalue, pool_type);
+		if (!pool) {
+			RDEBUG2(&quot;ERROR: Cannot proxy to unknown pool %s&quot;,
+				vp-&gt;vp_strvalue);
+			return 0;
+		}
+
+		realmname = NULL; /* no realms */
+		realm = NULL;
+		goto found_pool;
 	}
 
 	realmname = (char *) realmpair-&gt;vp_strvalue;
@@ -2015,6 +2053,12 @@ static int successfully_proxied_request(REQUEST *request)
 		pool = realm-&gt;acct_pool;
 #endif
 
+#ifdef WITH_COA
+	} else if ((request-&gt;packet-&gt;code == PW_COA_REQUEST) ||
+		   (request-&gt;packet-&gt;code == PW_DISCONNECT_REQUEST)) {
+		pool = realm-&gt;acct_pool;
+#endif
+
 	} else {
 		rad_panic(&quot;Internal sanity check failed&quot;);
 	}
@@ -2025,6 +2069,7 @@ static int successfully_proxied_request(REQUEST *request)
 		return 0;
 	}
 
+found_pool:
 	home = home_server_ldb(realmname, pool, request);
 	if (!home) {
 		RDEBUG2(&quot;ERROR: Failed to find live home server for realm %s&quot;,
@@ -2043,8 +2088,8 @@ static int successfully_proxied_request(REQUEST *request)
 	/*
 	 *	Remember that we sent the request to a Realm.
 	 */
-	pairadd(&amp;request-&gt;packet-&gt;vps,
-		pairmake(&quot;Realm&quot;, realmname, T_OP_EQ));
+	if (realmname) pairadd(&amp;request-&gt;packet-&gt;vps,
+			       pairmake(&quot;Realm&quot;, realmname, T_OP_EQ));
 
 	/*
 	 *	Strip the name, if told to.
@@ -2052,7 +2097,7 @@ static int successfully_proxied_request(REQUEST *request)
 	 *	Doing it here catches the case of proxied tunneled
 	 *	requests.
 	 */
-	if (realm-&gt;striprealm == TRUE &amp;&amp;
+	if (realm &amp;&amp; (realm-&gt;striprealm == TRUE) &amp;&amp;
 	   (strippedname = pairfind(request-&gt;proxy-&gt;vps, PW_STRIPPED_USER_NAME)) != NULL) {
 		/*
 		 *	If there's a Stripped-User-Name attribute in
@@ -2091,7 +2136,8 @@ static int successfully_proxied_request(REQUEST *request)
 	 *	since we can't use the request authenticator
 	 *	anymore - we changed it.
 	 */
-	if (pairfind(request-&gt;proxy-&gt;vps, PW_CHAP_PASSWORD) &amp;&amp;
+	if ((request-&gt;packet-&gt;code == PW_AUTHENTICATION_REQUEST) &amp;&amp;
+	    pairfind(request-&gt;proxy-&gt;vps, PW_CHAP_PASSWORD) &amp;&amp;
 	    pairfind(request-&gt;proxy-&gt;vps, PW_CHAP_CHALLENGE) == NULL) {
 		vp = radius_paircreate(request, &amp;request-&gt;proxy-&gt;vps,
 				       PW_CHAP_CHALLENGE, PW_TYPE_OCTETS);
@@ -2350,6 +2396,10 @@ static void request_post_handler(REQUEST *request)
 			}
 		}
 
+#ifdef WITH_COA
+	case PW_COA_REQUEST:
+	case PW_DISCONNECT_REQUEST:
+#endif
 		request-&gt;next_when.tv_sec += request-&gt;root-&gt;cleanup_delay;
 		request-&gt;next_callback = cleanup_delay;
 		child_state = REQUEST_CLEANUP_DELAY;
@@ -2953,6 +3003,11 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet)
 	 *	Having it here means that late or duplicate proxy
 	 *	replies no longer get the home server marked as
 	 *	&quot;alive&quot;.  This might be good for stability, though.
+	 *
+	 *	FIXME: Do we really want to do this whenever we
+	 *	receive a packet?  Setting this here means that we
+	 *	mark it alive on *any* packet, even if it's lost all
+	 *	of the *other* packets in the last 10s.
 	 */
 	request-&gt;home_server-&gt;state = HOME_STATE_ALIVE;
 	
@@ -3399,6 +3454,8 @@ int radius_event_init(CONF_SECTION *cs, int spawn_flag)
 
 #ifdef WITH_PROXY
 	if (mainconfig.proxy_requests) {
+		pthread_mutexattr_t attr;
+
 		/*
 		 *	Create the tree for managing proxied requests and
 		 *	responses.
@@ -3407,11 +3464,23 @@ int radius_event_init(CONF_SECTION *cs, int spawn_flag)
 		if (!proxy_list) return 0;
 
 #ifdef HAVE_PTHREAD_H
+		pthread_mutexattr_init(&amp;attr);
+
+#ifdef PTHREAD_MUTEX_RECURSIVE
+		if (pthread_mutexattr_settype(&amp;attr, PTHREAD_MUTEX_RECURSIVE) &lt; 0) {
+			radlog(L_ERR, &quot;FATAL: Failed to set type for proxy mutex: %s&quot;,
+			       strerror(errno));
+			exit(1);
+		}
+#endif
+
 		if (pthread_mutex_init(&amp;proxy_mutex, NULL) != 0) {
 			radlog(L_ERR, &quot;FATAL: Failed to initialize proxy mutex: %s&quot;,
 			       strerror(errno));
 			exit(1);
 		}
+
+		pthread_mutexattr_destroy(&amp;attr);
 #endif
 	}
 #endif</diff>
      <filename>src/main/event.c</filename>
    </modified>
    <modified>
      <diff>@@ -174,12 +174,12 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener,
 
 	request-&gt;listener = listener;
 	request-&gt;client = client;
-	request-&gt;packet = rad_alloc(0);
-	if (!request-&gt;packet) {
+	request-&gt;packet = rad_recv(listener-&gt;fd, 0x02); /* MSG_PEEK */
+	if (!request-&gt;packet) {				/* badly formed, etc */
 		request_free(&amp;request);
 		goto unknown;
 	}
-	request-&gt;reply = rad_alloc(0);
+	request-&gt;reply = rad_alloc_reply(request-&gt;packet);
 	if (!request-&gt;reply) {
 		request_free(&amp;request);
 		goto unknown;
@@ -198,23 +198,6 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener,
 	 *
 	 *	and create the RADCLIENT structure from that.
 	 */
-
-	sock = listener-&gt;data;
-	request-&gt;packet-&gt;sockfd = listener-&gt;fd;
-	request-&gt;packet-&gt;src_ipaddr = *ipaddr;
-	request-&gt;packet-&gt;src_port = 0; /* who cares... */
-	request-&gt;packet-&gt;dst_ipaddr = sock-&gt;ipaddr;
-	request-&gt;packet-&gt;dst_port = sock-&gt;port;
-
-	request-&gt;reply-&gt;sockfd = request-&gt;packet-&gt;sockfd;
-	request-&gt;reply-&gt;dst_ipaddr = request-&gt;packet-&gt;src_ipaddr;
-	request-&gt;reply-&gt;src_ipaddr = request-&gt;packet-&gt;dst_ipaddr;
-	request-&gt;reply-&gt;dst_port = request-&gt;packet-&gt;src_port;
-	request-&gt;reply-&gt;src_port = request-&gt;packet-&gt;dst_port;
-	request-&gt;reply-&gt;id = request-&gt;packet-&gt;id;
-	request-&gt;reply-&gt;code = 0; /* UNKNOWN code */
-
-	
 	DEBUG(&quot;server %s {&quot;, request-&gt;server);
 
 	rcode = module_authorize(0, request);
@@ -497,6 +480,11 @@ static int listen_bind(rad_listen_t *this)
 			break;
 #endif
 
+#ifdef WITH_COA
+		case RAD_LISTEN_COA:
+			sock-&gt;port = PW_COA_UDP_PORT;
+			break;
+#endif
 		default:
 			radlog(L_ERR, &quot;ERROR: Non-fatal internal sanity check failed in bind.&quot;);
 			return -1;
@@ -578,9 +566,12 @@ static int listen_bind(rad_listen_t *this)
 	rcode = bind(this-&gt;fd, (struct sockaddr *) &amp;salocal, salen);
 	fr_suid_down();
 	if (rcode &lt; 0) {
+		char buffer[256];
 		close(this-&gt;fd);
-		radlog(L_ERR, &quot;Failed binding to socket: %s\n&quot;,
-		       strerror(errno));
+		
+		this-&gt;print(this, buffer, sizeof(buffer));
+		radlog(L_ERR, &quot;Failed binding to %s: %s\n&quot;,
+		       buffer, strerror(errno));
 		return -1;
 	}
 	
@@ -721,6 +712,9 @@ rad_listen_t *listen_alloc(const char *type_name)
 #ifdef WITH_DHCP
 	case RAD_LISTEN_DHCP:
 #endif
+#ifdef WITH_COA
+	case RAD_LISTEN_COA:
+#endif
 		this-&gt;data = rad_malloc(sizeof(listen_socket_t));
 		memset(this-&gt;data, 0, sizeof(listen_socket_t));
 		break;
@@ -752,67 +746,91 @@ rad_listen_t *listen_alloc(const char *type_name)
 /*
  *	Externally visible function for creating a new proxy LISTENER.
  *
- *	For now, don't take ipaddr or port.
- *
  *	Not thread-safe, but all calls to it are protected by the
- *	proxy mutex in request_list.c
+ *	proxy mutex in event.c
  */
-rad_listen_t *proxy_new_listener()
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists)
 {
 	int last_proxy_port, port;
 	rad_listen_t *this, *tmp, **last;
 	listen_socket_t *sock, *old;
 
-	this = listen_alloc(&quot;proxy&quot;);
-	if (!this) return NULL;
-
 	/*
 	 *	Find an existing proxy socket to copy.
-	 *
-	 *	FIXME: Make it per-realm, or per-home server!
 	 */
 	last_proxy_port = 0;
 	old = NULL;
 	last = &amp;mainconfig.listen;
 	for (tmp = mainconfig.listen; tmp != NULL; tmp = tmp-&gt;next) {
-		if (tmp-&gt;type == RAD_LISTEN_PROXY) {
-			sock = tmp-&gt;data;
-			if (sock-&gt;port &gt; last_proxy_port) {
-				last_proxy_port = sock-&gt;port + 1;
-			}
-			if (!old) old = sock;
+		/*
+		 *	Not proxy, ignore it.
+		 */
+		if (tmp-&gt;type != RAD_LISTEN_PROXY) continue;
+
+		sock = tmp-&gt;data;
+
+		/*
+		 *	If we were asked to copy a specific one, do
+		 *	so.  If we're just finding one that already
+		 *	exists, return a pointer to it.  Otherwise,
+		 *	create ANOTHER one with the same IP address.
+		 */
+		if ((ipaddr-&gt;af != AF_UNSPEC) &amp;&amp;
+		    (fr_ipaddr_cmp(&amp;sock-&gt;ipaddr, ipaddr) != 0)) {
+			if (exists) return tmp;
+			continue;
+		}
+		
+		if (sock-&gt;port &gt; last_proxy_port) {
+			last_proxy_port = sock-&gt;port + 1;
 		}
+		if (!old) old = sock;
 
 		last = &amp;(tmp-&gt;next);
 	}
 
 	if (!old) {
-		listen_free(&amp;this);
-		return NULL;	/* This is a serious error. */
-	}
+		/*
+		 *	The socket MUST already exist if we're binding
+		 *	to an address while proxying.
+		 *
+		 *	If we're initializing the server, it's OK for the
+		 *	socket to NOT exist.
+		 */
+		if (!exists) return NULL;
 
-	/*
-	 *	FIXME: find a new IP address to listen on?
-	 *
-	 *	This could likely be done in the &quot;home server&quot;
-	 *	configuration, to have per-home-server source IP's.
-	 */
-	sock = this-&gt;data;
-	memcpy(&amp;sock-&gt;ipaddr, &amp;old-&gt;ipaddr, sizeof(sock-&gt;ipaddr));
+		this = listen_alloc(RAD_LISTEN_PROXY);
+
+		sock = this-&gt;data;
+		sock-&gt;ipaddr = *ipaddr;
+
+	} else {
+		this = listen_alloc(RAD_LISTEN_PROXY);
+		
+		sock = this-&gt;data;
+		sock-&gt;ipaddr = old-&gt;ipaddr;
+	}
 
 	/*
 	 *	Keep going until we find an unused port.
 	 */
 	for (port = last_proxy_port; port &lt; 64000; port++) {
+		int rcode;
+
 		sock-&gt;port = port;
-		if (listen_bind(this) == 0) {
-			/*
-			 *	Add the new listener to the list of
-			 *	listeners.
-			 */
-			*last = this;
-			return this;
+
+		rcode = listen_bind(this);
+		if (rcode &lt; 0) {
+			listen_free(&amp;this);
+			return NULL;
 		}
+		
+		/*
+		 *	Add the new listener to the list of
+		 *	listeners.
+		 */
+		*last = this;
+		return this;
 	}
 
 	listen_free(&amp;this);
@@ -1142,7 +1160,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head)
 		 */
 		if (!*head) return -1;
 
-		if (defined_proxy) goto done;
+		if (defined_proxy) goto check_home_servers;
 
 		/*
 		 *	Find the first authentication port,
@@ -1207,9 +1225,14 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head)
 			radlog(L_ERR, &quot;Failed to open socket for proxying&quot;);
 			return -1;
 		}
+		
+		/*
+		 *	Create *additional* proxy listeners, based
+		 *	on their src_ipaddr.
+		 */
+	check_home_servers:
+		if (home_server_create_listeners(*head) != 0) return -1;
 	}
-
- done:			/* used only in proxy code. */
 #endif
 
 	return 0;</diff>
      <filename>src/main/listen.c</filename>
    </modified>
    <modified>
      <diff>@@ -899,7 +899,6 @@ int read_mainconfig(int reload)
 
 	/*  Reload the modules.  */
 	if (setup_modules(reload, mainconfig.config) &lt; 0) {
-		radlog(L_ERR, &quot;Errors initializing modules&quot;);
 		return -1;
 	}
 
@@ -967,6 +966,15 @@ void hup_mainconfig(void)
 	cc = rad_malloc(sizeof(*cc));
 	memset(cc, 0, sizeof(*cc));
 
+	/*
+	 *	Save the current configuration.  Note that we do NOT
+	 *	free older ones.  We should probably do so at some
+	 *	point.  Doing so will require us to mark which modules
+	 *	are still in use, and which aren't.  Modules that
+	 *	can't be HUPed always use the original configuration.
+	 *	Modules that can be HUPed use one of the newer
+	 *	configurations.
+	 */
 	cc-&gt;created = time(NULL);
 	cc-&gt;cs = cs;
 	cc-&gt;next = cs_cache;
@@ -982,5 +990,5 @@ void hup_mainconfig(void)
 	 */
 	virtual_servers_load(cs);
 
-	virtual_servers_free(cc-&gt;created - 120);
+	virtual_servers_free(cc-&gt;created - mainconfig.max_request_time * 4);
 }</diff>
      <filename>src/main/mainconfig.c</filename>
    </modified>
    <modified>
      <diff>@@ -304,7 +304,12 @@ static int default_component_results[RLM_COMPONENT_COUNT] = {
 	RLM_MODULE_FAIL,	/* SESS */
 	RLM_MODULE_NOOP,	/* PRE_PROXY */
 	RLM_MODULE_NOOP,	/* POST_PROXY */
-	RLM_MODULE_NOOP		/* POST_AUTH */
+	RLM_MODULE_NOOP       	/* POST_AUTH */
+#ifdef WITH_COA
+	,
+	RLM_MODULE_NOOP,       	/* RECV_COA_TYPE */
+	RLM_MODULE_NOOP		/* SEND_COA_TYPE */
+#endif
 };
 
 
@@ -1179,6 +1184,87 @@ defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
 			MOD_ACTION_RETURN	/* updated  */
 		}
 	}
+#ifdef WITH_COA
+	,
+	/* recv-coa */
+	{
+		/* group */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			MOD_ACTION_RETURN,	/* fail     */
+			3,			/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			1,			/* notfound */
+			2,			/* noop     */
+			4			/* updated  */
+		},
+		/* redundant */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			1,			/* fail     */
+			MOD_ACTION_RETURN,	/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			MOD_ACTION_RETURN,	/* notfound */
+			MOD_ACTION_RETURN,	/* noop     */
+			MOD_ACTION_RETURN	/* updated  */
+		},
+		/* append */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			1,			/* fail     */
+			MOD_ACTION_RETURN,	/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			2,			/* notfound */
+			MOD_ACTION_RETURN,	/* noop     */
+			MOD_ACTION_RETURN	/* updated  */
+		}
+	},
+	/* send-coa */
+	{
+		/* group */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			MOD_ACTION_RETURN,	/* fail     */
+			3,			/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			1,			/* notfound */
+			2,			/* noop     */
+			4			/* updated  */
+		},
+		/* redundant */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			1,			/* fail     */
+			MOD_ACTION_RETURN,	/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			MOD_ACTION_RETURN,	/* notfound */
+			MOD_ACTION_RETURN,	/* noop     */
+			MOD_ACTION_RETURN	/* updated  */
+		},
+		/* append */
+		{
+			MOD_ACTION_RETURN,	/* reject   */
+			1,			/* fail     */
+			MOD_ACTION_RETURN,	/* ok       */
+			MOD_ACTION_RETURN,	/* handled  */
+			MOD_ACTION_RETURN,	/* invalid  */
+			MOD_ACTION_RETURN,	/* userlock */
+			2,			/* notfound */
+			MOD_ACTION_RETURN,	/* noop     */
+			MOD_ACTION_RETURN	/* updated  */
+		}
+	}
+#endif
 };
 
 </diff>
      <filename>src/main/modcall.c</filename>
    </modified>
    <modified>
      <diff>@@ -84,7 +84,12 @@ static const section_type_value_t section_type_value[RLM_COMPONENT_COUNT] = {
 	{ &quot;session&quot;,      &quot;Session-Type&quot;,    PW_SESSION_TYPE },
 	{ &quot;pre-proxy&quot;,    &quot;Pre-Proxy-Type&quot;,  PW_PRE_PROXY_TYPE },
 	{ &quot;post-proxy&quot;,   &quot;Post-Proxy-Type&quot;, PW_POST_PROXY_TYPE },
-	{ &quot;post-auth&quot;,    &quot;Post-Auth-Type&quot;,  PW_POST_AUTH_TYPE },
+	{ &quot;post-auth&quot;,    &quot;Post-Auth-Type&quot;,  PW_POST_AUTH_TYPE }
+#ifdef WITH_COA
+	,
+	{ &quot;recv-coa&quot;,     &quot;Recv-CoA-Type&quot;,   PW_RECV_COA_TYPE },
+	{ &quot;send-coa&quot;,     &quot;Send-CoA-Type&quot;,   PW_SEND_COA_TYPE }
+#endif
 };
 
 
@@ -1451,3 +1456,15 @@ int module_post_auth(int postauth_type, REQUEST *request)
 {
 	return indexed_modcall(RLM_COMPONENT_POST_AUTH, postauth_type, request);
 }
+
+#ifdef WITH_COA
+int module_recv_coa(int recv_coa_type, REQUEST *request)
+{
+	return indexed_modcall(RLM_COMPONENT_RECV_COA, recv_coa_type, request);
+}
+
+int module_send_coa(int send_coa_type, REQUEST *request)
+{
+	return indexed_modcall(RLM_COMPONENT_SEND_COA, send_coa_type, request);
+}
+#endif</diff>
      <filename>src/main/modules.c</filename>
    </modified>
    <modified>
      <diff>@@ -490,6 +490,7 @@ static int send_one_packet(radclient_t *radclient)
 		 *	this packet.
 		 */
 	retry:
+		radclient-&gt;request-&gt;src_ipaddr.af = AF_UNSPEC;
 		rcode = fr_packet_list_id_alloc(pl, radclient-&gt;request);
 		if (rcode &lt; 0) {
 			int mysockfd;
@@ -966,11 +967,11 @@ int main(int argc, char **argv)
 		packet_code = PW_STATUS_SERVER;
 
 	} else if (strcmp(argv[2], &quot;disconnect&quot;) == 0) {
-		if (server_port == 0) server_port = PW_POD_UDP_PORT;
+		if (server_port == 0) server_port = PW_COA_UDP_PORT;
 		packet_code = PW_DISCONNECT_REQUEST;
 
 	} else if (strcmp(argv[2], &quot;coa&quot;) == 0) {
-		if (server_port == 0) server_port = PW_POD_UDP_PORT;
+		if (server_port == 0) server_port = PW_COA_UDP_PORT;
 		packet_code = PW_COA_REQUEST;
 
 	} else if (strcmp(argv[2], &quot;auto&quot;) == 0) {</diff>
      <filename>src/main/radclient.c</filename>
    </modified>
    <modified>
      <diff>@@ -206,6 +206,7 @@ static void NEVER_RETURNS usage(int status)
 	fprintf(output, &quot;\t-f filter\tPCAP filter. (default is udp port 1812 or 1813 or 1814)\n&quot;);
 	fprintf(output, &quot;\t-h\t\tPrint this help message.\n&quot;);
 	fprintf(output, &quot;\t-i interface\tInterface to capture.\n&quot;);
+	fprintf(output, &quot;\t-I filename\tRead packets from filename.\n&quot;);
 	fprintf(output, &quot;\t-p port\tList for packets on port.\n&quot;);
 	fprintf(output, &quot;\t-r filter\tRADIUS attribute filter.\n&quot;);
 	fprintf(output, &quot;\t-s secret\tRADIUS secret.\n&quot;);
@@ -224,6 +225,7 @@ int main(int argc, char *argv[])
 	char buffer[1024];
 	char *pcap_filter = NULL;
 	char *radius_filter = NULL;
+	char *filename = NULL;
 	int packet_count = -1;		/* how many packets to sniff */
 	int opt;
 	FR_TOKEN parsecode;
@@ -234,7 +236,7 @@ int main(int argc, char *argv[])
 	dev = pcap_lookupdev(errbuf);
 
 	/* Get options */
-	while ((opt = getopt(argc, argv, &quot;c:d:f:hi:p:r:s:X&quot;)) != EOF) {
+	while ((opt = getopt(argc, argv, &quot;c:d:f:hi:I:p:r:s:X&quot;)) != EOF) {
 		switch (opt)
 		{
 		case 'c':
@@ -256,6 +258,9 @@ int main(int argc, char *argv[])
 		case 'i':
 			dev = optarg;
 			break;
+		case 'I':
+			filename = optarg;
+			break;
 		case 'p':
 			port = atoi(optarg);
 			break;
@@ -312,7 +317,11 @@ int main(int argc, char *argv[])
 	printf(&quot;RADIUS secret: [%s]\n&quot;, radius_secret);
 
 	/* Open the device so we can spy */
-	descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
+	if (filename) {
+		descr = pcap_open_offline(filename, errbuf);
+	} else {
+		descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
+	}
 	if (descr == NULL)
 	{
 		printf(&quot;radsniff: pcap_open_live failed (%s)\n&quot;, errbuf);</diff>
      <filename>src/main/radsniff.c</filename>
    </modified>
    <modified>
      <diff>@@ -276,6 +276,7 @@ void realms_free(void)
 #ifdef WITH_PROXY
 static struct in_addr hs_ip4addr;
 static struct in6_addr hs_ip6addr;
+static char *hs_srcipaddr = NULL;
 static char *hs_type = NULL;
 static char *hs_check = NULL;
 static char *hs_virtual_server = NULL;
@@ -297,6 +298,9 @@ static CONF_PARSER home_server_config[] = {
 	{ &quot;secret&quot;,  PW_TYPE_STRING_PTR,
 	  offsetof(home_server,secret), NULL,  NULL},
 
+	{ &quot;src_ipaddr&quot;,  PW_TYPE_STRING_PTR,
+	  0, &amp;hs_srcipaddr,  NULL },
+
 	{ &quot;response_window&quot;, PW_TYPE_INTEGER,
 	  offsetof(home_server,response_window), NULL,   &quot;30&quot; },
 	{ &quot;max_outstanding&quot;, PW_TYPE_INTEGER,
@@ -431,6 +435,8 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
 		hs_type = NULL;
 		free(hs_check);
 		hs_check = NULL;
+		free(hs_srcipaddr);
+		hs_srcipaddr = NULL;
 		return 0;
 	}
 
@@ -540,6 +546,19 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
 		goto error;
 	}
 
+	/*
+	 *	Look up the name using the *same* address family as
+	 *	for the home server.
+	 */
+	if (hs_srcipaddr &amp;&amp; (home-&gt;ipaddr.af != AF_UNSPEC)) {
+		if (ip_hton(hs_srcipaddr, home-&gt;ipaddr.af, &amp;home-&gt;src_ipaddr) &lt; 0) {
+			cf_log_err(cf_sectiontoitem(cs), &quot;Failed parsing src_ipaddr&quot;);
+			goto error;
+		}
+	}
+	free(hs_srcipaddr);
+	hs_srcipaddr = NULL;
+
 	if (!rbtree_insert(home_servers_byname, home)) {
 		cf_log_err(cf_sectiontoitem(cs),
 			   &quot;Internal error %d adding home server %s.&quot;,
@@ -2007,6 +2026,11 @@ home_server *home_server_ldb(const char *realmname,
 			 *	the 'hints' file.
 			 */
 			request-&gt;proxy-&gt;vps =  paircopy(request-&gt;packet-&gt;vps);
+
+			/*
+			 *	Set the source IP address for proxying.
+			 */
+			request-&gt;proxy-&gt;src_ipaddr = found-&gt;src_ipaddr;
 		}
 
 		/*
@@ -2135,3 +2159,54 @@ home_pool_t *home_pool_byname(const char *name, int type)
 }
 
 #endif
+
+#ifdef WITH_PROXY
+static int home_server_create_callback(void *ctx, void *data)
+{
+	rad_listen_t *head = ctx;
+	home_server *home = data;
+	rad_listen_t *this;
+
+	/*
+	 *	If there WAS a src address defined, ensure that a
+	 *	proxy listener has been defined.
+	 */
+	if (home-&gt;src_ipaddr.af != AF_UNSPEC) {
+		this = proxy_new_listener(&amp;home-&gt;src_ipaddr, TRUE);
+
+		/*
+		 *	Failed to create it: Die
+		 */
+		if (!this) return 1;
+
+		this-&gt;next = head-&gt;next;
+		head-&gt;next = this;
+	}
+
+	return 0;
+}
+
+/*
+ *	Taking a void* here solves some header issues.
+ */
+int home_server_create_listeners(void *ctx)
+{
+	rad_listen_t *head = ctx;
+
+	if (!home_servers_byaddr) return 0;
+
+	rad_assert(head != NULL);
+
+	/*
+	 *	Add the listeners to the TAIL of the list.
+	 */
+	while (head-&gt;next) head = head-&gt;next;
+
+	if (rbtree_walk(home_servers_byaddr, InOrder,
+			home_server_create_callback, head) != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+#endif</diff>
      <filename>src/main/realms.c</filename>
    </modified>
    <modified>
      <diff>@@ -490,6 +490,12 @@ REQUEST *request_alloc_coa(REQUEST *request)
 {
 	if (!request || request-&gt;coa) return NULL;
 
+	/*
+	 *	Originate CoA requests only when necessary.
+	 */
+	if ((request-&gt;packet-&gt;code != PW_AUTHENTICATION_REQUEST) &amp;&amp;
+	    (request-&gt;packet-&gt;code != PW_ACCOUNTING_REQUEST)) return NULL;
+
 	request-&gt;coa = request_alloc_fake(request);
 	request-&gt;coa-&gt;packet-&gt;code = 0; /* unknown, as of yet */
 	request-&gt;coa-&gt;child_state = REQUEST_RUNNING;</diff>
      <filename>src/main/util.c</filename>
    </modified>
    <modified>
      <diff>@@ -109,6 +109,45 @@ static int dhcp_header_sizes[] = {
 #define DEFAULT_PACKET_SIZE (300)
 #define MAX_PACKET_SIZE (1500 - 40)
 
+static int getcode(const uint8_t *data, size_t data_len, int *code)
+{
+	uint8_t *end, *p;
+
+	end = data + data_len;
+
+	while (p &lt; end) {
+		/*
+		 *	End of packet or end of options
+		 */
+		if ((p[0] == 0) || (p[0] == 255)) return 0;
+
+		/*
+		 *	Not enough room for 0x3501cc
+		 */
+		if ((end - p) &lt; 3) return 0; /* t l v */
+
+		/*
+		 *	Option is larger than the packet.
+		 */
+		if ((p + p[1] + 2) &gt; end) return 0;
+
+		/*
+		 *	Found it.  Ensure it's well formed.
+		 */
+		if (p[0] == 53) {
+			if ((p[1] != 1) || (p[2] == 0) || (p[2] &gt; 8)) {
+				return 0;
+			}
+			*code = p[2];
+			return 1;
+		}
+
+		p += 2 + p[1];
+	}
+
+	return 0;
+}
+
 /*
  *	DHCPv4 is only for IPv4.  Broadcast only works if udpfromto is
  *	defined.
@@ -191,10 +230,20 @@ RADIUS_PACKET *fr_dhcp_recv(int sockfd)
 	    (packet-&gt;data[241] != 1) ||
 	    (packet-&gt;data[242] == 0) ||
 	    (packet-&gt;data[242] &gt; 8)) {
-		fprintf(stderr, &quot;Unknown, or badly formatted DHCP packet\n&quot;);
-		rad_free(&amp;packet);
-		return NULL;
+		/*
+		 *	Some clients send the packet type buried
+		 *	inside of the packet...
+		 */
+		if (!getcode(packet-&gt;data + 240, packet-&gt;data_len - 240,
+			     &amp;packet-&gt;code)) {
+			fprintf(stderr, &quot;Unknown, or badly formatted DHCP packet\n&quot;);
+			rad_free(&amp;packet);
+			return NULL;
+		}
+	} else {
+		packet-&gt;code = packet-&gt;data[242];
 	}
+	packet-&gt;code |= PW_DHCP_OFFSET;
 
 	/*
 	 *	Create a unique vector from the MAC address and the
@@ -209,15 +258,13 @@ RADIUS_PACKET *fr_dhcp_recv(int sockfd)
 	 */
 	memset(packet-&gt;vector, 0, sizeof(packet-&gt;vector));
 	memcpy(packet-&gt;vector, packet-&gt;data + 28, packet-&gt;data[2]);
-	packet-&gt;vector[packet-&gt;data[2]] = packet-&gt;data[242];
+	packet-&gt;vector[packet-&gt;data[2]] = packet-&gt;code &amp; 0xff;
 
 	/*
 	 *	FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
 	 *	FIXME: for OFFER / ACK       : src_port = dst_port - 1
 	 */
 
-	packet-&gt;code = PW_DHCP_OFFSET | packet-&gt;data[242];
-
 	/*
 	 *	Unique keys are xid, client mac, and client ID?
 	 */</diff>
      <filename>src/modules/frs_dhcp/dhcp.c</filename>
    </modified>
    <modified>
      <diff>@@ -115,7 +115,6 @@ static int proxy_socket_recv(rad_listen_t *listener,
 	case PW_DISCONNECT_NAK:
 	case PW_COA_ACK:
 	case PW_COA_NAK:
-		fun = rad_coa_reply; /* run NEW function */
 		break;
 #endif
 
@@ -140,10 +139,20 @@ static int proxy_socket_recv(rad_listen_t *listener,
 	rad_assert(request-&gt;process != NULL);
 
 #ifdef WITH_COA
-	if (!fun)
+	/*
+	 *	Distinguish proxied CoA requests from ones we
+	 *	originate.  If we've proxied a DIFFERENT packet type
+	 *	than the original, then it MUST be a CoA packet.  In
+	 *	that case, we process it as a CoA reply packet, rather
+	 *	than re-running the original method.
+	 */
+	if (request-&gt;packet-&gt;code != request-&gt;proxy-&gt;code) {
+		rad_assert((request-&gt;proxy-&gt;code == PW_COA_REQUEST) ||
+			   (request-&gt;proxy-&gt;code == PW_DISCONNECT_REQUEST));
+		fun = rad_coa_reply; /* run NEW function */
+	} else
 #endif
-	  fun = request-&gt;process; /* re-run original function */
-	*pfun = fun;
+	*pfun = request-&gt;process; /* re-run original function */
 	*prequest = request;
 
 	return 1;</diff>
      <filename>src/modules/frs_proxy/frs_proxy.c</filename>
    </modified>
    <modified>
      <diff>@@ -166,5 +166,10 @@ module_t rlm_always = {
 		always_return,	       	/* pre-proxy */
 		always_return,		/* post-proxy */
 		always_return		/* post-auth */
+#ifdef WITH_COA
+		,
+		always_return,		/* recv-coa */
+		always_return		/* send-coa */
+#endif
 	},
 };</diff>
      <filename>src/modules/rlm_always/rlm_always.c</filename>
    </modified>
    <modified>
      <diff>@@ -46,6 +46,46 @@ static const char *packet_codes[] = {
   &quot;Password-Reject&quot;,
   &quot;Accounting-Message&quot;,
   &quot;Access-Challenge&quot;
+  &quot;Status-Server&quot;,
+  &quot;Status-Client&quot;,
+  &quot;14&quot;,
+  &quot;15&quot;,
+  &quot;16&quot;,
+  &quot;17&quot;,
+  &quot;18&quot;,
+  &quot;19&quot;,
+  &quot;20&quot;,
+  &quot;Resource-Free-Request&quot;,
+  &quot;Resource-Free-Response&quot;,
+  &quot;Resource-Query-Request&quot;,
+  &quot;Resource-Query-Response&quot;,
+  &quot;Alternate-Resource-Reclaim-Request&quot;,
+  &quot;NAS-Reboot-Request&quot;,
+  &quot;NAS-Reboot-Response&quot;,
+  &quot;28&quot;,
+  &quot;Next-Passcode&quot;,
+  &quot;New-Pin&quot;,
+  &quot;Terminate-Session&quot;,
+  &quot;Password-Expired&quot;,
+  &quot;Event-Request&quot;,
+  &quot;Event-Response&quot;,
+  &quot;35&quot;,
+  &quot;36&quot;,
+  &quot;37&quot;,
+  &quot;38&quot;,
+  &quot;39&quot;,
+  &quot;Disconnect-Request&quot;,
+  &quot;Disconnect-ACK&quot;,
+  &quot;Disconnect-NAK&quot;,
+  &quot;CoA-Request&quot;,
+  &quot;CoA-ACK&quot;,
+  &quot;CoA-NAK&quot;,
+  &quot;46&quot;,
+  &quot;47&quot;,
+  &quot;48&quot;,
+  &quot;49&quot;,
+  &quot;IP-Address-Allocate&quot;,
+  &quot;IP-Address-Release&quot;
 };
 
 
@@ -360,7 +400,7 @@ static int do_detail(void *instance, REQUEST *request, RADIUS_PACKET *packet,
 		 *	Numbers, if not.
 		 */
 		if ((packet-&gt;code &gt; 0) &amp;&amp;
-		    (packet-&gt;code &lt;= PW_ACCESS_CHALLENGE)) {
+		    (packet-&gt;code &lt; 52)) {
 			fprintf(outfp, &quot;\tPacket-Type = %s\n&quot;,
 				packet_codes[packet-&gt;code]);
 		} else {
@@ -515,6 +555,23 @@ static int detail_postauth(void *instance, REQUEST *request)
 	return do_detail(instance,request,request-&gt;reply, FALSE);
 }
 
+#ifdef WITH_COA
+/*
+ *	Incoming CoA - write the detail files.
+ */
+static int detail_recv_coa(void *instance, REQUEST *request)
+{
+	return do_detail(instance,request,request-&gt;packet, FALSE);
+}
+
+/*
+ *	Outgoing CoA - write the detail files.
+ */
+static int detail_send_coa(void *instance, REQUEST *request)
+{
+	return do_detail(instance,request,request-&gt;reply, FALSE);
+}
+#endif
 
 /*
  *	Outgoing Access-Request to home server - write the detail files.
@@ -577,6 +634,10 @@ module_t rlm_detail = {
 		detail_pre_proxy,      	/* pre-proxy */
 		detail_post_proxy,	/* post-proxy */
 		detail_postauth		/* post-auth */
+#ifdef WITH_COA
+		, detail_recv_coa,
+		detail_send_coa
+#endif
 	},
 };
 </diff>
      <filename>src/modules/rlm_detail/rlm_detail.c</filename>
    </modified>
    <modified>
      <diff>@@ -411,8 +411,11 @@ static int eap_authenticate(void *instance, REQUEST *request)
 		 */
 		vp = pairfind(request-&gt;reply-&gt;vps, PW_USER_NAME);
 		if (!vp) {
-			vp = pairmake(&quot;User-Name&quot;, request-&gt;username-&gt;vp_strvalue,
+			vp = pairmake(&quot;User-Name&quot;, &quot;&quot;,
 				      T_OP_EQ);
+			strlcpy(vp-&gt;vp_strvalue, request-&gt;username-&gt;vp_strvalue,
+				sizeof(vp-&gt;vp_strvalue));
+			vp-&gt;length = request-&gt;username-&gt;length;
 			rad_assert(vp != NULL);
 			pairadd(&amp;(request-&gt;reply-&gt;vps), vp);
 		}
@@ -511,6 +514,11 @@ static int eap_post_proxy(void *inst, REQUEST *request)
 	EAP_HANDLER	*handler;
 
 	/*
+	 *	Just in case the admin lists EAP in post-proxy-type Fail.
+	 */
+	if (!request-&gt;proxy_reply) return RLM_MODULE_NOOP;
+
+	/*
 	 *	If there was a handler associated with this request,
 	 *	then it's a tunneled request which was proxied...
 	 */
@@ -548,7 +556,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
 		 *	We are done, wrap the EAP-request in RADIUS to send
 		 *	with all other required radius attributes
 		 */
-		rcode = eap_compose(handler);
+		eap_compose(handler);
 
 		/*
 		 *	Add to the list only if it is EAP-Request, OR if
@@ -592,7 +600,6 @@ static int eap_post_proxy(void *inst, REQUEST *request)
 		RDEBUG2(&quot;No pre-existing handler found&quot;);
 	}
 
-
 	/*
 	 *	There may be more than one Cisco-AVPair.
 	 *	Ensure we find the one with the LEAP attribute.</diff>
      <filename>src/modules/rlm_eap/rlm_eap.c</filename>
    </modified>
    <modified>
      <diff>@@ -67,6 +67,10 @@ static const int JRADIUS_checksimul   = 5;
 static const int JRADIUS_pre_proxy    = 6;
 static const int JRADIUS_post_proxy   = 7;
 static const int JRADIUS_post_auth    = 8;
+#ifdef WITH_COA
+static const int JRADIUS_recv_coa     = 9;
+static const int JRADIUS_send_coa     = 10;
+#endif
 
 #define LOG_PREFIX  &quot;rlm_jradius: &quot;
 #define MAX_HOSTS   4
@@ -1062,6 +1066,17 @@ static int jradius_post_auth(void *instance, REQUEST *request)
   return rlm_jradius_call(JRADIUS_post_auth, instance, request, 0);
 }
 
+#ifdef WITH_COA
+static int jradius_recv_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_recv_coa, instance, request, 0);
+}
+static int jradius_send_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_send_coa, instance, request, 0);
+}
+#endif
+
 static int jradius_detach(void *instance)
 {
   JRADIUS *inst = (JRADIUS *) instance;
@@ -1085,6 +1100,10 @@ module_t rlm_jradius = {
     jradius_pre_proxy,
     jradius_post_proxy,
     jradius_post_auth
+#ifdef WITH_COA
+    , jradius_recv_coa,
+    jradius_send_coa
+#endif
   },
 };
 </diff>
      <filename>src/modules/rlm_jradius/rlm_jradius.c</filename>
    </modified>
    <modified>
      <diff>@@ -288,5 +288,9 @@ module_t rlm_linelog = {
 		do_linelog, 	/* pre-proxy */
 		do_linelog,	/* post-proxy */
 		do_linelog	/* post-auth */
+#ifdef WITH_COA
+		, do_linelog,	/* recv-coa */
+		do_linelog	/* send-coa */
+#endif
 	},
 };</diff>
      <filename>src/modules/rlm_linelog/rlm_linelog.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 1.3 .
+# From configure.in Revision.
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61.
 #
@@ -3301,6 +3301,55 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
 		targetname=
           fi
 
+	  cat &gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h &gt;&gt;conftest.$ac_ext
+cat &gt;&gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* end confdefs.h.  */
+extern char Perl_hv_store();
+int
+main ()
+{
+ Perl_hv_store()
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try=&quot;$ac_link&quot;
+case &quot;(($ac_try&quot; in
+  *\&quot;* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval &quot;echo \&quot;\$as_me:$LINENO: $ac_try_echo\&quot;&quot;) &gt;&amp;5
+  (eval &quot;$ac_link&quot;) 2&gt;conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 &gt;conftest.err
+  rm -f conftest.er1
+  cat conftest.err &gt;&amp;5
+  echo &quot;$as_me:$LINENO: \$? = $ac_status&quot; &gt;&amp;5
+  (exit $ac_status); } &amp;&amp; {
+	 test -z &quot;$ac_c_werror_flag&quot; ||
+	 test ! -s conftest.err
+       } &amp;&amp; test -s conftest$ac_exeext &amp;&amp;
+       $as_test_x conftest$ac_exeext; then
+  BROKEN=
+else
+  echo &quot;$as_me: failed program was:&quot; &gt;&amp;5
+sed 's/^/| /' conftest.$ac_ext &gt;&amp;5
+
+	BROKEN=&quot;yes&quot;
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+	 if test &quot;x$BROKEN&quot; != &quot;x&quot;; then
+	 	fail=&quot;$fail libperl.so&quot;
+		targetname=
+	  fi
+
           CFLAGS=$old_CFLAGS
         fi
 	targetname=rlm_perl
@@ -3334,7 +3383,11 @@ ac_config_headers=&quot;$ac_config_headers config.h&quot;
 
 
 
-ac_config_files=&quot;$ac_config_files Makefile&quot;
+
+  unset ac_cv_env_LIBS_set
+  unset ac_cv_env_LIBS_value
+
+  ac_config_files=&quot;$ac_config_files Makefile&quot;
 
 cat &gt;confcache &lt;&lt;\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -4428,3 +4481,4 @@ if test &quot;$no_create&quot; != yes; then
   $ac_cs_success || { (exit 1); exit 1; }
 fi
 
+</diff>
      <filename>src/modules/rlm_perl/configure</filename>
    </modified>
    <modified>
      <diff>@@ -50,6 +50,16 @@ if test x$with_[]modname != xno; then
 		targetname=
           fi
 
+	  AC_TRY_LINK([extern char Perl_hv_store();],
+		      [ Perl_hv_store()],
+		      BROKEN=,
+		      BROKEN=&quot;yes&quot;)
+
+	 if test &quot;x$BROKEN&quot; != &quot;x&quot;; then
+	 	fail=&quot;$fail libperl.so&quot;
+		targetname=
+	  fi
+
           CFLAGS=$old_CFLAGS
         fi
 	targetname=modname</diff>
      <filename>src/modules/rlm_perl/configure.in</filename>
    </modified>
    <modified>
      <diff>@@ -69,6 +69,10 @@ typedef struct perl_inst {
 	char	*func_pre_proxy;
 	char	*func_post_proxy;
 	char	*func_post_auth;
+#ifdef WITH_COA
+	char	*func_recv_coa;
+	char	*func_send_coa;
+#endif
 	char	*xlat_name;
 	char	*perl_flags;
 	PerlInterpreter *perl;
@@ -105,6 +109,12 @@ static const CONF_PARSER module_config[] = {
 	  offsetof(PERL_INST,func_post_proxy), NULL, &quot;post_proxy&quot;},
 	{ &quot;func_post_auth&quot;, PW_TYPE_STRING_PTR,
 	  offsetof(PERL_INST,func_post_auth), NULL, &quot;post_auth&quot;},
+#ifdef WITH_COA
+	{ &quot;func_recv_coa&quot;, PW_TYPE_STRING_PTR,
+	  offsetof(PERL_INST,func_recv_coa), NULL, &quot;recv_coa&quot;},
+	{ &quot;func_send_coa&quot;, PW_TYPE_STRING_PTR,
+	  offsetof(PERL_INST,func_send_coa), NULL, &quot;send_coa&quot;},
+#endif
 	{ &quot;perl_flags&quot;, PW_TYPE_STRING_PTR,
 	  offsetof(PERL_INST,perl_flags), NULL, NULL},
 	{ &quot;func_start_accounting&quot;, PW_TYPE_STRING_PTR,
@@ -868,6 +878,24 @@ static int perl_post_auth(void *instance, REQUEST *request)
 	return rlmperl_call(instance, request,
 			((PERL_INST *)instance)-&gt;func_post_auth);
 }
+#ifdef WITH_COA
+/*
+ *	Recv CoA request
+ */
+static int perl_recv_coa(void *instance, REQUEST *request)
+{
+	return rlmperl_call(instance, request,
+			((PERL_INST *)instance)-&gt;func_recv_coa);
+}
+/*
+ *	Send CoA request
+ */
+static int perl_send_coa(void *instance, REQUEST *request)
+{
+	return rlmperl_call(instance, request,
+			((PERL_INST *)instance)-&gt;func_send_coa);
+}
+#endif
 /*
  * Detach a instance give a chance to a module to make some internal setup ...
  */
@@ -970,5 +998,9 @@ module_t rlm_perl = {
 		perl_pre_proxy,		/* pre-proxy */
 		perl_post_proxy,	/* post-proxy */
 		perl_post_auth		/* post-auth */
+#ifdef WITH_COA
+		, perl_recv_coa,
+		perl_send_coa
+#endif
 	},
 };</diff>
      <filename>src/modules/rlm_perl/rlm_perl.c</filename>
    </modified>
    <modified>
      <diff>@@ -1095,6 +1095,10 @@ const FR_NAME_NUMBER policy_component_names[] = {
 	{ &quot;pre-proxy&quot;, RLM_COMPONENT_PRE_PROXY },
 	{ &quot;post-proxy&quot;, RLM_COMPONENT_POST_PROXY },
 	{ &quot;post-auth&quot;, RLM_COMPONENT_POST_AUTH },
+#ifdef WITH_COA
+	{ &quot;recv-coa&quot;, RLM_COMPONENT_RECV_COA },
+	{ &quot;send-coa&quot;, RLM_COMPONENT_SEND_COA },
+#endif
 	{ NULL, RLM_COMPONENT_COUNT }
 };
 </diff>
      <filename>src/modules/rlm_policy/parse.c</filename>
    </modified>
    <modified>
      <diff>@@ -189,6 +189,19 @@ static int policy_post_proxy(void *instance, REQUEST *request)
 				   &quot;post-proxy&quot;);
 }
 
+#ifdef WITH_COA
+static int policy_recv_coa(void *instance, REQUEST *request)
+{
+	return rlm_policy_evaluate((rlm_policy_t *) instance, request,
+				   &quot;recv-coa&quot;);
+}
+static int policy_send_coa(void *instance, REQUEST *request)
+{
+	return rlm_policy_evaluate((rlm_policy_t *) instance, request,
+				   &quot;send-coa&quot;);
+}
+#endif
+
 /*
  *	The &quot;free&quot; functions are here, for no particular reason.
  */
@@ -322,5 +335,9 @@ module_t rlm_policy = {
 		policy_pre_proxy,	/* pre-proxy */
 		policy_post_proxy,	/* post-proxy */
 		policy_post_auth	/* post-auth */
+#ifdef WITH_COA
+		, policy_recv_coa,
+		policy_send_coa
+#endif
 	},
 };</diff>
      <filename>src/modules/rlm_policy/rlm_policy.c</filename>
    </modified>
    <modified>
      <diff>@@ -31,18 +31,28 @@ def accounting(p):
   print p 
   return radiusd.RLM_MODULE_OK
 
-def preproxy(p):
-  print &quot;*** preproxy ***&quot;
+def pre_proxy(p):
+  print &quot;*** pre_proxy ***&quot;
   print p 
   return radiusd.RLM_MODULE_OK
 
-def postproxy(p):
-  print &quot;*** postproxy ***&quot;
+def post_proxy(p):
+  print &quot;*** post_proxy ***&quot;
   print p 
   return radiusd.RLM_MODULE_OK
 
-def postauth(p):
-  print &quot;*** postauth ***&quot;
+def post_auth(p):
+  print &quot;*** post_auth ***&quot;
+  print p 
+  return radiusd.RLM_MODULE_OK
+
+def recv_coa(p):
+  print &quot;*** recv_coa ***&quot;
+  print p 
+  return radiusd.RLM_MODULE_OK
+
+def send_coa(p):
+  print &quot;*** send_coa ***&quot;
   print p 
   return radiusd.RLM_MODULE_OK
 </diff>
      <filename>src/modules/rlm_python/radiusd_test.py</filename>
    </modified>
    <modified>
      <diff>@@ -54,6 +54,13 @@ struct rlm_python_t {
 		preacct,
 		accounting,
 		checksimul,
+		pre_proxy,
+		post_proxy,
+		post_auth,
+#ifdef WITH_COA
+		recv_coa,
+		send_coa,
+#endif
 		detach;
 };
 
@@ -77,6 +84,13 @@ static CONF_PARSER module_config[] = {
   A(preacct)
   A(accounting)
   A(checksimul)
+  A(pre_proxy)
+  A(post_proxy)
+  A(post_auth)
+#ifdef WITH_COA
+  A(recv_coa)
+  A(send_coa)
+#endif
   A(detach)
 
 #undef A
@@ -587,6 +601,13 @@ static int python_instantiate(CONF_SECTION *conf, void **instance)
         A(preacct);
         A(accounting);
         A(checksimul);
+        A(pre_proxy);
+        A(post_proxy);
+        A(post_auth);
+#ifdef WITH_COA
+        A(recv_coa);
+        A(send_coa);
+#endif
         A(detach);
 
 #undef A
@@ -628,6 +649,13 @@ A(authorize)
 A(preacct)
 A(accounting)
 A(checksimul)
+A(pre_proxy)
+A(post_proxy)
+A(post_auth)
+#ifdef WITH_COA
+A(recv_coa)
+A(send_coa)
+#endif
 
 #undef A
 
@@ -652,8 +680,12 @@ module_t rlm_python = {
 		python_preacct,		/* preaccounting */
 		python_accounting,	/* accounting */
 		python_checksimul,	/* checksimul */
-		NULL,			/* pre-proxy */
-		NULL,			/* post-proxy */
-		NULL			/* post-auth */
+		python_pre_proxy,	/* pre-proxy */
+		python_post_proxy,	/* post-proxy */
+		python_post_auth	/* post-auth */
+#ifdef WITH_COA
+		, python_recv_coa,
+		python_send_coa
+#endif
 	}
 };</diff>
      <filename>src/modules/rlm_python/rlm_python.c</filename>
    </modified>
    <modified>
      <diff>@@ -2903,6 +2903,209 @@ fi
 		old_CFLAGS=$CFLAGS
 		CFLAGS=&quot;$CFLAGS $RB_CFLAGS -I${RB_ARCH_DIR} -I${RB_INC_DIR}&quot;
 #		smart_try_dir=$RB_INC_DIR
+
+
+
+ac_safe=`echo &quot;ruby.h&quot; | sed 'y%./+-%__pm%'`
+{ echo &quot;$as_me:$LINENO: checking for ruby.h&quot; &gt;&amp;5
+echo $ECHO_N &quot;checking for ruby.h... $ECHO_C&quot; &gt;&amp;6; }
+
+old_CFLAGS=&quot;$CFLAGS&quot;
+smart_include=
+smart_include_dir=
+
+if test &quot;x$smart_try_dir&quot; != &quot;x&quot;; then
+  for try in $smart_try_dir; do
+    CFLAGS=&quot;$old_CFLAGS -I$try&quot;
+    cat &gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h &gt;&gt;conftest.$ac_ext
+cat &gt;&gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* end confdefs.h.  */
+
+		    #include &lt;ruby.h&gt;
+int
+main ()
+{
+ int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try=&quot;$ac_compile&quot;
+case &quot;(($ac_try&quot; in
+  *\&quot;* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval &quot;echo \&quot;\$as_me:$LINENO: $ac_try_echo\&quot;&quot;) &gt;&amp;5
+  (eval &quot;$ac_compile&quot;) 2&gt;conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 &gt;conftest.err
+  rm -f conftest.er1
+  cat conftest.err &gt;&amp;5
+  echo &quot;$as_me:$LINENO: \$? = $ac_status&quot; &gt;&amp;5
+  (exit $ac_status); } &amp;&amp; {
+	 test -z &quot;$ac_c_werror_flag&quot; ||
+	 test ! -s conftest.err
+       } &amp;&amp; test -s conftest.$ac_objext; then
+  smart_include=&quot;-I$try&quot;
+else
+  echo &quot;$as_me: failed program was:&quot; &gt;&amp;5
+sed 's/^/| /' conftest.$ac_ext &gt;&amp;5
+
+	smart_include=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test &quot;x$smart_include&quot; != &quot;x&quot;; then
+      break;
+    fi
+  done
+  CFLAGS=&quot;$old_CFLAGS&quot;
+fi
+
+if test &quot;x$smart_include&quot; = &quot;x&quot;; then
+  cat &gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h &gt;&gt;conftest.$ac_ext
+cat &gt;&gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* end confdefs.h.  */
+
+		  #include &lt;ruby.h&gt;
+int
+main ()
+{
+ int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try=&quot;$ac_compile&quot;
+case &quot;(($ac_try&quot; in
+  *\&quot;* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval &quot;echo \&quot;\$as_me:$LINENO: $ac_try_echo\&quot;&quot;) &gt;&amp;5
+  (eval &quot;$ac_compile&quot;) 2&gt;conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 &gt;conftest.err
+  rm -f conftest.er1
+  cat conftest.err &gt;&amp;5
+  echo &quot;$as_me:$LINENO: \$? = $ac_status&quot; &gt;&amp;5
+  (exit $ac_status); } &amp;&amp; {
+	 test -z &quot;$ac_c_werror_flag&quot; ||
+	 test ! -s conftest.err
+       } &amp;&amp; test -s conftest.$ac_objext; then
+  smart_include=&quot; &quot;
+else
+  echo &quot;$as_me: failed program was:&quot; &gt;&amp;5
+sed 's/^/| /' conftest.$ac_ext &gt;&amp;5
+
+	smart_include=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test &quot;x$smart_include&quot; = &quot;x&quot;; then
+
+
+if test &quot;x$LOCATE&quot; != &quot;x&quot;; then
+        DIRS=
+  file=ruby.h
+
+  for x in `${LOCATE} $file 2&gt;/dev/null`; do
+                                        base=`echo $x | sed &quot;s%/${file}%%&quot;`
+    if test &quot;x$x&quot; = &quot;x$base&quot;; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2&gt;/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test &quot;x$exclude&quot; != &quot;x&quot;; then
+      continue
+    fi
+
+                    already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+    if test &quot;x$already&quot; = &quot;x&quot;; then
+      DIRS=&quot;$DIRS $dir&quot;
+    fi
+  done
+fi
+
+eval &quot;smart_include_dir=\&quot;\$smart_include_dir $DIRS\&quot;&quot;
+
+
+  for try in $smart_include_dir /usr/local/include /opt/include; do
+    CFLAGS=&quot;$old_CFLAGS -I$try&quot;
+    cat &gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h &gt;&gt;conftest.$ac_ext
+cat &gt;&gt;conftest.$ac_ext &lt;&lt;_ACEOF
+/* end confdefs.h.  */
+
+		    #include &lt;ruby.h&gt;
+int
+main ()
+{
+ int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try=&quot;$ac_compile&quot;
+case &quot;(($ac_try&quot; in
+  *\&quot;* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval &quot;echo \&quot;\$as_me:$LINENO: $ac_try_echo\&quot;&quot;) &gt;&amp;5
+  (eval &quot;$ac_compile&quot;) 2&gt;conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 &gt;conftest.err
+  rm -f conftest.er1
+  cat conftest.err &gt;&amp;5
+  echo &quot;$as_me:$LINENO: \$? = $ac_status&quot; &gt;&amp;5
+  (exit $ac_status); } &amp;&amp; {
+	 test -z &quot;$ac_c_werror_flag&quot; ||
+	 test ! -s conftest.err
+       } &amp;&amp; test -s conftest.$ac_objext; then
+  smart_include=&quot;-I$try&quot;
+else
+  echo &quot;$as_me: failed program was:&quot; &gt;&amp;5
+sed 's/^/| /' conftest.$ac_ext &gt;&amp;5
+
+	smart_include=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test &quot;x$smart_include&quot; != &quot;x&quot;; then
+      break;
+    fi
+  done
+  CFLAGS=&quot;$old_CFLAGS&quot;
+fi
+
+if test &quot;x$smart_include&quot; != &quot;x&quot;; then
+  { echo &quot;$as_me:$LINENO: result: yes&quot; &gt;&amp;5
+echo &quot;${ECHO_T}yes&quot; &gt;&amp;6; }
+  eval &quot;ac_cv_header_$ac_safe=yes&quot;
+  CFLAGS=&quot;$old_CFLAGS $smart_include&quot;
+  SMART_CFLAGS=&quot;$SMART_CFLAGS $smart_include&quot;
+else
+  { echo &quot;$as_me:$LINENO: result: no&quot; &gt;&amp;5
+echo &quot;${ECHO_T}no&quot; &gt;&amp;6; }
+fi
+
+		if test &quot;x$ac_cv_header_ruby_h&quot; != &quot;xyes&quot;; then
+			fail=&quot;$fail ruby.h&quot;
+			targetname=
+		fi
 		ruby_cflags=$CFLAGS
 		CFLAGS=$old_CFLAGS
 </diff>
      <filename>src/modules/rlm_ruby/configure</filename>
    </modified>
    <modified>
      <diff>@@ -64,6 +64,11 @@ if test x$with_[]modname != xno; then
 		old_CFLAGS=$CFLAGS
 		CFLAGS=&quot;$CFLAGS $RB_CFLAGS -I${RB_ARCH_DIR} -I${RB_INC_DIR}&quot;
 #		smart_try_dir=$RB_INC_DIR
+		FR_SMART_CHECK_INCLUDE(ruby.h)
+		if test &quot;x$ac_cv_header_ruby_h&quot; != &quot;xyes&quot;; then
+			fail=&quot;$fail ruby.h&quot;
+			targetname=
+		fi
 		ruby_cflags=$CFLAGS
 		CFLAGS=$old_CFLAGS
 </diff>
      <filename>src/modules/rlm_ruby/configure.in</filename>
    </modified>
    <modified>
      <diff>@@ -47,6 +47,10 @@ typedef struct rlm_ruby_t {
     RLM_RUBY_STRUCT(preproxy);
     RLM_RUBY_STRUCT(postproxy);
     RLM_RUBY_STRUCT(postauth);
+#ifdef WITH_COA
+    RLM_RUBY_STRUCT(recvcoa);
+    RLM_RUBY_STRUCT(sendcoa);
+#endif
     RLM_RUBY_STRUCT(detach);
 
     char *scriptFile;
@@ -388,6 +392,10 @@ static int ruby_instantiate(CONF_SECTION *conf, void **instance) {
     RLM_RUBY_LOAD(preproxy);
     RLM_RUBY_LOAD(postproxy);
     RLM_RUBY_LOAD(postauth);
+#ifdef WITH_COA
+    RLM_RUBY_LOAD(recvcoa);
+    RLM_RUBY_LOAD(sendcoa);
+#endif
     RLM_RUBY_LOAD(detach);
 
     *instance = data;
@@ -411,6 +419,10 @@ RLM_RUBY_FUNC(checksimul)
 RLM_RUBY_FUNC(preproxy)
 RLM_RUBY_FUNC(postproxy)
 RLM_RUBY_FUNC(postauth)
+#ifdef WITH_COA
+RLM_RUBY_FUNC(recvcoa)
+RLM_RUBY_FUNC(sendcoa)
+#endif
 
 static int ruby_detach(void *instance) {
     int return_value;
@@ -455,5 +467,9 @@ module_t rlm_ruby = {
         ruby_preproxy, /* pre-proxy */
         ruby_postproxy, /* post-proxy */
         ruby_postauth /* post-auth */
+#ifdef WITH_COA
+	, ruby_recvcoa,
+	ruby_sendcoa
+#endif
     },
 };</diff>
      <filename>src/modules/rlm_ruby/rlm_ruby.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a62281184660ab621f4dd331f7ad94e207654685</id>
    </parent>
    <parent>
      <id>4a5b18a653c5a35786f8a9dcfab8b4ebc0671101</id>
    </parent>
  </parents>
  <author>
    <name>Antti</name>
    <email>refresh.xss@gmail.com</email>
  </author>
  <url>http://github.com/Antti/freeradius-server/commit/b06ff21b5e33995789c04366ce7326704f415c10</url>
  <id>b06ff21b5e33995789c04366ce7326704f415c10</id>
  <committed-date>2009-06-09T10:51:17-07:00</committed-date>
  <authored-date>2009-06-09T10:51:17-07:00</authored-date>
  <message>Merge branch 'master' of git://github.com/alandekok/freeradius-server</message>
  <tree>0f1da5a7ce451fc216f429526d80086f38344713</tree>
  <committer>
    <name>Antti</name>
    <email>refresh.xss@gmail.com</email>
  </committer>
</commit>
