1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * DECnet An implementation of the DECnet protocol suite for the LINUX
4*4882a593Smuzhiyun * operating system. DECnet is implemented using the BSD Socket
5*4882a593Smuzhiyun * interface as the means of communication with the user level.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * DECnet sysctl support functions
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Author: Steve Whitehouse <SteveW@ACM.org>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Changes:
13*4882a593Smuzhiyun * Steve Whitehouse - C99 changes and default device handling
14*4882a593Smuzhiyun * Steve Whitehouse - Memory buffer settings, like the tcp ones
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun #include <linux/mm.h>
18*4882a593Smuzhiyun #include <linux/sysctl.h>
19*4882a593Smuzhiyun #include <linux/fs.h>
20*4882a593Smuzhiyun #include <linux/netdevice.h>
21*4882a593Smuzhiyun #include <linux/string.h>
22*4882a593Smuzhiyun #include <net/neighbour.h>
23*4882a593Smuzhiyun #include <net/dst.h>
24*4882a593Smuzhiyun #include <net/flow.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <linux/uaccess.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <net/dn.h>
29*4882a593Smuzhiyun #include <net/dn_dev.h>
30*4882a593Smuzhiyun #include <net/dn_route.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun int decnet_debug_level;
34*4882a593Smuzhiyun int decnet_time_wait = 30;
35*4882a593Smuzhiyun int decnet_dn_count = 1;
36*4882a593Smuzhiyun int decnet_di_count = 3;
37*4882a593Smuzhiyun int decnet_dr_count = 3;
38*4882a593Smuzhiyun int decnet_log_martians = 1;
39*4882a593Smuzhiyun int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* Reasonable defaults, I hope, based on tcp's defaults */
42*4882a593Smuzhiyun long sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
43*4882a593Smuzhiyun int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
44*4882a593Smuzhiyun int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
47*4882a593Smuzhiyun extern int decnet_dst_gc_interval;
48*4882a593Smuzhiyun static int min_decnet_time_wait[] = { 5 };
49*4882a593Smuzhiyun static int max_decnet_time_wait[] = { 600 };
50*4882a593Smuzhiyun static int min_state_count[] = { 1 };
51*4882a593Smuzhiyun static int max_state_count[] = { NSP_MAXRXTSHIFT };
52*4882a593Smuzhiyun static int min_decnet_dst_gc_interval[] = { 1 };
53*4882a593Smuzhiyun static int max_decnet_dst_gc_interval[] = { 60 };
54*4882a593Smuzhiyun static int min_decnet_no_fc_max_cwnd[] = { NSP_MIN_WINDOW };
55*4882a593Smuzhiyun static int max_decnet_no_fc_max_cwnd[] = { NSP_MAX_WINDOW };
56*4882a593Smuzhiyun static char node_name[7] = "???";
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun static struct ctl_table_header *dn_table_header = NULL;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /*
61*4882a593Smuzhiyun * ctype.h :-)
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun #define ISNUM(x) (((x) >= '0') && ((x) <= '9'))
64*4882a593Smuzhiyun #define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
65*4882a593Smuzhiyun #define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
66*4882a593Smuzhiyun #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
67*4882a593Smuzhiyun #define INVALID_END_CHAR(x) (ISNUM(x) || ISALPHA(x))
68*4882a593Smuzhiyun
strip_it(char * str)69*4882a593Smuzhiyun static void strip_it(char *str)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun for(;;) {
72*4882a593Smuzhiyun switch (*str) {
73*4882a593Smuzhiyun case ' ':
74*4882a593Smuzhiyun case '\n':
75*4882a593Smuzhiyun case '\r':
76*4882a593Smuzhiyun case ':':
77*4882a593Smuzhiyun *str = 0;
78*4882a593Smuzhiyun fallthrough;
79*4882a593Smuzhiyun case 0:
80*4882a593Smuzhiyun return;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun str++;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /*
87*4882a593Smuzhiyun * Simple routine to parse an ascii DECnet address
88*4882a593Smuzhiyun * into a network order address.
89*4882a593Smuzhiyun */
parse_addr(__le16 * addr,char * str)90*4882a593Smuzhiyun static int parse_addr(__le16 *addr, char *str)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun __u16 area, node;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun while(*str && !ISNUM(*str)) str++;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun if (*str == 0)
97*4882a593Smuzhiyun return -1;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun area = (*str++ - '0');
100*4882a593Smuzhiyun if (ISNUM(*str)) {
101*4882a593Smuzhiyun area *= 10;
102*4882a593Smuzhiyun area += (*str++ - '0');
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (*str++ != '.')
106*4882a593Smuzhiyun return -1;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (!ISNUM(*str))
109*4882a593Smuzhiyun return -1;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun node = *str++ - '0';
112*4882a593Smuzhiyun if (ISNUM(*str)) {
113*4882a593Smuzhiyun node *= 10;
114*4882a593Smuzhiyun node += (*str++ - '0');
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun if (ISNUM(*str)) {
117*4882a593Smuzhiyun node *= 10;
118*4882a593Smuzhiyun node += (*str++ - '0');
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun if (ISNUM(*str)) {
121*4882a593Smuzhiyun node *= 10;
122*4882a593Smuzhiyun node += (*str++ - '0');
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if ((node > 1023) || (area > 63))
126*4882a593Smuzhiyun return -1;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (INVALID_END_CHAR(*str))
129*4882a593Smuzhiyun return -1;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun *addr = cpu_to_le16((area << 10) | node);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
dn_node_address_handler(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)136*4882a593Smuzhiyun static int dn_node_address_handler(struct ctl_table *table, int write,
137*4882a593Smuzhiyun void *buffer, size_t *lenp, loff_t *ppos)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun char addr[DN_ASCBUF_LEN];
140*4882a593Smuzhiyun size_t len;
141*4882a593Smuzhiyun __le16 dnaddr;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (!*lenp || (*ppos && !write)) {
144*4882a593Smuzhiyun *lenp = 0;
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (write) {
149*4882a593Smuzhiyun len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
150*4882a593Smuzhiyun memcpy(addr, buffer, len);
151*4882a593Smuzhiyun addr[len] = 0;
152*4882a593Smuzhiyun strip_it(addr);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (parse_addr(&dnaddr, addr))
155*4882a593Smuzhiyun return -EINVAL;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun dn_dev_devices_off();
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun decnet_address = dnaddr;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun dn_dev_devices_on();
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun *ppos += len;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun dn_addr2asc(le16_to_cpu(decnet_address), addr);
169*4882a593Smuzhiyun len = strlen(addr);
170*4882a593Smuzhiyun addr[len++] = '\n';
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (len > *lenp)
173*4882a593Smuzhiyun len = *lenp;
174*4882a593Smuzhiyun memcpy(buffer, addr, len);
175*4882a593Smuzhiyun *lenp = len;
176*4882a593Smuzhiyun *ppos += len;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
dn_def_dev_handler(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)181*4882a593Smuzhiyun static int dn_def_dev_handler(struct ctl_table *table, int write,
182*4882a593Smuzhiyun void *buffer, size_t *lenp, loff_t *ppos)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun size_t len;
185*4882a593Smuzhiyun struct net_device *dev;
186*4882a593Smuzhiyun char devname[17];
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (!*lenp || (*ppos && !write)) {
189*4882a593Smuzhiyun *lenp = 0;
190*4882a593Smuzhiyun return 0;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (write) {
194*4882a593Smuzhiyun if (*lenp > 16)
195*4882a593Smuzhiyun return -E2BIG;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun memcpy(devname, buffer, *lenp);
198*4882a593Smuzhiyun devname[*lenp] = 0;
199*4882a593Smuzhiyun strip_it(devname);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun dev = dev_get_by_name(&init_net, devname);
202*4882a593Smuzhiyun if (dev == NULL)
203*4882a593Smuzhiyun return -ENODEV;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (dev->dn_ptr == NULL) {
206*4882a593Smuzhiyun dev_put(dev);
207*4882a593Smuzhiyun return -ENODEV;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (dn_dev_set_default(dev, 1)) {
211*4882a593Smuzhiyun dev_put(dev);
212*4882a593Smuzhiyun return -ENODEV;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun *ppos += *lenp;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun dev = dn_dev_get_default();
220*4882a593Smuzhiyun if (dev == NULL) {
221*4882a593Smuzhiyun *lenp = 0;
222*4882a593Smuzhiyun return 0;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun strcpy(devname, dev->name);
226*4882a593Smuzhiyun dev_put(dev);
227*4882a593Smuzhiyun len = strlen(devname);
228*4882a593Smuzhiyun devname[len++] = '\n';
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (len > *lenp) len = *lenp;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun memcpy(buffer, devname, len);
233*4882a593Smuzhiyun *lenp = len;
234*4882a593Smuzhiyun *ppos += len;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun return 0;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun static struct ctl_table dn_table[] = {
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun .procname = "node_address",
242*4882a593Smuzhiyun .maxlen = 7,
243*4882a593Smuzhiyun .mode = 0644,
244*4882a593Smuzhiyun .proc_handler = dn_node_address_handler,
245*4882a593Smuzhiyun },
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun .procname = "node_name",
248*4882a593Smuzhiyun .data = node_name,
249*4882a593Smuzhiyun .maxlen = 7,
250*4882a593Smuzhiyun .mode = 0644,
251*4882a593Smuzhiyun .proc_handler = proc_dostring,
252*4882a593Smuzhiyun },
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun .procname = "default_device",
255*4882a593Smuzhiyun .maxlen = 16,
256*4882a593Smuzhiyun .mode = 0644,
257*4882a593Smuzhiyun .proc_handler = dn_def_dev_handler,
258*4882a593Smuzhiyun },
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun .procname = "time_wait",
261*4882a593Smuzhiyun .data = &decnet_time_wait,
262*4882a593Smuzhiyun .maxlen = sizeof(int),
263*4882a593Smuzhiyun .mode = 0644,
264*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
265*4882a593Smuzhiyun .extra1 = &min_decnet_time_wait,
266*4882a593Smuzhiyun .extra2 = &max_decnet_time_wait
267*4882a593Smuzhiyun },
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun .procname = "dn_count",
270*4882a593Smuzhiyun .data = &decnet_dn_count,
271*4882a593Smuzhiyun .maxlen = sizeof(int),
272*4882a593Smuzhiyun .mode = 0644,
273*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
274*4882a593Smuzhiyun .extra1 = &min_state_count,
275*4882a593Smuzhiyun .extra2 = &max_state_count
276*4882a593Smuzhiyun },
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun .procname = "di_count",
279*4882a593Smuzhiyun .data = &decnet_di_count,
280*4882a593Smuzhiyun .maxlen = sizeof(int),
281*4882a593Smuzhiyun .mode = 0644,
282*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
283*4882a593Smuzhiyun .extra1 = &min_state_count,
284*4882a593Smuzhiyun .extra2 = &max_state_count
285*4882a593Smuzhiyun },
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun .procname = "dr_count",
288*4882a593Smuzhiyun .data = &decnet_dr_count,
289*4882a593Smuzhiyun .maxlen = sizeof(int),
290*4882a593Smuzhiyun .mode = 0644,
291*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
292*4882a593Smuzhiyun .extra1 = &min_state_count,
293*4882a593Smuzhiyun .extra2 = &max_state_count
294*4882a593Smuzhiyun },
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun .procname = "dst_gc_interval",
297*4882a593Smuzhiyun .data = &decnet_dst_gc_interval,
298*4882a593Smuzhiyun .maxlen = sizeof(int),
299*4882a593Smuzhiyun .mode = 0644,
300*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
301*4882a593Smuzhiyun .extra1 = &min_decnet_dst_gc_interval,
302*4882a593Smuzhiyun .extra2 = &max_decnet_dst_gc_interval
303*4882a593Smuzhiyun },
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun .procname = "no_fc_max_cwnd",
306*4882a593Smuzhiyun .data = &decnet_no_fc_max_cwnd,
307*4882a593Smuzhiyun .maxlen = sizeof(int),
308*4882a593Smuzhiyun .mode = 0644,
309*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
310*4882a593Smuzhiyun .extra1 = &min_decnet_no_fc_max_cwnd,
311*4882a593Smuzhiyun .extra2 = &max_decnet_no_fc_max_cwnd
312*4882a593Smuzhiyun },
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun .procname = "decnet_mem",
315*4882a593Smuzhiyun .data = &sysctl_decnet_mem,
316*4882a593Smuzhiyun .maxlen = sizeof(sysctl_decnet_mem),
317*4882a593Smuzhiyun .mode = 0644,
318*4882a593Smuzhiyun .proc_handler = proc_doulongvec_minmax
319*4882a593Smuzhiyun },
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun .procname = "decnet_rmem",
322*4882a593Smuzhiyun .data = &sysctl_decnet_rmem,
323*4882a593Smuzhiyun .maxlen = sizeof(sysctl_decnet_rmem),
324*4882a593Smuzhiyun .mode = 0644,
325*4882a593Smuzhiyun .proc_handler = proc_dointvec,
326*4882a593Smuzhiyun },
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun .procname = "decnet_wmem",
329*4882a593Smuzhiyun .data = &sysctl_decnet_wmem,
330*4882a593Smuzhiyun .maxlen = sizeof(sysctl_decnet_wmem),
331*4882a593Smuzhiyun .mode = 0644,
332*4882a593Smuzhiyun .proc_handler = proc_dointvec,
333*4882a593Smuzhiyun },
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun .procname = "debug",
336*4882a593Smuzhiyun .data = &decnet_debug_level,
337*4882a593Smuzhiyun .maxlen = sizeof(int),
338*4882a593Smuzhiyun .mode = 0644,
339*4882a593Smuzhiyun .proc_handler = proc_dointvec,
340*4882a593Smuzhiyun },
341*4882a593Smuzhiyun { }
342*4882a593Smuzhiyun };
343*4882a593Smuzhiyun
dn_register_sysctl(void)344*4882a593Smuzhiyun void dn_register_sysctl(void)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun dn_table_header = register_net_sysctl(&init_net, "net/decnet", dn_table);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
dn_unregister_sysctl(void)349*4882a593Smuzhiyun void dn_unregister_sysctl(void)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun unregister_net_sysctl_table(dn_table_header);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun #else /* CONFIG_SYSCTL */
dn_unregister_sysctl(void)355*4882a593Smuzhiyun void dn_unregister_sysctl(void)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun }
dn_register_sysctl(void)358*4882a593Smuzhiyun void dn_register_sysctl(void)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun #endif
363