mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
ipv6: add ip6_sock_set_addr_preferences
Add a helper to directly set the IPV6_ADD_PREFERENCES sockopt from kernel space without going through a fake uaccess. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
fce934949c
commit
18d5ad6232
@ -1195,4 +1195,71 @@ static inline void ip6_sock_set_recverr(struct sock *sk)
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
static inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val)
|
||||
{
|
||||
unsigned int pref = 0;
|
||||
unsigned int prefmask = ~0;
|
||||
|
||||
/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_PUBLIC |
|
||||
IPV6_PREFER_SRC_TMP |
|
||||
IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
|
||||
case IPV6_PREFER_SRC_PUBLIC:
|
||||
pref |= IPV6_PREFER_SRC_PUBLIC;
|
||||
prefmask &= ~(IPV6_PREFER_SRC_PUBLIC |
|
||||
IPV6_PREFER_SRC_TMP);
|
||||
break;
|
||||
case IPV6_PREFER_SRC_TMP:
|
||||
pref |= IPV6_PREFER_SRC_TMP;
|
||||
prefmask &= ~(IPV6_PREFER_SRC_PUBLIC |
|
||||
IPV6_PREFER_SRC_TMP);
|
||||
break;
|
||||
case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
|
||||
prefmask &= ~(IPV6_PREFER_SRC_PUBLIC |
|
||||
IPV6_PREFER_SRC_TMP);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check HOME/COA conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_COA)) {
|
||||
case IPV6_PREFER_SRC_HOME:
|
||||
prefmask &= ~IPV6_PREFER_SRC_COA;
|
||||
break;
|
||||
case IPV6_PREFER_SRC_COA:
|
||||
pref |= IPV6_PREFER_SRC_COA;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check CGA/NONCGA conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
|
||||
case IPV6_PREFER_SRC_CGA:
|
||||
case IPV6_PREFER_SRC_NONCGA:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
inet6_sk(sk)->srcprefs = (inet6_sk(sk)->srcprefs & prefmask) | pref;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ip6_sock_set_addr_preferences(struct sock *sk, bool val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lock_sock(sk);
|
||||
ret = __ip6_sock_set_addr_preferences(sk, val);
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* _NET_IPV6_H */
|
||||
|
@ -845,67 +845,10 @@ done:
|
||||
break;
|
||||
|
||||
case IPV6_ADDR_PREFERENCES:
|
||||
{
|
||||
unsigned int pref = 0;
|
||||
unsigned int prefmask = ~0;
|
||||
|
||||
if (optlen < sizeof(int))
|
||||
goto e_inval;
|
||||
|
||||
retv = -EINVAL;
|
||||
|
||||
/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_PUBLIC|
|
||||
IPV6_PREFER_SRC_TMP|
|
||||
IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
|
||||
case IPV6_PREFER_SRC_PUBLIC:
|
||||
pref |= IPV6_PREFER_SRC_PUBLIC;
|
||||
break;
|
||||
case IPV6_PREFER_SRC_TMP:
|
||||
pref |= IPV6_PREFER_SRC_TMP;
|
||||
break;
|
||||
case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
|
||||
break;
|
||||
case 0:
|
||||
goto pref_skip_pubtmp;
|
||||
default:
|
||||
goto e_inval;
|
||||
}
|
||||
|
||||
prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
|
||||
IPV6_PREFER_SRC_TMP);
|
||||
pref_skip_pubtmp:
|
||||
|
||||
/* check HOME/COA conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
|
||||
case IPV6_PREFER_SRC_HOME:
|
||||
break;
|
||||
case IPV6_PREFER_SRC_COA:
|
||||
pref |= IPV6_PREFER_SRC_COA;
|
||||
case 0:
|
||||
goto pref_skip_coa;
|
||||
default:
|
||||
goto e_inval;
|
||||
}
|
||||
|
||||
prefmask &= ~IPV6_PREFER_SRC_COA;
|
||||
pref_skip_coa:
|
||||
|
||||
/* check CGA/NONCGA conflicts */
|
||||
switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
|
||||
case IPV6_PREFER_SRC_CGA:
|
||||
case IPV6_PREFER_SRC_NONCGA:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
goto e_inval;
|
||||
}
|
||||
|
||||
np->srcprefs = (np->srcprefs & prefmask) | pref;
|
||||
retv = 0;
|
||||
|
||||
retv = __ip6_sock_set_addr_preferences(sk, val);
|
||||
break;
|
||||
}
|
||||
case IPV6_MINHOPCOUNT:
|
||||
if (optlen < sizeof(int))
|
||||
goto e_inval;
|
||||
|
@ -2150,7 +2150,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
||||
|
||||
if (!transport->inet) {
|
||||
struct sock *sk = sock->sk;
|
||||
unsigned int addr_pref = IPV6_PREFER_SRC_PUBLIC;
|
||||
|
||||
/* Avoid temporary address, they are bad for long-lived
|
||||
* connections such as NFS mounts.
|
||||
@ -2159,8 +2158,10 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
||||
* knowledge about the normal duration of connections,
|
||||
* MAY override this as appropriate.
|
||||
*/
|
||||
kernel_setsockopt(sock, SOL_IPV6, IPV6_ADDR_PREFERENCES,
|
||||
(char *)&addr_pref, sizeof(addr_pref));
|
||||
if (xs_addr(xprt)->sa_family == PF_INET6) {
|
||||
ip6_sock_set_addr_preferences(sk,
|
||||
IPV6_PREFER_SRC_PUBLIC);
|
||||
}
|
||||
|
||||
xs_tcp_set_socket_timeouts(xprt, sock);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user