sysctl.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * File: sysctl.c
  4. *
  5. * Phonet /proc/sys/net/phonet interface implementation
  6. *
  7. * Copyright (C) 2008 Nokia Corporation.
  8. *
  9. * Author: Rémi Denis-Courmont
  10. */
  11. #include <linux/seqlock.h>
  12. #include <linux/sysctl.h>
  13. #include <linux/errno.h>
  14. #include <linux/init.h>
  15. #include <net/sock.h>
  16. #include <linux/phonet.h>
  17. #include <net/phonet/phonet.h>
  18. #define DYNAMIC_PORT_MIN 0x40
  19. #define DYNAMIC_PORT_MAX 0x7f
  20. static DEFINE_SEQLOCK(local_port_range_lock);
  21. static int local_port_range_min[2] = {0, 0};
  22. static int local_port_range_max[2] = {1023, 1023};
  23. static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
  24. static struct ctl_table_header *phonet_table_hrd;
  25. static void set_local_port_range(int range[2])
  26. {
  27. write_seqlock(&local_port_range_lock);
  28. local_port_range[0] = range[0];
  29. local_port_range[1] = range[1];
  30. write_sequnlock(&local_port_range_lock);
  31. }
  32. void phonet_get_local_port_range(int *min, int *max)
  33. {
  34. unsigned int seq;
  35. do {
  36. seq = read_seqbegin(&local_port_range_lock);
  37. if (min)
  38. *min = local_port_range[0];
  39. if (max)
  40. *max = local_port_range[1];
  41. } while (read_seqretry(&local_port_range_lock, seq));
  42. }
  43. static int proc_local_port_range(struct ctl_table *table, int write,
  44. void *buffer, size_t *lenp, loff_t *ppos)
  45. {
  46. int ret;
  47. int range[2] = {local_port_range[0], local_port_range[1]};
  48. struct ctl_table tmp = {
  49. .data = &range,
  50. .maxlen = sizeof(range),
  51. .mode = table->mode,
  52. .extra1 = &local_port_range_min,
  53. .extra2 = &local_port_range_max,
  54. };
  55. ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
  56. if (write && ret == 0) {
  57. if (range[1] < range[0])
  58. ret = -EINVAL;
  59. else
  60. set_local_port_range(range);
  61. }
  62. return ret;
  63. }
  64. static struct ctl_table phonet_table[] = {
  65. {
  66. .procname = "local_port_range",
  67. .data = &local_port_range,
  68. .maxlen = sizeof(local_port_range),
  69. .mode = 0644,
  70. .proc_handler = proc_local_port_range,
  71. },
  72. { }
  73. };
  74. int __init phonet_sysctl_init(void)
  75. {
  76. phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
  77. return phonet_table_hrd == NULL ? -ENOMEM : 0;
  78. }
  79. void phonet_sysctl_exit(void)
  80. {
  81. unregister_net_sysctl_table(phonet_table_hrd);
  82. }