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 */
41int 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			case 0:
78				return;
79		}
80		str++;
81	}
82}
83
84/*
85 * Simple routine to parse an ascii DECnet address
86 * into a network order address.
87 */
88static int parse_addr(__le16 *addr, char *str)
89{
90	__u16 area, node;
91
92	while(*str && !ISNUM(*str)) str++;
93
94	if (*str == 0)
95		return -1;
96
97	area = (*str++ - '0');
98	if (ISNUM(*str)) {
99		area *= 10;
100		area += (*str++ - '0');
101	}
102
103	if (*str++ != '.')
104		return -1;
105
106	if (!ISNUM(*str))
107		return -1;
108
109	node = *str++ - '0';
110	if (ISNUM(*str)) {
111		node *= 10;
112		node += (*str++ - '0');
113	}
114	if (ISNUM(*str)) {
115		node *= 10;
116		node += (*str++ - '0');
117	}
118	if (ISNUM(*str)) {
119		node *= 10;
120		node += (*str++ - '0');
121	}
122
123	if ((node > 1023) || (area > 63))
124		return -1;
125
126	if (INVALID_END_CHAR(*str))
127		return -1;
128
129	*addr = dn_htons((area << 10) | node);
130
131	return 0;
132}
133
134
135static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
136				void __user *oldval, size_t __user *oldlenp,
137				void __user *newval, size_t newlen)
138{
139	size_t len;
140	__le16 addr;
141
142	if (oldval && oldlenp) {
143		if (get_user(len, oldlenp))
144			return -EFAULT;
145		if (len) {
146			if (len != sizeof(unsigned short))
147				return -EINVAL;
148			if (put_user(decnet_address, (__le16 __user *)oldval))
149				return -EFAULT;
150		}
151	}
152	if (newval && newlen) {
153		if (newlen != sizeof(unsigned short))
154			return -EINVAL;
155		if (get_user(addr, (__le16 __user *)newval))
156			return -EFAULT;
157
158		dn_dev_devices_off();
159
160		decnet_address = addr;
161
162		dn_dev_devices_on();
163	}
164	return 0;
165}
166
167static int dn_node_address_handler(ctl_table *table, int write,
168				struct file *filp,
169				void __user *buffer,
170				size_t *lenp, loff_t *ppos)
171{
172	char addr[DN_ASCBUF_LEN];
173	size_t len;
174	__le16 dnaddr;
175
176	if (!*lenp || (*ppos && !write)) {
177		*lenp = 0;
178		return 0;
179	}
180
181	if (write) {
182		int len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
183
184		if (copy_from_user(addr, buffer, len))
185			return -EFAULT;
186
187		addr[len] = 0;
188		strip_it(addr);
189
190		if (parse_addr(&dnaddr, addr))
191			return -EINVAL;
192
193		dn_dev_devices_off();
194
195		decnet_address = dnaddr;
196
197		dn_dev_devices_on();
198
199		*ppos += len;
200
201		return 0;
202	}
203
204	dn_addr2asc(dn_ntohs(decnet_address), addr);
205	len = strlen(addr);
206	addr[len++] = '\n';
207
208	if (len > *lenp) len = *lenp;
209
210	if (copy_to_user(buffer, addr, len))
211		return -EFAULT;
212
213	*lenp = len;
214	*ppos += len;
215
216	return 0;
217}
218
219
220static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
221				void __user *oldval, size_t __user *oldlenp,
222				void __user *newval, size_t newlen)
223{
224	size_t len;
225	struct net_device *dev;
226	char devname[17];
227	size_t namel;
228	int rv = 0;
229
230	devname[0] = 0;
231
232	if (oldval && oldlenp) {
233		if (get_user(len, oldlenp))
234			return -EFAULT;
235		if (len) {
236			dev = dn_dev_get_default();
237			if (dev) {
238				strcpy(devname, dev->name);
239				dev_put(dev);
240			}
241
242			namel = strlen(devname) + 1;
243			if (len > namel) len = namel;
244
245			if (copy_to_user(oldval, devname, len))
246				return -EFAULT;
247
248			if (put_user(len, oldlenp))
249				return -EFAULT;
250		}
251	}
252
253	if (newval && newlen) {
254		if (newlen > 16)
255			return -E2BIG;
256
257		if (copy_from_user(devname, newval, newlen))
258			return -EFAULT;
259
260		devname[newlen] = 0;
261
262		dev = dev_get_by_name(devname);
263		if (dev == NULL)
264			return -ENODEV;
265
266		rv = -ENODEV;
267		if (dev->dn_ptr != NULL) {
268			rv = dn_dev_set_default(dev, 1);
269			if (rv)
270				dev_put(dev);
271		}
272	}
273
274	return rv;
275}
276
277
278static int dn_def_dev_handler(ctl_table *table, int write,
279				struct file * filp,
280				void __user *buffer,
281				size_t *lenp, loff_t *ppos)
282{
283	size_t len;
284	struct net_device *dev;
285	char devname[17];
286
287	if (!*lenp || (*ppos && !write)) {
288		*lenp = 0;
289		return 0;
290	}
291
292	if (write) {
293		if (*lenp > 16)
294			return -E2BIG;
295
296		if (copy_from_user(devname, buffer, *lenp))
297			return -EFAULT;
298
299		devname[*lenp] = 0;
300		strip_it(devname);
301
302		dev = dev_get_by_name(devname);
303		if (dev == NULL)
304			return -ENODEV;
305
306		if (dev->dn_ptr == NULL) {
307			dev_put(dev);
308			return -ENODEV;
309		}
310
311		if (dn_dev_set_default(dev, 1)) {
312			dev_put(dev);
313			return -ENODEV;
314		}
315		*ppos += *lenp;
316
317		return 0;
318	}
319
320	dev = dn_dev_get_default();
321	if (dev == NULL) {
322		*lenp = 0;
323		return 0;
324	}
325
326	strcpy(devname, dev->name);
327	dev_put(dev);
328	len = strlen(devname);
329	devname[len++] = '\n';
330
331	if (len > *lenp) len = *lenp;
332
333	if (copy_to_user(buffer, devname, len))
334		return -EFAULT;
335
336	*lenp = len;
337	*ppos += len;
338
339	return 0;
340}
341
342static ctl_table dn_table[] = {
343	{
344		.ctl_name = NET_DECNET_NODE_ADDRESS,
345		.procname = "node_address",
346		.maxlen = 7,
347		.mode = 0644,
348		.proc_handler = dn_node_address_handler,
349		.strategy = dn_node_address_strategy,
350	},
351	{
352		.ctl_name = NET_DECNET_NODE_NAME,
353		.procname = "node_name",
354		.data = node_name,
355		.maxlen = 7,
356		.mode = 0644,
357		.proc_handler = &proc_dostring,
358		.strategy = &sysctl_string,
359	},
360	{
361		.ctl_name = NET_DECNET_DEFAULT_DEVICE,
362		.procname = "default_device",
363		.maxlen = 16,
364		.mode = 0644,
365		.proc_handler = dn_def_dev_handler,
366		.strategy = dn_def_dev_strategy,
367	},
368	{
369		.ctl_name = NET_DECNET_TIME_WAIT,
370		.procname = "time_wait",
371		.data = &decnet_time_wait,
372		.maxlen = sizeof(int),
373		.mode = 0644,
374		.proc_handler = &proc_dointvec_minmax,
375		.strategy = &sysctl_intvec,
376		.extra1 = &min_decnet_time_wait,
377		.extra2 = &max_decnet_time_wait
378	},
379	{
380		.ctl_name = NET_DECNET_DN_COUNT,
381		.procname = "dn_count",
382		.data = &decnet_dn_count,
383		.maxlen = sizeof(int),
384		.mode = 0644,
385		.proc_handler = &proc_dointvec_minmax,
386		.strategy = &sysctl_intvec,
387		.extra1 = &min_state_count,
388		.extra2 = &max_state_count
389	},
390	{
391		.ctl_name = NET_DECNET_DI_COUNT,
392		.procname = "di_count",
393		.data = &decnet_di_count,
394		.maxlen = sizeof(int),
395		.mode = 0644,
396		.proc_handler = &proc_dointvec_minmax,
397		.strategy = &sysctl_intvec,
398		.extra1 = &min_state_count,
399		.extra2 = &max_state_count
400	},
401	{
402		.ctl_name = NET_DECNET_DR_COUNT,
403		.procname = "dr_count",
404		.data = &decnet_dr_count,
405		.maxlen = sizeof(int),
406		.mode = 0644,
407		.proc_handler = &proc_dointvec_minmax,
408		.strategy = &sysctl_intvec,
409		.extra1 = &min_state_count,
410		.extra2 = &max_state_count
411	},
412	{
413		.ctl_name = NET_DECNET_DST_GC_INTERVAL,
414		.procname = "dst_gc_interval",
415		.data = &decnet_dst_gc_interval,
416		.maxlen = sizeof(int),
417		.mode = 0644,
418		.proc_handler = &proc_dointvec_minmax,
419		.strategy = &sysctl_intvec,
420		.extra1 = &min_decnet_dst_gc_interval,
421		.extra2 = &max_decnet_dst_gc_interval
422	},
423	{
424		.ctl_name = NET_DECNET_NO_FC_MAX_CWND,
425		.procname = "no_fc_max_cwnd",
426		.data = &decnet_no_fc_max_cwnd,
427		.maxlen = sizeof(int),
428		.mode = 0644,
429		.proc_handler = &proc_dointvec_minmax,
430		.strategy = &sysctl_intvec,
431		.extra1 = &min_decnet_no_fc_max_cwnd,
432		.extra2 = &max_decnet_no_fc_max_cwnd
433	},
434       {
435		.ctl_name = NET_DECNET_MEM,
436		.procname = "decnet_mem",
437		.data = &sysctl_decnet_mem,
438		.maxlen = sizeof(sysctl_decnet_mem),
439		.mode = 0644,
440		.proc_handler = &proc_dointvec,
441		.strategy = &sysctl_intvec,
442	},
443	{
444		.ctl_name = NET_DECNET_RMEM,
445		.procname = "decnet_rmem",
446		.data = &sysctl_decnet_rmem,
447		.maxlen = sizeof(sysctl_decnet_rmem),
448		.mode = 0644,
449		.proc_handler = &proc_dointvec,
450		.strategy = &sysctl_intvec,
451	},
452	{
453		.ctl_name = NET_DECNET_WMEM,
454		.procname = "decnet_wmem",
455		.data = &sysctl_decnet_wmem,
456		.maxlen = sizeof(sysctl_decnet_wmem),
457		.mode = 0644,
458		.proc_handler = &proc_dointvec,
459		.strategy = &sysctl_intvec,
460	},
461	{
462		.ctl_name = NET_DECNET_DEBUG_LEVEL,
463		.procname = "debug",
464		.data = &decnet_debug_level,
465		.maxlen = sizeof(int),
466		.mode = 0644,
467		.proc_handler = &proc_dointvec,
468		.strategy = &sysctl_intvec,
469	},
470	{0}
471};
472
473static ctl_table dn_dir_table[] = {
474	{
475		.ctl_name = NET_DECNET,
476		.procname = "decnet",
477		.mode = 0555,
478		.child = dn_table},
479	{0}
480};
481
482static ctl_table dn_root_table[] = {
483	{
484		.ctl_name = CTL_NET,
485		.procname = "net",
486		.mode = 0555,
487		.child = dn_dir_table
488	},
489	{0}
490};
491
492void dn_register_sysctl(void)
493{
494	dn_table_header = register_sysctl_table(dn_root_table);
495}
496
497void dn_unregister_sysctl(void)
498{
499	unregister_sysctl_table(dn_table_header);
500}
501
502#else  /* CONFIG_SYSCTL */
503void dn_unregister_sysctl(void)
504{
505}
506void dn_register_sysctl(void)
507{
508}
509
510#endif
511