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