@@ -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,7 +1075,9 @@ 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 err = sock_error (sk );
10801083 if (err )
@@ -1083,13 +1086,15 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
10831086
10841087 return size ;
10851088
1089+ err_event_drop :
1090+ /* got signal: force tx state machine to be idle */
1091+ so -> tx .state = ISOTP_IDLE ;
1092+ hrtimer_cancel (& so -> txfrtimer );
1093+ hrtimer_cancel (& so -> txtimer );
10861094err_out_drop :
10871095 /* drop this PDU and unlock a potential wait queue */
1088- old_state = ISOTP_IDLE ;
1089- err_out :
1090- so -> tx .state = old_state ;
1091- if (so -> tx .state == ISOTP_IDLE )
1092- wake_up_interruptible (& so -> wait );
1096+ so -> tx .state = ISOTP_IDLE ;
1097+ wake_up_interruptible (& so -> wait );
10931098
10941099 return err ;
10951100}
@@ -1151,10 +1156,12 @@ static int isotp_release(struct socket *sock)
11511156 net = sock_net (sk );
11521157
11531158 /* wait for complete transmission of current pdu */
1154- wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE );
1159+ while (wait_event_interruptible (so -> wait , so -> tx .state == ISOTP_IDLE ) == 0 &&
1160+ cmpxchg (& so -> tx .state , ISOTP_IDLE , ISOTP_SHUTDOWN ) != ISOTP_IDLE )
1161+ ;
11551162
11561163 /* force state machines to be idle also when a signal occurred */
1157- so -> tx .state = ISOTP_IDLE ;
1164+ so -> tx .state = ISOTP_SHUTDOWN ;
11581165 so -> rx .state = ISOTP_IDLE ;
11591166
11601167 spin_lock (& isotp_notifier_lock );
0 commit comments