• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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