/* * Copyright (C) 2017 jianhui zhao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include "config.h" static struct proc_dir_entry *proc; static struct config conf; static int update_gw_interface(const char *interface) { int ret = 0; struct net_device *dev; struct in_device *in_dev; dev = dev_get_by_name(&init_net, interface); if (!dev) { pr_err("Not found interface: %s\n", interface); return -ENOENT; } conf.interface_ifindex = dev->ifindex; in_dev = inetdev_by_index(dev_net(dev), conf.interface_ifindex); if (!in_dev) { pr_err("Not found in_dev on %s\n", interface); ret = -ENOENT; goto QUIT; } for_primary_ifa(in_dev) { conf.interface_ipaddr = ifa->ifa_local; conf.interface_mask = ifa->ifa_mask; conf.interface_broadcast = ifa->ifa_broadcast; pr_info("Found ip from %s: %pI4\n", interface, &conf.interface_ipaddr); break; } endfor_ifa(in_dev) QUIT: dev_put(dev); return ret; } static int proc_config_show(struct seq_file *s, void *v) { seq_printf(s, "enabled(RW) = %d\n", conf.enabled); seq_printf(s, "interface(RW) = %s\n", conf.interface); seq_printf(s, "ipaddr(RO) = %pI4\n", &conf.interface_ipaddr); seq_printf(s, "netmask(RO) = %pI4\n", &conf.interface_mask); seq_printf(s, "broadcast(RO) = %pI4\n", &conf.interface_broadcast); seq_printf(s, "port(RW) = %d\n", conf.port); seq_printf(s, "ssl_port(RW) = %d\n", conf.ssl_port); return 0; } static ssize_t proc_config_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { char data[128]; char *delim, *key; const char *value; int update = 0; if (size == 0) return -EINVAL; if (size > sizeof(data)) size = sizeof(data); if (copy_from_user(data, buf, size)) return -EFAULT; data[size - 1] = 0; key = data; while (key && *key) { while (*key && (*key == ' ')) key++; delim = strchr(key, '='); if (!delim) break; *delim++ = 0; value = delim; delim = strchr(value, '\n'); if (delim) *delim++ = 0; if (!strcmp(key, "enabled")) { conf.enabled = simple_strtol(value, NULL, 0); if (conf.enabled) update = 1; pr_info("wifidog %s\n", conf.enabled ? "enabled" : "disabled"); } else if (!strcmp(key, "interface")) { strncpy(conf.interface, value, sizeof(conf.interface) - 1); update = 1; } else if (!strcmp(key, "port")) { conf.port = simple_strtol(value, NULL, 0); } else if (!strcmp(key, "ssl_port")) { conf.ssl_port = simple_strtol(value, NULL, 0); } key = delim; } if (update) update_gw_interface(conf.interface); return size; } static int proc_config_open(struct inode *inode, struct file *file) { return single_open(file, proc_config_show, NULL); } const static struct file_operations proc_config_ops = { .owner = THIS_MODULE, .open = proc_config_open, .read = seq_read, .write = proc_config_write, .llseek = seq_lseek, .release = single_release }; int init_config(void) { int ret = 0; conf.interface_ifindex= -1; conf.port = 2060; conf.ssl_port = 8443; strcpy(conf.interface, "br-lan"); proc = proc_mkdir(PROC_DIR_NAME, NULL); if (!proc) { pr_err("can't create dir /proc/"PROC_DIR_NAME"/\n"); return -ENODEV;; } if (!proc_create("config", 0644, proc, &proc_config_ops)) { pr_err("can't create file /proc/"PROC_DIR_NAME"/config\n"); ret = -EINVAL; goto remove; } return 0; remove: remove_proc_entry(PROC_DIR_NAME, NULL); return ret; } void deinit_config(void) { remove_proc_entry("config", proc); remove_proc_entry(PROC_DIR_NAME, NULL); } struct config *get_config(void) { return &conf; }