USB: serial: garmin_gps: fix memory leak on failed URB submit
[pandora-kernel.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 long 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 static struct ctl_table_header *dn_skeleton_table_header = NULL;
59
60 /*
61  * ctype.h :-)
62  */
63 #define ISNUM(x) (((x) >= '0') && ((x) <= '9'))
64 #define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
65 #define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
66 #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
67 #define INVALID_END_CHAR(x) (ISNUM(x) || ISALPHA(x))
68
69 static void strip_it(char *str)
70 {
71         for(;;) {
72                 switch (*str) {
73                 case ' ':
74                 case '\n':
75                 case '\r':
76                 case ':':
77                         *str = 0;
78                         /* Fallthrough */
79                 case 0:
80                         return;
81                 }
82                 str++;
83         }
84 }
85
86 /*
87  * Simple routine to parse an ascii DECnet address
88  * into a network order address.
89  */
90 static int parse_addr(__le16 *addr, char *str)
91 {
92         __u16 area, node;
93
94         while(*str && !ISNUM(*str)) str++;
95
96         if (*str == 0)
97                 return -1;
98
99         area = (*str++ - '0');
100         if (ISNUM(*str)) {
101                 area *= 10;
102                 area += (*str++ - '0');
103         }
104
105         if (*str++ != '.')
106                 return -1;
107
108         if (!ISNUM(*str))
109                 return -1;
110
111         node = *str++ - '0';
112         if (ISNUM(*str)) {
113                 node *= 10;
114                 node += (*str++ - '0');
115         }
116         if (ISNUM(*str)) {
117                 node *= 10;
118                 node += (*str++ - '0');
119         }
120         if (ISNUM(*str)) {
121                 node *= 10;
122                 node += (*str++ - '0');
123         }
124
125         if ((node > 1023) || (area > 63))
126                 return -1;
127
128         if (INVALID_END_CHAR(*str))
129                 return -1;
130
131         *addr = cpu_to_le16((area << 10) | node);
132
133         return 0;
134 }
135
136 static int dn_node_address_handler(ctl_table *table, int write,
137                                 void __user *buffer,
138                                 size_t *lenp, loff_t *ppos)
139 {
140         char addr[DN_ASCBUF_LEN];
141         size_t len;
142         __le16 dnaddr;
143
144         if (!*lenp || (*ppos && !write)) {
145                 *lenp = 0;
146                 return 0;
147         }
148
149         if (write) {
150                 len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
151
152                 if (copy_from_user(addr, buffer, len))
153                         return -EFAULT;
154
155                 addr[len] = 0;
156                 strip_it(addr);
157
158                 if (parse_addr(&dnaddr, addr))
159                         return -EINVAL;
160
161                 dn_dev_devices_off();
162
163                 decnet_address = dnaddr;
164
165                 dn_dev_devices_on();
166
167                 *ppos += len;
168
169                 return 0;
170         }
171
172         dn_addr2asc(le16_to_cpu(decnet_address), addr);
173         len = strlen(addr);
174         addr[len++] = '\n';
175
176         if (len > *lenp) len = *lenp;
177
178         if (copy_to_user(buffer, addr, len))
179                 return -EFAULT;
180
181         *lenp = len;
182         *ppos += len;
183
184         return 0;
185 }
186
187 static int dn_def_dev_handler(ctl_table *table, int write,
188                                 void __user *buffer,
189                                 size_t *lenp, loff_t *ppos)
190 {
191         size_t len;
192         struct net_device *dev;
193         char devname[17];
194
195         if (!*lenp || (*ppos && !write)) {
196                 *lenp = 0;
197                 return 0;
198         }
199
200         if (write) {
201                 if (*lenp > 16)
202                         return -E2BIG;
203
204                 if (copy_from_user(devname, buffer, *lenp))
205                         return -EFAULT;
206
207                 devname[*lenp] = 0;
208                 strip_it(devname);
209
210                 dev = dev_get_by_name(&init_net, devname);
211                 if (dev == NULL)
212                         return -ENODEV;
213
214                 if (dev->dn_ptr == NULL) {
215                         dev_put(dev);
216                         return -ENODEV;
217                 }
218
219                 if (dn_dev_set_default(dev, 1)) {
220                         dev_put(dev);
221                         return -ENODEV;
222                 }
223                 *ppos += *lenp;
224
225                 return 0;
226         }
227
228         dev = dn_dev_get_default();
229         if (dev == NULL) {
230                 *lenp = 0;
231                 return 0;
232         }
233
234         strcpy(devname, dev->name);
235         dev_put(dev);
236         len = strlen(devname);
237         devname[len++] = '\n';
238
239         if (len > *lenp) len = *lenp;
240
241         if (copy_to_user(buffer, devname, len))
242                 return -EFAULT;
243
244         *lenp = len;
245         *ppos += len;
246
247         return 0;
248 }
249
250 static ctl_table dn_table[] = {
251         {
252                 .procname = "node_address",
253                 .maxlen = 7,
254                 .mode = 0644,
255                 .proc_handler = dn_node_address_handler,
256         },
257         {
258                 .procname = "node_name",
259                 .data = node_name,
260                 .maxlen = 7,
261                 .mode = 0644,
262                 .proc_handler = proc_dostring,
263         },
264         {
265                 .procname = "default_device",
266                 .maxlen = 16,
267                 .mode = 0644,
268                 .proc_handler = dn_def_dev_handler,
269         },
270         {
271                 .procname = "time_wait",
272                 .data = &decnet_time_wait,
273                 .maxlen = sizeof(int),
274                 .mode = 0644,
275                 .proc_handler = proc_dointvec_minmax,
276                 .extra1 = &min_decnet_time_wait,
277                 .extra2 = &max_decnet_time_wait
278         },
279         {
280                 .procname = "dn_count",
281                 .data = &decnet_dn_count,
282                 .maxlen = sizeof(int),
283                 .mode = 0644,
284                 .proc_handler = proc_dointvec_minmax,
285                 .extra1 = &min_state_count,
286                 .extra2 = &max_state_count
287         },
288         {
289                 .procname = "di_count",
290                 .data = &decnet_di_count,
291                 .maxlen = sizeof(int),
292                 .mode = 0644,
293                 .proc_handler = proc_dointvec_minmax,
294                 .extra1 = &min_state_count,
295                 .extra2 = &max_state_count
296         },
297         {
298                 .procname = "dr_count",
299                 .data = &decnet_dr_count,
300                 .maxlen = sizeof(int),
301                 .mode = 0644,
302                 .proc_handler = proc_dointvec_minmax,
303                 .extra1 = &min_state_count,
304                 .extra2 = &max_state_count
305         },
306         {
307                 .procname = "dst_gc_interval",
308                 .data = &decnet_dst_gc_interval,
309                 .maxlen = sizeof(int),
310                 .mode = 0644,
311                 .proc_handler = proc_dointvec_minmax,
312                 .extra1 = &min_decnet_dst_gc_interval,
313                 .extra2 = &max_decnet_dst_gc_interval
314         },
315         {
316                 .procname = "no_fc_max_cwnd",
317                 .data = &decnet_no_fc_max_cwnd,
318                 .maxlen = sizeof(int),
319                 .mode = 0644,
320                 .proc_handler = proc_dointvec_minmax,
321                 .extra1 = &min_decnet_no_fc_max_cwnd,
322                 .extra2 = &max_decnet_no_fc_max_cwnd
323         },
324        {
325                 .procname = "decnet_mem",
326                 .data = &sysctl_decnet_mem,
327                 .maxlen = sizeof(sysctl_decnet_mem),
328                 .mode = 0644,
329                 .proc_handler = proc_doulongvec_minmax
330         },
331         {
332                 .procname = "decnet_rmem",
333                 .data = &sysctl_decnet_rmem,
334                 .maxlen = sizeof(sysctl_decnet_rmem),
335                 .mode = 0644,
336                 .proc_handler = proc_dointvec,
337         },
338         {
339                 .procname = "decnet_wmem",
340                 .data = &sysctl_decnet_wmem,
341                 .maxlen = sizeof(sysctl_decnet_wmem),
342                 .mode = 0644,
343                 .proc_handler = proc_dointvec,
344         },
345         {
346                 .procname = "debug",
347                 .data = &decnet_debug_level,
348                 .maxlen = sizeof(int),
349                 .mode = 0644,
350                 .proc_handler = proc_dointvec,
351         },
352         { }
353 };
354
355 static struct ctl_path dn_path[] = {
356         { .procname = "net", },
357         { .procname = "decnet", },
358         { }
359 };
360
361 static struct ctl_table empty[1];
362
363 static struct ctl_table dn_skeleton[] = {
364         {
365                 .procname = "conf",
366                 .mode = 0555,
367                 .child = empty,
368         },
369         { }
370 };
371
372 void dn_register_sysctl_skeleton(void)
373 {
374         dn_skeleton_table_header = register_sysctl_paths(dn_path, dn_skeleton);
375 }
376
377 void dn_unregister_sysctl_skeleton(void)
378 {
379         unregister_sysctl_table(dn_skeleton_table_header);
380 }
381
382 void dn_register_sysctl(void)
383 {
384         dn_table_header = register_sysctl_paths(dn_path, dn_table);
385 }
386
387 void dn_unregister_sysctl(void)
388 {
389         unregister_sysctl_table(dn_table_header);
390 }
391
392 #else  /* CONFIG_SYSCTL */
393 void dn_register_sysctl_skeleton(void)
394 {
395 }
396 void dn_unregister_sysctl_skeleton(void)
397 {
398 }
399 void dn_unregister_sysctl(void)
400 {
401 }
402 void dn_register_sysctl(void)
403 {
404 }
405
406 #endif