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 *
13 */
14 #include <linux/config.h>
15 #include <linux/mm.h>
16 #include <linux/sysctl.h>
17 #include <linux/fs.h>
18 #include <linux/netdevice.h>
19 #include <linux/string.h>
20 #include <net/neighbour.h>
21 #include <net/dst.h>
22
23 #include <asm/uaccess.h>
24
25 #include <net/dn.h>
26 #include <net/dn_dev.h>
27 #include <net/dn_route.h>
28
29
30 int decnet_debug_level;
31 int decnet_time_wait = 30;
32 int decnet_dn_count = 1;
33 int decnet_di_count = 3;
34 int decnet_dr_count = 3;
35 int decnet_log_martians = 1;
36 int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
37
38 #ifdef CONFIG_SYSCTL
39 extern int decnet_dst_gc_interval;
40 static int min_decnet_time_wait[] = { 5 };
41 static int max_decnet_time_wait[] = { 600 };
42 static int min_state_count[] = { 1 };
43 static int max_state_count[] = { NSP_MAXRXTSHIFT };
44 static int min_decnet_dst_gc_interval[] = { 1 };
45 static int max_decnet_dst_gc_interval[] = { 60 };
46 static int min_decnet_no_fc_max_cwnd[] = { NSP_MIN_WINDOW };
47 static int max_decnet_no_fc_max_cwnd[] = { NSP_MAX_WINDOW };
48 static char node_name[7] = "???";
49
50 static struct ctl_table_header *dn_table_header = NULL;
51
52 /*
53 * ctype.h :-)
54 */
55 #define ISNUM(x) (((x) >= '0') && ((x) <= '9'))
56 #define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
57 #define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
58 #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
59 #define INVALID_END_CHAR(x) (ISNUM(x) || ISALPHA(x))
60
strip_it(char * str)61 static void strip_it(char *str)
62 {
63 for(;;) {
64 switch(*str) {
65 case ' ':
66 case '\n':
67 case '\r':
68 case ':':
69 *str = 0;
70 case 0:
71 return;
72 }
73 str++;
74 }
75 }
76
77 /*
78 * Simple routine to parse an ascii DECnet address
79 * into a network order address.
80 */
parse_addr(dn_address * addr,char * str)81 static int parse_addr(dn_address *addr, char *str)
82 {
83 dn_address area, node;
84
85 while(*str && !ISNUM(*str)) str++;
86
87 if (*str == 0)
88 return -1;
89
90 area = (*str++ - '0');
91 if (ISNUM(*str)) {
92 area *= 10;
93 area += (*str++ - '0');
94 }
95
96 if (*str++ != '.')
97 return -1;
98
99 if (!ISNUM(*str))
100 return -1;
101
102 node = *str++ - '0';
103 if (ISNUM(*str)) {
104 node *= 10;
105 node += (*str++ - '0');
106 }
107 if (ISNUM(*str)) {
108 node *= 10;
109 node += (*str++ - '0');
110 }
111 if (ISNUM(*str)) {
112 node *= 10;
113 node += (*str++ - '0');
114 }
115
116 if ((node > 1023) || (area > 63))
117 return -1;
118
119 if (INVALID_END_CHAR(*str))
120 return -1;
121
122 *addr = dn_htons((area << 10) | node);
123
124 return 0;
125 }
126
127
dn_node_address_strategy(ctl_table * table,int * name,int nlen,void * oldval,size_t * oldlenp,void * newval,size_t newlen,void ** context)128 static int dn_node_address_strategy(ctl_table *table, int *name, int nlen,
129 void *oldval, size_t *oldlenp,
130 void *newval, size_t newlen,
131 void **context)
132 {
133 size_t len;
134 dn_address addr;
135
136 if (oldval && oldlenp) {
137 if (get_user(len, oldlenp))
138 return -EFAULT;
139 if (len) {
140 if (len != sizeof(unsigned short))
141 return -EINVAL;
142 if (put_user(decnet_address, (unsigned short *)oldval))
143 return -EFAULT;
144 }
145 }
146 if (newval && newlen) {
147 if (newlen != sizeof(unsigned short))
148 return -EINVAL;
149 if (get_user(addr, (unsigned short *)newval))
150 return -EFAULT;
151
152 dn_dev_devices_off();
153
154 decnet_address = addr;
155 dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
156
157 dn_dev_devices_on();
158 }
159 return 0;
160 }
161
dn_node_address_handler(ctl_table * table,int write,struct file * filp,void * buffer,size_t * lenp)162 static int dn_node_address_handler(ctl_table *table, int write,
163 struct file *filp,
164 void *buffer, size_t *lenp)
165 {
166 char addr[DN_ASCBUF_LEN];
167 size_t len;
168 dn_address dnaddr;
169
170 if (!*lenp || (filp->f_pos && !write)) {
171 *lenp = 0;
172 return 0;
173 }
174
175 if (write) {
176 int len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
177
178 if (copy_from_user(addr, buffer, len))
179 return -EFAULT;
180
181 addr[len] = 0;
182 strip_it(addr);
183
184 if (parse_addr(&dnaddr, addr))
185 return -EINVAL;
186
187 dn_dev_devices_off();
188
189 decnet_address = dnaddr;
190 dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
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
dn_def_dev_strategy(ctl_table * table,int * name,int nlen,void * oldval,size_t * oldlenp,void * newval,size_t newlen,void ** context)215 static int dn_def_dev_strategy(ctl_table *table, int *name, int nlen,
216 void *oldval, size_t *oldlenp,
217 void *newval, size_t newlen,
218 void **context)
219 {
220 size_t len;
221 struct net_device *dev = decnet_default_device;
222 char devname[17];
223 size_t namel;
224
225 devname[0] = 0;
226
227 if (oldval && oldlenp) {
228 if (get_user(len, oldlenp))
229 return -EFAULT;
230 if (len) {
231 if (dev)
232 strcpy(devname, dev->name);
233
234 namel = strlen(devname) + 1;
235 if (len > namel) len = namel;
236
237 if (copy_to_user(oldval, devname, len))
238 return -EFAULT;
239
240 if (put_user(len, oldlenp))
241 return -EFAULT;
242 }
243 }
244
245 if (newval && newlen) {
246 if (newlen > 16)
247 return -E2BIG;
248
249 if (copy_from_user(devname, newval, newlen))
250 return -EFAULT;
251
252 devname[newlen] = 0;
253
254 if ((dev = __dev_get_by_name(devname)) == NULL)
255 return -ENODEV;
256
257 if (dev->dn_ptr == NULL)
258 return -ENODEV;
259
260 decnet_default_device = dev;
261 }
262
263 return 0;
264 }
265
266
dn_def_dev_handler(ctl_table * table,int write,struct file * filp,void * buffer,size_t * lenp)267 static int dn_def_dev_handler(ctl_table *table, int write,
268 struct file * filp,
269 void *buffer, size_t *lenp)
270 {
271 size_t len;
272 struct net_device *dev = decnet_default_device;
273 char devname[17];
274
275 if (!*lenp || (filp->f_pos && !write)) {
276 *lenp = 0;
277 return 0;
278 }
279
280 if (write) {
281 if (*lenp > 16)
282 return -E2BIG;
283
284 if (copy_from_user(devname, buffer, *lenp))
285 return -EFAULT;
286
287 devname[*lenp] = 0;
288 strip_it(devname);
289
290 if ((dev = __dev_get_by_name(devname)) == NULL)
291 return -ENODEV;
292
293 if (dev->dn_ptr == NULL)
294 return -ENODEV;
295
296 decnet_default_device = dev;
297 filp->f_pos += *lenp;
298
299 return 0;
300 }
301
302 if (dev == NULL) {
303 *lenp = 0;
304 return 0;
305 }
306
307 strcpy(devname, dev->name);
308 len = strlen(devname);
309 devname[len++] = '\n';
310
311 if (len > *lenp) len = *lenp;
312
313 if (copy_to_user(buffer, devname, len))
314 return -EFAULT;
315
316 *lenp = len;
317 filp->f_pos += len;
318
319 return 0;
320 }
321
322 static ctl_table dn_table[] = {
323 {NET_DECNET_NODE_ADDRESS, "node_address", NULL, 7, 0644, NULL,
324 dn_node_address_handler, dn_node_address_strategy, NULL,
325 NULL, NULL},
326 {NET_DECNET_NODE_NAME, "node_name", node_name, 7, 0644, NULL,
327 &proc_dostring, &sysctl_string, NULL, NULL, NULL},
328 {NET_DECNET_DEFAULT_DEVICE, "default_device", NULL, 16, 0644, NULL,
329 dn_def_dev_handler, dn_def_dev_strategy, NULL, NULL, NULL},
330 {NET_DECNET_TIME_WAIT, "time_wait", &decnet_time_wait,
331 sizeof(int), 0644,
332 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
333 &min_decnet_time_wait, &max_decnet_time_wait},
334 {NET_DECNET_DN_COUNT, "dn_count", &decnet_dn_count,
335 sizeof(int), 0644,
336 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
337 &min_state_count, &max_state_count},
338 {NET_DECNET_DI_COUNT, "di_count", &decnet_di_count,
339 sizeof(int), 0644,
340 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
341 &min_state_count, &max_state_count},
342 {NET_DECNET_DR_COUNT, "dr_count", &decnet_dr_count,
343 sizeof(int), 0644,
344 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
345 &min_state_count, &max_state_count},
346 {NET_DECNET_DST_GC_INTERVAL, "dst_gc_interval", &decnet_dst_gc_interval,
347 sizeof(int), 0644,
348 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
349 &min_decnet_dst_gc_interval, &max_decnet_dst_gc_interval},
350 {NET_DECNET_NO_FC_MAX_CWND, "no_fc_max_cwnd", &decnet_no_fc_max_cwnd,
351 sizeof(int), 0644,
352 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
353 &min_decnet_no_fc_max_cwnd, &max_decnet_no_fc_max_cwnd},
354 {NET_DECNET_DEBUG_LEVEL, "debug", &decnet_debug_level,
355 sizeof(int), 0644,
356 NULL, &proc_dointvec, &sysctl_intvec, NULL,
357 NULL, NULL},
358 {0}
359 };
360
361 static ctl_table dn_dir_table[] = {
362 {NET_DECNET, "decnet", NULL, 0, 0555, dn_table},
363 {0}
364 };
365
366 static ctl_table dn_root_table[] = {
367 {CTL_NET, "net", NULL, 0, 0555, dn_dir_table},
368 {0}
369 };
370
dn_register_sysctl(void)371 void dn_register_sysctl(void)
372 {
373 dn_table_header = register_sysctl_table(dn_root_table, 1);
374 }
375
dn_unregister_sysctl(void)376 void dn_unregister_sysctl(void)
377 {
378 unregister_sysctl_table(dn_table_header);
379 }
380
381 #else /* CONFIG_SYSCTL */
dn_unregister_sysctl(void)382 void dn_unregister_sysctl(void)
383 {
384 }
dn_register_sysctl(void)385 void dn_register_sysctl(void)
386 {
387 }
388
389 #endif
390