Commit | Line | Data |
---|---|---|
87ab4e20 RDC |
1 | /* |
2 | * File: sysctl.c | |
3 | * | |
4 | * Phonet /proc/sys/net/phonet interface implementation | |
5 | * | |
6 | * Copyright (C) 2008 Nokia Corporation. | |
7 | * | |
8 | * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License | |
12 | * version 2 as published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
22 | * 02110-1301 USA | |
23 | */ | |
24 | ||
25 | #include <linux/seqlock.h> | |
26 | #include <linux/sysctl.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/init.h> | |
29 | ||
30 | #define DYNAMIC_PORT_MIN 0x40 | |
31 | #define DYNAMIC_PORT_MAX 0x7f | |
32 | ||
33 | static DEFINE_SEQLOCK(local_port_range_lock); | |
34 | static int local_port_range_min[2] = {0, 0}; | |
35 | static int local_port_range_max[2] = {1023, 1023}; | |
36 | static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX}; | |
37 | static struct ctl_table_header *phonet_table_hrd; | |
38 | ||
39 | static void set_local_port_range(int range[2]) | |
40 | { | |
41 | write_seqlock(&local_port_range_lock); | |
42 | local_port_range[0] = range[0]; | |
43 | local_port_range[1] = range[1]; | |
44 | write_sequnlock(&local_port_range_lock); | |
45 | } | |
46 | ||
47 | void phonet_get_local_port_range(int *min, int *max) | |
48 | { | |
49 | unsigned seq; | |
50 | do { | |
51 | seq = read_seqbegin(&local_port_range_lock); | |
52 | if (min) | |
53 | *min = local_port_range[0]; | |
54 | if (max) | |
55 | *max = local_port_range[1]; | |
56 | } while (read_seqretry(&local_port_range_lock, seq)); | |
57 | } | |
58 | ||
8d65af78 | 59 | static int proc_local_port_range(ctl_table *table, int write, |
87ab4e20 RDC |
60 | void __user *buffer, |
61 | size_t *lenp, loff_t *ppos) | |
62 | { | |
63 | int ret; | |
64 | int range[2] = {local_port_range[0], local_port_range[1]}; | |
65 | ctl_table tmp = { | |
66 | .data = &range, | |
67 | .maxlen = sizeof(range), | |
68 | .mode = table->mode, | |
69 | .extra1 = &local_port_range_min, | |
70 | .extra2 = &local_port_range_max, | |
71 | }; | |
72 | ||
8d65af78 | 73 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); |
87ab4e20 RDC |
74 | |
75 | if (write && ret == 0) { | |
76 | if (range[1] < range[0]) | |
77 | ret = -EINVAL; | |
78 | else | |
79 | set_local_port_range(range); | |
80 | } | |
81 | ||
82 | return ret; | |
83 | } | |
84 | ||
85 | static struct ctl_table phonet_table[] = { | |
86 | { | |
87ab4e20 RDC |
87 | .procname = "local_port_range", |
88 | .data = &local_port_range, | |
89 | .maxlen = sizeof(local_port_range), | |
90 | .mode = 0644, | |
6d9f239a | 91 | .proc_handler = proc_local_port_range, |
87ab4e20 | 92 | }, |
f8572d8f | 93 | { } |
87ab4e20 RDC |
94 | }; |
95 | ||
5eaa65b2 | 96 | static struct ctl_path phonet_ctl_path[] = { |
f8572d8f EB |
97 | { .procname = "net", }, |
98 | { .procname = "phonet", }, | |
87ab4e20 RDC |
99 | { }, |
100 | }; | |
101 | ||
102 | int __init phonet_sysctl_init(void) | |
103 | { | |
104 | phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table); | |
105 | return phonet_table_hrd == NULL ? -ENOMEM : 0; | |
106 | } | |
107 | ||
108 | void phonet_sysctl_exit(void) | |
109 | { | |
110 | unregister_sysctl_table(phonet_table_hrd); | |
111 | } |