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