diff -urNb mpd-3.15.orig/src/bund.c mpd-3.15/src/bund.c --- mpd-3.15.orig/src/bund.c Sun Oct 26 18:38:13 2003 +++ mpd-3.15/src/bund.c Thu Nov 20 13:05:06 2003 @@ -269,6 +269,10 @@ TimerStart(&lnk->radius.radUpdate); } } + + /* clear statistics */ + memset(&lnk->stats, 0, sizeof(lnk->stats)); + /* Done */ return(bm->n_up); } diff -urNb mpd-3.15.orig/src/link.h mpd-3.15/src/link.h --- mpd-3.15.orig/src/link.h Sun Oct 26 18:38:13 2003 +++ mpd-3.15/src/link.h Thu Dec 11 11:07:22 2003 @@ -87,6 +87,16 @@ (o) == LINK_ORIGINATE_REMOTE ? "remote" : \ "unknown") + /* traffic statistics */ + + struct traf_stats { + unsigned int OctetsIn; /* bytes in */ + unsigned int OctetsOut; /* bytes out */ + unsigned int GigaWordsIn; /* how many times OctetsIn was wrapped */ + unsigned int GigaWordsOut; /* how many times OctetsOut was wrapped */ + int drop_user; /* Drop-User flag */ + }; + /* Total state of a link */ struct linkst { char name[LINK_MAX_NAME]; /* Human readable name */ @@ -120,6 +130,9 @@ /* some Infos needed for RADIUS */ struct radius_linkinfo radius; + + /* traffic statistic */ + struct traf_stats stats; }; /* diff -urNb mpd-3.15.orig/src/radius.c mpd-3.15/src/radius.c --- mpd-3.15.orig/src/radius.c Sun Oct 26 18:38:13 2003 +++ mpd-3.15/src/radius.c Tue Dec 16 19:08:15 2003 @@ -38,7 +38,9 @@ SET_TIMEOUT, SET_RETRIES, SET_CONFIG, - SET_UPDATE + SET_UPDATE, + SET_UPDATE_LIMIT_IN, + SET_UPDATE_LIMIT_OUT }; /* @@ -58,6 +60,10 @@ RadiusSetCommand, NULL, (void *) SET_CONFIG }, { "acct-update ", "set update interval", RadiusSetCommand, NULL, (void *) SET_UPDATE }, + { "update-limit-in ", "set update limit (inbound traffic)", + RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_IN }, + { "update-limit-out ", "set update limit (outbound traffic)", + RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_OUT }, { NULL }, }; @@ -159,6 +165,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) @@ -995,6 +1017,19 @@ lnk->name, function, res)); break; } + case RAD_VENDOR_UNIX: + switch (res) { + case RAD_UNIX_DROP_USER: + if (rad_cvt_int(data) == RAD_UNIX_DROP_USER_YES) + lnk->stats.drop_user++; + Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_UNIX_DROP_USER: %d", + lnk->name, function, lnk->stats.drop_user)); + break; + default: + Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping UNIX vendor specific attribute: %d ", + lnk->name, function, res)); + break; + } } break; @@ -1040,7 +1075,9 @@ lnk->name, function)); TimerStop(&lnk->radius.radUpdate); - RadiusAccount(RAD_UPDATE); + if (RadiusAccount(RAD_UPDATE) == RAD_ACK) + if (RadiusGetParams() == RAD_ACK && lnk->stats.drop_user) + BundCloseLinks(); TimerStart(&lnk->radius.radUpdate); } @@ -1051,6 +1088,7 @@ char function[] = "RadiusAccount"; struct radius *rad = &bund->radius; int authentic; + int send_update = 0; /* Should we send Interim-Update? */ /* if Radius-Auth wasn't used, then copy in authname */ if (!strlen(rad->authname)) @@ -1148,16 +1186,53 @@ } if (NgFuncGetStats(lnk->bundleIndex, 0, &stats) >= 0) { - if (rad_put_int(rad->radh, RAD_ACCT_INPUT_OCTETS, stats.recvOctets) != 0 || + + if (stats.recvOctets < lnk->stats.OctetsIn) { + lnk->stats.GigaWordsIn++; + send_update++; /* Send update if we overlapped 4G */ + } else if (rad->conf.update_limit_in && + (stats.recvOctets - lnk->stats.OctetsIn > rad->conf.update_limit_in)) + send_update++; + + lnk->stats.OctetsIn = stats.recvOctets; + + if (stats.xmitOctets < lnk->stats.OctetsOut) { + lnk->stats.GigaWordsOut++; + send_update++; /* Send update if we overlapped 4G */ + } else if (rad->conf.update_limit_out && + (stats.xmitOctets - lnk->stats.OctetsOut > rad->conf.update_limit_out)) + send_update++; + + lnk->stats.OctetsOut = stats.xmitOctets; + + if (rad_put_int(rad->radh, RAD_ACCT_INPUT_OCTETS, lnk->stats.OctetsIn) != 0 || rad_put_int(rad->radh, RAD_ACCT_INPUT_PACKETS, stats.recvFrames) != 0 || - rad_put_int(rad->radh, RAD_ACCT_OUTPUT_OCTETS, stats.xmitOctets) != 0 || - rad_put_int(rad->radh, RAD_ACCT_OUTPUT_PACKETS, stats.xmitFrames) != 0) { + rad_put_int(rad->radh, RAD_ACCT_INPUT_GIGAWORDS, lnk->stats.GigaWordsIn) != 0 || + rad_put_int(rad->radh, RAD_ACCT_OUTPUT_OCTETS, lnk->stats.OctetsOut) != 0 || + rad_put_int(rad->radh, RAD_ACCT_OUTPUT_PACKETS, stats.xmitFrames) != 0 || + rad_put_int(rad->radh, RAD_ACCT_OUTPUT_GIGAWORDS, lnk->stats.GigaWordsOut) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: put stats: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } } + + 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, lnk->stats.OctetsIn, + lnk->stats.OctetsOut, lnk->stats.GigaWordsIn, lnk->stats.GigaWordsOut)); + + } + + if ((rad->conf.update_limit_in || rad->conf.update_limit_in) && + 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)", @@ -1231,7 +1306,7 @@ auth->range.width = 0; auth->range_valid = 1; - } else if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.254") == 0) { + } else if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.254") == 0 || bund->radius.ip.s_addr == INADDR_ANY) { /* we should choose the ip */ Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that we should choose an address", @@ -1263,6 +1338,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) { diff -urNb mpd-3.15.orig/src/radius.h mpd-3.15/src/radius.h --- mpd-3.15.orig/src/radius.h Sun Oct 26 18:38:13 2003 +++ mpd-3.15/src/radius.h Tue Dec 16 18:19:20 2003 @@ -25,6 +25,20 @@ #define RAD_UPDATE 3 #endif +#ifndef RAD_ACCT_INPUT_GIGAWORDS +#define RAD_ACCT_INPUT_GIGAWORDS 52 /* Acct-Input-Gigawords attribute */ +#endif /* RAD_ACCT_INPUT_GIGAWORDS */ + +#ifndef RAD_ACCT_OUTPUT_GIGAWORDS +#define RAD_ACCT_OUTPUT_GIGAWORDS 53 /* Acct-Output-Gigawords attribute */ +#endif /* RAD_ACCT_OUTPUT_GIGAWORDS */ + +/* for dropping user */ +#define RAD_VENDOR_UNIX 4 /* std2 */ +#define RAD_UNIX_DROP_USER 154 /* Drop-User attribute */ +#define RAD_UNIX_DROP_USER_NO 0 /* Drop-User: "No" value */ +#define RAD_UNIX_DROP_USER_YES 1 /* Drop-User: "Yes" value */ + /* for mppe-keys */ #define AUTH_LEN 16 #define SALT_LEN 2 @@ -81,6 +95,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;