diff options
author | tuexen <tuexen@FreeBSD.org> | 2011-06-16 21:12:36 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2011-06-16 21:12:36 +0000 |
commit | b127ed6f91700e786b6d214b85775e125cb5688b (patch) | |
tree | bdf39aa7368dd0a526c5e240dfdc9439b6b9b758 | |
parent | 812705c73fa07bb533f76478b6af65d2852e201b (diff) | |
download | FreeBSD-src-b127ed6f91700e786b6d214b85775e125cb5688b.zip FreeBSD-src-b127ed6f91700e786b6d214b85775e125cb5688b.tar.gz |
Add SCTP_DEFAULT_PRINFO socket option.
Fix the SCTP_DEFAULT_SNDINFO socket option: Don't clear the
PR SCTP policy when setting sinfo_flags.
MFC after: 1 month.
-rw-r--r-- | sys/netinet/sctp.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 74 |
3 files changed, 81 insertions, 0 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index f496d26..3c8cf36 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -118,6 +118,7 @@ struct sctp_paramhdr { #define SCTP_RECVRCVINFO 0x0000001f #define SCTP_RECVNXTINFO 0x00000020 #define SCTP_DEFAULT_SNDINFO 0x00000021 +#define SCTP_DEFAULT_PRINFO 0x00000022 /* * read-only options diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 91a5a10..a798682 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -162,6 +162,12 @@ struct sctp_prinfo { uint32_t pr_value; }; +struct sctp_default_prinfo { + uint16_t pr_policy; + uint32_t pr_value; + sctp_assoc_t pr_assoc_id; +}; + struct sctp_authinfo { uint16_t auth_keyid; }; diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 2fcf306..4c1d726 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -3030,6 +3030,7 @@ flags_out: if (stcb) { info->snd_sid = stcb->asoc.def_send.sinfo_stream; info->snd_flags = stcb->asoc.def_send.sinfo_flags; + info->snd_flags &= 0xfff0; info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; info->snd_context = stcb->asoc.def_send.sinfo_context; SCTP_TCB_UNLOCK(stcb); @@ -3038,6 +3039,7 @@ flags_out: SCTP_INP_RLOCK(inp); info->snd_sid = inp->def_send.sinfo_stream; info->snd_flags = inp->def_send.sinfo_flags; + info->snd_flags &= 0xfff0; info->snd_ppid = inp->def_send.sinfo_ppid; info->snd_context = inp->def_send.sinfo_context; SCTP_INP_RUNLOCK(inp); @@ -3051,6 +3053,33 @@ flags_out: } break; } + case SCTP_DEFAULT_PRINFO: + { + struct sctp_default_prinfo *info; + + SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); + SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); + + if (stcb) { + info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); + info->pr_value = stcb->asoc.def_send.sinfo_timetolive; + SCTP_TCB_UNLOCK(stcb); + } else { + if (info->pr_assoc_id == SCTP_FUTURE_ASSOC) { + SCTP_INP_RLOCK(inp); + info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); + info->pr_value = inp->def_send.sinfo_timetolive; + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_default_prinfo); + } + break; + } default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; @@ -5043,6 +5072,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_DEFAULT_SNDINFO: { struct sctp_sndinfo *info; + uint16_t policy; SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); @@ -5050,7 +5080,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (stcb) { if (info->snd_sid < stcb->asoc.streamoutcnt) { stcb->asoc.def_send.sinfo_stream = info->snd_sid; + policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); stcb->asoc.def_send.sinfo_flags = info->snd_flags; + stcb->asoc.def_send.sinfo_flags |= policy; stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; stcb->asoc.def_send.sinfo_context = info->snd_context; } else { @@ -5063,7 +5095,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (info->snd_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->def_send.sinfo_stream = info->snd_sid; + policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); inp->def_send.sinfo_flags = info->snd_flags; + inp->def_send.sinfo_flags |= policy; inp->def_send.sinfo_ppid = info->snd_ppid; inp->def_send.sinfo_context = info->snd_context; SCTP_INP_WUNLOCK(inp); @@ -5075,7 +5109,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_TCB_LOCK(stcb); if (info->snd_sid < stcb->asoc.streamoutcnt) { stcb->asoc.def_send.sinfo_stream = info->snd_sid; + policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); stcb->asoc.def_send.sinfo_flags = info->snd_flags; + stcb->asoc.def_send.sinfo_flags |= policy; stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; stcb->asoc.def_send.sinfo_context = info->snd_context; } @@ -5086,6 +5122,44 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_DEFAULT_PRINFO: + { + struct sctp_default_prinfo *info; + + SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); + SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); + + if (PR_SCTP_INVALID_POLICY(info->pr_policy)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + break; + } + if (stcb) { + stcb->asoc.def_send.sinfo_flags &= 0xfff0; + stcb->asoc.def_send.sinfo_flags |= info->pr_policy; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((info->pr_assoc_id == SCTP_FUTURE_ASSOC) || + (info->pr_assoc_id == SCTP_ALL_ASSOC)) { + SCTP_INP_WLOCK(inp); + inp->def_send.sinfo_flags &= 0xfff0; + inp->def_send.sinfo_flags |= info->pr_policy; + SCTP_INP_WUNLOCK(inp); + } + if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || + (info->pr_assoc_id == SCTP_ALL_ASSOC)) { + SCTP_INP_RLOCK(inp); + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + SCTP_TCB_LOCK(stcb); + stcb->asoc.def_send.sinfo_flags &= 0xfff0; + stcb->asoc.def_send.sinfo_flags |= info->pr_policy; + SCTP_TCB_UNLOCK(stcb); + } + SCTP_INP_RUNLOCK(inp); + } + } + break; + } default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; |