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