at v5.2-rc1 373 lines 7.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * DECnet An implementation of the DECnet protocol suite for the LINUX 4 * operating system. DECnet is implemented using the BSD Socket 5 * interface as the means of communication with the user level. 6 * 7 * DECnet sysctl support functions 8 * 9 * Author: Steve Whitehouse <SteveW@ACM.org> 10 * 11 * 12 * Changes: 13 * Steve Whitehouse - C99 changes and default device handling 14 * Steve Whitehouse - Memory buffer settings, like the tcp ones 15 * 16 */ 17#include <linux/mm.h> 18#include <linux/sysctl.h> 19#include <linux/fs.h> 20#include <linux/netdevice.h> 21#include <linux/string.h> 22#include <net/neighbour.h> 23#include <net/dst.h> 24#include <net/flow.h> 25 26#include <linux/uaccess.h> 27 28#include <net/dn.h> 29#include <net/dn_dev.h> 30#include <net/dn_route.h> 31 32 33int decnet_debug_level; 34int decnet_time_wait = 30; 35int decnet_dn_count = 1; 36int decnet_di_count = 3; 37int decnet_dr_count = 3; 38int decnet_log_martians = 1; 39int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW; 40 41/* Reasonable defaults, I hope, based on tcp's defaults */ 42long sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 }; 43int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 }; 44int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 }; 45 46#ifdef CONFIG_SYSCTL 47extern int decnet_dst_gc_interval; 48static int min_decnet_time_wait[] = { 5 }; 49static int max_decnet_time_wait[] = { 600 }; 50static int min_state_count[] = { 1 }; 51static int max_state_count[] = { NSP_MAXRXTSHIFT }; 52static int min_decnet_dst_gc_interval[] = { 1 }; 53static int max_decnet_dst_gc_interval[] = { 60 }; 54static int min_decnet_no_fc_max_cwnd[] = { NSP_MIN_WINDOW }; 55static int max_decnet_no_fc_max_cwnd[] = { NSP_MAX_WINDOW }; 56static char node_name[7] = "???"; 57 58static struct ctl_table_header *dn_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 69static 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 */ 90static 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 136static int dn_node_address_handler(struct 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 187static int dn_def_dev_handler(struct 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 250static struct 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 355void dn_register_sysctl(void) 356{ 357 dn_table_header = register_net_sysctl(&init_net, "net/decnet", dn_table); 358} 359 360void dn_unregister_sysctl(void) 361{ 362 unregister_net_sysctl_table(dn_table_header); 363} 364 365#else /* CONFIG_SYSCTL */ 366void dn_unregister_sysctl(void) 367{ 368} 369void dn_register_sysctl(void) 370{ 371} 372 373#endif