linux/net/decnet/sysctl_net_decnet.c
<<
>>
Prefs
   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 = cpu_to_le16((area << 10) | node);
 130
 131        return 0;
 132}
 133
 134
 135static int dn_node_address_strategy(ctl_table *table,
 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(le16_to_cpu(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,
 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(&init_net, 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(&init_net, 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 struct ctl_path dn_path[] = {
 474        { .procname = "net", .ctl_name = CTL_NET, },
 475        { .procname = "decnet", .ctl_name = NET_DECNET, },
 476        { }
 477};
 478
 479void dn_register_sysctl(void)
 480{
 481        dn_table_header = register_sysctl_paths(dn_path, dn_table);
 482}
 483
 484void dn_unregister_sysctl(void)
 485{
 486        unregister_sysctl_table(dn_table_header);
 487}
 488
 489#else  /* CONFIG_SYSCTL */
 490void dn_unregister_sysctl(void)
 491{
 492}
 493void dn_register_sysctl(void)
 494{
 495}
 496
 497#endif
 498