1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Based on net/ipv4/ip_sockglue.c
4 * Authors: see ip.c
5 *
6 * Fixes:
7 * Many : Split from ip.c , see ip.c for history.
8 * Martin Mares : TOS setting fixed.
9 * Alan Cox : Fixed a couple of oopses in Martin's
10 * TOS tweaks.
11 * Mike McLagan : Routing by source
12 *
13 * NewIP INET An implementation of the TCP/IP protocol suite for the LINUX
14 * operating system. NewIP is implemented using the BSD Socket
15 * interface as the means of communication with the user level.
16 *
17 * The NewIP to API glue.
18 */
19 #define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
20
21 #include <net/sock.h>
22 #include <net/nip.h>
23 #include <net/nip_udp.h>
24 #include <net/route.h>
25 #include <net/nip_fib.h>
26 #include <net/nip_addrconf.h>
27 #include <linux/module.h>
28 #include <linux/types.h>
29 #include <linux/skbuff.h>
30 #include <linux/nip.h>
31 #include <linux/inetdevice.h>
32 #include <linux/netdevice.h>
33 #include "tcp_nip_parameter.h"
34
35 #define NIP_OPTNAME_MAX 255
36
__nip_set_sock_tos(struct sock * sk,int val)37 static void __nip_set_sock_tos(struct sock *sk, int val)
38 {
39 sk->sk_priority = rt_tos2priority(val);
40 sk_dst_reset(sk);
41 }
42
nip_setsockopt_needs_rtnl(int optname)43 static bool nip_setsockopt_needs_rtnl(int optname)
44 {
45 switch (optname) {
46 case IP_MSFILTER:
47 return true;
48 default:
49 return false;
50 }
51 }
52
nip_getsockopt_needs_rtnl(int optname)53 static bool nip_getsockopt_needs_rtnl(int optname)
54 {
55 switch (optname) {
56 case IP_MSFILTER:
57 return true;
58 default:
59 return false;
60 }
61 }
62
do_nip_setsockopt(struct sock * sk,int level,int optname,sockptr_t optval,unsigned int optlen)63 static int do_nip_setsockopt(struct sock *sk, int level, int optname,
64 sockptr_t optval, unsigned int optlen)
65 {
66 struct inet_sock *inet = inet_sk(sk);
67 int val = 0;
68 int err = 0;
69 bool needs_rtnl = nip_setsockopt_needs_rtnl(optname);
70
71 if (optlen >= sizeof(int)) {
72 if (copy_from_sockptr(&val, optval, sizeof(val)))
73 return -EFAULT;
74 } else if (optlen >= sizeof(char)) {
75 unsigned char ucval;
76
77 if (copy_from_sockptr(&ucval, optval, sizeof(ucval)))
78 return -EFAULT;
79 val = (int)ucval;
80 }
81
82 if (needs_rtnl)
83 rtnl_lock();
84 lock_sock(sk);
85
86 switch (optname) {
87 case IP_TOS:
88 inet->tos = val;
89 __nip_set_sock_tos(sk, val);
90 break;
91 default:
92 err = -ENOPROTOOPT;
93 break;
94 }
95
96 release_sock(sk);
97 if (needs_rtnl)
98 rtnl_unlock();
99
100 return err;
101 }
102
nip_setsockopt(struct sock * sk,int level,int optname,sockptr_t optval,unsigned int optlen)103 int nip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
104 unsigned int optlen)
105 {
106 int err;
107
108 if (level != SOL_IP)
109 return -ENOPROTOOPT;
110
111 err = do_nip_setsockopt(sk, level, optname, optval, optlen);
112
113 return err;
114 }
115
do_nip_getsockopt(struct sock * sk,int level,int optname,char __user * optval,int __user * optlen)116 static int do_nip_getsockopt(struct sock *sk, int level, int optname,
117 char __user *optval, int __user *optlen)
118 {
119 struct inet_sock *inet = inet_sk(sk);
120 bool needs_rtnl = nip_getsockopt_needs_rtnl(optname);
121 int val, err = 0;
122 int len;
123
124 if (level != SOL_IP)
125 return -EOPNOTSUPP;
126 if (get_user(len, optlen))
127 return -EFAULT;
128 if (len < 0)
129 return -EINVAL;
130
131 if (needs_rtnl)
132 rtnl_lock();
133 lock_sock(sk);
134
135 switch (optname) {
136 case IP_TOS:
137 val = inet->tos;
138 break;
139 default:
140 err = -ENOPROTOOPT;
141 goto out;
142 }
143
144 if (len < sizeof(int) && len > 0 && val >= 0 && val <= NIP_OPTNAME_MAX) {
145 unsigned char ucval = (unsigned char)val;
146
147 len = 1;
148 if (put_user(len, optlen)) {
149 err = -EFAULT;
150 goto out;
151 }
152 if (copy_to_user(optval, &ucval, 1)) {
153 err = -EFAULT;
154 goto out;
155 }
156 } else {
157 len = min_t(unsigned int, sizeof(int), len);
158 if (put_user(len, optlen)) {
159 err = -EFAULT;
160 goto out;
161 }
162 if (copy_to_user(optval, &val, len)) {
163 err = -EFAULT;
164 goto out;
165 }
166 }
167 out:
168 release_sock(sk);
169 if (needs_rtnl)
170 rtnl_unlock();
171
172 return err;
173 }
174
nip_getsockopt(struct sock * sk,int level,int optname,char __user * optval,int __user * optlen)175 int nip_getsockopt(struct sock *sk, int level,
176 int optname, char __user *optval, int __user *optlen)
177 {
178 return do_nip_getsockopt(sk, level, optname, optval, optlen);
179 }
180
nip_sock_debug_output(const struct nip_addr * nip_daddr,const struct nip_addr * nip_saddr,__be16 dport,__be16 sport,const char * name)181 void nip_sock_debug_output(const struct nip_addr *nip_daddr, const struct nip_addr *nip_saddr,
182 __be16 dport, __be16 sport, const char *name)
183 {
184 if (get_nip_debug()) {
185 char saddr[NIP_ADDR_BIT_LEN_MAX] = {0};
186 char daddr[NIP_ADDR_BIT_LEN_MAX] = {0};
187
188 nip_addr_to_str(nip_daddr, daddr, NIP_ADDR_BIT_LEN_MAX);
189 nip_addr_to_str(nip_saddr, saddr, NIP_ADDR_BIT_LEN_MAX);
190
191 nip_dbg("%s (saddr=%s, daddr=%s, sport=%u, dport=%u)",
192 name, saddr, daddr, ntohs(sport), ntohs(dport));
193 }
194 }
195
nip_sock_debug(const struct sock * sk,const char * name)196 void nip_sock_debug(const struct sock *sk, const char *name)
197 {
198 if (sk) {
199 struct inet_sock *inet = inet_sk(sk);
200
201 nip_sock_debug_output(&sk->SK_NIP_DADDR, &sk->SK_NIP_RCV_SADDR,
202 inet->inet_dport, inet->inet_sport, name);
203 }
204 }
205
206