@@ -126,7 +126,12 @@ static int tcp_endpoint_set(union tcp_endpoint *ep, struct net_pkt *pkt,
126126 case AF_INET :
127127 if (IS_ENABLED (CONFIG_NET_IPV4 )) {
128128 struct net_ipv4_hdr * ip = NET_IPV4_HDR (pkt );
129- struct tcphdr * th = th_get (pkt );
129+ struct tcphdr * th ;
130+
131+ th = th_get (pkt );
132+ if (!th ) {
133+ return - ENOBUFS ;
134+ }
130135
131136 memset (ep , 0 , sizeof (* ep ));
132137
@@ -145,7 +150,12 @@ static int tcp_endpoint_set(union tcp_endpoint *ep, struct net_pkt *pkt,
145150 case AF_INET6 :
146151 if (IS_ENABLED (CONFIG_NET_IPV6 )) {
147152 struct net_ipv6_hdr * ip = NET_IPV6_HDR (pkt );
148- struct tcphdr * th = th_get (pkt );
153+ struct tcphdr * th ;
154+
155+ th = th_get (pkt );
156+ if (!th ) {
157+ return - ENOBUFS ;
158+ }
149159
150160 memset (ep , 0 , sizeof (* ep ));
151161
@@ -361,8 +371,12 @@ static void tcp_send_process(struct k_work *work)
361371
362372 if (conn -> in_retransmission ) {
363373 if (conn -> send_retries > 0 ) {
364- tcp_send (tcp_pkt_clone (pkt ));
365- conn -> send_retries -- ;
374+ struct net_pkt * clone = tcp_pkt_clone (pkt );
375+
376+ if (clone ) {
377+ tcp_send (clone );
378+ conn -> send_retries -- ;
379+ }
366380 } else {
367381 tcp_conn_unref (conn );
368382 conn = NULL ;
@@ -376,7 +390,6 @@ static void tcp_send_process(struct k_work *work)
376390 next ) : tcp_pkt_clone (pkt );
377391 if (!pkt ) {
378392 NET_ERR ("net_pkt alloc failure" );
379- tcp_conn_unref (conn );
380393 return ;
381394 }
382395
@@ -634,22 +647,22 @@ static int ip_header_add(struct tcp *conn, struct net_pkt *pkt)
634647 return - EINVAL ;
635648}
636649
637- static void tcp_out_ext (struct tcp * conn , uint8_t flags , struct net_pkt * data ,
638- uint32_t seq )
650+ static int tcp_out_ext (struct tcp * conn , uint8_t flags , struct net_pkt * data ,
651+ uint32_t seq )
639652{
640653 struct net_pkt * pkt ;
641- int ret ;
654+ int ret = 0 ;
642655
643656 pkt = tcp_pkt_alloc (conn , sizeof (struct tcphdr ));
644657 if (!pkt ) {
658+ ret = - ENOBUFS ;
645659 goto out ;
646660 }
647661
648662 if (data ) {
649663 /* Append the data buffer to the pkt */
650664 net_pkt_append_buffer (pkt , data -> buffer );
651665 data -> buffer = NULL ;
652- tcp_pkt_unref (data );
653666 }
654667
655668 ret = ip_header_add (conn , pkt );
@@ -673,20 +686,20 @@ static void tcp_out_ext(struct tcp *conn, uint8_t flags, struct net_pkt *data,
673686 NET_DBG ("%s" , log_strdup (tcp_th (pkt )));
674687
675688 if (tcp_send_cb ) {
676- tcp_send_cb (pkt );
689+ ret = tcp_send_cb (pkt );
677690 goto out ;
678691 }
679692
680693 sys_slist_append (& conn -> send_queue , & pkt -> next );
681694
682695 tcp_send_process ((struct k_work * )& conn -> send_timer );
683696out :
684- return ;
697+ return ret ;
685698}
686699
687700static void tcp_out (struct tcp * conn , uint8_t flags )
688701{
689- tcp_out_ext (conn , flags , NULL /* no data */ , conn -> seq );
702+ ( void ) tcp_out_ext (conn , flags , NULL /* no data */ , conn -> seq );
690703}
691704
692705static int tcp_pkt_pull (struct net_pkt * pkt , size_t len )
@@ -707,8 +720,8 @@ static int tcp_pkt_pull(struct net_pkt *pkt, size_t len)
707720 return ret ;
708721}
709722
710- static void tcp_pkt_peek (struct net_pkt * to , struct net_pkt * from , size_t pos ,
711- size_t len )
723+ static int tcp_pkt_peek (struct net_pkt * to , struct net_pkt * from , size_t pos ,
724+ size_t len )
712725{
713726 net_pkt_cursor_init (to );
714727 net_pkt_cursor_init (from );
@@ -718,7 +731,7 @@ static void tcp_pkt_peek(struct net_pkt *to, struct net_pkt *from, size_t pos,
718731 net_pkt_skip (from , pos );
719732 }
720733
721- net_pkt_copy (to , from , len );
734+ return net_pkt_copy (to , from , len );
722735}
723736
724737static bool tcp_window_full (struct tcp * conn )
@@ -766,14 +779,27 @@ static int tcp_send_data(struct tcp *conn)
766779 goto out ;
767780 }
768781
769- tcp_pkt_peek (pkt , conn -> send_data , pos , len );
782+ ret = tcp_pkt_peek (pkt , conn -> send_data , pos , len );
783+ if (ret < 0 ) {
784+ tcp_pkt_unref (pkt );
785+ ret = - ENOBUFS ;
786+ goto out ;
787+ }
788+
789+ ret = tcp_out_ext (conn , PSH | ACK , pkt , conn -> seq + conn -> unacked_len );
790+ if (ret == 0 ) {
791+ conn -> unacked_len += len ;
792+ }
770793
771- tcp_out_ext (conn , PSH | ACK , pkt , conn -> seq + conn -> unacked_len );
794+ /* The data we want to send, has been moved to the send queue so we
795+ * can unref the head net_pkt. If there was an error, we need to remove
796+ * the packet anyway.
797+ */
798+ tcp_pkt_unref (pkt );
772799
773- conn -> unacked_len += len ;
774- out :
775800 conn_send_data_dump (conn );
776801
802+ out :
777803 return ret ;
778804}
779805
@@ -809,6 +835,14 @@ static int tcp_send_queued_data(struct tcp *conn)
809835 subscribe = false;
810836 }
811837
838+ /* If we have out-of-bufs case, then do not start retransmit timer
839+ * yet. The socket layer will catch this and resend data if needed.
840+ */
841+ if (ret == - ENOBUFS ) {
842+ NET_DBG ("No bufs, cancelling retransmit timer" );
843+ k_delayed_work_cancel (& conn -> send_data_timer );
844+ }
845+
812846 if (subscribe ) {
813847 conn -> send_data_retries = 0 ;
814848 k_delayed_work_submit (& conn -> send_data_timer , K_MSEC (tcp_rto ));
@@ -821,6 +855,7 @@ static void tcp_resend_data(struct k_work *work)
821855{
822856 struct tcp * conn = CONTAINER_OF (work , struct tcp , send_data_timer );
823857 bool conn_unref = false;
858+ int ret ;
824859
825860 NET_DBG ("send_data_retries=%hu" , conn -> send_data_retries );
826861
@@ -832,10 +867,14 @@ static void tcp_resend_data(struct k_work *work)
832867
833868 conn -> data_mode = TCP_DATA_MODE_RESEND ;
834869 conn -> unacked_len = 0 ;
835- tcp_send_data (conn );
836870
837- conn -> send_data_retries ++ ;
871+ ret = tcp_send_data (conn );
872+ if (ret == 0 ) {
873+ conn -> send_data_retries ++ ;
874+ }
875+
838876 k_delayed_work_submit (& conn -> send_data_timer , K_MSEC (tcp_rto ));
877+
839878 out :
840879 if (conn_unref ) {
841880 tcp_conn_unref (conn );
@@ -1088,6 +1127,7 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
10881127 uint8_t next = 0 , fl = th ? th -> th_flags : 0 ;
10891128 size_t tcp_options_len = th ? (th -> th_off - 5 ) * 4 : 0 ;
10901129 size_t len ;
1130+ int ret ;
10911131
10921132 k_mutex_lock (& conn -> lock , K_FOREVER );
10931133
@@ -1217,10 +1257,8 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
12171257 conn_send_data_dump (conn );
12181258
12191259 if (!k_delayed_work_remaining_get (& conn -> send_data_timer )) {
1220- NET_ERR ("conn: %p, Missing a subscription "
1260+ NET_DBG ("conn: %p, Missing a subscription "
12211261 "of the send_data queue timer" , conn );
1222- tcp_out (conn , RST );
1223- conn_state (conn , TCP_CLOSED );
12241262 break ;
12251263 }
12261264 conn -> send_data_retries = 0 ;
@@ -1230,7 +1268,8 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
12301268 }
12311269 conn -> data_mode = TCP_DATA_MODE_SEND ;
12321270
1233- if (tcp_send_queued_data (conn ) < 0 ) {
1271+ ret = tcp_send_queued_data (conn );
1272+ if (ret < 0 && ret != - ENOBUFS ) {
12341273 tcp_out (conn , RST );
12351274 conn_state (conn , TCP_CLOSED );
12361275 break ;
@@ -1324,7 +1363,6 @@ int net_tcp_put(struct net_context *context)
13241363 tcp_out_ext (conn , FIN | ACK , NULL ,
13251364 conn -> seq + conn -> unacked_len );
13261365 conn_seq (conn , + 1 );
1327-
13281366 conn_state (conn , TCP_FIN_WAIT_1 );
13291367
13301368 k_mutex_unlock (& conn -> lock );
@@ -1355,18 +1393,22 @@ int net_tcp_update_recv_wnd(struct net_context *context, int32_t delta)
13551393int net_tcp_queue_data (struct net_context * context , struct net_pkt * pkt )
13561394{
13571395 struct tcp * conn = context -> tcp ;
1396+ struct net_buf * orig_buf = NULL ;
13581397 int ret = 0 ;
13591398 size_t len ;
13601399
13611400 if (!conn || conn -> state != TCP_ESTABLISHED ) {
1362- ret = - ENOTCONN ;
1363- goto out ;
1401+ return - ENOTCONN ;
13641402 }
13651403
13661404 k_mutex_lock (& conn -> lock , K_FOREVER );
13671405
13681406 len = net_pkt_get_len (pkt );
13691407
1408+ if (conn -> send_data -> buffer ) {
1409+ orig_buf = net_buf_frag_last (conn -> send_data -> buffer );
1410+ }
1411+
13701412 net_pkt_append_buffer (conn -> send_data , pkt -> buffer );
13711413 conn -> send_data_total += len ;
13721414 NET_DBG ("conn: %p Queued %zu bytes (total %zu)" , conn , len ,
@@ -1375,14 +1417,28 @@ int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt)
13751417 tcp_pkt_unref (pkt );
13761418
13771419 ret = tcp_send_queued_data (conn );
1378- if (ret < 0 ) {
1379- k_mutex_unlock (& conn -> lock );
1420+ if (ret < 0 && ret != - ENOBUFS ) {
13801421 tcp_conn_unref (conn );
13811422 goto out ;
13821423 }
13831424
1425+ if (ret == - ENOBUFS ) {
1426+ /* Restore the original data so that we do not resend the pkt
1427+ * data multiple times.
1428+ */
1429+ conn -> send_data_total -= len ;
1430+
1431+ if (orig_buf ) {
1432+ pkt -> buffer = orig_buf -> frags ;
1433+ orig_buf -> frags = NULL ;
1434+ } else {
1435+ pkt -> buffer = conn -> send_data -> buffer ;
1436+ conn -> send_data -> buffer = NULL ;
1437+ }
1438+ }
1439+ out :
13841440 k_mutex_unlock (& conn -> lock );
1385- out :
1441+
13861442 return ret ;
13871443}
13881444
0 commit comments