sysctl_net_decnet.c (7247B)
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 *buffer, 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 memcpy(addr, buffer, len); 151 addr[len] = 0; 152 strip_it(addr); 153 154 if (parse_addr(&dnaddr, addr)) 155 return -EINVAL; 156 157 dn_dev_devices_off(); 158 159 decnet_address = dnaddr; 160 161 dn_dev_devices_on(); 162 163 *ppos += len; 164 165 return 0; 166 } 167 168 dn_addr2asc(le16_to_cpu(decnet_address), addr); 169 len = strlen(addr); 170 addr[len++] = '\n'; 171 172 if (len > *lenp) 173 len = *lenp; 174 memcpy(buffer, addr, len); 175 *lenp = len; 176 *ppos += len; 177 178 return 0; 179} 180 181static int dn_def_dev_handler(struct ctl_table *table, int write, 182 void *buffer, size_t *lenp, loff_t *ppos) 183{ 184 size_t len; 185 struct net_device *dev; 186 char devname[17]; 187 188 if (!*lenp || (*ppos && !write)) { 189 *lenp = 0; 190 return 0; 191 } 192 193 if (write) { 194 if (*lenp > 16) 195 return -E2BIG; 196 197 memcpy(devname, buffer, *lenp); 198 devname[*lenp] = 0; 199 strip_it(devname); 200 201 dev = dev_get_by_name(&init_net, devname); 202 if (dev == NULL) 203 return -ENODEV; 204 205 if (dev->dn_ptr == NULL) { 206 dev_put(dev); 207 return -ENODEV; 208 } 209 210 if (dn_dev_set_default(dev, 1)) { 211 dev_put(dev); 212 return -ENODEV; 213 } 214 *ppos += *lenp; 215 216 return 0; 217 } 218 219 dev = dn_dev_get_default(); 220 if (dev == NULL) { 221 *lenp = 0; 222 return 0; 223 } 224 225 strcpy(devname, dev->name); 226 dev_put(dev); 227 len = strlen(devname); 228 devname[len++] = '\n'; 229 230 if (len > *lenp) len = *lenp; 231 232 memcpy(buffer, devname, len); 233 *lenp = len; 234 *ppos += len; 235 236 return 0; 237} 238 239static struct ctl_table dn_table[] = { 240 { 241 .procname = "node_address", 242 .maxlen = 7, 243 .mode = 0644, 244 .proc_handler = dn_node_address_handler, 245 }, 246 { 247 .procname = "node_name", 248 .data = node_name, 249 .maxlen = 7, 250 .mode = 0644, 251 .proc_handler = proc_dostring, 252 }, 253 { 254 .procname = "default_device", 255 .maxlen = 16, 256 .mode = 0644, 257 .proc_handler = dn_def_dev_handler, 258 }, 259 { 260 .procname = "time_wait", 261 .data = &decnet_time_wait, 262 .maxlen = sizeof(int), 263 .mode = 0644, 264 .proc_handler = proc_dointvec_minmax, 265 .extra1 = &min_decnet_time_wait, 266 .extra2 = &max_decnet_time_wait 267 }, 268 { 269 .procname = "dn_count", 270 .data = &decnet_dn_count, 271 .maxlen = sizeof(int), 272 .mode = 0644, 273 .proc_handler = proc_dointvec_minmax, 274 .extra1 = &min_state_count, 275 .extra2 = &max_state_count 276 }, 277 { 278 .procname = "di_count", 279 .data = &decnet_di_count, 280 .maxlen = sizeof(int), 281 .mode = 0644, 282 .proc_handler = proc_dointvec_minmax, 283 .extra1 = &min_state_count, 284 .extra2 = &max_state_count 285 }, 286 { 287 .procname = "dr_count", 288 .data = &decnet_dr_count, 289 .maxlen = sizeof(int), 290 .mode = 0644, 291 .proc_handler = proc_dointvec_minmax, 292 .extra1 = &min_state_count, 293 .extra2 = &max_state_count 294 }, 295 { 296 .procname = "dst_gc_interval", 297 .data = &decnet_dst_gc_interval, 298 .maxlen = sizeof(int), 299 .mode = 0644, 300 .proc_handler = proc_dointvec_minmax, 301 .extra1 = &min_decnet_dst_gc_interval, 302 .extra2 = &max_decnet_dst_gc_interval 303 }, 304 { 305 .procname = "no_fc_max_cwnd", 306 .data = &decnet_no_fc_max_cwnd, 307 .maxlen = sizeof(int), 308 .mode = 0644, 309 .proc_handler = proc_dointvec_minmax, 310 .extra1 = &min_decnet_no_fc_max_cwnd, 311 .extra2 = &max_decnet_no_fc_max_cwnd 312 }, 313 { 314 .procname = "decnet_mem", 315 .data = &sysctl_decnet_mem, 316 .maxlen = sizeof(sysctl_decnet_mem), 317 .mode = 0644, 318 .proc_handler = proc_doulongvec_minmax 319 }, 320 { 321 .procname = "decnet_rmem", 322 .data = &sysctl_decnet_rmem, 323 .maxlen = sizeof(sysctl_decnet_rmem), 324 .mode = 0644, 325 .proc_handler = proc_dointvec, 326 }, 327 { 328 .procname = "decnet_wmem", 329 .data = &sysctl_decnet_wmem, 330 .maxlen = sizeof(sysctl_decnet_wmem), 331 .mode = 0644, 332 .proc_handler = proc_dointvec, 333 }, 334 { 335 .procname = "debug", 336 .data = &decnet_debug_level, 337 .maxlen = sizeof(int), 338 .mode = 0644, 339 .proc_handler = proc_dointvec, 340 }, 341 { } 342}; 343 344void dn_register_sysctl(void) 345{ 346 dn_table_header = register_net_sysctl(&init_net, "net/decnet", dn_table); 347} 348 349void dn_unregister_sysctl(void) 350{ 351 unregister_net_sysctl_table(dn_table_header); 352} 353 354#else /* CONFIG_SYSCTL */ 355void dn_unregister_sysctl(void) 356{ 357} 358void dn_register_sysctl(void) 359{ 360} 361 362#endif