/* * apuled - show network traffic on apu LEDs * Copyright (c) 2013 Christian Herzog * based on ifled by Mattias Wadman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Last modified: 20140109 * changed LED control from mmap'd memory poking to /sys/class/led/ writes * in order to comply with newer kernels with CONFIG_STRICT_DEVMEM set * */ #include #include #include #include #include #include #include #include #include #include #include const char *banner = "apuled v1.0 - (c) 2013 Christian Herzog \n" "based on ifled by Mattias Wadman \n" "This program is distributed under the terms of GPL.\n"; const char *help = "%sUsage: %s interface [options]\n" "\tinterface\tInterface to monitor, for example: eth0\n" "Options:\n" "\t-c crt\t\tLED config 3 chars, num, caps and scroll-lock.\n" "\t\t\tr = Receive t = Transmit\n" "\t\t\tu = Drop (receive) i = Drop (transmit)\n" "\t\t\tj = Error (receive) k = Error (transmit)\n" "\t\t\tReceive or transmit:\n" "\t\t\te = Error d = Drop\n" "\t\t\ta = Activity c = Collision\n" "\t\t\tn = None (will not touch this LED)\n" "\t\t\tDefault: crt\n" "\t-d delay\tLED update delay in ms. Default: 50\n" "\t-f\t\tFork program into background.\n\n"; volatile unsigned char *ptr; #define TRUE 1 #define FALSE 0 #define IF_RX 0 #define IF_TX 1 #define IF_COLL 2 #define IF_DROP_RX 4 #define IF_DROP_TX 5 #define IF_ERR_TX 6 #define IF_ERR_RX 7 #define IF_RXTX 8 #define IF_DROP 9 #define IF_ERR 10 #define IF_NONE 11 #define OPT_FORK 1 #define OPT_KERNEL_2_0 2 int ledfd[3]; unsigned long int if_info[8]; // current interface values. unsigned long int l_if_info[8]; // last interface values. unsigned char led_config[3] = {IF_COLL,IF_RX,IF_TX}; char options = 0; void freakout(char *why) { fprintf(stderr,"Error: %s\n",why); exit(1); } void set_led(char mode,char led) { if (mode) { write(ledfd[led], "1", 1); } else { write(ledfd[led], "0", 1); } } void update_netproc(char *interface) { char b[255]; char dummy; FILE *procfd; if ((procfd = fopen("/proc/net/dev","r")) == NULL) freakout("Unable to open /proc/net/dev."); while (fgets(b,sizeof(b),procfd) != NULL) { char *bp = b; while (*bp == ' ') *bp++; if (strncmp(bp,interface,strlen(interface)) == 0 && *(bp+strlen(interface)) == ':' ) { bp = bp+strlen(interface)+1; if (options & OPT_KERNEL_2_0) sscanf(bp,"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &if_info[IF_RX],&if_info[IF_ERR_RX],&if_info[IF_DROP_RX], &dummy,&dummy,&if_info[IF_TX],&if_info[IF_ERR_TX], &if_info[IF_DROP_TX],&dummy,&if_info[IF_COLL]); else sscanf(bp,"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &if_info[IF_RX],&dummy,&if_info[IF_ERR_RX],&if_info[IF_DROP_RX], &dummy,&dummy,&dummy,&dummy,&if_info[IF_TX],&dummy, &if_info[IF_ERR_TX],&if_info[IF_DROP_TX],&dummy,&if_info[IF_COLL]); fclose(procfd); return; } } fclose(procfd); freakout("Unable to find interface."); } char is_changed(char temp) { switch(temp) { case IF_RXTX: return (((if_info[IF_TX] != l_if_info[IF_TX]) || (if_info[IF_RX] != l_if_info[IF_RX])) ? TRUE : FALSE); case IF_DROP: return (((if_info[IF_DROP_TX] != l_if_info[IF_DROP_TX]) || (if_info[IF_DROP_RX] != l_if_info[IF_DROP_RX])) ? TRUE : FALSE); case IF_ERR: return (((if_info[IF_ERR_TX] != l_if_info[IF_ERR_TX]) || (if_info[IF_ERR_RX] != l_if_info[IF_ERR_RX])) ? TRUE : FALSE); default: return (if_info[temp] != l_if_info[temp] ? TRUE : FALSE); } } void update_leds() { char led; for (led=0;led < 3;led++) { if(led_config[led] == IF_NONE) continue; if(is_changed(led_config[led])) set_led(TRUE,led); else set_led(FALSE,led); } memcpy(&l_if_info,&if_info,sizeof(if_info)); } char select_mode(char mode) { switch(mode) { case 'r': return IF_RX; case 't': return IF_TX; case 'e': return IF_ERR; case 'c': return IF_COLL; case 'd': return IF_DROP; case 'a': return IF_RXTX; case 'u': return IF_DROP_RX; case 'i': return IF_DROP_TX; case 'j': return IF_ERR_RX; case 'k': return IF_ERR_TX; default: return IF_NONE; } } void signal_handler(int signal) { exit(0); } void fork_program() { pid_t program_pid; program_pid = fork(); if (program_pid == -1) freakout("Unable to fork program."); if (program_pid != 0) exit(0); } int main(int argc, char *argv[]) { FILE *procfd; int delay = 50; struct utsname uname_dummy; char arg_dummy; if (argc < 3) { printf(help,banner,argv[0]); exit(0); } for (arg_dummy=2;arg_dummy < argc;arg_dummy++) { if(argv[arg_dummy][0] != '-') { printf("Error: option: %s\n",argv[arg_dummy]); exit(1); } switch (argv[arg_dummy][1]) { case 'c': if(argv[arg_dummy+1] == NULL || strlen(argv[arg_dummy+1]) != 3) freakout("-c option needs 3 chars"); led_config[0] = select_mode(argv[arg_dummy+1][0]); led_config[1] = select_mode(argv[arg_dummy+1][1]); led_config[2] = select_mode(argv[arg_dummy+1][2]); arg_dummy++; break; case 'd': if(argv[arg_dummy+1] == NULL) freakout("-d option needs an integer"); delay = atol(argv[arg_dummy+1]); arg_dummy++; break; case 'f': options |= OPT_FORK; break; default: printf("Error: option: %s\n",argv[arg_dummy]); exit(1); break; } } if (options & OPT_FORK) fork_program(); else printf("%s", banner); signal(SIGINT,signal_handler); signal(SIGTERM,signal_handler); update_netproc(argv[1]); memcpy(&l_if_info,&if_info,sizeof(if_info)); char fd[255]; int led; for (led=0;led < 3;led++) { sprintf(fd, "/sys/class/leds/apu:%d/brightness", led+1); ledfd[led] = open(fd, O_WRONLY); } while(1) { #if DEBUG printf("tx:%lu rx:%lu coll:%lu tx_drop:%lu rx_drop:%lu err_tx:%lu err_rx:%lu\n", if_info[IF_TX],if_info[IF_RX],if_info[IF_COLL],if_info[IF_DROP_TX], if_info[IF_DROP_RX],if_info[IF_ERR_TX],if_info[IF_ERR_RX]); #endif update_netproc(argv[1]); update_leds(); usleep(delay*1000); } for (led=0;led < 3;led++) { close(ledfd[led]); } return 0; }