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.

pxe_udp.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /** @file
  2. *
  3. * PXE UDP API
  4. *
  5. */
  6. #include "pxe.h"
  7. #include "io.h"
  8. #include "string.h"
  9. /*
  10. * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License as
  14. * published by the Free Software Foundation; either version 2 of the
  15. * License, or any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25. */
  26. /**
  27. * UDP OPEN
  28. *
  29. * @v udp_open Pointer to a struct s_PXENV_UDP_OPEN
  30. * @v s_PXENV_UDP_OPEN::src_ip IP address of this station, or 0.0.0.0
  31. * @ret #PXENV_EXIT_SUCCESS Always
  32. * @ret s_PXENV_UDP_OPEN::Status PXE status code
  33. * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
  34. *
  35. * Prepares the PXE stack for communication using pxenv_udp_write()
  36. * and pxenv_udp_read().
  37. *
  38. * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
  39. * recorded and used as the local station's IP address for all further
  40. * communication, including communication by means other than
  41. * pxenv_udp_write() and pxenv_udp_read(). (If
  42. * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
  43. * will remain unchanged.)
  44. *
  45. * You can only have one open UDP connection at a time. You cannot
  46. * have a UDP connection open at the same time as a TFTP connection.
  47. * (This is not strictly true for Etherboot; see the relevant @ref
  48. * pxe_note_udp "implementation note" for more details.)
  49. *
  50. * On x86, you must set the s_PXE::StatusCallout field to a nonzero
  51. * value before calling this function in protected mode. You cannot
  52. * call this function with a 32-bit stack segment. (See the relevant
  53. * @ref pxe_x86_pmode16 "implementation note" for more details.)
  54. *
  55. * @note The PXE specification does not make it clear whether the IP
  56. * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
  57. * for this UDP connection, or retained for all future communication.
  58. * The latter seems more consistent with typical PXE stack behaviour.
  59. *
  60. */
  61. PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
  62. DBG ( "PXENV_UDP_OPEN" );
  63. ENSURE_READY ( udp_open );
  64. if ( udp_open->src_ip &&
  65. udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
  66. /* Overwrite our IP address */
  67. DBG ( " with new IP %@", udp_open->src_ip );
  68. arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
  69. }
  70. udp_open->Status = PXENV_STATUS_SUCCESS;
  71. return PXENV_EXIT_SUCCESS;
  72. }
  73. /**
  74. * UDP CLOSE
  75. *
  76. * @v udp_close Pointer to a struct s_PXENV_UDP_CLOSE
  77. * @ret #PXENV_EXIT_SUCCESS Always
  78. * @ret s_PXENV_UDP_CLOSE::Status PXE status code
  79. * @err None -
  80. *
  81. * Closes a UDP "connection" opened with pxenv_udp_open().
  82. *
  83. * You can only have one open UDP connection at a time. You cannot
  84. * have a UDP connection open at the same time as a TFTP connection.
  85. * You cannot use pxenv_udp_close() to close a TFTP connection; use
  86. * pxenv_tftp_close() instead. (This is not strictly true for
  87. * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
  88. * for more details.)
  89. *
  90. * On x86, you must set the s_PXE::StatusCallout field to a nonzero
  91. * value before calling this function in protected mode. You cannot
  92. * call this function with a 32-bit stack segment. (See the relevant
  93. * @ref pxe_x86_pmode16 "implementation note" for more details.)
  94. *
  95. */
  96. PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
  97. DBG ( "PXENV_UDP_CLOSE" );
  98. udp_close->Status = PXENV_STATUS_SUCCESS;
  99. return PXENV_EXIT_SUCCESS;
  100. }
  101. /**
  102. * UDP WRITE
  103. *
  104. * @v udp_write Pointer to a struct s_PXENV_UDP_WRITE
  105. * @v s_PXENV_UDP_WRITE::ip Destination IP address
  106. * @v s_PXENV_UDP_WRITE::gw Relay agent IP address, or 0.0.0.0
  107. * @v s_PXENV_UDP_WRITE::src_port Source UDP port, or 0
  108. * @v s_PXENV_UDP_WRITE::dst_port Destination UDP port
  109. * @v s_PXENV_UDP_WRITE::buffer_size Length of the UDP payload
  110. * @v s_PXENV_UDP_WRITE::buffer Address of the UDP payload
  111. * @ret #PXENV_EXIT_SUCCESS Packet was transmitted successfully
  112. * @ret #PXENV_EXIT_FAILURE Packet could not be transmitted
  113. * @ret s_PXENV_UDP_WRITE::Status PXE status code
  114. * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
  115. * @err #PXENV_STATUS_OUT_OF_RESOURCES Packet was too large to transmit
  116. * @err other Any error from pxenv_undi_transmit()
  117. *
  118. * Transmits a single UDP packet. A valid IP and UDP header will be
  119. * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
  120. * should not contain precomputed IP and UDP headers, nor should it
  121. * contain space allocated for these headers. The first byte of the
  122. * buffer will be transmitted as the first byte following the UDP
  123. * header.
  124. *
  125. * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
  126. * place. See the relevant @ref pxe_routing "implementation note" for
  127. * more details.
  128. *
  129. * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
  130. *
  131. * You must have opened a UDP connection with pxenv_udp_open() before
  132. * calling pxenv_udp_write(). (This is not strictly true for
  133. * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
  134. * for more details.)
  135. *
  136. * On x86, you must set the s_PXE::StatusCallout field to a nonzero
  137. * value before calling this function in protected mode. You cannot
  138. * call this function with a 32-bit stack segment. (See the relevant
  139. * @ref pxe_x86_pmode16 "implementation note" for more details.)
  140. *
  141. */
  142. PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write ) {
  143. uint16_t src_port;
  144. uint16_t dst_port;
  145. struct udppacket *packet = (struct udppacket *)nic.packet;
  146. int packet_size;
  147. DBG ( "PXENV_UDP_WRITE" );
  148. ENSURE_READY ( udp_write );
  149. /* PXE spec says source port is 2069 if not specified */
  150. src_port = ntohs(udp_write->src_port);
  151. if ( src_port == 0 ) src_port = 2069;
  152. dst_port = ntohs(udp_write->dst_port);
  153. DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
  154. udp_write->buffer_size );
  155. /* FIXME: we ignore the gateway specified, since we're
  156. * confident of being able to do our own routing. We should
  157. * probably allow for multiple gateways.
  158. */
  159. /* Copy payload to packet buffer */
  160. packet_size = ( (void*)&packet->payload - (void*)packet )
  161. + udp_write->buffer_size;
  162. if ( packet_size > ETH_FRAME_LEN ) {
  163. udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  164. return PXENV_EXIT_FAILURE;
  165. }
  166. memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
  167. udp_write->buffer_size );
  168. /* Transmit packet */
  169. if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
  170. packet_size, packet ) ) {
  171. udp_write->Status = errno;
  172. return PXENV_EXIT_FAILURE;
  173. }
  174. udp_write->Status = PXENV_STATUS_SUCCESS;
  175. return PXENV_EXIT_SUCCESS;
  176. }
  177. /* Utility function for pxenv_udp_read() */
  178. static int await_pxe_udp ( int ival __unused, void *ptr,
  179. unsigned short ptype __unused,
  180. struct iphdr *ip, struct udphdr *udp,
  181. struct tcphdr *tcp __unused ) {
  182. struct s_PXENV_UDP_READ *udp_read = (struct s_PXENV_UDP_READ*)ptr;
  183. uint16_t d_port;
  184. size_t size;
  185. /* Ignore non-UDP packets */
  186. if ( !udp ) {
  187. DBG ( " non-UDP" );
  188. return 0;
  189. }
  190. /* Check dest_ip */
  191. if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
  192. DBG ( " wrong dest IP (got %@, wanted %@)",
  193. ip->dest.s_addr, udp_read->dest_ip );
  194. return 0;
  195. }
  196. /* Check dest_port */
  197. d_port = ntohs ( udp_read->d_port );
  198. if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
  199. DBG ( " wrong dest port (got %d, wanted %d)",
  200. ntohs(udp->dest), d_port );
  201. return 0;
  202. }
  203. /* Copy packet to buffer and fill in information */
  204. udp_read->src_ip = ip->src.s_addr;
  205. udp_read->s_port = udp->src; /* Both in network order */
  206. size = ntohs(udp->len) - sizeof(*udp);
  207. /* Workaround: NTLDR expects us to fill these in, even though
  208. * PXESPEC clearly defines them as input parameters.
  209. */
  210. udp_read->dest_ip = ip->dest.s_addr;
  211. udp_read->d_port = udp->dest;
  212. DBG ( " %@:%d->%@:%d (%d)",
  213. udp_read->src_ip, ntohs(udp_read->s_port),
  214. udp_read->dest_ip, ntohs(udp_read->d_port), size );
  215. if ( udp_read->buffer_size < size ) {
  216. /* PXESPEC: what error code should we actually return? */
  217. DBG ( " buffer too small (%d)", udp_read->buffer_size );
  218. udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  219. return 0;
  220. }
  221. memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
  222. udp_read->buffer_size = size;
  223. return 1;
  224. }
  225. /**
  226. * UDP READ
  227. *
  228. * @v udp_read Pointer to a struct s_PXENV_UDP_READ
  229. * @v s_PXENV_UDP_READ::dest_ip Destination IP address, or 0.0.0.0
  230. * @v s_PXENV_UDP_READ::d_port Destination UDP port, or 0
  231. * @v s_PXENV_UDP_READ::buffer_size Size of the UDP payload buffer
  232. * @v s_PXENV_UDP_READ::buffer Address of the UDP payload buffer
  233. * @ret #PXENV_EXIT_SUCCESS A packet has been received
  234. * @ret #PXENV_EXIT_FAILURE No packet has been received
  235. * @ret s_PXENV_UDP_READ::Status PXE status code
  236. * @ret s_PXENV_UDP_READ::src_ip Source IP address
  237. * @ret s_PXENV_UDP_READ::dest_ip Destination IP address
  238. * @ret s_PXENV_UDP_READ::s_port Source UDP port
  239. * @ret s_PXENV_UDP_READ::d_port Destination UDP port
  240. * @ret s_PXENV_UDP_READ::buffer_size Length of UDP payload
  241. * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
  242. * @err #PXENV_STATUS_OUT_OF_RESOURCES Buffer was too small for payload
  243. * @err #PXENV_STATUS_FAILURE No packet was ready to read
  244. *
  245. * Receive a single UDP packet. This is a non-blocking call; if no
  246. * packet is ready to read, the call will return instantly with
  247. * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
  248. *
  249. * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
  250. * any IP address will be accepted and may be returned to the caller.
  251. *
  252. * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
  253. * port will be accepted and may be returned to the caller.
  254. *
  255. * You must have opened a UDP connection with pxenv_udp_open() before
  256. * calling pxenv_udp_read(). (This is not strictly true for
  257. * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
  258. * for more details.)
  259. *
  260. * On x86, you must set the s_PXE::StatusCallout field to a nonzero
  261. * value before calling this function in protected mode. You cannot
  262. * call this function with a 32-bit stack segment. (See the relevant
  263. * @ref pxe_x86_pmode16 "implementation note" for more details.)
  264. *
  265. * @note The PXE specification (version 2.1) does not state that we
  266. * should fill in s_PXENV_UDP_READ::dest_ip and
  267. * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
  268. * expects us to do so, and will fail if we don't.
  269. *
  270. */
  271. PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ) {
  272. DBG ( "PXENV_UDP_READ" );
  273. ENSURE_READY ( udp_read );
  274. /* Use await_reply with a timeout of zero */
  275. /* Allow await_reply to change Status if necessary */
  276. udp_read->Status = PXENV_STATUS_FAILURE;
  277. if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
  278. return PXENV_EXIT_FAILURE;
  279. }
  280. udp_read->Status = PXENV_STATUS_SUCCESS;
  281. return PXENV_EXIT_SUCCESS;
  282. }
  283. /** @page pxe_notes Etherboot PXE implementation notes
  284. @section pxe_note_udp The connectionless nature of UDP
  285. The PXE specification states that it is possible to have only one open
  286. UDP or TFTP connection at any one time. Etherboot does not
  287. rigourously enforce this restriction, on the UNIX principle that the
  288. code should not prevent the user from doing stupid things, because
  289. that would also prevent the user from doing clever things. Since UDP
  290. is a connectionless protocol, it is perfectly possible to have
  291. multiple concurrent UDP "connections" open, provided that you take the
  292. multiplicity of connections into account when calling
  293. pxenv_udp_read(). Similarly, there is no technical reason that
  294. prevents you from calling pxenv_udp_write() in the middle of a TFTP
  295. download.
  296. Etherboot will therefore never return error codes indicating "a
  297. connection is already open", such as #PXENV_STATUS_UDP_OPEN. If you
  298. want to have multiple concurrent connections, go for it (but don't
  299. expect your perfectly sensible code to work with any other PXE stack).
  300. Since Etherboot treats UDP as the connectionless protocol that it
  301. really is, pxenv_udp_close() is actually a no-op, and there is no need
  302. to call pxenv_udp_open() before using pxenv_udp_write() or
  303. pxenv_udp_read().
  304. */