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 | * | |
31fdc555 | 8 | * Author: Rémi Denis-Courmont |
87ab4e20 RDC |
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 | ||
8e052e52 RDC |
30 | #include <net/sock.h> |
31 | #include <linux/phonet.h> | |
32 | #include <net/phonet/phonet.h> | |
33 | ||
87ab4e20 RDC |
34 | #define DYNAMIC_PORT_MIN 0x40 |
35 | #define DYNAMIC_PORT_MAX 0x7f | |
36 | ||
37 | static DEFINE_SEQLOCK(local_port_range_lock); | |
38 | static int local_port_range_min[2] = {0, 0}; | |
39 | static int local_port_range_max[2] = {1023, 1023}; | |
40 | static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX}; | |
41 | static struct ctl_table_header *phonet_table_hrd; | |
42 | ||
43 | static void set_local_port_range(int range[2]) | |
44 | { | |
45 | write_seqlock(&local_port_range_lock); | |
46 | local_port_range[0] = range[0]; | |
47 | local_port_range[1] = range[1]; | |
48 | write_sequnlock(&local_port_range_lock); | |
49 | } | |
50 | ||
51 | void phonet_get_local_port_range(int *min, int *max) | |
52 | { | |
95c96174 ED |
53 | unsigned int seq; |
54 | ||
87ab4e20 RDC |
55 | do { |
56 | seq = read_seqbegin(&local_port_range_lock); | |
57 | if (min) | |
58 | *min = local_port_range[0]; | |
59 | if (max) | |
60 | *max = local_port_range[1]; | |
61 | } while (read_seqretry(&local_port_range_lock, seq)); | |
62 | } | |
63 | ||
8d65af78 | 64 | static int proc_local_port_range(ctl_table *table, int write, |
87ab4e20 RDC |
65 | void __user *buffer, |
66 | size_t *lenp, loff_t *ppos) | |
67 | { | |
68 | int ret; | |
69 | int range[2] = {local_port_range[0], local_port_range[1]}; | |
70 | ctl_table tmp = { | |
71 | .data = &range, | |
72 | .maxlen = sizeof(range), | |
73 | .mode = table->mode, | |
74 | .extra1 = &local_port_range_min, | |
75 | .extra2 = &local_port_range_max, | |
76 | }; | |
77 | ||
8d65af78 | 78 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); |
87ab4e20 RDC |
79 | |
80 | if (write && ret == 0) { | |
81 | if (range[1] < range[0]) | |
82 | ret = -EINVAL; | |
83 | else | |
84 | set_local_port_range(range); | |
85 | } | |
86 | ||
87 | return ret; | |
88 | } | |
89 | ||
90 | static struct ctl_table phonet_table[] = { | |
91 | { | |
87ab4e20 RDC |
92 | .procname = "local_port_range", |
93 | .data = &local_port_range, | |
94 | .maxlen = sizeof(local_port_range), | |
95 | .mode = 0644, | |
6d9f239a | 96 | .proc_handler = proc_local_port_range, |
87ab4e20 | 97 | }, |
f8572d8f | 98 | { } |
87ab4e20 RDC |
99 | }; |
100 | ||
87ab4e20 RDC |
101 | int __init phonet_sysctl_init(void) |
102 | { | |
ec8f23ce | 103 | phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table); |
87ab4e20 RDC |
104 | return phonet_table_hrd == NULL ? -ENOMEM : 0; |
105 | } | |
106 | ||
107 | void phonet_sysctl_exit(void) | |
108 | { | |
5dd3df10 | 109 | unregister_net_sysctl_table(phonet_table_hrd); |
87ab4e20 | 110 | } |