162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * File: sysctl.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Phonet /proc/sys/net/phonet interface implementation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Rémi Denis-Courmont 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/seqlock.h> 1362306a36Sopenharmony_ci#include <linux/sysctl.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci#include <linux/phonet.h> 1962306a36Sopenharmony_ci#include <net/phonet/phonet.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define DYNAMIC_PORT_MIN 0x40 2262306a36Sopenharmony_ci#define DYNAMIC_PORT_MAX 0x7f 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic DEFINE_SEQLOCK(local_port_range_lock); 2562306a36Sopenharmony_cistatic int local_port_range_min[2] = {0, 0}; 2662306a36Sopenharmony_cistatic int local_port_range_max[2] = {1023, 1023}; 2762306a36Sopenharmony_cistatic int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX}; 2862306a36Sopenharmony_cistatic struct ctl_table_header *phonet_table_hrd; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void set_local_port_range(int range[2]) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci write_seqlock(&local_port_range_lock); 3362306a36Sopenharmony_ci local_port_range[0] = range[0]; 3462306a36Sopenharmony_ci local_port_range[1] = range[1]; 3562306a36Sopenharmony_ci write_sequnlock(&local_port_range_lock); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_civoid phonet_get_local_port_range(int *min, int *max) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci unsigned int seq; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci do { 4362306a36Sopenharmony_ci seq = read_seqbegin(&local_port_range_lock); 4462306a36Sopenharmony_ci if (min) 4562306a36Sopenharmony_ci *min = local_port_range[0]; 4662306a36Sopenharmony_ci if (max) 4762306a36Sopenharmony_ci *max = local_port_range[1]; 4862306a36Sopenharmony_ci } while (read_seqretry(&local_port_range_lock, seq)); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int proc_local_port_range(struct ctl_table *table, int write, 5262306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int ret; 5562306a36Sopenharmony_ci int range[2] = {local_port_range[0], local_port_range[1]}; 5662306a36Sopenharmony_ci struct ctl_table tmp = { 5762306a36Sopenharmony_ci .data = &range, 5862306a36Sopenharmony_ci .maxlen = sizeof(range), 5962306a36Sopenharmony_ci .mode = table->mode, 6062306a36Sopenharmony_ci .extra1 = &local_port_range_min, 6162306a36Sopenharmony_ci .extra2 = &local_port_range_max, 6262306a36Sopenharmony_ci }; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (write && ret == 0) { 6762306a36Sopenharmony_ci if (range[1] < range[0]) 6862306a36Sopenharmony_ci ret = -EINVAL; 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci set_local_port_range(range); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct ctl_table phonet_table[] = { 7762306a36Sopenharmony_ci { 7862306a36Sopenharmony_ci .procname = "local_port_range", 7962306a36Sopenharmony_ci .data = &local_port_range, 8062306a36Sopenharmony_ci .maxlen = sizeof(local_port_range), 8162306a36Sopenharmony_ci .mode = 0644, 8262306a36Sopenharmony_ci .proc_handler = proc_local_port_range, 8362306a36Sopenharmony_ci }, 8462306a36Sopenharmony_ci { } 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciint __init phonet_sysctl_init(void) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table); 9062306a36Sopenharmony_ci return phonet_table_hrd == NULL ? -ENOMEM : 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_civoid phonet_sysctl_exit(void) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci unregister_net_sysctl_table(phonet_table_hrd); 9662306a36Sopenharmony_ci} 97