You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tcpip.c 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include <stdint.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <byteswap.h>
  6. #include <ipxe/iobuf.h>
  7. #include <ipxe/tables.h>
  8. #include <ipxe/ipstat.h>
  9. #include <ipxe/netdevice.h>
  10. #include <ipxe/tcpip.h>
  11. /** @file
  12. *
  13. * Transport-network layer interface
  14. *
  15. * This file contains functions and utilities for the
  16. * TCP/IP transport-network layer interface
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  19. /**
  20. * Process a received TCP/IP packet
  21. *
  22. * @v iobuf I/O buffer
  23. * @v netdev Network device
  24. * @v tcpip_proto Transport-layer protocol number
  25. * @v st_src Partially-filled source address
  26. * @v st_dest Partially-filled destination address
  27. * @v pshdr_csum Pseudo-header checksum
  28. * @v stats IP statistics
  29. * @ret rc Return status code
  30. *
  31. * This function expects a transport-layer segment from the network
  32. * layer. The network layer should fill in as much as it can of the
  33. * source and destination addresses (i.e. it should fill in the
  34. * address family and the network-layer addresses, but leave the ports
  35. * and the rest of the structures as zero).
  36. */
  37. int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev,
  38. uint8_t tcpip_proto, struct sockaddr_tcpip *st_src,
  39. struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum,
  40. struct ip_statistics *stats ) {
  41. struct tcpip_protocol *tcpip;
  42. /* Hand off packet to the appropriate transport-layer protocol */
  43. for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) {
  44. if ( tcpip->tcpip_proto == tcpip_proto ) {
  45. DBG ( "TCP/IP received %s packet\n", tcpip->name );
  46. stats->in_delivers++;
  47. return tcpip->rx ( iobuf, netdev, st_src, st_dest,
  48. pshdr_csum );
  49. }
  50. }
  51. DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
  52. stats->in_unknown_protos++;
  53. free_iob ( iobuf );
  54. return -EPROTONOSUPPORT;
  55. }
  56. /**
  57. * Find TCP/IP network-layer protocol
  58. *
  59. * @v sa_family Address family
  60. * @ret tcpip_net TCP/IP network-layer protocol, or NULL if not found
  61. */
  62. struct tcpip_net_protocol * tcpip_net_protocol ( sa_family_t sa_family ) {
  63. struct tcpip_net_protocol *tcpip_net;
  64. for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) {
  65. if ( tcpip_net->sa_family == sa_family )
  66. return tcpip_net;
  67. }
  68. DBG ( "Unrecognised TCP/IP address family %d\n", sa_family );
  69. return NULL;
  70. }
  71. /**
  72. * Transmit a TCP/IP packet
  73. *
  74. * @v iobuf I/O buffer
  75. * @v tcpip_protocol Transport-layer protocol
  76. * @v st_src Source address, or NULL to use route default
  77. * @v st_dest Destination address
  78. * @v netdev Network device to use if no route found, or NULL
  79. * @v trans_csum Transport-layer checksum to complete, or NULL
  80. * @ret rc Return status code
  81. */
  82. int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
  83. struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest,
  84. struct net_device *netdev, uint16_t *trans_csum ) {
  85. struct tcpip_net_protocol *tcpip_net;
  86. /* Hand off packet to the appropriate network-layer protocol */
  87. tcpip_net = tcpip_net_protocol ( st_dest->st_family );
  88. if ( tcpip_net ) {
  89. DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
  90. return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, st_dest,
  91. netdev, trans_csum );
  92. }
  93. free_iob ( iobuf );
  94. return -EAFNOSUPPORT;
  95. }
  96. /**
  97. * Determine transmitting network device
  98. *
  99. * @v st_dest Destination address
  100. * @ret netdev Network device, or NULL
  101. */
  102. struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ) {
  103. struct tcpip_net_protocol *tcpip_net;
  104. /* Hand off to the appropriate network-layer protocol */
  105. tcpip_net = tcpip_net_protocol ( st_dest->st_family );
  106. if ( tcpip_net )
  107. return tcpip_net->netdev ( st_dest );
  108. return NULL;
  109. }
  110. /**
  111. * Determine maximum transmission unit
  112. *
  113. * @v st_dest Destination address
  114. * @ret mtu Maximum transmission unit
  115. */
  116. size_t tcpip_mtu ( struct sockaddr_tcpip *st_dest ) {
  117. struct tcpip_net_protocol *tcpip_net;
  118. struct net_device *netdev;
  119. size_t mtu;
  120. /* Find appropriate network-layer protocol */
  121. tcpip_net = tcpip_net_protocol ( st_dest->st_family );
  122. if ( ! tcpip_net )
  123. return 0;
  124. /* Find transmitting network device */
  125. netdev = tcpip_net->netdev ( st_dest );
  126. if ( ! netdev )
  127. return 0;
  128. /* Calculate MTU */
  129. mtu = ( netdev->max_pkt_len - netdev->ll_protocol->ll_header_len -
  130. tcpip_net->header_len );
  131. return mtu;
  132. }
  133. /**
  134. * Calculate continued TCP/IP checkum
  135. *
  136. * @v partial Checksum of already-summed data, in network byte order
  137. * @v data Data buffer
  138. * @v len Length of data buffer
  139. * @ret cksum Updated checksum, in network byte order
  140. *
  141. * Calculates a TCP/IP-style 16-bit checksum over the data block. The
  142. * checksum is returned in network byte order.
  143. *
  144. * This function may be used to add new data to an existing checksum.
  145. * The function assumes that both the old data and the new data start
  146. * on even byte offsets; if this is not the case then you will need to
  147. * byte-swap either the input partial checksum, the output checksum,
  148. * or both. Deciding which to swap is left as an exercise for the
  149. * interested reader.
  150. */
  151. uint16_t generic_tcpip_continue_chksum ( uint16_t partial,
  152. const void *data, size_t len ) {
  153. unsigned int cksum = ( ( ~partial ) & 0xffff );
  154. unsigned int value;
  155. unsigned int i;
  156. for ( i = 0 ; i < len ; i++ ) {
  157. value = * ( ( uint8_t * ) data + i );
  158. if ( i & 1 ) {
  159. /* Odd bytes: swap on little-endian systems */
  160. value = be16_to_cpu ( value );
  161. } else {
  162. /* Even bytes: swap on big-endian systems */
  163. value = le16_to_cpu ( value );
  164. }
  165. cksum += value;
  166. if ( cksum > 0xffff )
  167. cksum -= 0xffff;
  168. }
  169. return ( ~cksum );
  170. }
  171. /**
  172. * Calculate TCP/IP checkum
  173. *
  174. * @v data Data buffer
  175. * @v len Length of data buffer
  176. * @ret cksum Checksum, in network byte order
  177. *
  178. * Calculates a TCP/IP-style 16-bit checksum over the data block. The
  179. * checksum is returned in network byte order.
  180. */
  181. uint16_t tcpip_chksum ( const void *data, size_t len ) {
  182. return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
  183. }
  184. /**
  185. * Bind to local TCP/IP port
  186. *
  187. * @v st_local Local TCP/IP socket address, or NULL
  188. * @v available Function to check port availability
  189. * @ret port Local port number, or negative error
  190. */
  191. int tcpip_bind ( struct sockaddr_tcpip *st_local,
  192. int ( * available ) ( int port ) ) {
  193. uint16_t flags = 0;
  194. uint16_t try_port = 0;
  195. uint16_t min_port;
  196. uint16_t max_port;
  197. unsigned int offset;
  198. unsigned int i;
  199. /* Extract parameters from local socket address */
  200. if ( st_local ) {
  201. flags = st_local->st_flags;
  202. try_port = ntohs ( st_local->st_port );
  203. }
  204. /* If an explicit port is specified, check its availability */
  205. if ( try_port )
  206. return available ( try_port );
  207. /* Otherwise, find an available port in the range [1,1023] or
  208. * [1025,65535] as appropriate.
  209. */
  210. min_port = ( ( ( ~flags ) & TCPIP_BIND_PRIVILEGED ) + 1 );
  211. max_port = ( ( flags & TCPIP_BIND_PRIVILEGED ) - 1 );
  212. offset = random();
  213. for ( i = 0 ; i <= max_port ; i++ ) {
  214. try_port = ( ( i + offset ) & max_port );
  215. if ( try_port < min_port )
  216. continue;
  217. if ( available ( try_port ) < 0 )
  218. continue;
  219. return try_port;
  220. }
  221. return -EADDRINUSE;
  222. }