aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-03-24 20:37:42 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-03-24 21:24:01 -0400
commit7cbca67c073263c179f605bdbbdc565ab29d801d (patch)
tree124ce8c81f3e033790416d3d16bd23e2f7bfed07 /net/ipv6/ipv6_sockglue.c
parent1d5d236d309ab90fa6aedf712f586b3595721373 (diff)
[IPV6]: Support Source Address Selection API (RFC5014).
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 8e29fb1d1df6..dc6695cc5767 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -617,7 +617,67 @@ done:
617 retv = xfrm_user_policy(sk, optname, optval, optlen); 617 retv = xfrm_user_policy(sk, optname, optval, optlen);
618 break; 618 break;
619 619
620 case IPV6_ADDR_PREFERENCES:
621 {
622 unsigned int pref = 0;
623 unsigned int prefmask = ~0;
624
625 retv = -EINVAL;
626
627 /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
628 switch (val & (IPV6_PREFER_SRC_PUBLIC|
629 IPV6_PREFER_SRC_TMP|
630 IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
631 case IPV6_PREFER_SRC_PUBLIC:
632 pref |= IPV6_PREFER_SRC_PUBLIC;
633 break;
634 case IPV6_PREFER_SRC_TMP:
635 pref |= IPV6_PREFER_SRC_TMP;
636 break;
637 case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
638 break;
639 case 0:
640 goto pref_skip_pubtmp;
641 default:
642 goto e_inval;
643 }
644
645 prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
646 IPV6_PREFER_SRC_TMP);
647pref_skip_pubtmp:
648
649 /* check HOME/COA conflicts */
650 switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
651 case IPV6_PREFER_SRC_HOME:
652 break;
653 case IPV6_PREFER_SRC_COA:
654 pref |= IPV6_PREFER_SRC_COA;
655 case 0:
656 goto pref_skip_coa;
657 default:
658 goto e_inval;
659 }
660
661 prefmask &= ~IPV6_PREFER_SRC_COA;
662pref_skip_coa:
663
664 /* check CGA/NONCGA conflicts */
665 switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
666 case IPV6_PREFER_SRC_CGA:
667 case IPV6_PREFER_SRC_NONCGA:
668 case 0:
669 break;
670 default:
671 goto e_inval;
672 }
673
674 np->srcprefs = (np->srcprefs & prefmask) | pref;
675 retv = 0;
676
677 break;
678 }
620 } 679 }
680
621 release_sock(sk); 681 release_sock(sk);
622 682
623 return retv; 683 return retv;
@@ -932,6 +992,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
932 val = np->sndflow; 992 val = np->sndflow;
933 break; 993 break;
934 994
995 case IPV6_ADDR_PREFERENCES:
996 val = 0;
997
998 if (np->srcprefs & IPV6_PREFER_SRC_TMP)
999 val |= IPV6_PREFER_SRC_TMP;
1000 else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
1001 val |= IPV6_PREFER_SRC_PUBLIC;
1002 else {
1003 /* XXX: should we return system default? */
1004 val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
1005 }
1006
1007 if (np->srcprefs & IPV6_PREFER_SRC_COA)
1008 val |= IPV6_PREFER_SRC_COA;
1009 else
1010 val |= IPV6_PREFER_SRC_HOME;
1011 break;
1012
935 default: 1013 default:
936 return -ENOPROTOOPT; 1014 return -ENOPROTOOPT;
937 } 1015 }