#include #include #include #include #include #include #include #define DEVICE "ppp0" int getticks() { struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } int get_field(char *buf, int indx) { // Get space separated integer field at indx int count = 0; char *p = buf; while (isspace(*p)) p++; while (*p != 0) { if (isspace(*p)) { count++; while (isspace(*p)) p++; } if (count == indx) { return atoi(p); } p++; } return -1; } void read_procnet(char *device, int *bytesrx, int *bytestx) { FILE *file = fopen("/proc/net/dev", "r"); char linebuf[256]; while (fgets(linebuf, 256, file)) { char *pos = strstr(linebuf, ":"); if (!pos) continue; if (memcmp(pos - strlen(device), device, strlen(device)) != 0) continue; *bytesrx = get_field(pos + 1, 0); *bytestx = get_field(pos + 1, 8); fclose(file); return; } fclose(file); return; } int period_changed(time_t oldtime, time_t newtime) { struct tm period_s; time_t period_t; /* Find the next period change after oldtime */ localtime_r(&oldtime, &period_s); const int change_day = 24; if (period_s.tm_mday >= change_day) period_s.tm_mon++; period_s.tm_mday = change_day; period_s.tm_hour = period_s.tm_min = period_s.tm_sec = 0; period_t = mktime(&period_s); /* Is newtime after the change? */ if (period_t < newtime) { fprintf(stderr, "GPRS period has changed\n"); return 1; } else { return 0; } } static int total_ineeprom = 0; // Value currently in eeprom void read_values(int *update, int *counter) { unsigned char buf[8]; eeprom_readpage(PAGE_TRAFFIC, buf); memcpy(update, buf, sizeof(int)); memcpy(counter, buf + sizeof(int), sizeof(int)); } void write_values(int update, int counter) { unsigned char buf[8]; memcpy(buf, &update, sizeof(int)); memcpy(buf + sizeof(int), &counter, sizeof(int)); eeprom_writepage(PAGE_TRAFFIC, buf); total_ineeprom = counter; } static float rxspeed = 0., txspeed = 0.; // Speeds in kB/s static int total_bytes = 0; // Count of bytes static int total_update = 0; /* Public functions */ void traffic_updatespeeds() { static int lastticks = 0; static int lastrx = 0, lasttx = 0; int nowrx = 0, nowtx = 0; if (lastticks == 0) { read_procnet(DEVICE, &lastrx, &lasttx); lastticks = getticks(); return; } int timedelta = getticks() - lastticks; read_procnet(DEVICE, &nowrx, &nowtx); lastticks = getticks(); if (nowrx < lastrx || nowtx < lasttx) // If counters have been reset lastrx = lasttx = 0; rxspeed = ((float) nowrx - lastrx) / timedelta; // bytes per milliseconds = kilobytes per second txspeed = ((float) nowtx - lasttx) / timedelta; lasttx = nowtx; lastrx = nowrx; } void traffic_writetotal() { if (total_update != 0) { fprintf(stderr, "Writing traffic counts to EEPROM\n"); write_values(total_update, total_bytes); } } void traffic_updatetotal() { static int last_count = 0; int now_ifrx = 0, now_iftx = 0; read_procnet(DEVICE, &now_ifrx, &now_iftx); int now_count = now_ifrx + now_iftx; if (now_count < last_count) // Interface counter has reset last_count = 0; if (total_update == 0) { // First run read_values(&total_update, &total_bytes); last_count = now_count; total_ineeprom = total_bytes; } if (time(NULL) < 1183137239) // Some 2007 time to compare if time is valid return; // WRT54GL resets to 1.1.2000 on power-up if (period_changed(total_update, time(NULL))) // Period has changed total_bytes = 0; total_bytes += now_count - last_count; last_count = now_count; total_update = time(NULL); const int max_delta = 100000; if (now_count > total_ineeprom + max_delta) traffic_writetotal(); } void traffic_getspeeds(float *rx, float *tx) { *rx = rxspeed; *tx = txspeed; } int traffic_gettotal() { return total_bytes; }