diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-24 20:37:42 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-24 21:24:01 -0400 |
commit | 7cbca67c073263c179f605bdbbdc565ab29d801d (patch) | |
tree | 124ce8c81f3e033790416d3d16bd23e2f7bfed07 /net/ipv6/ipv6_sockglue.c | |
parent | 1d5d236d309ab90fa6aedf712f586b3595721373 (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.c | 78 |
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); | ||
647 | pref_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; | ||
662 | pref_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 | } |