@ -1914,6 +1914,9 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
goto out_free ;
}
if ( sctp_wspace ( asoc ) < msg_len )
sctp_prsctp_prune ( asoc , sinfo , msg_len - sctp_wspace ( asoc ) ) ;
timeo = sock_sndtimeo ( sk , msg - > msg_flags & MSG_DONTWAIT ) ;
if ( ! sctp_wspace ( asoc ) ) {
err = sctp_wait_for_sndbuf ( asoc , & timeo , msg_len ) ;
@ -3661,6 +3664,80 @@ static int sctp_setsockopt_recvnxtinfo(struct sock *sk,
return 0 ;
}
static int sctp_setsockopt_pr_supported ( struct sock * sk ,
char __user * optval ,
unsigned int optlen )
{
struct sctp_assoc_value params ;
struct sctp_association * asoc ;
int retval = - EINVAL ;
if ( optlen ! = sizeof ( params ) )
goto out ;
if ( copy_from_user ( & params , optval , optlen ) ) {
retval = - EFAULT ;
goto out ;
}
asoc = sctp_id2assoc ( sk , params . assoc_id ) ;
if ( asoc ) {
asoc - > prsctp_enable = ! ! params . assoc_value ;
} else if ( ! params . assoc_id ) {
struct sctp_sock * sp = sctp_sk ( sk ) ;
sp - > ep - > prsctp_enable = ! ! params . assoc_value ;
} else {
goto out ;
}
retval = 0 ;
out :
return retval ;
}
static int sctp_setsockopt_default_prinfo ( struct sock * sk ,
char __user * optval ,
unsigned int optlen )
{
struct sctp_default_prinfo info ;
struct sctp_association * asoc ;
int retval = - EINVAL ;
if ( optlen ! = sizeof ( info ) )
goto out ;
if ( copy_from_user ( & info , optval , sizeof ( info ) ) ) {
retval = - EFAULT ;
goto out ;
}
if ( info . pr_policy & ~ SCTP_PR_SCTP_MASK )
goto out ;
if ( info . pr_policy = = SCTP_PR_SCTP_NONE )
info . pr_value = 0 ;
asoc = sctp_id2assoc ( sk , info . pr_assoc_id ) ;
if ( asoc ) {
SCTP_PR_SET_POLICY ( asoc - > default_flags , info . pr_policy ) ;
asoc - > default_timetolive = info . pr_value ;
} else if ( ! info . pr_assoc_id ) {
struct sctp_sock * sp = sctp_sk ( sk ) ;
SCTP_PR_SET_POLICY ( sp - > default_flags , info . pr_policy ) ;
sp - > default_timetolive = info . pr_value ;
} else {
goto out ;
}
retval = 0 ;
out :
return retval ;
}
/* API 6.2 setsockopt(), getsockopt()
*
* Applications use setsockopt ( ) and getsockopt ( ) to set or retrieve
@ -3821,6 +3898,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_RECVNXTINFO :
retval = sctp_setsockopt_recvnxtinfo ( sk , optval , optlen ) ;
break ;
case SCTP_PR_SUPPORTED :
retval = sctp_setsockopt_pr_supported ( sk , optval , optlen ) ;
break ;
case SCTP_DEFAULT_PRINFO :
retval = sctp_setsockopt_default_prinfo ( sk , optval , optlen ) ;
break ;
default :
retval = - ENOPROTOOPT ;
break ;
@ -6166,6 +6249,148 @@ static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len,
return 0 ;
}
static int sctp_getsockopt_pr_supported ( struct sock * sk , int len ,
char __user * optval ,
int __user * optlen )
{
struct sctp_assoc_value params ;
struct sctp_association * asoc ;
int retval = - EFAULT ;
if ( len < sizeof ( params ) ) {
retval = - EINVAL ;
goto out ;
}
len = sizeof ( params ) ;
if ( copy_from_user ( & params , optval , len ) )
goto out ;
asoc = sctp_id2assoc ( sk , params . assoc_id ) ;
if ( asoc ) {
params . assoc_value = asoc - > prsctp_enable ;
} else if ( ! params . assoc_id ) {
struct sctp_sock * sp = sctp_sk ( sk ) ;
params . assoc_value = sp - > ep - > prsctp_enable ;
} else {
retval = - EINVAL ;
goto out ;
}
if ( put_user ( len , optlen ) )
goto out ;
if ( copy_to_user ( optval , & params , len ) )
goto out ;
retval = 0 ;
out :
return retval ;
}
static int sctp_getsockopt_default_prinfo ( struct sock * sk , int len ,
char __user * optval ,
int __user * optlen )
{
struct sctp_default_prinfo info ;
struct sctp_association * asoc ;
int retval = - EFAULT ;
if ( len < sizeof ( info ) ) {
retval = - EINVAL ;
goto out ;
}
len = sizeof ( info ) ;
if ( copy_from_user ( & info , optval , len ) )
goto out ;
asoc = sctp_id2assoc ( sk , info . pr_assoc_id ) ;
if ( asoc ) {
info . pr_policy = SCTP_PR_POLICY ( asoc - > default_flags ) ;
info . pr_value = asoc - > default_timetolive ;
} else if ( ! info . pr_assoc_id ) {
struct sctp_sock * sp = sctp_sk ( sk ) ;
info . pr_policy = SCTP_PR_POLICY ( sp - > default_flags ) ;
info . pr_value = sp - > default_timetolive ;
} else {
retval = - EINVAL ;
goto out ;
}
if ( put_user ( len , optlen ) )
goto out ;
if ( copy_to_user ( optval , & info , len ) )
goto out ;
retval = 0 ;
out :
return retval ;
}
static int sctp_getsockopt_pr_assocstatus ( struct sock * sk , int len ,
char __user * optval ,
int __user * optlen )
{
struct sctp_prstatus params ;
struct sctp_association * asoc ;
int policy ;
int retval = - EINVAL ;
if ( len < sizeof ( params ) )
goto out ;
len = sizeof ( params ) ;
if ( copy_from_user ( & params , optval , len ) ) {
retval = - EFAULT ;
goto out ;
}
policy = params . sprstat_policy ;
if ( policy & ~ SCTP_PR_SCTP_MASK )
goto out ;
asoc = sctp_id2assoc ( sk , params . sprstat_assoc_id ) ;
if ( ! asoc )
goto out ;
if ( policy = = SCTP_PR_SCTP_NONE ) {
params . sprstat_abandoned_unsent = 0 ;
params . sprstat_abandoned_sent = 0 ;
for ( policy = 0 ; policy < = SCTP_PR_INDEX ( MAX ) ; policy + + ) {
params . sprstat_abandoned_unsent + =
asoc - > abandoned_unsent [ policy ] ;
params . sprstat_abandoned_sent + =
asoc - > abandoned_sent [ policy ] ;
}
} else {
params . sprstat_abandoned_unsent =
asoc - > abandoned_unsent [ __SCTP_PR_INDEX ( policy ) ] ;
params . sprstat_abandoned_sent =
asoc - > abandoned_sent [ __SCTP_PR_INDEX ( policy ) ] ;
}
if ( put_user ( len , optlen ) ) {
retval = - EFAULT ;
goto out ;
}
if ( copy_to_user ( optval , & params , len ) ) {
retval = - EFAULT ;
goto out ;
}
retval = 0 ;
out :
return retval ;
}
static int sctp_getsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int __user * optlen )
{
@ -6319,6 +6544,17 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_RECVNXTINFO :
retval = sctp_getsockopt_recvnxtinfo ( sk , len , optval , optlen ) ;
break ;
case SCTP_PR_SUPPORTED :
retval = sctp_getsockopt_pr_supported ( sk , len , optval , optlen ) ;
break ;
case SCTP_DEFAULT_PRINFO :
retval = sctp_getsockopt_default_prinfo ( sk , len , optval ,
optlen ) ;
break ;
case SCTP_PR_ASSOC_STATUS :
retval = sctp_getsockopt_pr_assocstatus ( sk , len , optval ,
optlen ) ;
break ;
default :
retval = - ENOPROTOOPT ;
break ;
@ -6866,7 +7102,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
if ( cmsgs - > srinfo - > sinfo_flags &
~ ( SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_SACK_IMMEDIATELY |
SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
SCTP_ABORT | SCTP_EOF ) )
return - EINVAL ;
break ;
@ -6890,7 +7126,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
if ( cmsgs - > sinfo - > snd_flags &
~ ( SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_SACK_IMMEDIATELY |
SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
SCTP_ABORT | SCTP_EOF ) )
return - EINVAL ;
break ;