tcp_appsend.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /****************************************************************************
  2. * net/tcp/tcp_appsend.c
  3. *
  4. * Copyright (C) 2007-2010, 2014 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Adapted for NuttX from logic in uIP which also has a BSD-like license:
  8. *
  9. * Original author Adam Dunkels <adam@dunkels.com>
  10. * Copyright () 2001-2003, Adam Dunkels.
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. *
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. * 3. The name of the author may not be used to endorse or promote
  23. * products derived from this software without specific prior
  24. * written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  27. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  28. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  30. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  32. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  34. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. ****************************************************************************/
  39. /****************************************************************************
  40. * Included Files
  41. ****************************************************************************/
  42. #include <nuttx/config.h>
  43. #if defined(CONFIG_NET) && defined(CONFIG_NET_TCP)
  44. #include <stdint.h>
  45. #include <assert.h>
  46. #include <debug.h>
  47. #include <nuttx/net/netconfig.h>
  48. #include <nuttx/net/netdev.h>
  49. #include <nuttx/net/tcp.h>
  50. #include "devif/devif.h"
  51. #include "tcp/tcp.h"
  52. /****************************************************************************
  53. * Public Functions
  54. ****************************************************************************/
  55. /****************************************************************************
  56. * Name: tcp_appsend
  57. *
  58. * Description:
  59. * Handle application or TCP protocol response. If this function is called
  60. * with dev->d_sndlen > 0, then this is an application attempting to send
  61. * packet.
  62. *
  63. * Input Parameters:
  64. * dev - The device driver structure to use in the send operation
  65. * conn - The TCP connection structure holding connection information
  66. * result - App result event sent
  67. *
  68. * Returned Value:
  69. * None
  70. *
  71. * Assumptions:
  72. * The network is locked.
  73. *
  74. ****************************************************************************/
  75. void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
  76. uint16_t result)
  77. {
  78. uint8_t hdrlen;
  79. /* Handle the result based on the application response */
  80. ninfo("result: %04x d_sndlen: %d conn->unacked: %d\n",
  81. result, dev->d_sndlen, conn->unacked);
  82. /* Get the IP header length associated with the IP domain configured for
  83. * this TCP connection.
  84. */
  85. #ifdef CONFIG_NET_IPv4
  86. #ifdef CONFIG_NET_IPv6
  87. if (conn->domain == PF_INET)
  88. #endif
  89. {
  90. DEBUGASSERT(IFF_IS_IPv4(dev->d_flags));
  91. hdrlen = IPv4TCP_HDRLEN;
  92. }
  93. #endif /* CONFIG_NET_IPv4 */
  94. #ifdef CONFIG_NET_IPv6
  95. #ifdef CONFIG_NET_IPv4
  96. else
  97. #endif
  98. {
  99. DEBUGASSERT(IFF_IS_IPv6(dev->d_flags));
  100. hdrlen = IPv6TCP_HDRLEN;
  101. }
  102. #endif /* CONFIG_NET_IPv6 */
  103. /* Check If the device went down */
  104. if ((result & NETDEV_DOWN) != 0)
  105. {
  106. /* If so, make sure that the connection is marked closed
  107. * and do not try to send anything.
  108. */
  109. dev->d_sndlen = 0;
  110. conn->tcpstateflags = TCP_CLOSED;
  111. ninfo("TCP state: NETDEV_DOWN\n");
  112. }
  113. /* Check for connection aborted */
  114. else if ((result & TCP_ABORT) != 0)
  115. {
  116. dev->d_sndlen = 0;
  117. conn->tcpstateflags = TCP_CLOSED;
  118. ninfo("TCP state: TCP_CLOSED\n");
  119. tcp_send(dev, conn, TCP_RST | TCP_ACK, hdrlen);
  120. }
  121. /* Check for connection closed */
  122. else if ((result & TCP_CLOSE) != 0)
  123. {
  124. conn->tcpstateflags = TCP_FIN_WAIT_1;
  125. conn->unacked = 1;
  126. conn->nrtx = 0;
  127. #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
  128. conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1;
  129. #endif
  130. ninfo("TCP state: TCP_FIN_WAIT_1\n");
  131. dev->d_sndlen = 0;
  132. tcp_send(dev, conn, TCP_FIN | TCP_ACK, hdrlen);
  133. }
  134. /* None of the above */
  135. else
  136. {
  137. #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
  138. DEBUGASSERT(dev->d_sndlen <= conn->mss);
  139. #else
  140. /* If d_sndlen > 0, the application has data to be sent. */
  141. if (dev->d_sndlen > 0)
  142. {
  143. /* Remember how much data we send out now so that we know
  144. * when everything has been acknowledged. Just increment the amount
  145. * of data sent. This will be needed in sequence number calculations
  146. * and we know that this is not a re-transmission. Retransmissions
  147. * do not go through this path.
  148. */
  149. conn->unacked += dev->d_sndlen;
  150. /* The application cannot send more than what is allowed by the
  151. * MSS (the minumum of the MSS and the available window).
  152. */
  153. DEBUGASSERT(dev->d_sndlen <= conn->mss);
  154. }
  155. conn->nrtx = 0;
  156. #endif
  157. /* Then handle the rest of the operation just as for the rexmit case */
  158. tcp_rexmit(dev, conn, result);
  159. }
  160. }
  161. /****************************************************************************
  162. * Name: tcp_rexmit
  163. *
  164. * Description:
  165. * Handle application retransmission
  166. *
  167. * Input Parameters:
  168. * dev - The device driver structure to use in the send operation
  169. * conn - The TCP connection structure holding connection information
  170. * result - App result event sent
  171. *
  172. * Returned Value:
  173. * None
  174. *
  175. * Assumptions:
  176. * The network is locked.
  177. *
  178. ****************************************************************************/
  179. void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
  180. uint16_t result)
  181. {
  182. uint8_t hdrlen;
  183. ninfo("result: %04x d_sndlen: %d conn->unacked: %d\n",
  184. result, dev->d_sndlen, conn->unacked);
  185. /* Get the IP header length associated with the IP domain configured for
  186. * this TCP connection.
  187. */
  188. #ifdef CONFIG_NET_IPv4
  189. #ifdef CONFIG_NET_IPv6
  190. if (conn->domain == PF_INET)
  191. #endif
  192. {
  193. DEBUGASSERT(IFF_IS_IPv4(dev->d_flags));
  194. hdrlen = IPv4TCP_HDRLEN;
  195. }
  196. #endif /* CONFIG_NET_IPv4 */
  197. #ifdef CONFIG_NET_IPv6
  198. #ifdef CONFIG_NET_IPv4
  199. else
  200. #endif
  201. {
  202. DEBUGASSERT(IFF_IS_IPv6(dev->d_flags));
  203. hdrlen = IPv6TCP_HDRLEN;
  204. }
  205. #endif /* CONFIG_NET_IPv6 */
  206. /* If the application has data to be sent, or if the incoming packet had
  207. * new data in it, we must send out a packet.
  208. */
  209. #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
  210. if (dev->d_sndlen > 0)
  211. #else
  212. if (dev->d_sndlen > 0 && conn->unacked > 0)
  213. #endif
  214. {
  215. /* We always set the ACK flag in response packets adding the length of
  216. * the IP and TCP headers.
  217. */
  218. tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen);
  219. }
  220. /* If there is no data to send, just send out a pure ACK if one is requested`. */
  221. else if ((result & TCP_SNDACK) != 0)
  222. {
  223. tcp_send(dev, conn, TCP_ACK, hdrlen);
  224. }
  225. /* There is nothing to do -- drop the packet */
  226. else
  227. {
  228. dev->d_len = 0;
  229. }
  230. }
  231. #endif /* CONFIG_NET && CONFIG_NET_TCP */