sysctl.c 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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(const 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. int __init phonet_sysctl_init(void)
  74. {
  75. phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
  76. return phonet_table_hrd == NULL ? -ENOMEM : 0;
  77. }
  78. void phonet_sysctl_exit(void)
  79. {
  80. unregister_net_sysctl_table(phonet_table_hrd);
  81. }