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