12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
287ab4e20SRemi Denis-Courmont /*
387ab4e20SRemi Denis-Courmont * File: sysctl.c
487ab4e20SRemi Denis-Courmont *
587ab4e20SRemi Denis-Courmont * Phonet /proc/sys/net/phonet interface implementation
687ab4e20SRemi Denis-Courmont *
787ab4e20SRemi Denis-Courmont * Copyright (C) 2008 Nokia Corporation.
887ab4e20SRemi Denis-Courmont *
931fdc555SRémi Denis-Courmont * Author: Rémi Denis-Courmont
1087ab4e20SRemi Denis-Courmont */
1187ab4e20SRemi Denis-Courmont
1287ab4e20SRemi Denis-Courmont #include <linux/seqlock.h>
1387ab4e20SRemi Denis-Courmont #include <linux/sysctl.h>
1487ab4e20SRemi Denis-Courmont #include <linux/errno.h>
1587ab4e20SRemi Denis-Courmont #include <linux/init.h>
1687ab4e20SRemi Denis-Courmont
178e052e52SRémi Denis-Courmont #include <net/sock.h>
188e052e52SRémi Denis-Courmont #include <linux/phonet.h>
198e052e52SRémi Denis-Courmont #include <net/phonet/phonet.h>
208e052e52SRémi Denis-Courmont
2187ab4e20SRemi Denis-Courmont #define DYNAMIC_PORT_MIN 0x40
2287ab4e20SRemi Denis-Courmont #define DYNAMIC_PORT_MAX 0x7f
2387ab4e20SRemi Denis-Courmont
2487ab4e20SRemi Denis-Courmont static DEFINE_SEQLOCK(local_port_range_lock);
2587ab4e20SRemi Denis-Courmont static int local_port_range_min[2] = {0, 0};
2687ab4e20SRemi Denis-Courmont static int local_port_range_max[2] = {1023, 1023};
2787ab4e20SRemi Denis-Courmont static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
2887ab4e20SRemi Denis-Courmont static struct ctl_table_header *phonet_table_hrd;
2987ab4e20SRemi Denis-Courmont
set_local_port_range(int range[2])3087ab4e20SRemi Denis-Courmont static void set_local_port_range(int range[2])
3187ab4e20SRemi Denis-Courmont {
3287ab4e20SRemi Denis-Courmont write_seqlock(&local_port_range_lock);
3387ab4e20SRemi Denis-Courmont local_port_range[0] = range[0];
3487ab4e20SRemi Denis-Courmont local_port_range[1] = range[1];
3587ab4e20SRemi Denis-Courmont write_sequnlock(&local_port_range_lock);
3687ab4e20SRemi Denis-Courmont }
3787ab4e20SRemi Denis-Courmont
phonet_get_local_port_range(int * min,int * max)3887ab4e20SRemi Denis-Courmont void phonet_get_local_port_range(int *min, int *max)
3987ab4e20SRemi Denis-Courmont {
4095c96174SEric Dumazet unsigned int seq;
4195c96174SEric Dumazet
4287ab4e20SRemi Denis-Courmont do {
4387ab4e20SRemi Denis-Courmont seq = read_seqbegin(&local_port_range_lock);
4487ab4e20SRemi Denis-Courmont if (min)
4587ab4e20SRemi Denis-Courmont *min = local_port_range[0];
4687ab4e20SRemi Denis-Courmont if (max)
4787ab4e20SRemi Denis-Courmont *max = local_port_range[1];
4887ab4e20SRemi Denis-Courmont } while (read_seqretry(&local_port_range_lock, seq));
4987ab4e20SRemi Denis-Courmont }
5087ab4e20SRemi Denis-Courmont
proc_local_port_range(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)51fe2c6338SJoe Perches static int proc_local_port_range(struct ctl_table *table, int write,
52*32927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos)
5387ab4e20SRemi Denis-Courmont {
5487ab4e20SRemi Denis-Courmont int ret;
5587ab4e20SRemi Denis-Courmont int range[2] = {local_port_range[0], local_port_range[1]};
56fe2c6338SJoe Perches struct ctl_table tmp = {
5787ab4e20SRemi Denis-Courmont .data = &range,
5887ab4e20SRemi Denis-Courmont .maxlen = sizeof(range),
5987ab4e20SRemi Denis-Courmont .mode = table->mode,
6087ab4e20SRemi Denis-Courmont .extra1 = &local_port_range_min,
6187ab4e20SRemi Denis-Courmont .extra2 = &local_port_range_max,
6287ab4e20SRemi Denis-Courmont };
6387ab4e20SRemi Denis-Courmont
648d65af78SAlexey Dobriyan ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
6587ab4e20SRemi Denis-Courmont
6687ab4e20SRemi Denis-Courmont if (write && ret == 0) {
6787ab4e20SRemi Denis-Courmont if (range[1] < range[0])
6887ab4e20SRemi Denis-Courmont ret = -EINVAL;
6987ab4e20SRemi Denis-Courmont else
7087ab4e20SRemi Denis-Courmont set_local_port_range(range);
7187ab4e20SRemi Denis-Courmont }
7287ab4e20SRemi Denis-Courmont
7387ab4e20SRemi Denis-Courmont return ret;
7487ab4e20SRemi Denis-Courmont }
7587ab4e20SRemi Denis-Courmont
7687ab4e20SRemi Denis-Courmont static struct ctl_table phonet_table[] = {
7787ab4e20SRemi Denis-Courmont {
7887ab4e20SRemi Denis-Courmont .procname = "local_port_range",
7987ab4e20SRemi Denis-Courmont .data = &local_port_range,
8087ab4e20SRemi Denis-Courmont .maxlen = sizeof(local_port_range),
8187ab4e20SRemi Denis-Courmont .mode = 0644,
826d9f239aSAlexey Dobriyan .proc_handler = proc_local_port_range,
8387ab4e20SRemi Denis-Courmont },
84f8572d8fSEric W. Biederman { }
8587ab4e20SRemi Denis-Courmont };
8687ab4e20SRemi Denis-Courmont
phonet_sysctl_init(void)8787ab4e20SRemi Denis-Courmont int __init phonet_sysctl_init(void)
8887ab4e20SRemi Denis-Courmont {
89ec8f23ceSEric W. Biederman phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
9087ab4e20SRemi Denis-Courmont return phonet_table_hrd == NULL ? -ENOMEM : 0;
9187ab4e20SRemi Denis-Courmont }
9287ab4e20SRemi Denis-Courmont
phonet_sysctl_exit(void)9387ab4e20SRemi Denis-Courmont void phonet_sysctl_exit(void)
9487ab4e20SRemi Denis-Courmont {
955dd3df10SEric W. Biederman unregister_net_sysctl_table(phonet_table_hrd);
9687ab4e20SRemi Denis-Courmont }
97