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