alistair23-linux/net/phonet/sysctl.c
Christoph Hellwig 32927393dc sysctl: pass kernel pointers to ->proc_handler
Instead of having all the sysctl handlers deal with user pointers, which
is rather hairy in terms of the BPF interaction, copy the input to and
from  userspace in common code.  This also means that the strings are
always NUL-terminated by the common code, making the API a little bit
safer.

As most handler just pass through the data to one of the common handlers
a lot of the changes are mechnical.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2020-04-27 02:07:40 -04:00

97 lines
2.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* File: sysctl.c
*
* Phonet /proc/sys/net/phonet interface implementation
*
* Copyright (C) 2008 Nokia Corporation.
*
* Author: RĂ©mi Denis-Courmont
*/
#include <linux/seqlock.h>
#include <linux/sysctl.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/phonet.h>
#include <net/phonet/phonet.h>
#define DYNAMIC_PORT_MIN 0x40
#define DYNAMIC_PORT_MAX 0x7f
static DEFINE_SEQLOCK(local_port_range_lock);
static int local_port_range_min[2] = {0, 0};
static int local_port_range_max[2] = {1023, 1023};
static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
static struct ctl_table_header *phonet_table_hrd;
static void set_local_port_range(int range[2])
{
write_seqlock(&local_port_range_lock);
local_port_range[0] = range[0];
local_port_range[1] = range[1];
write_sequnlock(&local_port_range_lock);
}
void phonet_get_local_port_range(int *min, int *max)
{
unsigned int seq;
do {
seq = read_seqbegin(&local_port_range_lock);
if (min)
*min = local_port_range[0];
if (max)
*max = local_port_range[1];
} while (read_seqretry(&local_port_range_lock, seq));
}
static int proc_local_port_range(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
int range[2] = {local_port_range[0], local_port_range[1]};
struct ctl_table tmp = {
.data = &range,
.maxlen = sizeof(range),
.mode = table->mode,
.extra1 = &local_port_range_min,
.extra2 = &local_port_range_max,
};
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && ret == 0) {
if (range[1] < range[0])
ret = -EINVAL;
else
set_local_port_range(range);
}
return ret;
}
static struct ctl_table phonet_table[] = {
{
.procname = "local_port_range",
.data = &local_port_range,
.maxlen = sizeof(local_port_range),
.mode = 0644,
.proc_handler = proc_local_port_range,
},
{ }
};
int __init phonet_sysctl_init(void)
{
phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
return phonet_table_hrd == NULL ? -ENOMEM : 0;
}
void phonet_sysctl_exit(void)
{
unregister_net_sysctl_table(phonet_table_hrd);
}