Skip to content

Commit eee2fa6

Browse files
kcp-gitdavem330
authored andcommitted
rds: Changing IP address internal representation to struct in6_addr
This patch changes the internal representation of an IP address to use struct in6_addr. IPv4 address is stored as an IPv4 mapped address. All the functions which take an IP address as argument are also changed to use struct in6_addr. But RDS socket layer is not modified such that it still does not accept IPv6 address from an application. And RDS layer does not accept nor initiate IPv6 connections. v2: Fixed sparse warnings. Signed-off-by: Ka-Cheong Poon <[email protected]> Acked-by: Santosh Shilimkar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a6c90dd commit eee2fa6

23 files changed

+863
-369
lines changed

net/rds/af_rds.c

Lines changed: 99 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006 Oracle. All rights reserved.
2+
* Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This software is available to you under a choice of one of two
55
* licenses. You may choose to be licensed under the terms of the GNU
@@ -35,6 +35,7 @@
3535
#include <linux/kernel.h>
3636
#include <linux/gfp.h>
3737
#include <linux/in.h>
38+
#include <linux/ipv6.h>
3839
#include <linux/poll.h>
3940
#include <net/sock.h>
4041

@@ -113,26 +114,63 @@ void rds_wake_sk_sleep(struct rds_sock *rs)
113114
static int rds_getname(struct socket *sock, struct sockaddr *uaddr,
114115
int peer)
115116
{
116-
struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
117117
struct rds_sock *rs = rds_sk_to_rs(sock->sk);
118-
119-
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
118+
struct sockaddr_in6 *sin6;
119+
struct sockaddr_in *sin;
120+
int uaddr_len;
120121

121122
/* racey, don't care */
122123
if (peer) {
123-
if (!rs->rs_conn_addr)
124+
if (ipv6_addr_any(&rs->rs_conn_addr))
124125
return -ENOTCONN;
125126

126-
sin->sin_port = rs->rs_conn_port;
127-
sin->sin_addr.s_addr = rs->rs_conn_addr;
127+
if (ipv6_addr_v4mapped(&rs->rs_conn_addr)) {
128+
sin = (struct sockaddr_in *)uaddr;
129+
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
130+
sin->sin_family = AF_INET;
131+
sin->sin_port = rs->rs_conn_port;
132+
sin->sin_addr.s_addr = rs->rs_conn_addr_v4;
133+
uaddr_len = sizeof(*sin);
134+
} else {
135+
sin6 = (struct sockaddr_in6 *)uaddr;
136+
sin6->sin6_family = AF_INET6;
137+
sin6->sin6_port = rs->rs_conn_port;
138+
sin6->sin6_addr = rs->rs_conn_addr;
139+
sin6->sin6_flowinfo = 0;
140+
/* scope_id is the same as in the bound address. */
141+
sin6->sin6_scope_id = rs->rs_bound_scope_id;
142+
uaddr_len = sizeof(*sin6);
143+
}
128144
} else {
129-
sin->sin_port = rs->rs_bound_port;
130-
sin->sin_addr.s_addr = rs->rs_bound_addr;
145+
/* If socket is not yet bound, set the return address family
146+
* to be AF_UNSPEC (value 0) and the address size to be that
147+
* of an IPv4 address.
148+
*/
149+
if (ipv6_addr_any(&rs->rs_bound_addr)) {
150+
sin = (struct sockaddr_in *)uaddr;
151+
memset(sin, 0, sizeof(*sin));
152+
sin->sin_family = AF_UNSPEC;
153+
return sizeof(*sin);
154+
}
155+
if (ipv6_addr_v4mapped(&rs->rs_bound_addr)) {
156+
sin = (struct sockaddr_in *)uaddr;
157+
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
158+
sin->sin_family = AF_INET;
159+
sin->sin_port = rs->rs_bound_port;
160+
sin->sin_addr.s_addr = rs->rs_bound_addr_v4;
161+
uaddr_len = sizeof(*sin);
162+
} else {
163+
sin6 = (struct sockaddr_in6 *)uaddr;
164+
sin6->sin6_family = AF_INET6;
165+
sin6->sin6_port = rs->rs_bound_port;
166+
sin6->sin6_addr = rs->rs_bound_addr;
167+
sin6->sin6_flowinfo = 0;
168+
sin6->sin6_scope_id = rs->rs_bound_scope_id;
169+
uaddr_len = sizeof(*sin6);
170+
}
131171
}
132172

133-
sin->sin_family = AF_INET;
134-
135-
return sizeof(*sin);
173+
return uaddr_len;
136174
}
137175

138176
/*
@@ -203,26 +241,36 @@ static int rds_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
203241
static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
204242
int len)
205243
{
244+
struct sockaddr_in6 sin6;
206245
struct sockaddr_in sin;
207246
int ret = 0;
208247

209248
/* racing with another thread binding seems ok here */
210-
if (rs->rs_bound_addr == 0) {
249+
if (ipv6_addr_any(&rs->rs_bound_addr)) {
211250
ret = -ENOTCONN; /* XXX not a great errno */
212251
goto out;
213252
}
214253

215254
if (len < sizeof(struct sockaddr_in)) {
216255
ret = -EINVAL;
217256
goto out;
257+
} else if (len < sizeof(struct sockaddr_in6)) {
258+
/* Assume IPv4 */
259+
if (copy_from_user(&sin, optval, sizeof(struct sockaddr_in))) {
260+
ret = -EFAULT;
261+
goto out;
262+
}
263+
ipv6_addr_set_v4mapped(sin.sin_addr.s_addr, &sin6.sin6_addr);
264+
sin6.sin6_port = sin.sin_port;
265+
} else {
266+
if (copy_from_user(&sin6, optval,
267+
sizeof(struct sockaddr_in6))) {
268+
ret = -EFAULT;
269+
goto out;
270+
}
218271
}
219272

220-
if (copy_from_user(&sin, optval, sizeof(sin))) {
221-
ret = -EFAULT;
222-
goto out;
223-
}
224-
225-
rds_send_drop_to(rs, &sin);
273+
rds_send_drop_to(rs, &sin6);
226274
out:
227275
return ret;
228276
}
@@ -435,31 +483,41 @@ static int rds_connect(struct socket *sock, struct sockaddr *uaddr,
435483
int addr_len, int flags)
436484
{
437485
struct sock *sk = sock->sk;
438-
struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
486+
struct sockaddr_in *sin;
439487
struct rds_sock *rs = rds_sk_to_rs(sk);
440488
int ret = 0;
441489

442490
lock_sock(sk);
443491

444-
if (addr_len != sizeof(struct sockaddr_in)) {
445-
ret = -EINVAL;
446-
goto out;
447-
}
492+
switch (addr_len) {
493+
case sizeof(struct sockaddr_in):
494+
sin = (struct sockaddr_in *)uaddr;
495+
if (sin->sin_family != AF_INET) {
496+
ret = -EAFNOSUPPORT;
497+
break;
498+
}
499+
if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
500+
ret = -EDESTADDRREQ;
501+
break;
502+
}
503+
if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) ||
504+
sin->sin_addr.s_addr == htonl(INADDR_BROADCAST)) {
505+
ret = -EINVAL;
506+
break;
507+
}
508+
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &rs->rs_conn_addr);
509+
rs->rs_conn_port = sin->sin_port;
510+
break;
448511

449-
if (sin->sin_family != AF_INET) {
450-
ret = -EAFNOSUPPORT;
451-
goto out;
452-
}
512+
case sizeof(struct sockaddr_in6):
513+
ret = -EPROTONOSUPPORT;
514+
break;
453515

454-
if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
455-
ret = -EDESTADDRREQ;
456-
goto out;
516+
default:
517+
ret = -EINVAL;
518+
break;
457519
}
458520

459-
rs->rs_conn_addr = sin->sin_addr.s_addr;
460-
rs->rs_conn_port = sin->sin_port;
461-
462-
out:
463521
release_sock(sk);
464522
return ret;
465523
}
@@ -578,8 +636,10 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len,
578636
list_for_each_entry(inc, &rs->rs_recv_queue, i_item) {
579637
total++;
580638
if (total <= len)
581-
rds_inc_info_copy(inc, iter, inc->i_saddr,
582-
rs->rs_bound_addr, 1);
639+
rds_inc_info_copy(inc, iter,
640+
inc->i_saddr.s6_addr32[3],
641+
rs->rs_bound_addr_v4,
642+
1);
583643
}
584644

585645
read_unlock(&rs->rs_recv_lock);
@@ -608,8 +668,8 @@ static void rds_sock_info(struct socket *sock, unsigned int len,
608668
list_for_each_entry(rs, &rds_sock_list, rs_item) {
609669
sinfo.sndbuf = rds_sk_sndbuf(rs);
610670
sinfo.rcvbuf = rds_sk_rcvbuf(rs);
611-
sinfo.bound_addr = rs->rs_bound_addr;
612-
sinfo.connected_addr = rs->rs_conn_addr;
671+
sinfo.bound_addr = rs->rs_bound_addr_v4;
672+
sinfo.connected_addr = rs->rs_conn_addr_v4;
613673
sinfo.bound_port = rs->rs_bound_port;
614674
sinfo.connected_port = rs->rs_conn_port;
615675
sinfo.inum = sock_i_ino(rds_rs_to_sk(rs));

0 commit comments

Comments
 (0)