diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2008-07-19 02:05:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-19 02:05:40 -0400 |
commit | 7dab83de50c7b2b7ceac695a0b56fa6c0f95b0bc (patch) | |
tree | 979c6905f2ef643acccfea9ab9ed926e764e72c8 /net | |
parent | 6d0ccbac688207ca0616ab5094932af4db4747b3 (diff) |
sctp: Support ipv6only AF_INET6 sockets.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sctp/bind_addr.c | 37 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 20 | ||||
-rw-r--r-- | net/sctp/protocol.c | 7 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 7 | ||||
-rw-r--r-- | net/sctp/socket.c | 30 |
5 files changed, 91 insertions, 10 deletions
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 80e6df06967a..f62bc2468935 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c | |||
@@ -348,6 +348,43 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp, | |||
348 | return match; | 348 | return match; |
349 | } | 349 | } |
350 | 350 | ||
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 | |||
351 | /* Get the state of the entry in the bind_addr_list */ | 388 | /* Get the state of the entry in the bind_addr_list */ |
352 | int sctp_bind_addr_state(const struct sctp_bind_addr *bp, | 389 | int sctp_bind_addr_state(const struct sctp_bind_addr *bp, |
353 | const union sctp_addr *addr) | 390 | const union sctp_addr *addr) |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a2f4d4d51593..a238d6834b33 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -818,7 +818,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp) | |||
818 | return 1; | 818 | return 1; |
819 | /* v4-mapped-v6 addresses */ | 819 | /* v4-mapped-v6 addresses */ |
820 | case AF_INET: | 820 | case AF_INET: |
821 | if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) | 821 | if (!__ipv6_only_sock(sctp_opt2sk(sp))) |
822 | return 1; | 822 | return 1; |
823 | default: | 823 | default: |
824 | return 0; | 824 | return 0; |
@@ -840,6 +840,11 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, | |||
840 | 840 | ||
841 | if (!af1 || !af2) | 841 | if (!af1 || !af2) |
842 | return 0; | 842 | 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 | |||
843 | /* Today, wildcard AF_INET/AF_INET6. */ | 848 | /* Today, wildcard AF_INET/AF_INET6. */ |
844 | if (sctp_is_any(addr1) || sctp_is_any(addr2)) | 849 | if (sctp_is_any(addr1) || sctp_is_any(addr2)) |
845 | return 1; | 850 | return 1; |
@@ -876,7 +881,11 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) | |||
876 | return 0; | 881 | return 0; |
877 | } | 882 | } |
878 | dev_put(dev); | 883 | dev_put(dev); |
884 | } else if (type == IPV6_ADDR_MAPPED) { | ||
885 | if (!opt->v4mapped) | ||
886 | return 0; | ||
879 | } | 887 | } |
888 | |||
880 | af = opt->pf->af; | 889 | af = opt->pf->af; |
881 | } | 890 | } |
882 | return af->available(addr, opt); | 891 | return af->available(addr, opt); |
@@ -919,9 +928,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr) | |||
919 | static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, | 928 | static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, |
920 | __be16 *types) | 929 | __be16 *types) |
921 | { | 930 | { |
922 | types[0] = SCTP_PARAM_IPV4_ADDRESS; | 931 | types[0] = SCTP_PARAM_IPV6_ADDRESS; |
923 | types[1] = SCTP_PARAM_IPV6_ADDRESS; | 932 | if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) { |
924 | return 2; | 933 | types[1] = SCTP_PARAM_IPV4_ADDRESS; |
934 | return 2; | ||
935 | } | ||
936 | return 1; | ||
925 | } | 937 | } |
926 | 938 | ||
927 | static const struct proto_ops inet6_seqpacket_ops = { | 939 | static const struct proto_ops inet6_seqpacket_ops = { |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index dd811a8456a8..cdd881142f2c 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -381,6 +381,10 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, | |||
381 | struct sctp_sock *sp, | 381 | struct sctp_sock *sp, |
382 | const struct sk_buff *skb) | 382 | const struct sk_buff *skb) |
383 | { | 383 | { |
384 | /* IPv4 addresses not allowed */ | ||
385 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) | ||
386 | return 0; | ||
387 | |||
384 | /* Is this a non-unicast address or a unusable SCTP address? */ | 388 | /* Is this a non-unicast address or a unusable SCTP address? */ |
385 | if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) | 389 | if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) |
386 | return 0; | 390 | return 0; |
@@ -404,6 +408,9 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp) | |||
404 | !sysctl_ip_nonlocal_bind) | 408 | !sysctl_ip_nonlocal_bind) |
405 | return 0; | 409 | return 0; |
406 | 410 | ||
411 | if (ipv6_only_sock(sctp_opt2sk(sp))) | ||
412 | return 0; | ||
413 | |||
407 | return 1; | 414 | return 1; |
408 | } | 415 | } |
409 | 416 | ||
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index bbc7107c86cf..e8ca4e54981f 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -2364,8 +2364,13 @@ static int sctp_process_param(struct sctp_association *asoc, | |||
2364 | case SCTP_PARAM_IPV6_ADDRESS: | 2364 | case SCTP_PARAM_IPV6_ADDRESS: |
2365 | if (PF_INET6 != asoc->base.sk->sk_family) | 2365 | if (PF_INET6 != asoc->base.sk->sk_family) |
2366 | break; | 2366 | break; |
2367 | /* Fall through. */ | 2367 | goto do_addr_param; |
2368 | |||
2368 | case SCTP_PARAM_IPV4_ADDRESS: | 2369 | 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: | ||
2369 | af = sctp_get_af_specific(param_type2af(param.p->type)); | 2374 | af = sctp_get_af_specific(param_type2af(param.p->type)); |
2370 | af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0); | 2375 | af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0); |
2371 | scope = sctp_scope(peer_addr); | 2376 | scope = sctp_scope(peer_addr); |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6aba01b0ce4e..a0e879bb202d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -308,9 +308,16 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, | |||
308 | if (len < sizeof (struct sockaddr)) | 308 | if (len < sizeof (struct sockaddr)) |
309 | return NULL; | 309 | return NULL; |
310 | 310 | ||
311 | /* Does this PF support this AF? */ | 311 | /* V4 mapped address are really of AF_INET family */ |
312 | if (!opt->pf->af_supported(addr->sa.sa_family, opt)) | 312 | if (addr->sa.sa_family == AF_INET6 && |
313 | return NULL; | 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 | } | ||
314 | 321 | ||
315 | /* If we get this far, af is valid. */ | 322 | /* If we get this far, af is valid. */ |
316 | af = sctp_get_af_specific(addr->sa.sa_family); | 323 | 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, | |||
4395 | (AF_INET6 == addr->a.sa.sa_family)) | 4402 | (AF_INET6 == addr->a.sa.sa_family)) |
4396 | continue; | 4403 | continue; |
4397 | 4404 | ||
4405 | if ((PF_INET6 == sk->sk_family) && | ||
4406 | inet_v6_ipv6only(sk) && | ||
4407 | (AF_INET == addr->a.sa.sa_family)) | ||
4408 | continue; | ||
4409 | |||
4398 | cnt++; | 4410 | cnt++; |
4399 | } | 4411 | } |
4400 | rcu_read_unlock(); | 4412 | rcu_read_unlock(); |
@@ -4435,6 +4447,10 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, | |||
4435 | if ((PF_INET == sk->sk_family) && | 4447 | if ((PF_INET == sk->sk_family) && |
4436 | (AF_INET6 == addr->a.sa.sa_family)) | 4448 | (AF_INET6 == addr->a.sa.sa_family)) |
4437 | continue; | 4449 | continue; |
4450 | if ((PF_INET6 == sk->sk_family) && | ||
4451 | inet_v6_ipv6only(sk) && | ||
4452 | (AF_INET == addr->a.sa.sa_family)) | ||
4453 | continue; | ||
4438 | memcpy(&temp, &addr->a, sizeof(temp)); | 4454 | memcpy(&temp, &addr->a, sizeof(temp)); |
4439 | if (!temp.v4.sin_port) | 4455 | if (!temp.v4.sin_port) |
4440 | temp.v4.sin_port = htons(port); | 4456 | temp.v4.sin_port = htons(port); |
@@ -4470,6 +4486,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | |||
4470 | if ((PF_INET == sk->sk_family) && | 4486 | if ((PF_INET == sk->sk_family) && |
4471 | (AF_INET6 == addr->a.sa.sa_family)) | 4487 | (AF_INET6 == addr->a.sa.sa_family)) |
4472 | continue; | 4488 | continue; |
4489 | if ((PF_INET6 == sk->sk_family) && | ||
4490 | inet_v6_ipv6only(sk) && | ||
4491 | (AF_INET == addr->a.sa.sa_family)) | ||
4492 | continue; | ||
4473 | memcpy(&temp, &addr->a, sizeof(temp)); | 4493 | memcpy(&temp, &addr->a, sizeof(temp)); |
4474 | if (!temp.v4.sin_port) | 4494 | if (!temp.v4.sin_port) |
4475 | temp.v4.sin_port = htons(port); | 4495 | temp.v4.sin_port = htons(port); |
@@ -5568,8 +5588,8 @@ pp_found: | |||
5568 | sk2->sk_state != SCTP_SS_LISTENING) | 5588 | sk2->sk_state != SCTP_SS_LISTENING) |
5569 | continue; | 5589 | continue; |
5570 | 5590 | ||
5571 | if (sctp_bind_addr_match(&ep2->base.bind_addr, addr, | 5591 | if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr, |
5572 | sctp_sk(sk))) { | 5592 | sctp_sk(sk2), sctp_sk(sk))) { |
5573 | ret = (long)sk2; | 5593 | ret = (long)sk2; |
5574 | goto fail_unlock; | 5594 | goto fail_unlock; |
5575 | } | 5595 | } |