From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:05:27
This cleanup mostly does three things:
- extract some codes into functions to make sendmsg more readable.
- tidy up some codes to avoid the unnecessary checks.
- adjust some logic so that it will be easier to add the send flags
and cmsgs features that I will post after this.
To make it easy to review and to check if the code is compatible with
before, this patchset is to do it step by step in 9 patches.
NOTE:
There will be a conflict when merging
Commit 2277c7cd75e3 ("sctp: Add LSM hooks") from selinux tree,
the solution is to:
1. remove all the lines in [B]:
<<<<<<< HEAD
[A]
=======
[B]
>>>>>>> 2277c7c... sctp: Add LSM hooks
2. and apply the following diff-output:
@@ -1711,6 +1712,22 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,scope=sctp_scope(daddr);+/* Label connection socket for first association 1-to-many+*styleforclientsequencesocket()->sendmsg().This+*needstobedonebeforesctp_assoc_add_peer()asthatwill+*setuptheinitialpacketthatneedstoaccountforany+*securityipoptions(CIPSO/CALIPSO)addedtothepacket.+*/+af=sctp_get_af_specific(daddr->sa.sa_family);+if(!af)+return-EINVAL;++err=security_sctp_bind_connect(sk,SCTP_SENDMSG_CONNECT,+(structsockaddr*)daddr,+af->sockaddr_len);+if(err<0)+returnerr;+asoc=sctp_association_new(ep,sk,scope,GFP_KERNEL);if(!asoc)return-ENOMEM;
Xin Long (9):
sctp: factor out sctp_sendmsg_to_asoc from sctp_sendmsg
sctp: factor out sctp_sendmsg_new_asoc from sctp_sendmsg
sctp: factor out sctp_sendmsg_check_sflags from sctp_sendmsg
sctp: factor out sctp_sendmsg_get_daddr from sctp_sendmsg
sctp: factor out sctp_sendmsg_parse from sctp_sendmsg
sctp: factor out sctp_sendmsg_update_sinfo from sctp_sendmsg
sctp: remove the unnecessary transport looking up from sctp_sendmsg
sctp: improve some variables in sctp_sendmsg
sctp: adjust some codes in a better order in sctp_sendmsg
net/sctp/socket.c | 638 +++++++++++++++++++++++-------------------------------
1 file changed, 274 insertions(+), 364 deletions(-)
--
2.1.0
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:05:36
This patch is to move the codes for checking and sending on
one asoc after this asoc has been found or created into
sctp_sendmsg_to_asoc.
Note that 'err != -ESRCH' check is for the case that asoc is
freed when waiting for tx buffer in sctp_sendmsg_to_asoc.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 230 +++++++++++++++++++++++-------------------------------
1 file changed, 99 insertions(+), 131 deletions(-)
@@ -1606,6 +1606,100 @@ static int sctp_error(struct sock *sk, int flags, int err)staticintsctp_msghdr_parse(conststructmsghdr*msg,structsctp_cmsgs*cmsgs);+staticintsctp_sendmsg_to_asoc(structsctp_association*asoc,+structmsghdr*msg,size_tmsg_len,+structsctp_transport*transport,+structsctp_sndrcvinfo*sinfo)+{+structsock*sk=asoc->base.sk;+structnet*net=sock_net(sk);+structsctp_datamsg*datamsg;+boolwait_connect=false;+structsctp_chunk*chunk;+longtimeo;+interr;++if(sinfo->sinfo_stream>=asoc->stream.outcnt){+err=-EINVAL;+gotoerr;+}++if(unlikely(!asoc->stream.out[sinfo->sinfo_stream].ext)){+err=sctp_stream_init_ext(&asoc->stream,sinfo->sinfo_stream);+if(err)+gotoerr;+}++if(sctp_sk(sk)->disable_fragments&&msg_len>asoc->frag_point){+err=-EMSGSIZE;+gotoerr;+}++if(sctp_state(asoc,CLOSED)){+err=sctp_primitive_ASSOCIATE(net,asoc,NULL);+if(err)+gotoerr;++if(sctp_sk(sk)->strm_interleave){+timeo=sock_sndtimeo(sk,0);+err=sctp_wait_for_connect(asoc,&timeo);+if(err)+gotoerr;+}else{+wait_connect=true;+}++pr_debug("%s: we associated primitively\n",__func__);+}++if(asoc->pmtu_pending)+sctp_assoc_pending_pmtu(asoc);++if(sctp_wspace(asoc)<msg_len)+sctp_prsctp_prune(asoc,sinfo,msg_len-sctp_wspace(asoc));++if(!sctp_wspace(asoc)){+timeo=sock_sndtimeo(sk,msg->msg_flags&MSG_DONTWAIT);+err=sctp_wait_for_sndbuf(asoc,&timeo,msg_len);+if(err)+gotoerr;+}++datamsg=sctp_datamsg_from_user(asoc,sinfo,&msg->msg_iter);+if(IS_ERR(datamsg)){+err=PTR_ERR(datamsg);+gotoerr;+}++asoc->force_delay=!!(msg->msg_flags&MSG_MORE);++list_for_each_entry(chunk,&datamsg->chunks,frag_list){+sctp_chunk_hold(chunk);+sctp_set_owner_w(chunk);+chunk->transport=transport;+}++err=sctp_primitive_SEND(net,asoc,datamsg);+if(err){+sctp_datamsg_free(datamsg);+gotoerr;+}++pr_debug("%s: we sent primitively\n",__func__);++sctp_datamsg_put(datamsg);++if(unlikely(wait_connect)){+timeo=sock_sndtimeo(sk,msg->msg_flags&MSG_DONTWAIT);+sctp_wait_for_connect(asoc,&timeo);+}++err=msg_len;++err:+returnerr;+}+staticintsctp_sendmsg(structsock*sk,structmsghdr*msg,size_tmsg_len){structnet*net=sock_net(sk);
@@ -1923,49 +2014,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)gotoout_free;}-if(asoc->pmtu_pending)-sctp_assoc_pending_pmtu(asoc);--/* If fragmentation is disabled and the message length exceeds the-*associationfragmentationpoint,returnEMSGSIZE.TheI-D-*doesnotspecifywhatthiserroris,butthislookslike-*agreatfit.-*/-if(sctp_sk(sk)->disable_fragments&&(msg_len>asoc->frag_point)){-err=-EMSGSIZE;-gotoout_free;-}--/* Check for invalid stream. */-if(sinfo->sinfo_stream>=asoc->stream.outcnt){-err=-EINVAL;-gotoout_free;-}--/* Allocate sctp_stream_out_ext if not already done */-if(unlikely(!asoc->stream.out[sinfo->sinfo_stream].ext)){-err=sctp_stream_init_ext(&asoc->stream,sinfo->sinfo_stream);-if(err)-gotoout_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)){-/* sk can be changed by peel off when waiting for buf. */-err=sctp_wait_for_sndbuf(asoc,&timeo,msg_len);-if(err){-if(err==-ESRCH){-/* asoc is already dead. */-new_asoc=NULL;-err=-EPIPE;-}-gotoout_free;-}-}-/* If an address is passed with the sendto/sendmsg call, it is used*tooverridetheprimarydestinationaddressintheTCPmodel,or*whenSCTP_ADDR_OVERflagissetintheUDPmodel.
@@ -1980,96 +2028,16 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)}elsechunk_tp=NULL;-/* Auto-connect, if we aren't connected already. */-if(sctp_state(asoc,CLOSED)){-err=sctp_primitive_ASSOCIATE(net,asoc,NULL);-if(err<0)-gotoout_free;--/* If stream interleave is enabled, wait_connect has to be-*doneearlierthandataenqueue,asitneedstomakedata-*oridataaccordingtoasoc->intl_enablewhichisset-*afterconnectionisdone.-*/-if(sctp_sk(asoc->base.sk)->strm_interleave){-timeo=sock_sndtimeo(sk,0);-err=sctp_wait_for_connect(asoc,&timeo);-if(err)-gotoout_unlock;-}else{-wait_connect=true;-}--pr_debug("%s: we associated primitively\n",__func__);-}--/* Break the message into multiple chunks of maximum size. */-datamsg=sctp_datamsg_from_user(asoc,sinfo,&msg->msg_iter);-if(IS_ERR(datamsg)){-err=PTR_ERR(datamsg);-gotoout_free;-}-asoc->force_delay=!!(msg->msg_flags&MSG_MORE);--/* Now send the (possibly) fragmented message. */-list_for_each_entry(chunk,&datamsg->chunks,frag_list){-sctp_chunk_hold(chunk);--/* Do accounting for the write space. */-sctp_set_owner_w(chunk);--chunk->transport=chunk_tp;-}--/* Send it to the lower layers. Note: all chunks-*musteitherfailorsucceed.Thelowerlayer-*worksthatwaytoday.Keepitthatwayorthis-*breaks.-*/-err=sctp_primitive_SEND(net,asoc,datamsg);-/* Did the lower layer accept the chunk? */-if(err){-sctp_datamsg_free(datamsg);-gotoout_free;-}--pr_debug("%s: we sent primitively\n",__func__);--sctp_datamsg_put(datamsg);-err=msg_len;--if(unlikely(wait_connect)){-timeo=sock_sndtimeo(sk,msg_flags&MSG_DONTWAIT);-sctp_wait_for_connect(asoc,&timeo);-}--/* If we are already past ASSOCIATE, the lower-*layersareresponsibleforassociationcleanup.-*/-gotoout_unlock;+/* Send msg to the asoc */+err=sctp_sendmsg_to_asoc(asoc,msg,msg_len,chunk_tp,sinfo);out_free:-if(new_asoc)+if(err<0&&err!=-ESRCH&&new_asoc)sctp_association_free(asoc);out_unlock:release_sock(sk);-out_nounlock:-returnsctp_error(sk,msg_flags,err);--#if 0-do_sock_err:-if(msg_len)-err=msg_len;-else-err=sock_error(sk);-gotoout;--do_interrupted:-if(msg_len)-err=msg_len;-gotoout;-#endif /* 0 */+returnsctp_error(sk,msg->msg_flags,err);}/* This is an extended version of skb_pull() that removes the data from the
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:05:44
This patch is to move the codes for creating a new asoc if
no asoc was found into sctp_sendmsg_new_asoc.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 201 +++++++++++++++++++++++-------------------------------
1 file changed, 86 insertions(+), 115 deletions(-)
@@ -1606,6 +1606,87 @@ static int sctp_error(struct sock *sk, int flags, int err)staticintsctp_msghdr_parse(conststructmsghdr*msg,structsctp_cmsgs*cmsgs);+staticintsctp_sendmsg_new_asoc(structsock*sk,__u16sflags,+structsctp_cmsgs*cmsgs,+unionsctp_addr*daddr,+structsctp_transport**tp)+{+structsctp_endpoint*ep=sctp_sk(sk)->ep;+structnet*net=sock_net(sk);+structsctp_association*asoc;+enumsctp_scopescope;+interr=-EINVAL;++*tp=NULL;++if(sflags&(SCTP_EOF|SCTP_ABORT))+return-EINVAL;++if(sctp_style(sk,TCP)&&(sctp_sstate(sk,ESTABLISHED)||+sctp_sstate(sk,CLOSING)))+return-EADDRNOTAVAIL;++if(sctp_endpoint_is_peeled_off(ep,daddr))+return-EADDRNOTAVAIL;++if(!ep->base.bind_addr.port){+if(sctp_autobind(sk))+return-EAGAIN;+}else{+if(ep->base.bind_addr.port<inet_prot_sock(net)&&+!ns_capable(net->user_ns,CAP_NET_BIND_SERVICE))+return-EACCES;+}++scope=sctp_scope(daddr);++asoc=sctp_association_new(ep,sk,scope,GFP_KERNEL);+if(!asoc)+return-ENOMEM;++if(sctp_assoc_set_bind_addr_from_ep(asoc,scope,GFP_KERNEL)<0){+err=-ENOMEM;+gotofree;+}++if(cmsgs->init){+structsctp_initmsg*init=cmsgs->init;++if(init->sinit_num_ostreams){+__u16outcnt=init->sinit_num_ostreams;++asoc->c.sinit_num_ostreams=outcnt;+/* outcnt has been changed, need to re-init stream */+err=sctp_stream_init(&asoc->stream,outcnt,0,+GFP_KERNEL);+if(err)+gotofree;+}++if(init->sinit_max_instreams)+asoc->c.sinit_max_instreams=init->sinit_max_instreams;++if(init->sinit_max_attempts)+asoc->max_init_attempts=init->sinit_max_attempts;++if(init->sinit_max_init_timeo)+asoc->max_init_timeo=+msecs_to_jiffies(init->sinit_max_init_timeo);+}++*tp=sctp_assoc_add_peer(asoc,daddr,GFP_KERNEL,SCTP_UNKNOWN);+if(!*tp){+err=-ENOMEM;+gotofree;+}++return0;++free:+sctp_association_free(asoc);+returnerr;+}+staticintsctp_sendmsg_to_asoc(structsctp_association*asoc,structmsghdr*msg,size_tmsg_len,structsctp_transport*transport,
@@ -1817,20 +1897,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)if(msg_name){/* Look for a matching association on the endpoint. */asoc=sctp_endpoint_lookup_assoc(ep,&to,&transport);--/* If we could not find a matching association on the-*endpoint,makesurethatitisnotaTCP-style-*socketthatalreadyhasanassociationorthereis-*nopeeled-offassociationonanothersocket.-*/-if(!asoc&&-((sctp_style(sk,TCP)&&-(sctp_sstate(sk,ESTABLISHED)||-sctp_sstate(sk,CLOSING)))||-sctp_endpoint_is_peeled_off(ep,&to))){-err=-EADDRNOTAVAIL;-gotoout_unlock;-}}else{asoc=sctp_id2assoc(sk,associd);if(!asoc){
@@ -1879,108 +1945,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)/* Do we need to create the association? */if(!asoc){-pr_debug("%s: there is no association yet\n",__func__);--if(sinfo_flags&(SCTP_EOF|SCTP_ABORT)){-err=-EINVAL;-gotoout_unlock;-}--/* Check for invalid stream against the stream counts,-*eitherthedefaultortheuserspecifiedstreamcounts.-*/-if(sinfo){-if(!sinit||!sinit->sinit_num_ostreams){-/* Check against the defaults. */-if(sinfo->sinfo_stream>=-sp->initmsg.sinit_num_ostreams){-err=-EINVAL;-gotoout_unlock;-}-}else{-/* Check against the requested. */-if(sinfo->sinfo_stream>=-sinit->sinit_num_ostreams){-err=-EINVAL;-gotoout_unlock;-}-}-}--/*-*API3.1.2bind()-UDPStyleSyntax-*Ifabind()orsctp_bindx()isnotcalledpriortoa-*sendmsg()callthatinitiatesanewassociation,the-*systempicksanephemeralportandwillchooseanaddress-*setequivalenttobindingwithawildcardaddress.-*/-if(!ep->base.bind_addr.port){-if(sctp_autobind(sk)){-err=-EAGAIN;-gotoout_unlock;-}-}else{-/*-*Ifanunprivilegeduserinheritsaone-to-many-*stylesocketwithopenassociationsonaprivileged-*port,itMAYbepermittedtoacceptnewassociations,-*butitSHOULDNOTbepermittedtoopennew-*associations.-*/-if(ep->base.bind_addr.port<inet_prot_sock(net)&&-!ns_capable(net->user_ns,CAP_NET_BIND_SERVICE)){-err=-EACCES;-gotoout_unlock;-}-}--scope=sctp_scope(&to);-new_asoc=sctp_association_new(ep,sk,scope,GFP_KERNEL);-if(!new_asoc){-err=-ENOMEM;+err=sctp_sendmsg_new_asoc(sk,sinfo_flags,&cmsgs,&to,+&transport);+if(err)gotoout_unlock;-}-asoc=new_asoc;-err=sctp_assoc_set_bind_addr_from_ep(asoc,scope,GFP_KERNEL);-if(err<0){-err=-ENOMEM;-gotoout_free;-}--/* If the SCTP_INIT ancillary data is specified, set all-*theassociationinitvaluesaccordingly.-*/-if(sinit){-if(sinit->sinit_num_ostreams){-__u16outcnt=sinit->sinit_num_ostreams;--asoc->c.sinit_num_ostreams=outcnt;-/* outcnt has been changed, so re-init stream */-err=sctp_stream_init(&asoc->stream,outcnt,0,-GFP_KERNEL);-if(err)-gotoout_free;-}-if(sinit->sinit_max_instreams){-asoc->c.sinit_max_instreams=-sinit->sinit_max_instreams;-}-if(sinit->sinit_max_attempts){-asoc->max_init_attempts-=sinit->sinit_max_attempts;-}-if(sinit->sinit_max_init_timeo){-asoc->max_init_timeo=-msecs_to_jiffies(sinit->sinit_max_init_timeo);-}-}-/* Prime the peer's transport structures. */-transport=sctp_assoc_add_peer(asoc,&to,GFP_KERNEL,SCTP_UNKNOWN);-if(!transport){-err=-ENOMEM;-gotoout_free;-}+asoc=transport->asoc;+new_asoc=asoc;}/* ASSERT: we have a valid association at this point. */
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:05:52
This patch is to move the codes for checking sinfo_flags on one asoc
after this asoc has been found into sctp_sendmsg_check_sflags.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 72 +++++++++++++++++++++++++++----------------------------
1 file changed, 36 insertions(+), 36 deletions(-)
@@ -1687,6 +1687,39 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,returnerr;}+staticintsctp_sendmsg_check_sflags(structsctp_association*asoc,+__u16sflags,structmsghdr*msg,+size_tmsg_len)+{+structsock*sk=asoc->base.sk;+structnet*net=sock_net(sk);++if(sctp_state(asoc,CLOSED)&&sctp_style(sk,TCP))+return-EPIPE;++if(sflags&SCTP_EOF){+pr_debug("%s: shutting down association:%p\n",__func__,asoc);+sctp_primitive_SHUTDOWN(net,asoc,NULL);++return0;+}++if(sflags&SCTP_ABORT){+structsctp_chunk*chunk;++chunk=sctp_make_abort_user(asoc,msg,msg_len);+if(!chunk)+return-ENOMEM;++pr_debug("%s: aborting association:%p\n",__func__,asoc);+sctp_primitive_ABORT(net,asoc,chunk);++return0;+}++return1;+}+staticintsctp_sendmsg_to_asoc(structsctp_association*asoc,structmsghdr*msg,size_tmsg_len,structsctp_transport*transport,
@@ -1783,12 +1816,10 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,staticintsctp_sendmsg(structsock*sk,structmsghdr*msg,size_tmsg_len){-structnet*net=sock_net(sk);structsctp_sock*sp;structsctp_endpoint*ep;structsctp_association*new_asoc=NULL,*asoc=NULL;structsctp_transport*transport,*chunk_tp;-structsctp_chunk*chunk;unionsctp_addrto;structsockaddr*msg_name=NULL;structsctp_sndrcvinfodefault_sinfo;
@@ -1906,41 +1937,10 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)}if(asoc){-pr_debug("%s: just looked up association:%p\n",__func__,asoc);--/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED-*socketthathasanassociationinCLOSEDstate.Thiscan-*happenwhenanacceptedsockethasanassociationthatis-*alreadyCLOSED.-*/-if(sctp_state(asoc,CLOSED)&&sctp_style(sk,TCP)){-err=-EPIPE;-gotoout_unlock;-}--if(sinfo_flags&SCTP_EOF){-pr_debug("%s: shutting down association:%p\n",-__func__,asoc);--sctp_primitive_SHUTDOWN(net,asoc,NULL);-err=0;+err=sctp_sendmsg_check_sflags(asoc,sinfo_flags,msg,+msg_len);+if(err<=0)gotoout_unlock;-}-if(sinfo_flags&SCTP_ABORT){--chunk=sctp_make_abort_user(asoc,msg,msg_len);-if(!chunk){-err=-ENOMEM;-gotoout_unlock;-}--pr_debug("%s: aborting association:%p\n",-__func__,asoc);--sctp_primitive_ABORT(net,asoc,chunk);-err=0;-gotoout_unlock;-}}/* Do we need to create the association? */
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:00
This patch is to move the codes for trying to get daddr from
msg->msg_name into sctp_sendmsg_get_daddr.
Note that after adding 'daddr', 'to' and 'msg_name' can be
deleted.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 58 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 34 insertions(+), 24 deletions(-)
@@ -1851,23 +1873,11 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)gotoout_nounlock;}-/* Fetch the destination address for this packet. This-*addressonlyselectstheassociation--itisnotnecessarily-*theaddresswewillsendto.-*Forapeeled-offsocket,msg_nameisignored.-*/-if(!sctp_style(sk,UDP_HIGH_BANDWIDTH)&&msg->msg_name){-intmsg_namelen=msg->msg_namelen;--err=sctp_verify_addr(sk,(unionsctp_addr*)msg->msg_name,-msg_namelen);-if(err)-returnerr;--if(msg_namelen>sizeof(to))-msg_namelen=sizeof(to);-memcpy(&to,msg->msg_name,msg_namelen);-msg_name=msg->msg_name;+/* Get daddr from msg */+daddr=sctp_sendmsg_get_daddr(sk,msg,&cmsgs);+if(IS_ERR(daddr)){+err=PTR_ERR(daddr);+gotoout_nounlock;}sinit=cmsgs.init;
@@ -1925,9 +1935,9 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)lock_sock(sk);/* If a msg_name has been specified, assume this is to be used. */-if(msg_name){+if(daddr){/* Look for a matching association on the endpoint. */-asoc=sctp_endpoint_lookup_assoc(ep,&to,&transport);+asoc=sctp_endpoint_lookup_assoc(ep,daddr,&transport);}else{asoc=sctp_id2assoc(sk,associd);if(!asoc){
@@ -1945,7 +1955,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)/* Do we need to create the association? */if(!asoc){-err=sctp_sendmsg_new_asoc(sk,sinfo_flags,&cmsgs,&to,+err=sctp_sendmsg_new_asoc(sk,sinfo_flags,&cmsgs,daddr,&transport);if(err)gotoout_unlock;
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:09
This patch is to move the codes for parsing msghdr and checking
sk into sctp_sendmsg_parse.
Note that different from before, 'sinfo' in sctp_sendmsg won't
be NULL any more. It gets the value either from cmsgs->srinfo,
cmsgs->sinfo or asoc. With it, the 'sinfo' and 'fill_sinfo_ttl'
check can be removed from sctp_sendmsg.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 172 ++++++++++++++++++++++--------------------------------
1 file changed, 69 insertions(+), 103 deletions(-)
@@ -1606,6 +1606,61 @@ static int sctp_error(struct sock *sk, int flags, int err)staticintsctp_msghdr_parse(conststructmsghdr*msg,structsctp_cmsgs*cmsgs);+staticintsctp_sendmsg_parse(structsock*sk,structsctp_cmsgs*cmsgs,+structsctp_sndrcvinfo*srinfo,+conststructmsghdr*msg,size_tmsg_len)+{+__u16sflags;+interr;++if(sctp_sstate(sk,LISTENING)&&sctp_style(sk,TCP))+return-EPIPE;++if(msg_len>sk->sk_sndbuf)+return-EMSGSIZE;++memset(cmsgs,0,sizeof(*cmsgs));+err=sctp_msghdr_parse(msg,cmsgs);+if(err){+pr_debug("%s: msghdr parse err:%x\n",__func__,err);+returnerr;+}++memset(srinfo,0,sizeof(*srinfo));+if(cmsgs->srinfo){+srinfo->sinfo_stream=cmsgs->srinfo->sinfo_stream;+srinfo->sinfo_flags=cmsgs->srinfo->sinfo_flags;+srinfo->sinfo_ppid=cmsgs->srinfo->sinfo_ppid;+srinfo->sinfo_context=cmsgs->srinfo->sinfo_context;+srinfo->sinfo_assoc_id=cmsgs->srinfo->sinfo_assoc_id;+srinfo->sinfo_timetolive=cmsgs->srinfo->sinfo_timetolive;+}++if(cmsgs->sinfo){+srinfo->sinfo_stream=cmsgs->sinfo->snd_sid;+srinfo->sinfo_flags=cmsgs->sinfo->snd_flags;+srinfo->sinfo_ppid=cmsgs->sinfo->snd_ppid;+srinfo->sinfo_context=cmsgs->sinfo->snd_context;+srinfo->sinfo_assoc_id=cmsgs->sinfo->snd_assoc_id;+}++sflags=srinfo->sinfo_flags;+if(!sflags&&msg_len)+return0;++if(sctp_style(sk,TCP)&&(sflags&(SCTP_EOF|SCTP_ABORT)))+return-EINVAL;++if(((sflags&SCTP_EOF)&&msg_len>0)||+(!(sflags&(SCTP_EOF|SCTP_ABORT))&&msg_len==0))+return-EINVAL;++if((sflags&SCTP_ADDR_OVER)&&!msg->msg_name)+return-EINVAL;++return0;+}+staticintsctp_sendmsg_new_asoc(structsock*sk,__u16sflags,structsctp_cmsgs*cmsgs,unionsctp_addr*daddr,
@@ -1839,39 +1894,23 @@ static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk,staticintsctp_sendmsg(structsock*sk,structmsghdr*msg,size_tmsg_len){-structsctp_sock*sp;-structsctp_endpoint*ep;+structsctp_endpoint*ep=sctp_sk(sk)->ep;structsctp_association*new_asoc=NULL,*asoc=NULL;structsctp_transport*transport,*chunk_tp;-structsctp_sndrcvinfodefault_sinfo;-structsctp_sndrcvinfo*sinfo;-structsctp_initmsg*sinit;+structsctp_sndrcvinfo_sinfo,*sinfo;sctp_assoc_tassocid=0;structsctp_cmsgscmsgs={NULL};-boolfill_sinfo_ttl=false;__u16sinfo_flags=0;unionsctp_addr*daddr;interr;-err=0;-sp=sctp_sk(sk);-ep=sp->ep;--pr_debug("%s: sk:%p, msg:%p, msg_len:%zu ep:%p\n",__func__,sk,-msg,msg_len,ep);--/* We cannot send a message over a TCP-style listening socket. */-if(sctp_style(sk,TCP)&&sctp_sstate(sk,LISTENING)){-err=-EPIPE;+/* Parse and get snd_info */+err=sctp_sendmsg_parse(sk,&cmsgs,&_sinfo,msg,msg_len);+if(err)gotoout_nounlock;-}-/* Parse out the SCTP CMSGs. */-err=sctp_msghdr_parse(msg,&cmsgs);-if(err){-pr_debug("%s: msghdr parse err:%x\n",__func__,err);-gotoout_nounlock;-}+sinfo=&_sinfo;+sinfo_flags=sinfo->sinfo_flags;/* Get daddr from msg */daddr=sctp_sendmsg_get_daddr(sk,msg,&cmsgs);
@@ -1880,58 +1919,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)gotoout_nounlock;}-sinit=cmsgs.init;-if(cmsgs.sinfo!=NULL){-memset(&default_sinfo,0,sizeof(default_sinfo));-default_sinfo.sinfo_stream=cmsgs.sinfo->snd_sid;-default_sinfo.sinfo_flags=cmsgs.sinfo->snd_flags;-default_sinfo.sinfo_ppid=cmsgs.sinfo->snd_ppid;-default_sinfo.sinfo_context=cmsgs.sinfo->snd_context;-default_sinfo.sinfo_assoc_id=cmsgs.sinfo->snd_assoc_id;--sinfo=&default_sinfo;-fill_sinfo_ttl=true;-}else{-sinfo=cmsgs.srinfo;-}-/* Did the user specify SNDINFO/SNDRCVINFO? */-if(sinfo){-sinfo_flags=sinfo->sinfo_flags;-associd=sinfo->sinfo_assoc_id;-}--pr_debug("%s: msg_len:%zu, sinfo_flags:0x%x\n",__func__,-msg_len,sinfo_flags);--/* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */-if(sctp_style(sk,TCP)&&(sinfo_flags&(SCTP_EOF|SCTP_ABORT))){-err=-EINVAL;-gotoout_nounlock;-}--/* If SCTP_EOF is set, no data can be sent. Disallow sending zero-*lengthmessageswhenSCTP_EOF|SCTP_ABORTisnotset.-*IfSCTP_ABORTisset,themessagelengthcouldbenonzerowith-*themsg_iovsettotheuserabortreason.-*/-if(((sinfo_flags&SCTP_EOF)&&(msg_len>0))||-(!(sinfo_flags&(SCTP_EOF|SCTP_ABORT))&&(msg_len==0))){-err=-EINVAL;-gotoout_nounlock;-}--/* If SCTP_ADDR_OVER is set, there must be an address-*specifiedinmsg_name.-*/-if((sinfo_flags&SCTP_ADDR_OVER)&&(!msg->msg_name)){-err=-EINVAL;-gotoout_nounlock;-}--transport=NULL;--pr_debug("%s: about to look up association\n",__func__);-lock_sock(sk);/* If a msg_name has been specified, assume this is to be used. */
@@ -1964,36 +1951,15 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)new_asoc=asoc;}-/* ASSERT: we have a valid association at this point. */-pr_debug("%s: we have a valid association\n",__func__);--if(!sinfo){-/* If the user didn't specify SNDINFO/SNDRCVINFO, make up-*onewithsomedefaults.-*/-memset(&default_sinfo,0,sizeof(default_sinfo));-default_sinfo.sinfo_stream=asoc->default_stream;-default_sinfo.sinfo_flags=asoc->default_flags;-default_sinfo.sinfo_ppid=asoc->default_ppid;-default_sinfo.sinfo_context=asoc->default_context;-default_sinfo.sinfo_timetolive=asoc->default_timetolive;-default_sinfo.sinfo_assoc_id=sctp_assoc2id(asoc);--sinfo=&default_sinfo;-}elseif(fill_sinfo_ttl){-/* In case SNDINFO was specified, we still need to fill-*itwithadefaultttlfromtheassochere.-*/-sinfo->sinfo_timetolive=asoc->default_timetolive;+if(!cmsgs.srinfo&&!cmsgs.sinfo){+sinfo->sinfo_stream=asoc->default_stream;+sinfo->sinfo_ppid=asoc->default_ppid;+sinfo->sinfo_context=asoc->default_context;+sinfo->sinfo_assoc_id=sctp_assoc2id(asoc);}-/* API 7.1.7, the sndbuf size per association bounds the-*maximumsizeofdatathatcanbesentinasinglesendcall.-*/-if(msg_len>sk->sk_sndbuf){-err=-EMSGSIZE;-gotoout_free;-}+if(!cmsgs.srinfo)+sinfo->sinfo_timetolive=asoc->default_timetolive;/* If an address is passed with the sendto/sendmsg call, it is used*tooverridetheprimarydestinationaddressintheTCPmodel,or
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:17
This patch is to move the codes for trying to get sinfo from
asoc into sctp_sendmsg_update_sinfo.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
@@ -1892,6 +1892,21 @@ static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk,returndaddr;}+staticvoidsctp_sendmsg_update_sinfo(structsctp_association*asoc,+structsctp_sndrcvinfo*sinfo,+structsctp_cmsgs*cmsgs)+{+if(!cmsgs->srinfo&&!cmsgs->sinfo){+sinfo->sinfo_stream=asoc->default_stream;+sinfo->sinfo_ppid=asoc->default_ppid;+sinfo->sinfo_context=asoc->default_context;+sinfo->sinfo_assoc_id=sctp_assoc2id(asoc);+}++if(!cmsgs->srinfo)+sinfo->sinfo_timetolive=asoc->default_timetolive;+}+staticintsctp_sendmsg(structsock*sk,structmsghdr*msg,size_tmsg_len){structsctp_endpoint*ep=sctp_sk(sk)->ep;
@@ -1951,15 +1966,8 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)new_asoc=asoc;}-if(!cmsgs.srinfo&&!cmsgs.sinfo){-sinfo->sinfo_stream=asoc->default_stream;-sinfo->sinfo_ppid=asoc->default_ppid;-sinfo->sinfo_context=asoc->default_context;-sinfo->sinfo_assoc_id=sctp_assoc2id(asoc);-}--if(!cmsgs.srinfo)-sinfo->sinfo_timetolive=asoc->default_timetolive;+/* Update snd_info with the asoc */+sctp_sendmsg_update_sinfo(asoc,sinfo,&cmsgs);/* If an address is passed with the sendto/sendmsg call, it is used*tooverridetheprimarydestinationaddressintheTCPmodel,or
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:25
Now sctp_assoc_lookup_paddr can only be called only if daddr has
been set. But if daddr has been set, sctp_endpoint_lookup_assoc
would be done, where it could already have the transport.
So this unnecessary transport looking up should be removed, but
only reset transport as NULL when SCTP_ADDR_OVER is not set for
UDP type socket.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
@@ -1966,29 +1966,17 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)new_asoc=asoc;}+if(!sctp_style(sk,TCP)&&!(sinfo_flags&SCTP_ADDR_OVER))+transport=NULL;+/* Update snd_info with the asoc */sctp_sendmsg_update_sinfo(asoc,sinfo,&cmsgs);-/* If an address is passed with the sendto/sendmsg call, it is used-*tooverridetheprimarydestinationaddressintheTCPmodel,or-*whenSCTP_ADDR_OVERflagissetintheUDPmodel.-*/-if((sctp_style(sk,TCP)&&daddr)||-(sinfo_flags&SCTP_ADDR_OVER)){-chunk_tp=sctp_assoc_lookup_paddr(asoc,daddr);-if(!chunk_tp){-err=-EINVAL;-gotoout_free;-}-}else-chunk_tp=NULL;-/* Send msg to the asoc */-err=sctp_sendmsg_to_asoc(asoc,msg,msg_len,chunk_tp,sinfo);--out_free:+err=sctp_sendmsg_to_asoc(asoc,msg,msg_len,transport,sinfo);if(err<0&&err!=-ESRCH&&new_asoc)sctp_association_free(asoc);+out_unlock:release_sock(sk);out_nounlock:
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:31
This patch mostly is to:
- rename sinfo_flags as sflags, to make the indents look better, and
also keep consistent with other sctp_sendmsg_xx functions.
- replace new_asoc with bool new, no need to define a pointer here,
as if new_asoc is set, it must be asoc.
- rename the 'out_nounlock:' as 'out', shorter and nicer.
- remove associd, only one place is using it now, just use
sinfo->sinfo_assoc_id directly.
- remove 'cmsgs' initialization in sctp_sendmsg, as it will be done
in sctp_sendmsg_parse.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
@@ -1910,28 +1910,28 @@ static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,staticintsctp_sendmsg(structsock*sk,structmsghdr*msg,size_tmsg_len){structsctp_endpoint*ep=sctp_sk(sk)->ep;-structsctp_association*new_asoc=NULL,*asoc=NULL;structsctp_transport*transport=NULL;structsctp_sndrcvinfo_sinfo,*sinfo;-sctp_assoc_tassocid=0;-structsctp_cmsgscmsgs={NULL};-__u16sinfo_flags=0;+structsctp_association*asoc;+structsctp_cmsgscmsgs;unionsctp_addr*daddr;+boolnew=false;+__u16sflags;interr;/* Parse and get snd_info */err=sctp_sendmsg_parse(sk,&cmsgs,&_sinfo,msg,msg_len);if(err)-gotoout_nounlock;+gotoout;sinfo=&_sinfo;-sinfo_flags=sinfo->sinfo_flags;+sflags=sinfo->sinfo_flags;/* Get daddr from msg */daddr=sctp_sendmsg_get_daddr(sk,msg,&cmsgs);if(IS_ERR(daddr)){err=PTR_ERR(daddr);-gotoout_nounlock;+gotoout;}lock_sock(sk);
@@ -1941,7 +1941,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)/* Look for a matching association on the endpoint. */asoc=sctp_endpoint_lookup_assoc(ep,daddr,&transport);}else{-asoc=sctp_id2assoc(sk,associd);+asoc=sctp_id2assoc(sk,sinfo->sinfo_assoc_id);if(!asoc){err=-EPIPE;gotoout_unlock;
@@ -1949,24 +1949,23 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)}if(asoc){-err=sctp_sendmsg_check_sflags(asoc,sinfo_flags,msg,-msg_len);+err=sctp_sendmsg_check_sflags(asoc,sflags,msg,msg_len);if(err<=0)gotoout_unlock;}/* Do we need to create the association? */if(!asoc){-err=sctp_sendmsg_new_asoc(sk,sinfo_flags,&cmsgs,daddr,+err=sctp_sendmsg_new_asoc(sk,sflags,&cmsgs,daddr,&transport);if(err)gotoout_unlock;asoc=transport->asoc;-new_asoc=asoc;+new=true;}-if(!sctp_style(sk,TCP)&&!(sinfo_flags&SCTP_ADDR_OVER))+if(!sctp_style(sk,TCP)&&!(sflags&SCTP_ADDR_OVER))transport=NULL;/* Update snd_info with the asoc */
@@ -1974,12 +1973,12 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)/* Send msg to the asoc */err=sctp_sendmsg_to_asoc(asoc,msg,msg_len,transport,sinfo);-if(err<0&&err!=-ESRCH&&new_asoc)+if(err<0&&err!=-ESRCH&&new)sctp_association_free(asoc);out_unlock:release_sock(sk);-out_nounlock:+out:returnsctp_error(sk,msg->msg_flags,err);}
From: Xin Long <lucien.xin@gmail.com> Date: 2018-03-01 15:06:39
sctp_sendmsg_new_asoc and SCTP_ADDR_OVER check is only necessary
when daddr is set, so move them up to if (daddr) statement.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
@@ -1936,38 +1936,38 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)lock_sock(sk);-/* If a msg_name has been specified, assume this is to be used. */+/* Get and check or create asoc */if(daddr){-/* Look for a matching association on the endpoint. */asoc=sctp_endpoint_lookup_assoc(ep,daddr,&transport);+if(asoc){+err=sctp_sendmsg_check_sflags(asoc,sflags,msg,+msg_len);+if(err<=0)+gotoout_unlock;+}else{+err=sctp_sendmsg_new_asoc(sk,sflags,&cmsgs,daddr,+&transport);+if(err)+gotoout_unlock;++asoc=transport->asoc;+new=true;+}++if(!sctp_style(sk,TCP)&&!(sflags&SCTP_ADDR_OVER))+transport=NULL;}else{asoc=sctp_id2assoc(sk,sinfo->sinfo_assoc_id);if(!asoc){err=-EPIPE;gotoout_unlock;}-}-if(asoc){err=sctp_sendmsg_check_sflags(asoc,sflags,msg,msg_len);if(err<=0)gotoout_unlock;}-/* Do we need to create the association? */-if(!asoc){-err=sctp_sendmsg_new_asoc(sk,sflags,&cmsgs,daddr,-&transport);-if(err)-gotoout_unlock;--asoc=transport->asoc;-new=true;-}--if(!sctp_style(sk,TCP)&&!(sflags&SCTP_ADDR_OVER))-transport=NULL;-/* Update snd_info with the asoc */sctp_sendmsg_update_sinfo(asoc,sinfo,&cmsgs);
From: Neil Horman <nhorman@tuxdriver.com> Date: 2018-03-01 18:10:03
On Thu, Mar 01, 2018 at 11:05:09PM +0800, Xin Long wrote:
quoted hunk
This cleanup mostly does three things:
- extract some codes into functions to make sendmsg more readable.
- tidy up some codes to avoid the unnecessary checks.
- adjust some logic so that it will be easier to add the send flags
and cmsgs features that I will post after this.
To make it easy to review and to check if the code is compatible with
before, this patchset is to do it step by step in 9 patches.
NOTE:
There will be a conflict when merging
Commit 2277c7cd75e3 ("sctp: Add LSM hooks") from selinux tree,
the solution is to:
1. remove all the lines in [B]:
<<<<<<< HEAD
[A]
=======
[B]
>>>>>>> 2277c7c... sctp: Add LSM hooks
2. and apply the following diff-output:
@@ -1711,6 +1712,22 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,scope=sctp_scope(daddr);+/* Label connection socket for first association 1-to-many+*styleforclientsequencesocket()->sendmsg().This+*needstobedonebeforesctp_assoc_add_peer()asthatwill+*setuptheinitialpacketthatneedstoaccountforany+*securityipoptions(CIPSO/CALIPSO)addedtothepacket.+*/+af=sctp_get_af_specific(daddr->sa.sa_family);+if(!af)+return-EINVAL;++err=security_sctp_bind_connect(sk,SCTP_SENDMSG_CONNECT,+(structsockaddr*)daddr,+af->sockaddr_len);+if(err<0)+returnerr;+asoc=sctp_association_new(ep,sk,scope,GFP_KERNEL);if(!asoc)return-ENOMEM;
Xin Long (9):
sctp: factor out sctp_sendmsg_to_asoc from sctp_sendmsg
sctp: factor out sctp_sendmsg_new_asoc from sctp_sendmsg
sctp: factor out sctp_sendmsg_check_sflags from sctp_sendmsg
sctp: factor out sctp_sendmsg_get_daddr from sctp_sendmsg
sctp: factor out sctp_sendmsg_parse from sctp_sendmsg
sctp: factor out sctp_sendmsg_update_sinfo from sctp_sendmsg
sctp: remove the unnecessary transport looking up from sctp_sendmsg
sctp: improve some variables in sctp_sendmsg
sctp: adjust some codes in a better order in sctp_sendmsg
net/sctp/socket.c | 638 +++++++++++++++++++++++-------------------------------
1 file changed, 274 insertions(+), 364 deletions(-)
--
2.1.0
Series
Acked-by: Neil Horman <nhorman@tuxdriver.com>
From: David Miller <davem@davemloft.net> Date: 2018-03-04 18:02:58
From: Xin Long <lucien.xin@gmail.com>
Date: Thu, 1 Mar 2018 23:05:09 +0800
This cleanup mostly does three things:
- extract some codes into functions to make sendmsg more readable.
- tidy up some codes to avoid the unnecessary checks.
- adjust some logic so that it will be easier to add the send flags
and cmsgs features that I will post after this.
To make it easy to review and to check if the code is compatible with
before, this patchset is to do it step by step in 9 patches.
NOTE:
There will be a conflict when merging
Commit 2277c7cd75e3 ("sctp: Add LSM hooks") from selinux tree,
the solution is to:
1. remove all the lines in [B]:
<<<<<<< HEAD
[A]
=======
[B]
>>>>>>> 2277c7c... sctp: Add LSM hooks
2. and apply the following diff-output:
...
Series applied, thank you.
In particular, thanks for the merge resolution details.