aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2008-07-19 02:05:40 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-19 02:05:40 -0400
commit7dab83de50c7b2b7ceac695a0b56fa6c0f95b0bc (patch)
tree979c6905f2ef643acccfea9ab9ed926e764e72c8 /net/sctp
parent6d0ccbac688207ca0616ab5094932af4db4747b3 (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/sctp')
-rw-r--r--net/sctp/bind_addr.c37
-rw-r--r--net/sctp/ipv6.c20
-rw-r--r--net/sctp/protocol.c7
-rw-r--r--net/sctp/sm_make_chunk.c7
-rw-r--r--net/sctp/socket.c30
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 */
354int 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 */
352int sctp_bind_addr_state(const struct sctp_bind_addr *bp, 389int 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)
919static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, 928static 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
927static const struct proto_ops inet6_seqpacket_ops = { 939static 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;
2373do_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 }