#include #include #include #include #include #include #include #include #include #include #include "notify_avmnet.h" #define DEBUG 1 #define LOG_TO_FILE 1 #define LOGFILE "/var/log/notify_avmnet.log" #define CONSOLE "/dev/console" #define ERROR -1 #define MODULE_BUFFER_SIZE 1024 #define DEVNAME_MAX_LEN 64 #define PARAM_STR_LEN 128 #define MAX_MOD_PARAMS 32 char *ethwan_default = "ethwan=2"; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum reboot_request { DONT_REBOOT_IF_MODULE_PRESENT = 0, REBOOT_IF_MODULE_PRESENT = 1 }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum system_state { NO_REBOOT = 0, REBOOT = 1 }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum module_state { MODULE_NOT_PRESENT = 0, MODULE_PRESENT = 1, MODULE_CHECK_FAILED = 2 }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void dbg_to_logfile(const char *logfile, const char *t,...){ FILE *log_fp; log_fp = fopen(logfile, "a"); if (log_fp != NULL){ va_list ap; va_start(ap, t); vfprintf(log_fp, t, ap); va_end(ap); fclose(log_fp); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define CONSOLE_PRINT(format, arg...) dbg_to_logfile( CONSOLE, format, ##arg ); #if defined(DEBUG) && DEBUG #if defined(LOG_TO_FILE) && LOG_TO_FILE #define DBG_PRINT(format, arg...) dbg_to_logfile(LOGFILE, "[%s/%d]: " format "\n", __func__, __LINE__, ##arg); #else //#if defined(LOG_TO_FILE) #define DBG_PRINT(format, arg...) printf("[%s/%d]: " format "\n", __func__, __LINE__, ##arg); #endif //#if defined(LOG_TO_FILE) #else //#if defined(DEBUG) #define DBG_PRINT(format, arg...) #endif //#if defined(DEBUG) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static char module_buffer[MODULE_BUFFER_SIZE]; #if defined(CONFIG_VR9) #define CPU "vr9" #define HW_NEEDS_REBOOT_IF_MP DONT_REBOOT_IF_MODULE_PRESENT #endif #if defined(CONFIG_AR9) #define CPU "ar9" #define HW_NEEDS_REBOOT_IF_MP DONT_REBOOT_IF_MODULE_PRESENT #endif #if defined(CONFIG_AR10) #define CPU "ar10" #define HW_NEEDS_REBOOT_IF_MP DONT_REBOOT_IF_MODULE_PRESENT #endif #ifndef CPU #error CPU has to be AR9, AR10 or VR9 #endif static char *all_modules_list[] = { "ifx_ppa_mini_qos", "ifx_ppa_mini_sessions", "ifxmips_ppa_hal_" CPU "_e5", "ifxmips_ppa_datapath_" CPU "_e5", "ifxmips_ppa_hal_" CPU "_a5", "ifxmips_ppa_datapath_" CPU "_a5"}; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static enum module_state check_module_present( const char *module_name ){ int read_len = 0; int fd = open("/proc/modules", O_RDONLY); if (fd < 0) return MODULE_CHECK_FAILED; while ( read_len = read(fd, module_buffer, MODULE_BUFFER_SIZE - 1) ) { if (read_len < 0 ) break; module_buffer[read_len] = 0; if( strstr(module_buffer, module_name) ){ close(fd); return MODULE_PRESENT; } } close(fd); return MODULE_NOT_PRESENT; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void exec_subproc_block(const char *path, char *const argv[]){ pid_t pid; int status; pid_t ret; int i = 0; DBG_PRINT("run cmd '%s' ", path ); while(argv[i]){ DBG_PRINT(" argv[%d]='%s'",i, argv[i]); i++; } pid = fork(); if (pid == -1) { DBG_PRINT("cannot fork: %d", errno); return; } else if (pid != 0) { while ((ret = waitpid(pid, &status, 0)) == -1) { if (errno != EINTR) { DBG_PRINT("waitpid error: %d", errno); break; } } } else { if (execve(path, argv, NULL) == -1) { DBG_PRINT("execve error: %d", errno); return; } } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void modprobe_once( char *module_name, size_t paramc, char **paramv ){ if ( check_module_present( module_name ) == MODULE_NOT_PRESENT ){ if (paramc == 0) { char *modprobe_argv[] = {"modprobe", module_name, NULL}; exec_subproc_block("/sbin/modprobe", modprobe_argv); } else if (paramc we need to reboot the box", all_modules_list[i]); CONSOLE_PRINT("\nAVMNET:PPA Module %s present -> we need to reboot the box\n", all_modules_list[i]); system( "reboot" ); return REBOOT; } else { char *const rmmod_argv[] = {"rmmod", all_modules_list[i], NULL}; exec_subproc_block("/sbin/rmmod", rmmod_argv ); if ( check_module_present( all_modules_list[i] ) == MODULE_PRESENT ) { DBG_PRINT("ERROR: unload '%s' did not work", all_modules_list[i] ); CONSOLE_PRINT("ERROR: unload '%s' did not work", all_modules_list[i] ); CONSOLE_PRINT("\nAVMNET:PPA Module %s present -> we need to reboot the box\n", all_modules_list[i]); system( "reboot" ); } } } else { DBG_PRINT("%s not loaded", all_modules_list[i] ); } } return NO_REBOOT; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int kernel_read_current_ata_dev(char *dst) { int read_len = 0; int fd; if (!dst) return ERROR; fd = open("/proc/eth/avm_ata_dev", O_RDONLY); if (fd < 0){ DBG_PRINT("cannot open /proc/eth/avm_ata_dev"); dst[0] = 0; return ERROR; } read_len = read(fd, dst, DEVNAME_MAX_LEN - 1) ; if (read_len > 0 ){ dst[read_len] = 0; } else { dst[0] = 0; } close(fd); DBG_PRINT("current_ata_dev: %s", dst ); return read_len; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int kernel_read_current_wan_mode() { int read_len = 0; int fd = open("/proc/eth/avm_wan_mode", O_RDONLY); if (fd < 0){ DBG_PRINT("cannot open /proc/eth/avm_wan_mode"); return ERROR; } while ( read_len = read(fd, module_buffer, MODULE_BUFFER_SIZE - 1) ) { if (read_len < 0 ) break; module_buffer[read_len] = 0; if( strstr(module_buffer, "ATM") ){ close(fd); return TRANSFER_MODE_ATM; } if( strstr(module_buffer, "PTM") ){ close(fd); return TRANSFER_MODE_PTM; } if( strstr(module_buffer, "ETH") ){ close(fd); return TRANSFER_MODE_ETH; } if( strstr(module_buffer, "KDEV") ){ close(fd); return TRANSFER_MODE_KDEV; } } close(fd); return TRANSFER_MODE_NONE; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void notify_avmnet_hw_start_selected_tm_generic( uint32_t new_transfer_mode, uint32_t broadband_type, uint32_t no_dsl_init ) { char no_dsl_init_str[PARAM_STR_LEN]; int current_transfer_mode; char *paramv[MAX_MOD_PARAMS]; size_t paramc = 0; DBG_PRINT("called, avm_dsl_no_init=%lu",(unsigned long)no_dsl_init ); if ( no_dsl_init ) { #if(CONFIG_VR9) snprintf( no_dsl_init_str, PARAM_STR_LEN - 1, "avm_dsl_no_init=%lu", (unsigned long)no_dsl_init ); paramv[paramc++] = no_dsl_init_str; #else DBG_PRINT("avm_dsl_no_init not supported on this platform!" ); #endif } if (broadband_type != BROADBAND_TYPE_DSL){ DBG_PRINT("ignoring unknown broadband type: %d", broadband_type); return; } current_transfer_mode = kernel_read_current_wan_mode(); if ( new_transfer_mode == current_transfer_mode ){ DBG_PRINT("Tranfermode: %d already set", current_transfer_mode); return; } if ( new_transfer_mode == TRANSFER_MODE_ATM ){ DBG_PRINT("Start Training ATM"); if ( unload_all_ppa_modules( HW_NEEDS_REBOOT_IF_MP ) == REBOOT) return; modprobe_once("ifxmips_ppa_datapath_" CPU "_a5", paramc, paramv); } else if( new_transfer_mode == TRANSFER_MODE_PTM ) { DBG_PRINT("Start Training PTM"); if ( unload_all_ppa_modules( HW_NEEDS_REBOOT_IF_MP ) == REBOOT) return; modprobe_once("ifxmips_ppa_datapath_" CPU "_e5", paramc, paramv); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_start_selected_tm( uint32_t new_transfer_mode, uint32_t broadband_type ){ notify_avmnet_hw_start_selected_tm_generic( new_transfer_mode, broadband_type, 0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_start_selected_tm_no_dsl_init( uint32_t new_transfer_mode, uint32_t broadband_type ){ notify_avmnet_hw_start_selected_tm_generic( new_transfer_mode, broadband_type, 1 ); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_link_established( uint32_t transfer_mode, uint32_t broadband_type ) { DBG_PRINT("called"); if (broadband_type != BROADBAND_TYPE_DSL){ DBG_PRINT("ignoring unknown broadband type: %d", broadband_type); return; } if ( transfer_mode == TRANSFER_MODE_ATM ){ DBG_PRINT("Showtime ATM"); modprobe_once("ifxmips_ppa_hal_" CPU "_a5", 0, NULL); } else if( transfer_mode == TRANSFER_MODE_PTM ) { DBG_PRINT("Showtime PTM"); modprobe_once("ifxmips_ppa_hal_" CPU "_e5", 0, NULL); } if (( transfer_mode == TRANSFER_MODE_ATM ) || ( transfer_mode == TRANSFER_MODE_PTM ) ){ modprobe_once("ifx_ppa_mini_sessions", 0, NULL); modprobe_once("ifx_ppa_mini_qos", 0, NULL); } } /*------------------------------------------------------------------------------------------*\ * depricated, is replaced by notify_avmnet_hw_setup_ata_dev \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_disable_phy( uint32_t broadband_type ) { #if defined(USE_HW_DISABLE_PHY) && USE_HW_DISABLE_PHY int current_transfer_mode; char *paramv[MAX_MOD_PARAMS]; size_t paramc = 0; if (broadband_type != BROADBAND_TYPE_DSL){ DBG_PRINT("ignoring unknown broadband type: %d", broadband_type); return; } current_transfer_mode = kernel_read_current_wan_mode(); if ( (current_transfer_mode == TRANSFER_MODE_ETH ) || (current_transfer_mode == TRANSFER_MODE_KDEV ) ) { DBG_PRINT("ATA-Mode already set"); return; } DBG_PRINT("starting AVM ATA Mode"); if ( unload_all_ppa_modules( HW_NEEDS_REBOOT_IF_MP ) == REBOOT) return; paramv[paramc++] = ethwan_default; #if defined(CONFIG_VR9) //ethwan=2 --> EthernetWan modprobe_once("ifxmips_ppa_datapath_" CPU "_e5", paramc, paramv ); modprobe_once("ifxmips_ppa_hal_" CPU "_e5", 0, NULL); #else //ethwan=2 --> EthernetWan modprobe_once("ifxmips_ppa_datapath_" CPU "_a5", paramc, paramv ); modprobe_once("ifxmips_ppa_hal_" CPU "_a5",0 , NULL); #endif modprobe_once("ifx_ppa_mini_sessions", 0, NULL); modprobe_once("ifx_ppa_mini_qos", 0, NULL); #else //#if defined(USE_HW_DISABLE_PHY) && USE_HW_DISABLE_PHY DBG_PRINT("called, but obsolete - use notify_avmnet_hw_setup_wan_dev instead"); #endif //#if defined(USE_HW_DISABLE_PHY) && USE_HW_DISABLE_PHY } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_setup_ata_kdev( char *wan_dev_name ){ DBG_PRINT("setup_ata_kdev - just keep old state"); return; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_setup_ata_eth_dev( char *wan_dev_name ) { char ata_param_str[PARAM_STR_LEN]; int current_transfer_mode; char *paramv[MAX_MOD_PARAMS]; size_t paramc = 0; DBG_PRINT("called, wan_dev=%s", wan_dev_name?wan_dev_name:"NO_WAN_DEV"); current_transfer_mode = kernel_read_current_wan_mode(); if ( current_transfer_mode == TRANSFER_MODE_ETH ) { char current_ata_dev[DEVNAME_MAX_LEN]; DBG_PRINT("ATA-Mode already set"); kernel_read_current_ata_dev(current_ata_dev); if (wan_dev_name == NULL) { if ( strncmp( current_ata_dev,"NONE", DEVNAME_MAX_LEN) == 0) { DBG_PRINT("no wan dev in past, no wan dev in future"); return; } } else { if ( strncmp( current_ata_dev, wan_dev_name , DEVNAME_MAX_LEN) == 0 ){ DBG_PRINT("keep module state, ata dev %s was already set", wan_dev_name); return; } } } if ( unload_all_ppa_modules( HW_NEEDS_REBOOT_IF_MP ) == REBOOT ) return; paramv[paramc++]=ethwan_default; if ( wan_dev_name ){ snprintf( ata_param_str, PARAM_STR_LEN - 1, "avm_ata_dev=%s", wan_dev_name ); paramv[paramc++]=ata_param_str; } DBG_PRINT("starting AVM ATA Mode %s",wan_dev_name?ata_param_str:""); #if defined(CONFIG_AR9) || defined(CONFIG_AR10) //ethwan=2 --> EthernetWan modprobe_once("ifxmips_ppa_datapath_" CPU "_a5" , paramc, paramv); modprobe_once("ifxmips_ppa_hal_" CPU "_a5", 0, NULL); #else //ethwan=2 --> EthernetWan modprobe_once("ifxmips_ppa_datapath_" CPU "_e5" , paramc, paramv); modprobe_once("ifxmips_ppa_hal_" CPU "_e5", 0, NULL); #endif modprobe_once("ifx_ppa_mini_sessions", 0, NULL); modprobe_once("ifx_ppa_mini_qos", 0, NULL); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void notify_avmnet_hw_exit( uint32_t broadband_type ){ DBG_PRINT("called"); if (broadband_type != BROADBAND_TYPE_DSL){ DBG_PRINT("ignoring unknown broadband type: %d", broadband_type); return; } DBG_PRINT("Unloading all PPA Modules"); unload_all_ppa_modules( DONT_REBOOT_IF_MODULE_PRESENT ); }