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