#include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_OF_AVM_DT_ENV) #include #include #include /* * Retrieves the AVM Environment Variables from the Device Tree */ char *__must_check prom_getenv_device_tree(char *envname){ //Check if we have a device tree if(of_have_populated_dt()){ struct device_node *node; char *string = 0; //Go to the chosen node where the environment is stored node = of_find_node_by_path("/chosen"); if(!node){ pr_err("Chosen node not found\n"); return 0; } //check if the is a property with the name specified by envname if(of_property_read_string(node, envname, (const char **) &string) == 0){ pr_debug("Found env %s\n", string); return string; } else{ pr_err("Could not find Env '%s' in the device tree \n", envname); return 0; } } else{ pr_err("Device Tree not populated\n"); return NULL; } } #else /* === Support for old urlader env mechanism used for scorpion et al. === */ #include char *dst_env[64 * 2] __attribute__ ((section(".init.data"))); char *dst_config[4] __attribute__ ((section(".init.data"))); char dst_env_buff[2048] __attribute__((section(".init.data"))); char *dst_cmdline[COMMAND_LINE_SIZE] __attribute__ ((section(".init.data"))); char dst_cmdline_buff[64 *1024] __attribute__((section(".init.data"))); /* --- #define DEBUG_PROM_INIT --- */ #if defined(DEBUG_PROM_INIT) #define PROM_PRINTK(...) printk(__VA_ARGS__) #else #define PROM_PRINTK(...) #endif #define prom_envp(index) ((char *)(long)_prom_envp[(index)]) static char env_buffer[2048]; static char *_local_envp[64 * 2]; unsigned int fritz_box_hw_revision = 0; int *_prom_envp; #if defined(DEBUG_PROM_INIT) void print_env( char **myenv ){ int i = 0; PROM_PRINTK( "myenvp=%p\n", myenv ); while ( myenv[i] && myenv[i+1] ) { PROM_PRINTK( "(%p)%s : (%p)%s\n", myenv[i], myenv[i], myenv[i+1],myenv[i+1]); i += 2; } } void print_cmdline( int argc, char **argv ){ int i = 0; PROM_PRINTK( "argc=%d argv=%p\n", argc, argv ); for (i = 0; i < argc; i++) { PROM_PRINTK ( "[%d]: %s \n", i, argv[i]); } } extern unsigned long fw_arg0, fw_arg1; #endif /*--- #if defined(DEBUG_PROM_INIT) ---*/ void __init env_init(int *fw_arg2, enum _env_location env_location) { unsigned int i; char *p; struct _avm_kernel_urlader_env *urlader_env; static unsigned int once = 0; if(once) return; once = 1; if(env_location == ENV_LOCATION_AVM_CONF) { urlader_env = (struct _avm_kernel_urlader_env *) fw_arg2; for(i = 0; urlader_env[i].name[0] && i < 64; i++) { _local_envp[2*i] = (urlader_env[i].name); _local_envp[2*i + 1] = (urlader_env[i].value); } i *= 2; } else { _prom_envp = fw_arg2; #if defined(DEBUG_PROM_INIT) print_env( (char **)_prom_envp ); print_cmdline( fw_arg0, (char**)fw_arg1 ); #endif /*--- #if defined(DEBUG_PROM_INIT) ---*/ PROM_PRINTK("[prom_init] 0\n"); env_buffer[0] = '\0'; p = env_buffer; /*--------------------------------------------------------------------------------------*\ * copy envp values from urlader memory to (non init) kernel memory \*--------------------------------------------------------------------------------------*/ for(i = 0 ; _prom_envp && _prom_envp[i] && _prom_envp[i + 1] ; i += 2) { #if defined(DEBUG_PROM_INIT) PROM_PRINTK("[prom_init] envp[%u]= \"%s\"=\"%s\" \n", i, (char *)_prom_envp[i], (char *)_prom_envp[i + 1]); #endif /*--- #if defined(DEBUG_PROM_INIT) ---*/ _local_envp[i] = p; strcat(p, (char *)(_prom_envp[i])); p += strlen((char *)(_prom_envp[i])) + 1; while((unsigned int)p & 0x3) /*--- align auf naechstes wort ---*/ *p++ = '\0'; _local_envp[i + 1] = p; switch(env_location) { case ENV_LOCATION_FLASH: strcat(p, (char *)_prom_envp[i + 1]); p += strlen((char *)_prom_envp[i + 1]) + 1; break; case ENV_LOCATION_PHY_RAM: strcat(p, (char *)phys_to_virt(_prom_envp[i + 1])); p += strlen((char *)phys_to_virt(_prom_envp[i + 1])) + 1; break; case ENV_LOCATION_VIRT_RAM: strcat(p, (char *)(_prom_envp[i + 1])); p += strlen((char *)(_prom_envp[i + 1])) + 1; break; case ENV_LOCATION_AVM_CONF: /* Can not happen !! */ break; } while((unsigned int)p & 0x3) /*--- align auf naechstes wort ---*/ *p++ = '\0'; } } _local_envp[i] = NULL; _local_envp[i + 1] = NULL; _prom_envp = (int *)_local_envp; fritz_box_hw_revision = simple_strtoul(prom_getenv("HWRevision"), NULL, 10); } #endif char *__must_check prom_getenv(char *envname) { /* * Return a pointer to the given environment variable. * In 64-bit mode: we're using 64-bit pointers, but all pointers * in the PROM structures are only 32-bit, so we need some * workarounds, if we are running in 64-bit mode. */ #if IS_ENABLED(CONFIG_OF_AVM_DT_ENV) pr_debug("Retrieving %s from device tree\n", envname); return prom_getenv_device_tree(envname); #else int i, index=0; if(!_prom_envp) return NULL; i = strlen(envname); while (prom_envp(index)) { if(strncmp(envname, prom_envp(index), i) == 0) { return (prom_envp(index+1)); } index += 2; } return NULL; #endif } EXPORT_SYMBOL(prom_getenv); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- #define DEBUG_WLAN_DECT_CONFIG ---*/ #if defined(DEBUG_WLAN_DECT_CONFIG) #define DBG_WLAN_DECT(arg...) printk(KERN_ERR arg) #else #define DBG_WLAN_DECT(arg...) #endif #include #include #include #include extern struct mtd_info *urlader_mtd; static unsigned int wlan_dect_config[AVM_MAX_CONFIG_ENTRIES]; /*--------------------------------------------------------------------------------*\ * Sets the WLAN config pointers from the wlan_dect_configs entry in the device tree \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_ARCH_QCOM) || defined (CONFIG_OF_AVM_DT_ENV) int __init set_wlan_dect_config_address(unsigned int *pConfig __attribute__((unused))) { int i = 0; uint32_t _len; const uint32_t *config_ptr; //check for populated device tree if(of_have_populated_dt() == 0){ pr_err("[%s] Device Tree is not populated\n", __func__); return -1; } //check if the chosen node is set (should be set during unflattening) if(of_chosen == 0){ pr_err("[%s] Chosen Node not set \n", __func__); return -1; } //get the pointer to the wlan_dect_configs config_ptr = of_get_property(of_chosen, "wlan_dect_configs", &_len); if(!config_ptr){ pr_err("[%s] No wlan_dect_config found\n",__func__); return -1; } //len is given in bytes, but we store uint32_t pointers _len /= sizeof(uint32_t); //check if too many configs are stored in the device tree if(_len > AVM_MAX_CONFIG_ENTRIES) pr_err("[%s] Found more wlan_dect_configs than configured, %d > %d\n", __func__, _len, AVM_MAX_CONFIG_ENTRIES); //set the config pointers for(i = 0; i < _len; i++){ wlan_dect_config[i] = __be32_to_cpu(config_ptr[i]); DBG_WLAN_DECT("[set_wlan_dect_config] pConfig[%d] 0x%x\n", i, wlan_dect_config[i]); } //set the rest to 0 for(; i < AVM_MAX_CONFIG_ENTRIES; i++){ wlan_dect_config[i] = 0; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int __init wlan_dect_config_init(void) { return set_wlan_dect_config_address(NULL); } late_initcall(wlan_dect_config_init); //initialisation via late initcall #else /*--- #if defined(CONFIG_ARCH_QCOM) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int __init set_wlan_dect_config_address(unsigned int *pConfig) { int i = 0; while (i < AVM_MAX_CONFIG_ENTRIES) { wlan_dect_config[i] = pConfig[i] & ((128 << 10) - 1); #if defined(DEBUG_WLAN_DECT_CONFIG) prom_printf("[set_wlan_dect_config] pConfig[%d] 0x%x\n", i, wlan_dect_config[i]); #endif i++; } return 0; } #endif /*--- #else ---*/ /*--- #if defined(CONFIG_ARCH_QCOM) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int wlan_dect_read_config(struct wlan_dect_config *config, int offset, unsigned char *buffer, unsigned int bufferlen) { unsigned int readlen, status; unsigned int configlen = config->Len + sizeof(struct wlan_dect_config); /*--- den Header mitlesen ---*/ unsigned char *tmpbuffer; z_stream stream; memset(&stream, 0, sizeof(stream)); tmpbuffer = vmalloc(configlen + sizeof(unsigned int)); /*--- wir brauchen einen Buffer zum umkopieren ---*/ if (!tmpbuffer) { printk(KERN_ERR "[%s] ERROR: no mem %d\n", __FUNCTION__, configlen); return -1; } DBG_WLAN_DECT("[%s] Reading from 0x%x\n", __FUNCTION__, offset); urlader_mtd->_read(urlader_mtd, offset & ~1, configlen + sizeof(unsigned int), &readlen, tmpbuffer); if (readlen != (configlen + sizeof(unsigned int))) { printk(KERN_ERR"[%s] ERROR: read Data\n", __FUNCTION__); return -5; } if ((config->Type == WLAN_ZIP) || (config->Type == WLAN2_ZIP) || (config->Type == WLAN3_ZIP)) { struct wlan_dect_config *pconfig; stream.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); if ( ! stream.workspace) { printk(KERN_ERR "[%s] no space for workspace\n", __func__); return -7; } stream.data_type = Z_BINARY; stream.total_in = 0; zlib_inflateInit(&stream); memcpy(buffer, &tmpbuffer[offset & 1], sizeof(struct wlan_dect_config)); stream.next_in = &tmpbuffer[offset & 1] + sizeof(struct wlan_dect_config); stream.avail_in = config->Len; stream.next_out = buffer + sizeof(struct wlan_dect_config); stream.avail_out = bufferlen - sizeof(struct wlan_dect_config); status = zlib_inflate(&stream, Z_SYNC_FLUSH); if (status == Z_STREAM_END) { status = zlib_inflateEnd(&stream); } if (unlikely(status != Z_OK)) { pr_err("[%s:%d] ERROR: zlib_inflate Type %d %s %d\n", __func__, __LINE__, config->Type, stream.msg, status); } vfree(stream.workspace); pconfig = (struct wlan_dect_config *)buffer; pconfig->Len = stream.total_out; if (config->Type == WLAN_ZIP) config->Type = pconfig->Type = WLAN; else if (config->Type == WLAN2_ZIP) config->Type = pconfig->Type = WLAN2; else if (config->Type == WLAN3_ZIP) config->Type = pconfig->Type = WLAN3; } else { memcpy(buffer, config, sizeof(struct wlan_dect_config)); memcpy(&buffer[sizeof(struct wlan_dect_config)], &tmpbuffer[(offset & 1) + sizeof(struct wlan_dect_config)], config->Len); } vfree(tmpbuffer); #if defined(DEBUG_WLAN_DECT_CONFIG) { int x; printk(KERN_ERR "0x"); for (x=0;xLen;x++) printk("%02x ", buffer[x]); printk("\n"); } #endif return 0; } /*------------------------------------------------------------------------------------------*\ * die dect_wlan_config kann an einer ungeraden Adresse beginnen \*------------------------------------------------------------------------------------------*/ int get_wlan_dect_config(enum wlan_dect_type Type, unsigned char *buffer, unsigned int len) { int i; unsigned int readlen = 0; struct wlan_dect_config config; int offset; unsigned char tmpbuffer[2 * sizeof(struct wlan_dect_config)]; DBG_WLAN_DECT("[%s] Type %d buffer 0x%p len %d\n", __FUNCTION__, Type, buffer , len); for (i=0;i_read(urlader_mtd, offset & ~1, 2 * sizeof(struct wlan_dect_config), &readlen, tmpbuffer); DBG_WLAN_DECT("[%s] offset 0x%x readlen %d\n", __FUNCTION__, offset, readlen); if (readlen != 2 * sizeof(struct wlan_dect_config)) { DBG_WLAN_DECT("[%s] ERROR: read wlan_dect_config\n", __FUNCTION__); return -1; } memcpy(&config, &tmpbuffer[offset & 1], sizeof(struct wlan_dect_config)); config.Len = be16_to_cpu(config.Len); DBG_WLAN_DECT("[%s] Version 0x%x Type %d Len 0x%x\n", __FUNCTION__, config.Version, config.Type, config.Len); switch (config.Version) { case 1: case 2: if ((Type == WLAN) || (Type == WLAN2) || (Type == WLAN3)) { if ((config.Type == WLAN_ZIP) || (config.Type == WLAN2_ZIP) || (config.Type == WLAN3_ZIP)) { int status = wlan_dect_read_config(&config, offset, buffer, len); if (status < 0) { DBG_WLAN_DECT("[%s]ERROR: read ZIP Data\n", __func__); return -6; } DBG_WLAN_DECT("{%s} Type %d config.Type %d\n", __func__, Type, config.Type); if (Type == config.Type) return 0; } } if (Type != config.Type) { DBG_WLAN_DECT("[%s/%d] config.Type(%d) != Type(%d)\n", __FUNCTION__, __LINE__, config.Type, Type); break; /*--- nächster Konfigeintrag ---*/ } if ( ! (len >= config.Len + sizeof(struct wlan_dect_config))) { DBG_WLAN_DECT("[%s/%d] config.Type(%d) != Type(%d)\n", __FUNCTION__, __LINE__, config.Type, Type); return -2; /*--- buffer zu klein ---*/ } DBG_WLAN_DECT("[%s] read ", __FUNCTION__); switch (config.Type) { case WLAN: case WLAN2: case WLAN3: DBG_WLAN_DECT("WLAN\n"); break; case DECT: DBG_WLAN_DECT("DECT\n"); break; case DOCSIS: DBG_WLAN_DECT("DOCSIS\n"); break; case DSL: DBG_WLAN_DECT("DSL\n"); break; case ZERTIFIKATE: DBG_WLAN_DECT("ZERTIFIKATE\n"); break; default: DBG_WLAN_DECT("Type unknown\n"); return -3; } DBG_WLAN_DECT("[%s] uralder_mtd='%s', offset=%d, len=%d \n", __FUNCTION__, urlader_mtd->name, offset,config.Len + sizeof(struct wlan_dect_config)); if (wlan_dect_read_config(&config, offset, buffer, len) < 0) { DBG_WLAN_DECT("ERROR: read Data\n"); return -5; } return 0; case 0xFF: DBG_WLAN_DECT("[%s] Config Empty %x\n", __FUNCTION__, config.Version); break; default: DBG_WLAN_DECT("[%s] unknown Version %x\n", __FUNCTION__, config.Version); return -3; } } } return -1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int search_wlan_dect_config(enum wlan_dect_type Type, struct wlan_dect_config *config) { int i; unsigned int readlen = 0; int offset; unsigned char tmpbuffer[2 * sizeof(struct wlan_dect_config)]; if (!config) { printk( KERN_ERR "[%s] ERROR: no configbuffer\n", __FUNCTION__); return -1; } for (i=0;i_read(urlader_mtd, offset & ~1, 2 * sizeof(struct wlan_dect_config), &readlen, tmpbuffer); if (readlen != 2 * sizeof(struct wlan_dect_config)) { DBG_WLAN_DECT("[%s] ERROR: read wlan_dect_config\n", __FUNCTION__); return -2; } memcpy(config, &tmpbuffer[offset & 1], sizeof(struct wlan_dect_config)); config->Len = be16_to_cpu(config->Len); switch (config->Version) { case 1: case 2: DBG_WLAN_DECT("[%s] Type %d Len 0x%x\n", __FUNCTION__, config->Type, config->Len); if (Type != config->Type) { break; /*--- nächster Konfigeintrag ---*/ } return 1; default: printk( KERN_ERR "[%s] ERROR: unknown ConfigVersion 0x%x\n", __FUNCTION__, config->Version); break; } } } /*--- nix gefunden ---*/ memset(config, 0, sizeof(struct wlan_dect_config)); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int test_wlan_dect_config(char *buffer, size_t *bufferlen) { struct wlan_dect_config config; enum wlan_dect_type count = WLAN; int tmp = 0, len, error = 0; len = *bufferlen; *bufferlen = 0; buffer[0] = 0; /*--- damit strcat auch funktioniert ---*/ while (count < MAX_TYPE) { if (search_wlan_dect_config(count, &config)) { switch (config.Version) { case 1: case 2: switch (config.Type) { case WLAN: case WLAN_ZIP: strcat(buffer, "WLAN\n"); tmp = strlen("WLAN\n"); break; case WLAN2: case WLAN2_ZIP: strcat(buffer, "WLAN2\n"); tmp = strlen("WLAN2\n"); break; case WLAN3_ZIP: strcat(buffer, "WLAN3\n"); tmp = strlen("WLAN3\n"); break; case DECT: strcat(buffer, "DECT\n"); tmp = strlen("DECT\n"); break; case DOCSIS: strcat(buffer, "DOCSIS\n"); tmp = strlen("DOCSIS\n"); break; case ZERTIFIKATE: strcat(buffer, "ZERTIFIKATE\n"); tmp = strlen("ZERTIFIKATE\n"); break; default: printk( KERN_ERR "[%s] ERROR: unknown ConfigVersion 0x%x\n", __FUNCTION__, config.Version); error = -1; } break; case 0xFF: DBG_WLAN_DECT("[%s] Config Empty 0x%x\n", __func__, config.Version); break; default: printk( KERN_ERR "[%s] ERROR: unknown ConfigVersion 0x%x\n", __FUNCTION__, config.Version); error = -1; } if (len > tmp) { len -= tmp; *bufferlen += tmp; } else { DBG_WLAN_DECT( KERN_ERR "[%s] ERROR: Buffer\n", __FUNCTION__); error = -1; } } count++; } return error; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include int copy_wlan_dect_config2user(char *buffer, size_t bufferlen) { struct wlan_dect_config config; char *ConfigStrings[MAX_TYPE] = { "WLAN", /*--- 0 ---*/ "DECT", /*--- 1 ---*/ "WLAN2", /*--- 2 ---*/ "ZERTIFIKATE", /*--- 3 ---*/ "DOCSIS", /*--- 4 ---*/ "DSL" , /*--- 5 ---*/ "PROLIFIC", /*--- 6 ---*/ "WLAN_ZIP", /*--- 7 ---*/ "WLAN2_ZIP", /*--- 8 ---*/ "ZERTIFIKATE2", /*--- 9 ---*/ "ZERTIFIKATE3", /*--- 10 ---*/ "ZERTIFIKATE4", /*--- 11 ---*/ "FINAL", /*--- 12 ---*/ "PRODCERT1", /*--- 13 ---*/ "PRODCERT2", /*--- 14 ---*/ "PRODCERT3", /*--- 15 ---*/ "PRODCERT4", /*--- 16 ---*/ "PRODENV", /*--- 17 ---*/ "WLAN3_ZIP", /*--- 18 ---*/ "WLAN3" /*--- 19 ---*/ }; enum wlan_dect_type Type; char *p, *vbuffer, *map_buffer; struct file *fp; int configlen, written; if (!bufferlen) return -1; if (buffer[bufferlen-1] == '\n') { /*--- \n entfernen ---*/ buffer[bufferlen-1] = 0; bufferlen--; } for (Type = WLAN; Type < MAX_TYPE; Type++) { p = strstr(buffer, ConfigStrings[Type]); if (p) { if ((Type == WLAN) && (buffer[4] == '2')) /*--- WLAN & WLAN2 unterscheiden ---*/ continue; p += strlen(ConfigStrings[Type]); break; } } if (!p) { printk(KERN_ERR "ERROR: Type unknown\n"); return -1; } while (*p && (*p == ' ') && (p < &buffer[bufferlen])) /*--- die spaces im Pfadnamen löschen ---*/ p++; if (!search_wlan_dect_config(Type, &config)) { printk(KERN_ERR "ERROR: no Config found\n"); return -1; /*--- keine Config gefunden ---*/ } configlen = config.Len + sizeof(struct wlan_dect_config); /*--- wir müssen den Header mitlesen ---*/ fp = filp_open(p, O_CREAT, FMODE_READ|FMODE_WRITE); /*--- open read/write ---*/ if(IS_ERR(fp)) { printk("ERROR: Could not open file %s\n", p); return -1; } map_buffer = (unsigned char *)vm_mmap(0, 0, configlen, PROT_READ|PROT_WRITE, MAP_SHARED, 0); if (IS_ERR(buffer)) { printk("ERROR: no mem 0x%p\n", map_buffer); return -1; } vbuffer = (char *)vmalloc(configlen); /*--- wir brauchen einen Buffer zum umkopieren ---*/ if (!vbuffer) { printk("ERROR: no mem\n"); return -1; } /*--- printk("test 0x%p\n", current->mm); ---*/ if (!get_wlan_dect_config(Type, vbuffer, configlen)) { memcpy(map_buffer, &vbuffer[sizeof(struct wlan_dect_config)], config.Len); /*--- umkopieren & den Header verwerfen ---*/ written = fp->f_op->write(fp, map_buffer, config.Len, &fp->f_pos); /*--- die Datei schreiben ---*/ vm_munmap((unsigned long)map_buffer, configlen); /*--- den buffer wieder frei geben ---*/ vfree(vbuffer); if (written != config.Len) { printk("ERROR: write Config\n"); return -1; } } else { do_munmap(current->mm, (unsigned long)map_buffer, configlen); /*--- den buffer wieder frei geben ---*/ vfree(vbuffer); printk("ERROR: read Config\n"); return -1; } return 0; } EXPORT_SYMBOL(copy_wlan_dect_config2user); EXPORT_SYMBOL(test_wlan_dect_config); EXPORT_SYMBOL(get_wlan_dect_config); EXPORT_SYMBOL(set_wlan_dect_config_address); /* vim: set noexpandtab sw=4 ts=4 sts=0: */