Add a couple of small but vital parts to PXENV_UDP_WRITE.
[gpxe.git] / src / interface / pxe / pxe_udp.c
blob5f94e8c018f3f76f01e8ecc86f6273e2b5a0bedf
1 /** @file
3 * PXE UDP API
5 */
7 #include <string.h>
8 #include <byteswap.h>
9 #include <gpxe/udp.h>
10 #include <gpxe/uaccess.h>
11 #include <gpxe/process.h>
12 #include <pxe.h>
15 * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of the
20 * License, or any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 /** A PXE UDP connection */
33 struct pxe_udp_connection {
34 /** Etherboot UDP connection */
35 struct udp_connection udp;
36 /** "Connection is open" flag */
37 int open;
38 /** Current pxenv_udp_read() operation, if any */
39 struct s_PXENV_UDP_READ *pxenv_udp_read;
40 /** Current pxenv_udp_write() operation, if any */
41 struct s_PXENV_UDP_WRITE *pxenv_udp_write;
44 static inline struct pxe_udp_connection *
45 udp_to_pxe ( struct udp_connection *conn ) {
46 return container_of ( conn, struct pxe_udp_connection, udp );
49 /**
50 * Send PXE UDP data
52 * @v conn UDP connection
53 * @v data Temporary data buffer
54 * @v len Size of temporary data buffer
55 * @ret rc Return status code
57 * Sends the packet belonging to the current pxenv_udp_write()
58 * operation.
60 static int pxe_udp_senddata ( struct udp_connection *conn, void *data,
61 size_t len ) {
62 struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
63 struct s_PXENV_UDP_WRITE *pxenv_udp_write = pxe_udp->pxenv_udp_write;
64 userptr_t buffer;
66 /* Transmit packet */
67 buffer = real_to_user ( pxenv_udp_write->buffer.segment,
68 pxenv_udp_write->buffer.offset );
69 if ( len > pxenv_udp_write->buffer_size )
70 len = pxenv_udp_write->buffer_size;
71 copy_from_user ( data, buffer, 0, len );
72 return udp_send ( conn, data, len );
75 /**
76 * Receive PXE UDP data
78 * @v conn UDP connection
79 * @v data Received data
80 * @v len Length of received data
81 * @v st_src Source address
82 * @v st_dest Destination address
84 * Receives a packet as part of the current pxenv_udp_read()
85 * operation.
87 static int pxe_udp_newdata ( struct udp_connection *conn, void *data,
88 size_t len, struct sockaddr_tcpip *st_src,
89 struct sockaddr_tcpip *st_dest ) {
90 struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
91 struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
92 struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
93 struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
94 userptr_t buffer;
96 if ( ! pxenv_udp_read ) {
97 DBG ( "PXE discarded UDP packet\n" );
98 return -ENOBUFS;
101 /* Copy packet to buffer and record length */
102 buffer = real_to_user ( pxenv_udp_read->buffer.segment,
103 pxenv_udp_read->buffer.offset );
104 if ( len > pxenv_udp_read->buffer_size )
105 len = pxenv_udp_read->buffer_size;
106 copy_to_user ( buffer, 0, data, len );
107 pxenv_udp_read->buffer_size = len;
109 /* Fill in source/dest information */
110 assert ( sin_src->sin_family == AF_INET );
111 pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
112 pxenv_udp_read->s_port = sin_src->sin_port;
113 assert ( sin_dest->sin_family == AF_INET );
114 pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
115 pxenv_udp_read->d_port = sin_dest->sin_port;
117 /* Mark as received */
118 pxe_udp->pxenv_udp_read = NULL;
120 return 0;
123 /** PXE UDP operations */
124 static struct udp_operations pxe_udp_operations = {
125 .senddata = pxe_udp_senddata,
126 .newdata = pxe_udp_newdata,
129 /** The PXE UDP connection */
130 static struct pxe_udp_connection pxe_udp = {
131 .udp.udp_op = &pxe_udp_operations,
135 * UDP OPEN
137 * @v pxenv_udp_open Pointer to a struct s_PXENV_UDP_OPEN
138 * @v s_PXENV_UDP_OPEN::src_ip IP address of this station, or 0.0.0.0
139 * @ret #PXENV_EXIT_SUCCESS Always
140 * @ret s_PXENV_UDP_OPEN::Status PXE status code
141 * @err #PXENV_STATUS_UDP_OPEN UDP connection already open
142 * @err #PXENV_STATUS_OUT_OF_RESOURCES Could not open connection
144 * Prepares the PXE stack for communication using pxenv_udp_write()
145 * and pxenv_udp_read().
147 * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
148 * recorded and used as the local station's IP address for all further
149 * communication, including communication by means other than
150 * pxenv_udp_write() and pxenv_udp_read(). (If
151 * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
152 * will remain unchanged.)
154 * You can only have one open UDP connection at a time. This is not a
155 * meaningful restriction, since pxenv_udp_write() and
156 * pxenv_udp_read() allow you to specify arbitrary local and remote
157 * ports and an arbitrary remote address for each packet. According
158 * to the PXE specifiation, you cannot have a UDP connection open at
159 * the same time as a TFTP connection; this restriction does not apply
160 * to Etherboot.
162 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
163 * value before calling this function in protected mode. You cannot
164 * call this function with a 32-bit stack segment. (See the relevant
165 * @ref pxe_x86_pmode16 "implementation note" for more details.)
167 * @note The PXE specification does not make it clear whether the IP
168 * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
169 * for this UDP connection, or retained for all future communication.
170 * The latter seems more consistent with typical PXE stack behaviour.
172 * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
173 * parameter.
176 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
177 struct in_addr new_ip = { .s_addr = pxenv_udp_open->src_ip };
179 DBG ( "PXENV_UDP_OPEN" );
181 /* Check connection is not already open */
182 if ( pxe_udp.open ) {
183 pxenv_udp_open->Status = PXENV_STATUS_UDP_OPEN;
184 return PXENV_EXIT_FAILURE;
187 /* Set IP address if specified */
188 if ( new_ip.s_addr ) {
189 /* FIXME: actually do something here */
190 DBG ( " with new IP address %s", inet_ntoa ( new_ip ) );
193 /* Open UDP connection */
194 if ( udp_open ( &pxe_udp.udp, 0 ) != 0 ) {
195 pxenv_udp_open->Status = PXENV_STATUS_OUT_OF_RESOURCES;
196 return PXENV_EXIT_FAILURE;
198 pxe_udp.open = 1;
200 pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
201 return PXENV_EXIT_SUCCESS;
205 * UDP CLOSE
207 * @v pxenv_udp_close Pointer to a struct s_PXENV_UDP_CLOSE
208 * @ret #PXENV_EXIT_SUCCESS Always
209 * @ret s_PXENV_UDP_CLOSE::Status PXE status code
210 * @err None -
212 * Closes a UDP connection opened with pxenv_udp_open().
214 * You can only have one open UDP connection at a time. You cannot
215 * have a UDP connection open at the same time as a TFTP connection.
216 * You cannot use pxenv_udp_close() to close a TFTP connection; use
217 * pxenv_tftp_close() instead.
219 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
220 * value before calling this function in protected mode. You cannot
221 * call this function with a 32-bit stack segment. (See the relevant
222 * @ref pxe_x86_pmode16 "implementation note" for more details.)
225 PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
226 DBG ( "PXENV_UDP_CLOSE" );
228 /* Check connection is open */
229 if ( ! pxe_udp.open ) {
230 pxenv_udp_close->Status = PXENV_STATUS_UDP_CLOSED;
231 return PXENV_EXIT_SUCCESS; /* Well, it *is* closed */
234 /* Close UDP connection */
235 udp_close ( &pxe_udp.udp );
236 pxe_udp.open = 0;
238 pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
239 return PXENV_EXIT_SUCCESS;
243 * UDP WRITE
245 * @v pxenv_udp_write Pointer to a struct s_PXENV_UDP_WRITE
246 * @v s_PXENV_UDP_WRITE::ip Destination IP address
247 * @v s_PXENV_UDP_WRITE::gw Relay agent IP address, or 0.0.0.0
248 * @v s_PXENV_UDP_WRITE::src_port Source UDP port, or 0
249 * @v s_PXENV_UDP_WRITE::dst_port Destination UDP port
250 * @v s_PXENV_UDP_WRITE::buffer_size Length of the UDP payload
251 * @v s_PXENV_UDP_WRITE::buffer Address of the UDP payload
252 * @ret #PXENV_EXIT_SUCCESS Packet was transmitted successfully
253 * @ret #PXENV_EXIT_FAILURE Packet could not be transmitted
254 * @ret s_PXENV_UDP_WRITE::Status PXE status code
255 * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open
256 * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
258 * Transmits a single UDP packet. A valid IP and UDP header will be
259 * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
260 * should not contain precomputed IP and UDP headers, nor should it
261 * contain space allocated for these headers. The first byte of the
262 * buffer will be transmitted as the first byte following the UDP
263 * header.
265 * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
266 * place. See the relevant @ref pxe_routing "implementation note" for
267 * more details.
269 * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
271 * You must have opened a UDP connection with pxenv_udp_open() before
272 * calling pxenv_udp_write().
274 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
275 * value before calling this function in protected mode. You cannot
276 * call this function with a 32-bit stack segment. (See the relevant
277 * @ref pxe_x86_pmode16 "implementation note" for more details.)
279 * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
280 * parameter.
283 PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
284 union {
285 struct sockaddr_in sin;
286 struct sockaddr_tcpip st;
287 } dest;
288 int rc;
290 DBG ( "PXENV_UDP_WRITE" );
292 /* Check connection is open */
293 if ( ! pxe_udp.open ) {
294 pxenv_udp_write->Status = PXENV_STATUS_UDP_CLOSED;
295 return PXENV_EXIT_FAILURE;
298 /* Construct destination socket address */
299 memset ( &dest, 0, sizeof ( dest ) );
300 dest.sin.sin_family = AF_INET;
301 dest.sin.sin_addr.s_addr = pxenv_udp_write->ip;
302 dest.sin.sin_port = pxenv_udp_write->dst_port;
303 udp_connect ( &pxe_udp.udp, &dest.st );
305 /* Set local (source) port. PXE spec says source port is 2069
306 * if not specified. Really, this ought to be set at UDP open
307 * time but hey, we didn't design this API.
309 if ( ! pxenv_udp_write->src_port )
310 pxenv_udp_write->src_port = htons ( 2069 );
311 udp_bind ( &pxe_udp.udp, pxenv_udp_write->src_port );
313 /* FIXME: we ignore the gateway specified, since we're
314 * confident of being able to do our own routing. We should
315 * probably allow for multiple gateways.
318 DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
319 pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
320 ntohs ( pxenv_udp_write->src_port ),
321 inet_ntoa ( dest.sin.sin_addr ),
322 ntohs ( pxenv_udp_write->dst_port ) );
324 /* Transmit packet */
325 pxe_udp.pxenv_udp_write = pxenv_udp_write;
326 rc = udp_senddata ( &pxe_udp.udp );
327 pxe_udp.pxenv_udp_write = NULL;
328 if ( rc != 0 ) {
329 pxenv_udp_write->Status = PXENV_STATUS_UNDI_TRANSMIT_ERROR;
330 return PXENV_EXIT_FAILURE;
333 pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
334 return PXENV_EXIT_SUCCESS;
338 * UDP READ
340 * @v pxenv_udp_read Pointer to a struct s_PXENV_UDP_READ
341 * @v s_PXENV_UDP_READ::dest_ip Destination IP address, or 0.0.0.0
342 * @v s_PXENV_UDP_READ::d_port Destination UDP port, or 0
343 * @v s_PXENV_UDP_READ::buffer_size Size of the UDP payload buffer
344 * @v s_PXENV_UDP_READ::buffer Address of the UDP payload buffer
345 * @ret #PXENV_EXIT_SUCCESS A packet has been received
346 * @ret #PXENV_EXIT_FAILURE No packet has been received
347 * @ret s_PXENV_UDP_READ::Status PXE status code
348 * @ret s_PXENV_UDP_READ::src_ip Source IP address
349 * @ret s_PXENV_UDP_READ::dest_ip Destination IP address
350 * @ret s_PXENV_UDP_READ::s_port Source UDP port
351 * @ret s_PXENV_UDP_READ::d_port Destination UDP port
352 * @ret s_PXENV_UDP_READ::buffer_size Length of UDP payload
353 * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open
354 * @err #PXENV_STATUS_FAILURE No packet was ready to read
356 * Receive a single UDP packet. This is a non-blocking call; if no
357 * packet is ready to read, the call will return instantly with
358 * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
360 * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
361 * any IP address will be accepted and may be returned to the caller.
363 * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
364 * port will be accepted and may be returned to the caller.
366 * You must have opened a UDP connection with pxenv_udp_open() before
367 * calling pxenv_udp_read().
369 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
370 * value before calling this function in protected mode. You cannot
371 * call this function with a 32-bit stack segment. (See the relevant
372 * @ref pxe_x86_pmode16 "implementation note" for more details.)
374 * @note The PXE specification (version 2.1) does not state that we
375 * should fill in s_PXENV_UDP_READ::dest_ip and
376 * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
377 * expects us to do so, and will fail if we don't.
380 PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
381 struct in_addr dest_ip = { .s_addr = pxenv_udp_read->dest_ip };
382 uint16_t d_port = pxenv_udp_read->d_port;
384 DBG ( "PXENV_UDP_READ" );
386 /* Check connection is open */
387 if ( ! pxe_udp.open ) {
388 pxenv_udp_read->Status = PXENV_STATUS_UDP_CLOSED;
389 return PXENV_EXIT_FAILURE;
392 /* Bind promiscuously; we will do our own filtering */
393 udp_bind_promisc ( &pxe_udp.udp );
395 /* Try receiving a packet */
396 pxe_udp.pxenv_udp_read = pxenv_udp_read;
397 step();
398 if ( pxe_udp.pxenv_udp_read ) {
399 /* No packet received */
400 pxe_udp.pxenv_udp_read = NULL;
401 goto no_packet;
404 /* Filter on destination address and/or port */
405 if ( dest_ip.s_addr && ( dest_ip.s_addr != pxenv_udp_read->dest_ip ) )
406 goto no_packet;
407 if ( d_port && ( d_port != pxenv_udp_read->d_port ) )
408 goto no_packet;
410 pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
411 return PXENV_EXIT_SUCCESS;
413 no_packet:
414 pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
415 return PXENV_EXIT_FAILURE;