1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * File: sysctl.c |
4 | * |
5 | * Phonet /proc/sys/net/phonet interface implementation |
6 | * |
7 | * Copyright (C) 2008 Nokia Corporation. |
8 | * |
9 | * Author: RĂ©mi Denis-Courmont |
10 | */ |
11 | |
12 | #include <linux/seqlock.h> |
13 | #include <linux/sysctl.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/init.h> |
16 | |
17 | #include <net/sock.h> |
18 | #include <linux/phonet.h> |
19 | #include <net/phonet/phonet.h> |
20 | |
21 | #define DYNAMIC_PORT_MIN 0x40 |
22 | #define DYNAMIC_PORT_MAX 0x7f |
23 | |
24 | static DEFINE_SEQLOCK(local_port_range_lock); |
25 | static int local_port_range_min[2] = {0, 0}; |
26 | static int local_port_range_max[2] = {1023, 1023}; |
27 | static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX}; |
28 | static struct ctl_table_header *phonet_table_hrd; |
29 | |
30 | static void set_local_port_range(int range[2]) |
31 | { |
32 | write_seqlock(sl: &local_port_range_lock); |
33 | local_port_range[0] = range[0]; |
34 | local_port_range[1] = range[1]; |
35 | write_sequnlock(sl: &local_port_range_lock); |
36 | } |
37 | |
38 | void phonet_get_local_port_range(int *min, int *max) |
39 | { |
40 | unsigned int seq; |
41 | |
42 | do { |
43 | seq = read_seqbegin(sl: &local_port_range_lock); |
44 | if (min) |
45 | *min = local_port_range[0]; |
46 | if (max) |
47 | *max = local_port_range[1]; |
48 | } while (read_seqretry(sl: &local_port_range_lock, start: seq)); |
49 | } |
50 | |
51 | static int proc_local_port_range(struct ctl_table *table, int write, |
52 | void *buffer, size_t *lenp, loff_t *ppos) |
53 | { |
54 | int ret; |
55 | int range[2] = {local_port_range[0], local_port_range[1]}; |
56 | struct ctl_table tmp = { |
57 | .data = &range, |
58 | .maxlen = sizeof(range), |
59 | .mode = table->mode, |
60 | .extra1 = &local_port_range_min, |
61 | .extra2 = &local_port_range_max, |
62 | }; |
63 | |
64 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); |
65 | |
66 | if (write && ret == 0) { |
67 | if (range[1] < range[0]) |
68 | ret = -EINVAL; |
69 | else |
70 | set_local_port_range(range); |
71 | } |
72 | |
73 | return ret; |
74 | } |
75 | |
76 | static struct ctl_table phonet_table[] = { |
77 | { |
78 | .procname = "local_port_range" , |
79 | .data = &local_port_range, |
80 | .maxlen = sizeof(local_port_range), |
81 | .mode = 0644, |
82 | .proc_handler = proc_local_port_range, |
83 | }, |
84 | { } |
85 | }; |
86 | |
87 | int __init phonet_sysctl_init(void) |
88 | { |
89 | phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet" , phonet_table); |
90 | return phonet_table_hrd == NULL ? -ENOMEM : 0; |
91 | } |
92 | |
93 | void phonet_sysctl_exit(void) |
94 | { |
95 | unregister_net_sysctl_table(header: phonet_table_hrd); |
96 | } |
97 | |