#if __has_include() #include #else #include #endif #include #include #include #include "conf.h" struct avm_coredump_conf *conf; static char *family = NULL; static char *source_port = NULL; static char *logdump_port = NULL; static char *source_mac = NULL; static char *source_ip = NULL; static char *target_mac = NULL; static char *target_ip = NULL; module_param(family, charp, 0); MODULE_PARM_DESC(family, "Address family"); module_param(source_port, charp, 0); MODULE_PARM_DESC(source_port, "Source Port"); module_param(logdump_port, charp, 0); MODULE_PARM_DESC(logdump_part, "Logdump Port"); module_param(source_mac, charp, 0); MODULE_PARM_DESC(source_mac, "Source MAC Address"); module_param(source_ip, charp, 0); MODULE_PARM_DESC(source_ip, "Source IP Address"); module_param(target_mac, charp, 0); MODULE_PARM_DESC(target_mac, "Target MAC Address"); module_param(target_ip, charp, 0); MODULE_PARM_DESC(target_ip, "Target IP Address"); static bool is_ln_or_nul(char c) { return c == '\n' || c == '\0'; } static int input_family(char *buffer, void *dest) { sa_family_t *fam = dest; if (strlen(buffer) != strlen("ipv6") && strlen(buffer) != strlen("ipv6\n")) { return -EINVAL; } if (strncmp(buffer, "ipv6", strlen("ipv6")) == 0) { *fam = AF_INET6; } else if (strncmp(buffer, "ipv4", strlen("ipv4")) == 0) { *fam = AF_INET; } else { return -EINVAL; } return 0; } static void output_family(struct seq_file *file, void *dest) { static const char* fam_strs[] = { "ipv4", "ipv6" }; static const sa_family_t fams[] = { AF_INET, AF_INET6 }; sa_family_t *fam = dest; unsigned int i; for (i = 0; i < ARRAY_SIZE(fams); i++) { if (*fam == fams[i]) { seq_printf(file, "["); } seq_printf(file, "%s", fam_strs[i]); if (*fam == fams[i]) { seq_printf(file, "]"); } if (i != ARRAY_SIZE(fams) - 1) { seq_printf(file, " "); } } seq_printf(file, "\n"); } static int input_ip(char *buffer, void *dest) { const char *end = NULL; // Look for clearing ip address if (is_ln_or_nul(*buffer)) { memset(dest, 0, 16); } else if (conf->family == AF_INET6 && in6_pton(buffer, -1, dest, -1, &end) && end && is_ln_or_nul(*end)) { return 0; } else if (conf->family == AF_INET && in4_pton(buffer, -1, dest, -1, &end) && end && is_ln_or_nul(*end)) { return 0; } return -EINVAL; } static void output_ip(struct seq_file *file, void *source) { if (conf->family == AF_INET6) { seq_printf(file, "%pI6c\n", source); } else if (conf->family == AF_INET) { seq_printf(file, "%pI4\n", source); } } static int input_mac(char *buffer, void *dest) { int ret; int i; u8 *mac = (u8*)dest; if (strlen(buffer) < 17) { return -1; } for (i = 0; i < 6; i++, buffer += 3, mac++) { buffer[2] = '\0'; ret = kstrtou8(buffer, 16, mac); if (ret != 0) { return ret; } } return 0; } static void output_mac(struct seq_file *file, void *source) { seq_printf(file, "%pM\n", source); } static int input_port(char *buffer, void *dest) { u16* port = (u16*)dest; return kstrtou16(buffer, 10, port); } static void output_port(struct seq_file *file, void *source) { u16* port = (u16*)source; seq_printf(file, "%d\n", *port); } static int avm_coredump_late_conf_init(void) { int ret = 0; proc_mkdir("avm/coredump", NULL); #define ADD_PROC(name, func) \ ret = add_simple_proc_file("avm/coredump/" #name, input_##func, output_##func, &conf->name); \ if (ret != 0) { \ goto fail; \ } ADD_PROC(family, family); ADD_PROC(target_ip, ip); ADD_PROC(target_mac, mac); #if IS_MODULE(CONFIG_AVM_COREDUMP) ADD_PROC(coredump_port, port); #endif ADD_PROC(logdump_port, port); ADD_PROC(source_ip, ip); ADD_PROC(source_mac, mac); ADD_PROC(source_port, port); #undef ADD_PROC fail: return ret; } #if IS_BUILTIN(CONFIG_AVM_COREDUMP) late_initcall(avm_coredump_late_conf_init); #endif int avm_coredump_conf_init(void) { int ret = 0; #define PARSE_PARAM(name, func) \ if (name != NULL) { \ ret = input_##func(name, &conf->name); \ if (ret != 0) { \ goto fail; \ } \ } PARSE_PARAM(family, family); PARSE_PARAM(target_ip, ip); PARSE_PARAM(target_mac, mac); PARSE_PARAM(logdump_port, port); PARSE_PARAM(source_ip, ip); PARSE_PARAM(source_mac, mac); PARSE_PARAM(source_port, port); #undef PARSE_PARAM #if IS_MODULE(CONFIG_AVM_COREDUMP) avm_coredump_late_conf_init(); #endif fail: return ret; } void avm_coredump_conf_exit(void) { remove_simple_proc_file("avm/coredump/source_port"); remove_simple_proc_file("avm/coredump/source_mac"); remove_simple_proc_file("avm/coredump/source_ip"); #if IS_MODULE(CONFIG_AVM_COREDUMP) remove_simple_proc_file("avm/coredump/coredump_port"); #endif remove_simple_proc_file("avm/coredump/logdump_port"); remove_simple_proc_file("avm/coredump/target_mac"); remove_simple_proc_file("avm/coredump/target_ip"); remove_simple_proc_file("avm/coredump/family"); }