sysctl.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * File: sysctl.c
  3. *
  4. * Phonet /proc/sys/net/phonet interface implementation
  5. *
  6. * Copyright (C) 2008 Nokia Corporation.
  7. *
  8. * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * version 2 as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  22. * 02110-1301 USA
  23. */
  24. #include <linux/seqlock.h>
  25. #include <linux/sysctl.h>
  26. #include <linux/errno.h>
  27. #include <linux/init.h>
  28. #define DYNAMIC_PORT_MIN 0x40
  29. #define DYNAMIC_PORT_MAX 0x7f
  30. static DEFINE_SEQLOCK(local_port_range_lock);
  31. static int local_port_range_min[2] = {0, 0};
  32. static int local_port_range_max[2] = {1023, 1023};
  33. static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
  34. static struct ctl_table_header *phonet_table_hrd;
  35. static void set_local_port_range(int range[2])
  36. {
  37. write_seqlock(&local_port_range_lock);
  38. local_port_range[0] = range[0];
  39. local_port_range[1] = range[1];
  40. write_sequnlock(&local_port_range_lock);
  41. }
  42. void phonet_get_local_port_range(int *min, int *max)
  43. {
  44. unsigned seq;
  45. do {
  46. seq = read_seqbegin(&local_port_range_lock);
  47. if (min)
  48. *min = local_port_range[0];
  49. if (max)
  50. *max = local_port_range[1];
  51. } while (read_seqretry(&local_port_range_lock, seq));
  52. }
  53. static int proc_local_port_range(ctl_table *table, int write,
  54. void __user *buffer,
  55. size_t *lenp, loff_t *ppos)
  56. {
  57. int ret;
  58. int range[2] = {local_port_range[0], local_port_range[1]};
  59. ctl_table tmp = {
  60. .data = &range,
  61. .maxlen = sizeof(range),
  62. .mode = table->mode,
  63. .extra1 = &local_port_range_min,
  64. .extra2 = &local_port_range_max,
  65. };
  66. ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
  67. if (write && ret == 0) {
  68. if (range[1] < range[0])
  69. ret = -EINVAL;
  70. else
  71. set_local_port_range(range);
  72. }
  73. return ret;
  74. }
  75. static struct ctl_table phonet_table[] = {
  76. {
  77. .procname = "local_port_range",
  78. .data = &local_port_range,
  79. .maxlen = sizeof(local_port_range),
  80. .mode = 0644,
  81. .proc_handler = proc_local_port_range,
  82. },
  83. { }
  84. };
  85. static struct ctl_path phonet_ctl_path[] = {
  86. { .procname = "net", },
  87. { .procname = "phonet", },
  88. { },
  89. };
  90. int __init phonet_sysctl_init(void)
  91. {
  92. phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table);
  93. return phonet_table_hrd == NULL ? -ENOMEM : 0;
  94. }
  95. void phonet_sysctl_exit(void)
  96. {
  97. unregister_sysctl_table(phonet_table_hrd);
  98. }