You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

174 lines
4.2 KiB

/*
* Copyright (C) 2017 jianhui zhao <jianhuizhao329@gmail.com>
*
* 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 <linux/uaccess.h>
#include <linux/inetdevice.h>
#include <linux/seq_file.h>
#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;
}