Skip to content

Commit 7dab83d

Browse files
Vlad Yasevichdavem330
authored andcommitted
sctp: Support ipv6only AF_INET6 sockets.
Signed-off-by: Vlad Yasevich <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6d0ccba commit 7dab83d

File tree

6 files changed

+93
-10
lines changed

6 files changed

+93
-10
lines changed

include/net/sctp/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,8 @@ int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
12111211
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
12121212
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
12131213
struct sctp_sock *);
1214+
int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *,
1215+
struct sctp_sock *, struct sctp_sock *);
12141216
int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
12151217
const union sctp_addr *addr);
12161218
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,

net/sctp/bind_addr.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,43 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
348348
return match;
349349
}
350350

351+
/* Does the address 'addr' conflict with any addresses in
352+
* the bp.
353+
*/
354+
int sctp_bind_addr_conflict(struct sctp_bind_addr *bp,
355+
const union sctp_addr *addr,
356+
struct sctp_sock *bp_sp,
357+
struct sctp_sock *addr_sp)
358+
{
359+
struct sctp_sockaddr_entry *laddr;
360+
int conflict = 0;
361+
struct sctp_sock *sp;
362+
363+
/* Pick the IPv6 socket as the basis of comparison
364+
* since it's usually a superset of the IPv4.
365+
* If there is no IPv6 socket, then default to bind_addr.
366+
*/
367+
if (sctp_opt2sk(bp_sp)->sk_family == AF_INET6)
368+
sp = bp_sp;
369+
else if (sctp_opt2sk(addr_sp)->sk_family == AF_INET6)
370+
sp = addr_sp;
371+
else
372+
sp = bp_sp;
373+
374+
rcu_read_lock();
375+
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
376+
if (!laddr->valid)
377+
continue;
378+
379+
conflict = sp->pf->cmp_addr(&laddr->a, addr, sp);
380+
if (conflict)
381+
break;
382+
}
383+
rcu_read_unlock();
384+
385+
return conflict;
386+
}
387+
351388
/* Get the state of the entry in the bind_addr_list */
352389
int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
353390
const union sctp_addr *addr)

net/sctp/ipv6.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp)
818818
return 1;
819819
/* v4-mapped-v6 addresses */
820820
case AF_INET:
821-
if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped)
821+
if (!__ipv6_only_sock(sctp_opt2sk(sp)))
822822
return 1;
823823
default:
824824
return 0;
@@ -840,6 +840,11 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
840840

841841
if (!af1 || !af2)
842842
return 0;
843+
844+
/* If the socket is IPv6 only, v4 addrs will not match */
845+
if (__ipv6_only_sock(sctp_opt2sk(opt)) && af1 != af2)
846+
return 0;
847+
843848
/* Today, wildcard AF_INET/AF_INET6. */
844849
if (sctp_is_any(addr1) || sctp_is_any(addr2))
845850
return 1;
@@ -876,7 +881,11 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
876881
return 0;
877882
}
878883
dev_put(dev);
884+
} else if (type == IPV6_ADDR_MAPPED) {
885+
if (!opt->v4mapped)
886+
return 0;
879887
}
888+
880889
af = opt->pf->af;
881890
}
882891
return af->available(addr, opt);
@@ -919,9 +928,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
919928
static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
920929
__be16 *types)
921930
{
922-
types[0] = SCTP_PARAM_IPV4_ADDRESS;
923-
types[1] = SCTP_PARAM_IPV6_ADDRESS;
924-
return 2;
931+
types[0] = SCTP_PARAM_IPV6_ADDRESS;
932+
if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
933+
types[1] = SCTP_PARAM_IPV4_ADDRESS;
934+
return 2;
935+
}
936+
return 1;
925937
}
926938

927939
static const struct proto_ops inet6_seqpacket_ops = {

net/sctp/protocol.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
381381
struct sctp_sock *sp,
382382
const struct sk_buff *skb)
383383
{
384+
/* IPv4 addresses not allowed */
385+
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
386+
return 0;
387+
384388
/* Is this a non-unicast address or a unusable SCTP address? */
385389
if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr))
386390
return 0;
@@ -404,6 +408,9 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
404408
!sysctl_ip_nonlocal_bind)
405409
return 0;
406410

411+
if (ipv6_only_sock(sctp_opt2sk(sp)))
412+
return 0;
413+
407414
return 1;
408415
}
409416

net/sctp/sm_make_chunk.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2364,8 +2364,13 @@ static int sctp_process_param(struct sctp_association *asoc,
23642364
case SCTP_PARAM_IPV6_ADDRESS:
23652365
if (PF_INET6 != asoc->base.sk->sk_family)
23662366
break;
2367-
/* Fall through. */
2367+
goto do_addr_param;
2368+
23682369
case SCTP_PARAM_IPV4_ADDRESS:
2370+
/* v4 addresses are not allowed on v6-only socket */
2371+
if (ipv6_only_sock(asoc->base.sk))
2372+
break;
2373+
do_addr_param:
23692374
af = sctp_get_af_specific(param_type2af(param.p->type));
23702375
af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
23712376
scope = sctp_scope(peer_addr);

net/sctp/socket.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,16 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
308308
if (len < sizeof (struct sockaddr))
309309
return NULL;
310310

311-
/* Does this PF support this AF? */
312-
if (!opt->pf->af_supported(addr->sa.sa_family, opt))
313-
return NULL;
311+
/* V4 mapped address are really of AF_INET family */
312+
if (addr->sa.sa_family == AF_INET6 &&
313+
ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
314+
if (!opt->pf->af_supported(AF_INET, opt))
315+
return NULL;
316+
} else {
317+
/* Does this PF support this AF? */
318+
if (!opt->pf->af_supported(addr->sa.sa_family, opt))
319+
return NULL;
320+
}
314321

315322
/* If we get this far, af is valid. */
316323
af = sctp_get_af_specific(addr->sa.sa_family);
@@ -4395,6 +4402,11 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
43954402
(AF_INET6 == addr->a.sa.sa_family))
43964403
continue;
43974404

4405+
if ((PF_INET6 == sk->sk_family) &&
4406+
inet_v6_ipv6only(sk) &&
4407+
(AF_INET == addr->a.sa.sa_family))
4408+
continue;
4409+
43984410
cnt++;
43994411
}
44004412
rcu_read_unlock();
@@ -4435,6 +4447,10 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
44354447
if ((PF_INET == sk->sk_family) &&
44364448
(AF_INET6 == addr->a.sa.sa_family))
44374449
continue;
4450+
if ((PF_INET6 == sk->sk_family) &&
4451+
inet_v6_ipv6only(sk) &&
4452+
(AF_INET == addr->a.sa.sa_family))
4453+
continue;
44384454
memcpy(&temp, &addr->a, sizeof(temp));
44394455
if (!temp.v4.sin_port)
44404456
temp.v4.sin_port = htons(port);
@@ -4470,6 +4486,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
44704486
if ((PF_INET == sk->sk_family) &&
44714487
(AF_INET6 == addr->a.sa.sa_family))
44724488
continue;
4489+
if ((PF_INET6 == sk->sk_family) &&
4490+
inet_v6_ipv6only(sk) &&
4491+
(AF_INET == addr->a.sa.sa_family))
4492+
continue;
44734493
memcpy(&temp, &addr->a, sizeof(temp));
44744494
if (!temp.v4.sin_port)
44754495
temp.v4.sin_port = htons(port);
@@ -5568,8 +5588,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
55685588
sk2->sk_state != SCTP_SS_LISTENING)
55695589
continue;
55705590

5571-
if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
5572-
sctp_sk(sk))) {
5591+
if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
5592+
sctp_sk(sk2), sctp_sk(sk))) {
55735593
ret = (long)sk2;
55745594
goto fail_unlock;
55755595
}

0 commit comments

Comments
 (0)