• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 int decnet_debug_level;
33 int decnet_time_wait = 30;
34 int decnet_dn_count = 1;
35 int decnet_di_count = 3;
36 int decnet_dr_count = 3;
37 int decnet_log_martians = 1;
38 int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
39 
40 /* Reasonable defaults, I hope, based on tcp's defaults */
41 int sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
42 int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
43 int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
44 
45 #ifdef CONFIG_SYSCTL
46 extern int decnet_dst_gc_interval;
47 static int min_decnet_time_wait[] = { 5 };
48 static int max_decnet_time_wait[] = { 600 };
49 static int min_state_count[] = { 1 };
50 static int max_state_count[] = { NSP_MAXRXTSHIFT };
51 static int min_decnet_dst_gc_interval[] = { 1 };
52 static int max_decnet_dst_gc_interval[] = { 60 };
53 static int min_decnet_no_fc_max_cwnd[] = { NSP_MIN_WINDOW };
54 static int max_decnet_no_fc_max_cwnd[] = { NSP_MAX_WINDOW };
55 static char node_name[7] = "???";
56 
57 static 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 
strip_it(char * str)68 static 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  */
parse_addr(__le16 * addr,char * str)88 static 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 = cpu_to_le16((area << 10) | node);
130 
131 	return 0;
132 }
133 
134 
dn_node_address_strategy(ctl_table * table,void __user * oldval,size_t __user * oldlenp,void __user * newval,size_t newlen)135 static int dn_node_address_strategy(ctl_table *table,
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 
dn_node_address_handler(ctl_table * table,int write,struct file * filp,void __user * buffer,size_t * lenp,loff_t * ppos)167 static 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(le16_to_cpu(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 
dn_def_dev_strategy(ctl_table * table,void __user * oldval,size_t __user * oldlenp,void __user * newval,size_t newlen)220 static int dn_def_dev_strategy(ctl_table *table,
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(&init_net, 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 
dn_def_dev_handler(ctl_table * table,int write,struct file * filp,void __user * buffer,size_t * lenp,loff_t * ppos)278 static 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(&init_net, 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 
342 static 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 
473 static struct ctl_path dn_path[] = {
474 	{ .procname = "net", .ctl_name = CTL_NET, },
475 	{ .procname = "decnet", .ctl_name = NET_DECNET, },
476 	{ }
477 };
478 
dn_register_sysctl(void)479 void dn_register_sysctl(void)
480 {
481 	dn_table_header = register_sysctl_paths(dn_path, dn_table);
482 }
483 
dn_unregister_sysctl(void)484 void dn_unregister_sysctl(void)
485 {
486 	unregister_sysctl_table(dn_table_header);
487 }
488 
489 #else  /* CONFIG_SYSCTL */
dn_unregister_sysctl(void)490 void dn_unregister_sysctl(void)
491 {
492 }
dn_register_sysctl(void)493 void dn_register_sysctl(void)
494 {
495 }
496 
497 #endif
498