diff -urNb pppd-radius.orig/options.c pppd-radius/options.c
--- pppd-radius.orig/options.c	Wed Jul 16 14:53:46 2003
+++ pppd-radius/options.c	Wed Dec 10 19:39:28 2003
@@ -103,6 +103,7 @@
 #ifdef RADIUS
 int	useradius = 0;		/* Use RADIUS for checking PAP */
 u_int32_t nas_ip = 0;	/* NAS IP addresss */
+int	acct_update = 300;	/* send Interim-Update every 5 minutes */
 #endif
 int	lcp_echo_interval = 0; 	/* Interval between LCP echo-requests */
 int	lcp_echo_fails = 0;	/* Tolerance to unanswered echo-requests */
@@ -200,6 +201,7 @@
 #ifdef RADIUS
 static int setdoradius __P((char **));
 static int setnasip __P((char **));
+static int setacctupdate __P((char **));
 #endif
 static int setusehostname __P((char **));
 static int setnoipdflt __P((char **));
@@ -358,6 +360,7 @@
 #ifdef RADIUS
     {"radius", 0, setdoradius},	/* Use RADIUS for UPAP */
     {"nas_ip", 1, setnasip},	/* NAS IP address */
+    {"acct_update", 1, setacctupdate},	/* Interim-Update interval (seconds) */
 #endif
     {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
     {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
@@ -2055,6 +2058,22 @@
 	useradius = 1;
 	inet_aton(*argv, (struct in_addr *)&nas_ip);
 	return 1;
+}
+
+static int
+setacctupdate(argv)
+    char **argv;
+{
+    int value;
+
+    if (!int_option(*argv, &value))
+	return 0;
+    if (value < 0) {
+	option_error("acct_update time must be positive");
+	return 0;
+    }
+    acct_update = value;
+    return 1;
 }
 #endif
 
diff -urNb pppd-radius.orig/pppd.h pppd-radius/pppd.h
--- pppd-radius.orig/pppd.h	Wed Jul 16 14:54:07 2003
+++ pppd-radius/pppd.h	Mon Dec 15 17:13:43 2003
@@ -99,6 +99,7 @@
 #ifdef RADIUS
 extern int	useradius;	/* Use RADIUS for checking PAP */
 extern u_int32_t	nas_ip;	/* NAS IP address */
+extern int	acct_update;	/* Interim-Update interval */
 #endif
 extern int	lcp_echo_interval; /* Interval between LCP echo-requests */
 extern int	lcp_echo_fails;	/* Tolerance to unanswered echo-requests */
@@ -177,6 +178,13 @@
 /* Table of pointers to supported protocols */
 extern struct protent *protocols[];
 
+#ifdef RADIUS
+struct pppd_stats {
+    unsigned int	bytes_in;
+    unsigned int	bytes_out;
+};
+#endif
+
 /*
  * Prototypes.
  */
@@ -307,6 +315,10 @@
 #ifdef PPP_FILTER
 int  set_filters __P((struct bpf_program *pass, struct bpf_program *active));
 				/* Set filter programs in kernel */
+#endif
+#ifdef RADIUS
+int  get_ppp_stats __P((int, struct pppd_stats *));
+				/* Return link statistics */
 #endif
 
 /* Procedures exported from options.c */
diff -urNb pppd-radius.orig/radius.c pppd-radius/radius.c
--- pppd-radius.orig/radius.c	Wed Jul 23 17:53:27 2003
+++ pppd-radius/radius.c	Tue Dec 16 12:17:08 2003
@@ -13,6 +13,7 @@
 #include <libutil.h>
 #include <errno.h>
 
+#include "pppd.h"
 #include "radius.h"
 #include "fsm.h"
 #include "ipcp.h"
@@ -24,11 +25,11 @@
 static char rad_user[256], rad_tty[256], rad_session_id[17];
 static char rad_called_id[64], rad_calling_id[64];
 
+
 int rad_login(char *user, char *port, char *pwd, u_int32_t remote) {
     char *p;
     size_t len;
     int rad_ret;	/* RADIUS return code */
-//    struct tm *tm;
     struct utmp utmp;
     struct rad_handle * rad;
     struct stat st;
@@ -115,6 +116,8 @@
     while ((rad_ret = rad_get_attr(rad, (const void **) &p, &len)) && rad_ret != -1) {
 	    if (rad_ret == RAD_FRAMED_IP_ADDRESS) {
 		remote = htonl(rad_cvt_int(p));
+	    } else if (rad_ret == RAD_SESSION_TIMEOUT) {
+		maxconnect = rad_cvt_int(p);
 	    }
     }
 
@@ -127,7 +130,7 @@
     /* Create Session-ID */
     /* FIXME: try to md5(nas_ip, stime, pid) */
 
-    sprintf(rad_session_id, "%08X%08X", stime, getpid());
+    sprintf(rad_session_id, "%08X", getpid());
 
     /* RADIUS accounting */
 
@@ -172,6 +175,10 @@
 
     rad_close(rad);	/* RADIUS ACCT request finished successfully */
 
+    /* setup acct_update timer */
+    if (acct_update)
+	TIMEOUT(rad_alive_timeout, NULL, acct_update);
+
     bzero(&utmp, sizeof(utmp));
     time(&utmp.ut_time);
     strncpy(utmp.ut_name, rad_user, sizeof(utmp.ut_name));
@@ -194,6 +201,19 @@
     time_t etime = time((time_t *) NULL);
     extern u_int32_t nas_ip;
     ipcp_options *ho = &ipcp_hisoptions[0];	/* it's safe cause NUM_PPP == 1 */
+    struct pppd_stats link_stats;
+    int dummy = 0;
+
+    /* Stop Alive timer */
+
+    UNTIMEOUT(rad_alive_timeout, NULL);
+
+    /* Get some statistics */
+
+    memset(&link_stats, 0, sizeof(link_stats));
+
+    if (!get_ppp_stats(dummy, &link_stats))
+	syslog(LOG_ERR, "get_ppp_stats() failed");
 
     /* RADIUS accounting */
 
@@ -225,6 +245,8 @@
 	rad_put_string(rad, RAD_CALLING_STATION_ID, rad_calling_id) ||
 	rad_put_string(rad, RAD_CALLED_STATION_ID, rad_called_id) ||
 	rad_put_string(rad, RAD_ACCT_SESSION_ID, rad_session_id) ||
+	rad_put_int(rad, RAD_ACCT_INPUT_OCTETS, link_stats.bytes_in) ||
+	rad_put_int(rad, RAD_ACCT_OUTPUT_OCTETS, link_stats.bytes_out) ||
 	rad_put_int(rad, RAD_ACCT_STATUS_TYPE, RAD_STOP)) {
 	syslog(LOG_ERR, "rad_put_XXX: %s", rad_strerror(rad));
 	rad_close(rad);
@@ -245,4 +267,75 @@
     logout(rad_tty);		/* wipe out utmp log entry */
 
     rad_logged_in = 0;
+}
+
+void rad_acct_update() {
+    struct rad_handle * rad;
+    int rad_ret;	/* RADIUS return code */
+    extern time_t stime;
+    time_t now = time((time_t *) NULL); /* current time */
+    extern u_int32_t nas_ip;
+    ipcp_options *ho = &ipcp_hisoptions[0];	/* it's safe cause NUM_PPP == 1 */
+    struct pppd_stats link_stats;
+    int dummy = 0;
+
+    /* First, get some statistics */
+
+    memset(&link_stats, 0, sizeof(link_stats));
+
+    if (!get_ppp_stats(dummy, &link_stats))
+	syslog(LOG_ERR, "get_ppp_stats() failed");
+
+    /* RADIUS accounting */
+
+    if (!(rad = rad_acct_open())) {
+	syslog(LOG_ERR, "rad_acct_open: %d", errno);
+	return;
+    }
+
+    if (rad_config(rad, NULL)) {
+	    syslog(LOG_ERR, "rad_config: %s", rad_strerror(rad));
+	    rad_close(rad);
+	    return;
+    }
+
+    if (rad_create_request(rad, RAD_ACCOUNTING_REQUEST)) {
+	    syslog(LOG_ERR, "rad_create_request(acct): %s", rad_strerror(rad));
+	    rad_close(rad);
+	    return;
+    }
+
+    if (rad_put_int(rad, RAD_NAS_IP_ADDRESS, ntohl(nas_ip)) ||
+	rad_put_int(rad, RAD_NAS_PORT_TYPE, RAD_ASYNC) ||
+	rad_put_int(rad, RAD_NAS_PORT, rad_port) ||
+	rad_put_string(rad, RAD_USER_NAME, rad_user) ||
+	rad_put_int(rad, RAD_SERVICE_TYPE, RAD_FRAMED) ||
+	rad_put_int(rad, RAD_FRAMED_PROTOCOL, RAD_PPP) ||
+	rad_put_int(rad, RAD_FRAMED_IP_ADDRESS, ntohl(inet_addr(rad_ipaddr))) ||
+	rad_put_int(rad, RAD_ACCT_SESSION_TIME, now - stime) ||
+	rad_put_string(rad, RAD_CALLING_STATION_ID, rad_calling_id) ||
+	rad_put_string(rad, RAD_CALLED_STATION_ID, rad_called_id) ||
+	rad_put_string(rad, RAD_ACCT_SESSION_ID, rad_session_id) ||
+	rad_put_int(rad, RAD_ACCT_INPUT_OCTETS, link_stats.bytes_in) ||
+	rad_put_int(rad, RAD_ACCT_OUTPUT_OCTETS, link_stats.bytes_out) ||
+	rad_put_int(rad, RAD_ACCT_STATUS_TYPE, RAD_ALIVE)) {
+	syslog(LOG_ERR, "rad_put_XXX: %s", rad_strerror(rad));
+	rad_close(rad);
+	return;
+    }
+
+    if ((rad_ret = rad_send_request(rad)) == -1) {
+	    syslog(LOG_ERR, "rad_send_request(acct): %s", rad_strerror(rad));
+	    rad_close(rad);
+	    return;
+    }
+
+    rad_close(rad);	/* RADIUS ACCT request finished successfully */
+}
+
+void rad_alive_timeout()
+{
+    rad_acct_update();
+    if (acct_update)
+	TIMEOUT(rad_alive_timeout, NULL, acct_update);
 }
diff -urNb pppd-radius.orig/radius.h pppd-radius/radius.h
--- pppd-radius.orig/radius.h	Tue Jul 15 17:01:12 2003
+++ pppd-radius/radius.h	Wed Dec 10 19:40:03 2003
@@ -3,10 +3,15 @@
 
 #include <radlib.h>
 
+#ifndef RAD_ALIVE
+#define RAD_ALIVE 3	/* Interim-Update accounting type */
+#endif
+
 extern int rad_logged_in;
 extern char rad_ipaddr[64];
 
 int rad_login(char *, char *, char *, u_int32_t);
 void rad_logout();
+void rad_alive_timeout();
 
 #endif /* RADIUS_H */
diff -urNb pppd-radius.orig/sys-bsd.c pppd-radius/sys-bsd.c
--- pppd-radius.orig/sys-bsd.c	Mon Nov 04 19:02:46 2002
+++ pppd-radius/sys-bsd.c	Mon Dec 15 17:20:19 2003
@@ -1590,3 +1590,52 @@
 	lock_file = NULL;
     }
 }
+
+#ifdef RADIUS
+/* my own replacement for strlcpy(3) */
+
+size_t 
+xstrlcpy(char *dst, const char *src, size_t siz)
+{
+    register char *d = dst;
+    register const char *s = src;
+    register size_t n = siz;
+
+    /* Copy as many bytes as will fit */
+
+    if (n != 0 && --n != 0) {
+	do {
+	    if ((*d++ = *s++) == 0)
+		break;
+	} while (--n != 0);
+    }
+
+    /* Not enough room in dst, add NUL and traverse rest of src */
+
+    if (n == 0) {
+	if (siz != 0)
+	    *d = '\0';		/* NUL-terminate dst */
+	while (*s++);
+    }
+    return (s - src - 1);	/* count does not include NUL */
+}
+
+/*
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(u, stats)
+    int u;
+    struct pppd_stats *stats;
+{
+    struct ifpppstatsreq req;
+
+    memset (&req, 0, sizeof (req));
+    xstrlcpy(req.ifr_name, ifname, sizeof(req.ifr_name));
+    if (ioctl(sockfd, SIOCGPPPSTATS, &req) < 0)
+	return 0;
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
+    return 1;
+}
+#endif
