@@ -119,7 +119,8 @@ enum {
119119 ISOTP_WAIT_FIRST_FC ,
120120 ISOTP_WAIT_FC ,
121121 ISOTP_WAIT_DATA ,
122- ISOTP_SENDING
122+ ISOTP_SENDING ,
123+ ISOTP_SHUTDOWN ,
123124};
124125
125126struct tpcon {
@@ -880,8 +881,8 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
880881 txtimer );
881882 struct sock * sk = & so -> sk ;
882883
883- /* don't handle timeouts in IDLE state */
884- if (so -> tx .state == ISOTP_IDLE )
884+ /* don't handle timeouts in IDLE or SHUTDOWN state */
885+ if (so -> tx .state == ISOTP_IDLE || so -> tx . state == ISOTP_SHUTDOWN )
885886 return HRTIMER_NORESTART ;
886887
887888 /* we did not get any flow control or echo frame in time */
@@ -918,7 +919,6 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
918919{
919920 struct sock * sk = sock -> sk ;
920921 struct isotp_sock * so = isotp_sk (sk );
921- u32 old_state = so -> tx .state ;
922922 struct sk_buff * skb ;
923923 struct net_device * dev ;
924924 struct canfd_frame * cf ;
@@ -928,23 +928,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
928928 int off ;
929929 int err ;
930930
931- if (!so -> bound )
931+ if (!so -> bound || so -> tx . state == ISOTP_SHUTDOWN )
932932 return - EADDRNOTAVAIL ;
933933
934+ wait_free_buffer :
934935 /* we do not support multiple buffers - for now */
935- if (cmpxchg (& so -> tx .state , ISOTP_IDLE , ISOTP_SENDING ) != ISOTP_IDLE ||
936- wq_has_sleeper (& so -> wait )) {
937- if (msg -> msg_flags & MSG_DONTWAIT ) {
938- err = - EAGAIN ;
939- goto err_out ;
940- }
936+ if (wq_has_sleeper (& so -> wait ) && (msg -> msg_flags & MSG_DONTWAIT ))
937+ return - EAGAIN ;
941938
942- /* wait for complete transmission of current pdu */
943- err = wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
944- if (err )
945- goto err_out ;
939+ /* wait for complete transmission of current pdu */
940+ err = wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
941+ if (err )
942+ goto err_event_drop ;
946943
947- so -> tx .state = ISOTP_SENDING ;
944+ if (cmpxchg (& so -> tx .state , ISOTP_IDLE , ISOTP_SENDING ) != ISOTP_IDLE ) {
945+ if (so -> tx .state == ISOTP_SHUTDOWN )
946+ return - EADDRNOTAVAIL ;
947+
948+ goto wait_free_buffer ;
948949 }
949950
950951 if (!size || size > MAX_MSG_LENGTH ) {
@@ -1074,21 +1075,25 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
10741075
10751076 if (wait_tx_done ) {
10761077 /* wait for complete transmission of current pdu */
1077- wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
1078+ err = wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
1079+ if (err )
1080+ goto err_event_drop ;
10781081
10791082 if (sk -> sk_err )
10801083 return - sk -> sk_err ;
10811084 }
10821085
10831086 return size ;
10841087
1088+ err_event_drop :
1089+ /* got signal: force tx state machine to be idle */
1090+ so -> tx .state = ISOTP_IDLE ;
1091+ hrtimer_cancel (& so -> txfrtimer );
1092+ hrtimer_cancel (& so -> txtimer );
10851093err_out_drop :
10861094 /* drop this PDU and unlock a potential wait queue */
1087- old_state = ISOTP_IDLE ;
1088- err_out :
1089- so -> tx .state = old_state ;
1090- if (so -> tx .state == ISOTP_IDLE )
1091- wake_up_interruptible (& so -> wait );
1095+ so -> tx .state = ISOTP_IDLE ;
1096+ wake_up_interruptible (& so -> wait );
10921097
10931098 return err ;
10941099}
@@ -1150,10 +1155,12 @@ static int isotp_release(struct socket *sock)
11501155 net = sock_net (sk );
11511156
11521157 /* wait for complete transmission of current pdu */
1153- wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
1158+ while (wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE ) == 0 &&
1159+ cmpxchg (& so -> tx .state , ISOTP_IDLE , ISOTP_SHUTDOWN ) != ISOTP_IDLE )
1160+ ;
11541161
11551162 /* force state machines to be idle also when a signal occurred */
1156- so -> tx .state = ISOTP_IDLE ;
1163+ so -> tx .state = ISOTP_SHUTDOWN ;
11571164 so -> rx .state = ISOTP_IDLE ;
11581165
11591166 spin_lock (& isotp_notifier_lock );
0 commit comments