ba007ebeff0894c3844ddb80a5d9bf5b3584f438
[people/dverkamp/gpxe.git] / src / interface / pxe / pxe_udp.c
1 /** @file
2  *
3  * PXE UDP API
4  *
5  */
6
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>
13
14 /*
15  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
16  *
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.
21  *
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.
26  *
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.
30  */
31
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;
42 };
43
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 );
47 }
48
49 /**
50  * Send PXE UDP data
51  *
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
56  *
57  * Sends the packet belonging to the current pxenv_udp_write()
58  * operation.
59  */
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;
65
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 );
73 }
74
75 /**
76  * Receive PXE UDP data
77  *
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
83  *
84  * Receives a packet as part of the current pxenv_udp_read()
85  * operation.
86  */
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;
95
96         if ( ! pxenv_udp_read ) {
97                 DBG ( "PXE discarded UDP packet\n" );
98                 return -ENOBUFS;
99         }
100
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;
108
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;
116
117         /* Mark as received */
118         pxe_udp->pxenv_udp_read = NULL;
119
120         return 0;
121 }
122
123 /** PXE UDP operations */
124 static struct udp_operations pxe_udp_operations = {
125         .senddata = pxe_udp_senddata,
126         .newdata = pxe_udp_newdata,
127 };
128
129 /** The PXE UDP connection */
130 static struct pxe_udp_connection pxe_udp = {
131         .udp.udp_op = &pxe_udp_operations,
132 };
133
134 /**
135  * UDP OPEN
136  *
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
143  *
144  * Prepares the PXE stack for communication using pxenv_udp_write()
145  * and pxenv_udp_read().
146  *
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.)
153  *
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.
161  *
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.)
166  *
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.
171  *
172  * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
173  * parameter.
174  *
175  */
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 };
178
179         DBG ( "PXENV_UDP_OPEN" );
180
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;
185         }
186
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 ) );
191         }
192
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;
197         }
198         pxe_udp.open = 1;
199
200         pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
201         return PXENV_EXIT_SUCCESS;
202 }
203
204 /**
205  * UDP CLOSE
206  *
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                            -
211  *
212  * Closes a UDP connection opened with pxenv_udp_open().
213  *
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.
218  *
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.)
223  *
224  */
225 PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
226         DBG ( "PXENV_UDP_CLOSE" );
227
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 */
232         }
233
234         /* Close UDP connection */
235         udp_close ( &pxe_udp.udp );
236         pxe_udp.open = 0;
237
238         pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
239         return PXENV_EXIT_SUCCESS;
240 }
241
242 /**
243  * UDP WRITE
244  *
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
257  *
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.
264  *
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.
268  *
269  * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
270  *
271  * You must have opened a UDP connection with pxenv_udp_open() before
272  * calling pxenv_udp_write().
273  *
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.)
278  *
279  * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
280  * parameter.
281  *
282  */
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;
289
290         DBG ( "PXENV_UDP_WRITE" );
291
292         /* Check connection is open */
293         if ( ! pxe_udp.open ) {
294                 pxenv_udp_write->Status = PXENV_STATUS_UDP_CLOSED;
295                 return PXENV_EXIT_FAILURE;
296         }
297
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 );
304
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.
308          */
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 );
312
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.
316          */
317
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 ) );
323         
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;
331         }
332
333         pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
334         return PXENV_EXIT_SUCCESS;
335 }
336
337 /**
338  * UDP READ
339  *
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
355  *
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.
359  *
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.
362  *
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.
365  *
366  * You must have opened a UDP connection with pxenv_udp_open() before
367  * calling pxenv_udp_read().
368  *
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.)
373  *
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.
378  *
379  */
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;
383
384         DBG ( "PXENV_UDP_READ" );
385
386         /* Check connection is open */
387         if ( ! pxe_udp.open ) {
388                 pxenv_udp_read->Status = PXENV_STATUS_UDP_CLOSED;
389                 return PXENV_EXIT_FAILURE;
390         }
391
392         /* Bind promiscuously; we will do our own filtering */
393         udp_bind_promisc ( &pxe_udp.udp );
394
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;
402         }
403
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;
409
410         DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
411               pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
412               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
413         DBG ( "%d<-%s:%d",  ntohs ( pxenv_udp_read->s_port ),
414               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
415               ntohs ( pxenv_udp_read->d_port ) );
416
417         pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
418         return PXENV_EXIT_SUCCESS;
419
420  no_packet:
421         pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
422         return PXENV_EXIT_FAILURE;
423 }