diff -urNb mpd-3.17.orig/src/link.c mpd-3.17/src/link.c
--- mpd-3.17.orig/src/link.c	Fri Mar 12 02:33:27 2004
+++ mpd-3.17/src/link.c	Wed May  5 10:50:48 2004
@@ -236,6 +236,7 @@
   lnk->conf.retry_timeout = LINK_DEFAULT_RETRY;
   lnk->bandwidth = LINK_DEFAULT_BANDWIDTH;
   lnk->latency = LINK_DEFAULT_LATENCY;
+  lnk->dropUser = 0;
 
   Disable(&lnk->conf.options, LINK_CONF_CHAPMD5);
   Accept(&lnk->conf.options, LINK_CONF_CHAPMD5);
diff -urNb mpd-3.17.orig/src/link.h mpd-3.17/src/link.h
--- mpd-3.17.orig/src/link.h	Fri Mar 12 02:33:27 2004
+++ mpd-3.17/src/link.h	Wed May  5 10:50:48 2004
@@ -95,6 +95,8 @@
 	u_int64_t 	runts;		/* Too short MP fragments */
 	u_int64_t 	dupFragments;	/* MP frames with duplicate seq # */
 	u_int64_t	dropFragments;	/* MP fragments we had to drop */
+	u_int64_t	sv_xmitOctets;	/* update-limit support */
+	u_int64_t	sv_recvOctets;	/* update-limit support */
   };
   typedef struct linkstat *LinkStats;
 
@@ -133,6 +135,7 @@
     char		*downReason;	/* Reason for link going down */
     int			bandwidth;	/* Bandwidth in bits per second */
     int			latency;	/* Latency in microseconds */
+    int			dropUser;	/* should we drop connection? */
 
     /* Info gleaned from negotiations */
     struct in_range	peer_allow;	/* Range from /etc/ppp/secrets */
diff -urNb mpd-3.17.orig/src/ngfunc.c mpd-3.17/src/ngfunc.c
--- mpd-3.17.orig/src/ngfunc.c	Fri Mar 12 02:33:27 2004
+++ mpd-3.17/src/ngfunc.c	Wed May  5 10:50:48 2004
@@ -215,7 +215,7 @@
   newPpp = 1;
 
   /* Give it a name */
-  snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", getpid(), b->name);
+  snprintf(nm.name, sizeof(nm.name), "mpd-%s", b->name);
   if (NgSendMsg(b->csock, MPD_HOOK_PPP,
       NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
     Log(LG_ERR, ("[%s] can't name %s node: %s",
diff -urNb mpd-3.17.orig/src/radius.c mpd-3.17/src/radius.c
--- mpd-3.17.orig/src/radius.c	Fri Mar 12 02:33:27 2004
+++ mpd-3.17/src/radius.c	Wed May  5 10:53:54 2004
@@ -17,6 +17,14 @@
 #include <radlib_vs.h>
 #include <md5.h>
 
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
 /* Global variables */
 
   static int RadiusSetCommand(int ac, char *av[], void *arg);
@@ -28,6 +36,8 @@
   /* compatibility functions until libradius has these builtin */
   static int rad_demangle(struct rad_handle *, const void *, size_t, u_char *);
   static int rad_demangle_mppe_key(struct rad_handle *, const void *, size_t, u_char *, size_t *);
+  static int RadiusGetCurrentParams();
+  static void FillCallerId(char *, size_t, struct in_addr);
 
 
 /* Set menu options */
@@ -38,7 +48,9 @@
     SET_TIMEOUT,
     SET_RETRIES,
     SET_CONFIG,
-    SET_UPDATE
+    SET_UPDATE,
+    SET_UPDATE_LIMIT_IN,
+    SET_UPDATE_LIMIT_OUT
   };
 
 /*
@@ -58,6 +70,10 @@
 	RadiusSetCommand, NULL, (void *) SET_CONFIG },
     { "acct-update <seconds>",		"set update interval",
 	RadiusSetCommand, NULL, (void *) SET_UPDATE },
+    { "update-limit-in <bytes>",	"set update limit (inbound traffic)",
+	RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_IN },
+    { "update-limit-out <bytes>",	"set update limit (outbound traffic)",
+	RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_OUT },
     { NULL },
   };
   
@@ -159,6 +175,22 @@
 	     conf->acct_update = val;
 	break;
 
+      case SET_UPDATE_LIMIT_IN:
+	val = atoi(*av);
+	  if (val <= 0)
+	    Log(LG_ERR, ("Update limit (in) must be positive."));
+	  else
+	    conf->update_limit_in = val;
+	break;
+
+      case SET_UPDATE_LIMIT_OUT:
+	val = atoi(*av);
+	  if (val <= 0)
+	    Log(LG_ERR, ("Update limit (out) must be positive."));
+	  else
+	    conf->update_limit_out = val;
+	break;
+
       case SET_RETRIES:
 	val = atoi(*av);
 	if (val <= 0)
@@ -295,7 +327,7 @@
   struct radius		*rad = &bund->radius;
   char			host[MAXHOSTNAMELEN];
   struct in_addr	*peer_ip;
-  char			*peeripname;
+  char			caller_id[256];
   u_char		*peer_mac;
   char			peermacname[18];
 
@@ -358,9 +390,9 @@
 
   peer_ip = PptpGetPeerIp();
   if (peer_ip != NULL && peer_ip->s_addr != 0) {
-    peeripname = inet_ntoa(*peer_ip);
-    if (peeripname != NULL) {
-      if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, peeripname) == -1) {
+    FillCallerId(caller_id, sizeof(caller_id), *peer_ip);
+    if (caller_id[0]) {
+      if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, caller_id) == -1) {
 	Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s", lnk->name,
 	  function, rad_strerror(rad->radh)));
 	RadiusClose();
@@ -1035,6 +1067,13 @@
             	    Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_QUEUE: %s",
             		lnk->name, function, acl2));
 		    acls = &(rad->acl_queue);
+		} else if (res == RAD_MPD_DROP_USER) {
+		    if (rad_cvt_int(data) == RAD_MPD_DROP_USER_YES)
+			lnk->dropUser++;
+		    else
+			lnk->dropUser = 0;
+		    Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_DROP_USER: %d", lnk->name, function, lnk->dropUser));
+		    break;
 		} else {
     		    Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d ", lnk->name, function, res));
 		    break;
@@ -1114,6 +1153,61 @@
   return RAD_ACK;
 }
 
+static int
+RadiusGetCurrentParams() 
+{
+  char  function[] = "RadiusGetCurrentParams";
+  struct radius *rad = &bund->radius;
+  int res;
+  size_t len;
+  const void *data;
+  u_int32_t vendor;
+
+  while ((res = rad_get_attr(rad->radh, &data, &len)) > 0) {
+
+    switch (res) {
+
+      case RAD_VENDOR_SPECIFIC:
+	if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) {
+	  Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_get_vendor_attr failed: %s ", lnk->name, function, rad_strerror(rad->radh)));
+	  return RAD_NACK;
+	}
+
+	switch (vendor) {
+
+          case RAD_VENDOR_MPD:
+
+	    switch (res) {
+
+	      case RAD_MPD_DROP_USER:
+		if (rad_cvt_int(data) == RAD_MPD_DROP_USER_YES)
+			lnk->dropUser++;
+		else
+			lnk->dropUser = 0;
+		Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_DROP_USER: %d", lnk->name, function, lnk->dropUser));
+		break;
+
+	      default:
+		Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d", lnk->name, function, res));
+		break;
+	    } /* switch(res) */
+	    break;
+
+    	  default:
+    	    Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping vendor %d  attribute: %d ", lnk->name, function, vendor, res));
+    	    break;
+	} /* switch(vendor) */
+	break;
+
+      default:
+	Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping attribute: %d ", lnk->name, function, res));
+	break;
+    }
+  }
+
+  return RAD_ACK;
+}
+
 void
 RadiusAcctUpdate(void *a)
 {
@@ -1123,7 +1217,10 @@
       lnk->name, function));
 
   TimerStop(&lnk->radius.radUpdate);
-  RadiusAccount(RAD_UPDATE);
+  lnk->dropUser = 0;	/* we MUST clear drop-user every time before checking */
+  if (RadiusAccount(RAD_UPDATE) == RAD_ACK)
+      if (RadiusGetCurrentParams() == RAD_ACK && lnk->dropUser)
+	  BundCloseLinks();
   TimerStart(&lnk->radius.radUpdate);
 }
 
@@ -1134,6 +1231,7 @@
   char  function[]	= "RadiusAccount";
   struct radius		*rad = &bund->radius;
   int			authentic;
+  int	send_update	= 0;	/*  Should we send acct-update? */
 
   /* if Radius-Auth wasn't used, then copy in authname */
   if (!strlen(rad->authname))
@@ -1258,11 +1356,44 @@
     }
   }
 
+  Log(LG_ALWAYS, ("[%s] ACCT: User-Name=%s NAS-IP-Address=%s NAS-Port=%d "
+    "Acct-Status-Type=%d Acct-Session-Id=%s Acct-Input-Octets=%u "
+    "Acct-Output-Octets=%u Acct-Input-Gigawords=%u Acct-Output-Gigawords=%u",
+    lnk->name, lnk->peer_authname, inet_ntoa(rad->conf.radius_me),
+    GetLinkID(), acct_type, lnk->radius.session_id,
+    (unsigned int) (lnk->stats.recvOctets % MAX_U_INT32),
+    (unsigned int) (lnk->stats.xmitOctets % MAX_U_INT32),
+    (unsigned int) (lnk->stats.recvOctets / MAX_U_INT32),
+    (unsigned int) (lnk->stats.xmitOctets / MAX_U_INT32)));
+
+  if (!(rad->conf.update_limit_in || rad->conf.update_limit_out))
+    send_update++;
+  else {
+    if (rad->conf.update_limit_in &&
+	lnk->stats.recvOctets - lnk->stats.sv_recvOctets > rad->conf.update_limit_in)
+	  send_update++;
+    if (rad->conf.update_limit_out &&
+	lnk->stats.xmitOctets - lnk->stats.sv_xmitOctets > rad->conf.update_limit_out)
+	  send_update++;
+  }
+
+  if (acct_type == RAD_UPDATE && !send_update) {
+      Log(LG_RADIUS, ("[%s] RADIUS: %s: shouldn't send Interim-Update",
+	lnk->name, function));
+      RadiusClose();
+      return RAD_NACK;
+  }
+
   Log(LG_RADIUS, ("[%s] RADIUS: %s: Sending accounting data (Type: %d)",
     lnk->name, function, acct_type));
   if (RadiusSendRequest() == RAD_NACK) 
     return RAD_NACK;
 
+  /* save old statistics (update-limit feature) */
+
+  lnk->stats.sv_recvOctets = lnk->stats.recvOctets;
+  lnk->stats.sv_xmitOctets = lnk->stats.xmitOctets;
+
   return RAD_ACK;
 
 }
@@ -1321,7 +1452,7 @@
     Log(LG_RADIUS, ("[%s] RADIUS: %s: Trying to use IP-address from radius-server",
       lnk->name, function));
 
-    if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.255") == 0) {
+    if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.255") == 0  || bund->radius.ip.s_addr == INADDR_ANY) {
       /* the peer can choose an address */
       Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that the peer can choose an address",
         lnk->name, function));
@@ -1361,6 +1492,8 @@
   printf("\tConfig-file  : %s\n", conf->file);
   printf("\tMe (NAS-IP)  : %s\n", inet_ntoa(conf->radius_me));
   printf("\tAcct-Interval: %d\n", conf->acct_update);
+  printf("\tUpdate-Limit-In : %d\n", conf->update_limit_in);
+  printf("\tUpdate-Limit-Out: %d\n", conf->update_limit_out);
   
   if (conf->server != NULL) {
 
@@ -1573,4 +1706,56 @@
 
   memcpy(demangled, P + 1, *len);
   return 0;
+}
+
+#define ROUNDUP(a) \
+	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+static void FillCallerId(char * caller_id, size_t len, struct in_addr peer_ip)
+{
+	int mib[6];
+	int needed = 0;
+	int found = 0;
+	char * buf, * lim, * next;
+	struct rt_msghdr *rtm;
+	struct sockaddr_inarp *sin;
+	struct sockaddr_dl *sdl;
+	char ifname[IF_NAMESIZE];
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_INET;
+	mib[4] = NET_RT_FLAGS;
+	mib[5] = RTF_LLINFO;
+
+	memset(caller_id, 0, len);
+
+	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+		return;
+	if (!(buf = (char *) malloc(needed)))
+		return;
+	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+		return;
+	lim = buf + needed;
+
+	for (next = buf; next < lim; next += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)next;
+		sin = (struct sockaddr_inarp *)(rtm + 1);
+		if (sin->sin_addr.s_addr != peer_ip.s_addr)
+			continue;
+		(char *)sdl = (char *)sin + ROUNDUP(sin->sin_len);
+		if_indextoname(sdl->sdl_index, ifname);
+		snprintf(caller_id, len - 1, "%s / %s / %s",
+			       	inet_ntoa(peer_ip),
+				ether_ntoa((struct ether_addr *)LLADDR(sdl)),
+				ifname);
+		found++;
+		break;
+	}
+	free(buf);
+	if (!found) 
+		snprintf(caller_id, len - 1, "%s / (unknown) / (unknown)",
+				inet_ntoa(peer_ip));
+	return;
 }
diff -urNb mpd-3.17.orig/src/radius.h mpd-3.17/src/radius.h
--- mpd-3.17.orig/src/radius.h	Fri Mar 12 02:33:27 2004
+++ mpd-3.17/src/radius.h	Wed May  5 10:57:22 2004
@@ -61,6 +61,11 @@
 #define RAD_MPD_PIPE 2
 #define RAD_MPD_QUEUE 3
 
+/* for dropping users */
+#define RAD_MPD_DROP_USER 154		/* Drop-User attribute */
+#define RAD_MPD_DROP_USER_NO 0		/* Drop-User: "No" value */
+#define RAD_MPD_DROP_USER_YES 1		/* Drop-User: "Yes" value */
+
 /*
  * FUNCTIONS
  */
@@ -101,6 +106,10 @@
     int		radius_timeout;
     int		radius_retries;
     int 	acct_update;		/* Accounting Update Interval */
+    int		update_limit_in;	/* Send Update only when counters
+					   grow more than "update_limit_xx"
+					   since last update */
+    int		update_limit_out;
     struct	in_addr radius_me;
     char	file[PATH_MAX];
     struct radiusserver_conf *server;
