sysctl.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*
  2. * File: sysctl.c
  3. *
  4. * Phonet /proc/sys/net/phonet interface implementation
  5. *
  6. * Copyright (C) 2008 Nokia Corporation.
  7. *
  8. * Author: Rémi Denis-Courmont
  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. #include <net/sock.h>
  29. #include <linux/phonet.h>
  30. #include <net/phonet/phonet.h>
  31. #define DYNAMIC_PORT_MIN 0x40
  32. #define DYNAMIC_PORT_MAX 0x7f
  33. static DEFINE_SEQLOCK(local_port_range_lock);
  34. static int local_port_range_min[2] = {0, 0};
  35. static int local_port_range_max[2] = {1023, 1023};
  36. static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
  37. static struct ctl_table_header *phonet_table_hrd;
  38. static void set_local_port_range(int range[2])
  39. {
  40. write_seqlock(&local_port_range_lock);
  41. local_port_range[0] = range[0];
  42. local_port_range[1] = range[1];
  43. write_sequnlock(&local_port_range_lock);
  44. }
  45. void phonet_get_local_port_range(int *min, int *max)
  46. {
  47. unsigned int seq;
  48. do {
  49. seq = read_seqbegin(&local_port_range_lock);
  50. if (min)
  51. *min = local_port_range[0];
  52. if (max)
  53. *max = local_port_range[1];
  54. } while (read_seqretry(&local_port_range_lock, seq));
  55. }
  56. static int proc_local_port_range(struct ctl_table *table, int write,
  57. void __user *buffer,
  58. size_t *lenp, loff_t *ppos)
  59. {
  60. int ret;
  61. int range[2] = {local_port_range[0], local_port_range[1]};
  62. struct ctl_table tmp = {
  63. .data = &range,
  64. .maxlen = sizeof(range),
  65. .mode = table->mode,
  66. .extra1 = &local_port_range_min,
  67. .extra2 = &local_port_range_max,
  68. };
  69. ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
  70. if (write && ret == 0) {
  71. if (range[1] < range[0])
  72. ret = -EINVAL;
  73. else
  74. set_local_port_range(range);
  75. }
  76. return ret;
  77. }
  78. static struct ctl_table phonet_table[] = {
  79. {
  80. .procname = "local_port_range",
  81. .data = &local_port_range,
  82. .maxlen = sizeof(local_port_range),
  83. .mode = 0644,
  84. .proc_handler = proc_local_port_range,
  85. },
  86. { }
  87. };
  88. int __init phonet_sysctl_init(void)
  89. {
  90. phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
  91. return phonet_table_hrd == NULL ? -ENOMEM : 0;
  92. }
  93. void phonet_sysctl_exit(void)
  94. {
  95. unregister_net_sysctl_table(phonet_table_hrd);
  96. }