From 87ab4e20b445c6d2d2727ab4f96fa17f7259511e Mon Sep 17 00:00:00 2001 From: Remi Denis-Courmont Date: Mon, 22 Sep 2008 20:08:39 -0700 Subject: Phonet: proc interface for port range Phonet endpoints are bound to individual ports. This provides a /proc/sys/net/phonet (or sysctl) interface for selecting the range of automatically allocated ports (much like the ip_local_port_range with IPv4). Signed-off-by: Remi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/Makefile | 1 + net/phonet/af_phonet.c | 3 ++ net/phonet/socket.c | 3 +- net/phonet/sysctl.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 net/phonet/sysctl.c (limited to 'net/phonet') diff --git a/net/phonet/Makefile b/net/phonet/Makefile index d218abc3f06..ae9c3ed5be8 100644 --- a/net/phonet/Makefile +++ b/net/phonet/Makefile @@ -5,4 +5,5 @@ phonet-objs := \ pn_netlink.o \ socket.o \ datagram.o \ + sysctl.o \ af_phonet.o diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 51397ff308b..50dc258d5aa 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -350,6 +350,7 @@ static int __init phonet_init(void) phonet_device_init(); dev_add_pack(&phonet_packet_type); phonet_netlink_register(); + phonet_sysctl_init(); err = isi_register(); if (err) @@ -357,6 +358,7 @@ static int __init phonet_init(void) return 0; err: + phonet_sysctl_exit(); sock_unregister(AF_PHONET); dev_remove_pack(&phonet_packet_type); phonet_device_exit(); @@ -366,6 +368,7 @@ err: static void __exit phonet_exit(void) { isi_unregister(); + phonet_sysctl_exit(); sock_unregister(AF_PHONET); dev_remove_pack(&phonet_packet_type); phonet_device_exit(); diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 99a4945d565..dfd4061646d 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -273,8 +273,9 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) if (!sport) { /* search free port */ - int port, pmin = 0x40, pmax = 0x7f; + int port, pmin, pmax; + phonet_get_local_port_range(&pmin, &pmax); for (port = pmin; port <= pmax; port++) { port_cur++; if (port_cur < pmin || port_cur > pmax) diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c new file mode 100644 index 00000000000..600a4309b8c --- /dev/null +++ b/net/phonet/sysctl.c @@ -0,0 +1,113 @@ +/* + * File: sysctl.c + * + * Phonet /proc/sys/net/phonet interface implementation + * + * Copyright (C) 2008 Nokia Corporation. + * + * Contact: Remi Denis-Courmont + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include + +#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 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(ctl_table *table, int write, struct file *filp, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + int ret; + int range[2] = {local_port_range[0], local_port_range[1]}; + 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, filp, 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[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "local_port_range", + .data = &local_port_range, + .maxlen = sizeof(local_port_range), + .mode = 0644, + .proc_handler = &proc_local_port_range, + .strategy = NULL, + }, + { .ctl_name = 0 } +}; + +struct ctl_path phonet_ctl_path[] = { + { .procname = "net", .ctl_name = CTL_NET, }, + { .procname = "phonet", .ctl_name = CTL_UNNUMBERED, }, + { }, +}; + +int __init phonet_sysctl_init(void) +{ + phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table); + return phonet_table_hrd == NULL ? -ENOMEM : 0; +} + +void phonet_sysctl_exit(void) +{ + unregister_sysctl_table(phonet_table_hrd); +} -- cgit v1.2.3