@@ -119,7 +119,8 @@ enum {
119
119
ISOTP_WAIT_FIRST_FC ,
120
120
ISOTP_WAIT_FC ,
121
121
ISOTP_WAIT_DATA ,
122
- ISOTP_SENDING
122
+ ISOTP_SENDING ,
123
+ ISOTP_SHUTDOWN ,
123
124
};
124
125
125
126
struct tpcon {
@@ -880,8 +881,8 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
880
881
txtimer );
881
882
struct sock * sk = & so -> sk ;
882
883
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 )
885
886
return HRTIMER_NORESTART ;
886
887
887
888
/* 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)
918
919
{
919
920
struct sock * sk = sock -> sk ;
920
921
struct isotp_sock * so = isotp_sk (sk );
921
- u32 old_state = so -> tx .state ;
922
922
struct sk_buff * skb ;
923
923
struct net_device * dev ;
924
924
struct canfd_frame * cf ;
@@ -928,23 +928,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
928
928
int off ;
929
929
int err ;
930
930
931
- if (!so -> bound )
931
+ if (!so -> bound || so -> tx . state == ISOTP_SHUTDOWN )
932
932
return - EADDRNOTAVAIL ;
933
933
934
+ wait_free_buffer :
934
935
/* 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 ;
941
938
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 ;
946
943
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 ;
948
949
}
949
950
950
951
if (!size || size > MAX_MSG_LENGTH ) {
@@ -1074,21 +1075,25 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
1074
1075
1075
1076
if (wait_tx_done ) {
1076
1077
/* 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 ;
1078
1081
1079
1082
if (sk -> sk_err )
1080
1083
return - sk -> sk_err ;
1081
1084
}
1082
1085
1083
1086
return size ;
1084
1087
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 );
1085
1093
err_out_drop :
1086
1094
/* 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 );
1092
1097
1093
1098
return err ;
1094
1099
}
@@ -1150,10 +1155,12 @@ static int isotp_release(struct socket *sock)
1150
1155
net = sock_net (sk );
1151
1156
1152
1157
/* 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
+ ;
1154
1161
1155
1162
/* force state machines to be idle also when a signal occurred */
1156
- so -> tx .state = ISOTP_IDLE ;
1163
+ so -> tx .state = ISOTP_SHUTDOWN ;
1157
1164
so -> rx .state = ISOTP_IDLE ;
1158
1165
1159
1166
spin_lock (& isotp_notifier_lock );
0 commit comments