#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; } pr_err("Could not find Env '%s' in the device tree\n", envname); return 0; } 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; 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; } } #if defined(CONFIG_MIPS) 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]); } } #include #endif /*--- #if defined(CONFIG_MIPS) ---*/ #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; 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); #if defined(CONFIG_MIPS) print_cmdline(fw_arg0, (char **)fw_arg1); #endif /*--- #if defined(CONFIG_MIPS) ---*/ #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; /*--- align auf naechstes wort ---*/ while ((unsigned int)p & 0x3) *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; } /*--- align auf naechstes wort ---*/ while ((unsigned int)p & 0x3) *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...) pr_err(arg) #else #define DBG_WLAN_DECT(arg...) #endif #include #include #include #include #include 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) ---*/ EXPORT_SYMBOL(set_wlan_dect_config_address); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static int wlan_dect_read_config(struct wlan_dect_config *config, int offset, unsigned char *buffer, unsigned int bufferlen) { unsigned int readlen, status; /*--- den Header mitlesen ---*/ unsigned int configlen = config->Len + sizeof(struct wlan_dect_config); unsigned char *tmpbuffer; z_stream stream; memset(&stream, 0, sizeof(stream)); /*--- wir brauchen einen Buffer zum umkopieren ---*/ tmpbuffer = vmalloc(configlen + sizeof(unsigned int)); if (!tmpbuffer) { pr_err("[%s] ERROR: no mem %d\n", __func__, configlen); return -1; } DBG_WLAN_DECT("[%s] Reading from 0x%x\n", __func__, offset); urlader_mtd->_read(urlader_mtd, offset & ~1, configlen + sizeof(unsigned int), &readlen, tmpbuffer); if (readlen != (configlen + sizeof(unsigned int))) { pr_err("[%s] ERROR: read Data\n", __func__); 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) { pr_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; pr_err("0x"); for (x = 0; x < config->Len; x++) pr_err("%02x ", buffer[x]); pr_err("\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", __func__, Type, buffer, len); for (i = 0; i < AVM_MAX_CONFIG_ENTRIES; i++) { DBG_WLAN_DECT("[%s] wlan_dect_config[%d] 0x%x\n", __func__, i, wlan_dect_config[i]); if (!wlan_dect_config[i]) continue; /*--- Eintrag vorhanden und nicht leer ---*/ offset = wlan_dect_config[i]; urlader_mtd->_read(urlader_mtd, offset & ~1, 2 * sizeof(struct wlan_dect_config), &readlen, tmpbuffer); DBG_WLAN_DECT("[%s] offset 0x%x readlen %d\n", __func__, offset, readlen); if (readlen != 2 * sizeof(struct wlan_dect_config)) { DBG_WLAN_DECT("[%s] ERROR: read wlan_dect_config\n", __func__); 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", __func__, config.Version, config.Type, config.Len); switch (config.Version) { case 1: case 2: if (( (Type == WLAN) || (Type == WLAN2) || (Type == WLAN3) ) && ( (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", __func__, __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", __func__, __LINE__, config.Type, Type); return -2; /*--- buffer zu klein ---*/ } DBG_WLAN_DECT("[%s] read ", __func__); 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; case AVMZERTIFIKATE: DBG_WLAN_DECT("AVMZERTIFIKATE\n"); break; default: DBG_WLAN_DECT("Type unknown\n"); return -3; } DBG_WLAN_DECT("[%s] uralder_mtd='%s', offset=%d, len=%d\n", __func__, 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", __func__, config.Version); break; default: DBG_WLAN_DECT("[%s] unknown Version %x\n", __func__, config.Version); return -3; } } return -1; } EXPORT_SYMBOL(get_wlan_dect_config); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ 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) { pr_err("[%s] ERROR: no configbuffer\n", __func__); return -1; } for (i = 0; i < AVM_MAX_CONFIG_ENTRIES; i++) { DBG_WLAN_DECT("[%s] wlan_dect_config[%d] 0x%x\n", __func__, i, wlan_dect_config[i]); if (wlan_dect_config[i]) { /*--- Eintrag vorhanden und nicht leer ---*/ offset = wlan_dect_config[i]; urlader_mtd->_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", __func__); 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", __func__, config->Type, config->Len); if (Type != config->Type) { /*--- nächster Konfigeintrag ---*/ break; } return 1; default: pr_err("[%s] ERROR: unknown ConfigVersion 0x%x\n", __func__, 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; case AVMZERTIFIKATE: strcat(buffer, "AVMZERTIFIKATE\n"); tmp = strlen("AVMZERTIFIKATE\n"); break; default: pr_err("[%s] ERROR: unknown ConfigVersion 0x%x\n", __func__, config.Version); error = -1; } break; case 0xFF: DBG_WLAN_DECT("[%s] Config Empty 0x%x\n", __func__, config.Version); break; default: pr_err("[%s] ERROR: unknown ConfigVersion 0x%x\n", __func__, config.Version); error = -1; } if (len > tmp) { len -= tmp; *bufferlen += tmp; } else { DBG_WLAN_DECT(KERN_ERR "[%s] ERROR: Buffer\n", __func__); error = -1; } } count++; } return error; } EXPORT_SYMBOL(test_wlan_dect_config); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ #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 ---*/ "AVMZERTIFIKATE" /*--- 20 ---*/ }; 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) { /*--- WLAN & WLAN2 unterscheiden ---*/ if ((Type == WLAN) && (buffer[4] == '2')) continue; p += strlen(ConfigStrings[Type]); break; } } if (!p) { pr_err("ERROR: Type unknown\n"); return -1; } /*--- die spaces im Pfadnamen löschen ---*/ while (*p && (*p == ' ') && (p < &buffer[bufferlen])) p++; if (!search_wlan_dect_config(Type, &config)) { pr_err("ERROR: no Config found\n"); return -1; /*--- keine Config gefunden ---*/ } /*--- wir müssen den Header mitlesen ---*/ configlen = config.Len + sizeof(struct wlan_dect_config); /*--- open read/write ---*/ fp = filp_open(p, O_CREAT, FMODE_READ|FMODE_WRITE); if (IS_ERR(fp)) { pr_err("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)) { pr_err("ERROR: no mem 0x%p\n", map_buffer); return -1; } /*--- wir brauchen einen Buffer zum umkopieren ---*/ vbuffer = vmalloc(configlen); if (!vbuffer) { pr_err("ERROR: no mem\n"); return -1; } /*--- printk("test 0x%p\n", current->mm); ---*/ if (!get_wlan_dect_config(Type, vbuffer, configlen)) { /*--- umkopieren & den Header verwerfen ---*/ memcpy(map_buffer, &vbuffer[sizeof(struct wlan_dect_config)], config.Len); /*--- die Datei schreiben ---*/ written = fp->f_op->write(fp, map_buffer, config.Len, &fp->f_pos); /*--- den buffer wieder frei geben ---*/ vm_munmap((unsigned long)map_buffer, configlen); vfree(vbuffer); if (written != config.Len) { pr_err("ERROR: write Config\n"); return -1; } } else { /*--- den buffer wieder frei geben ---*/ do_munmap(current->mm, (unsigned long)map_buffer, configlen); vfree(vbuffer); pr_err("ERROR: read Config\n"); return -1; } return 0; } EXPORT_SYMBOL(copy_wlan_dect_config2user);