34a24883153df58b054f0f77767a2d23899bc2e1
[people/andreif/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  *
56  * Sends the packet belonging to the current pxenv_udp_write()
57  * operation.
58  */
59 static void pxe_udp_senddata ( struct udp_connection *conn, void *data,
60                                size_t len ) {
61         struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
62         struct s_PXENV_UDP_WRITE *pxenv_udp_write = pxe_udp->pxenv_udp_write;
63         userptr_t buffer;
64
65         /* Transmit packet */
66         buffer = real_to_user ( pxenv_udp_write->buffer.segment,
67                                 pxenv_udp_write->buffer.offset );
68         if ( len > pxenv_udp_write->buffer_size )
69                 len = pxenv_udp_write->buffer_size;
70         copy_from_user ( data, buffer, 0, len );
71         udp_send ( conn, data, len );
72 }
73
74 /**
75  * Receive PXE UDP data
76  *
77  * @v conn                      UDP connection
78  * @v data                      Received data
79  * @v len                       Length of received data
80  * @v st_src                    Source address
81  * @v st_dest                   Destination address
82  *
83  * Receives a packet as part of the current pxenv_udp_read()
84  * operation.
85  */
86 static int pxe_udp_newdata ( struct udp_connection *conn, void *data,
87                              size_t len, struct sockaddr_tcpip *st_src,
88                              struct sockaddr_tcpip *st_dest ) {
89         struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
90         struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
91         struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
92         struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
93         userptr_t buffer;
94
95         if ( ! pxenv_udp_read ) {
96                 DBG ( "PXE discarded UDP packet\n" );
97                 return -ENOBUFS;
98         }
99
100         /* Copy packet to buffer and record length */
101         buffer = real_to_user ( pxenv_udp_read->buffer.segment,
102                                 pxenv_udp_read->buffer.offset );
103         if ( len > pxenv_udp_read->buffer_size )
104                 len = pxenv_udp_read->buffer_size;
105         copy_to_user ( buffer, 0, data, len );
106         pxenv_udp_read->buffer_size = len;
107
108         /* Fill in source/dest information */
109         assert ( sin_src->sin_family == AF_INET );
110         pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
111         pxenv_udp_read->s_port = sin_src->sin_port;
112         assert ( sin_dest->sin_family == AF_INET );
113         pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
114         pxenv_udp_read->d_port = sin_dest->sin_port;
115
116         /* Mark as received */
117         pxe_udp->pxenv_udp_read = NULL;
118
119         return 0;
120 }
121
122 /** PXE UDP operations */
123 static struct udp_operations pxe_udp_operations = {
124         .senddata = pxe_udp_senddata,
125         .newdata = pxe_udp_newdata,
126 };
127
128 /** The PXE UDP connection */
129 static struct pxe_udp_connection pxe_udp = {
130         .udp.udp_op = &pxe_udp_operations,
131 };
132
133 /**
134  * UDP OPEN
135  *
136  * @v pxenv_udp_open                    Pointer to a struct s_PXENV_UDP_OPEN
137  * @v s_PXENV_UDP_OPEN::src_ip          IP address of this station, or 0.0.0.0
138  * @ret #PXENV_EXIT_SUCCESS             Always
139  * @ret s_PXENV_UDP_OPEN::Status        PXE status code
140  * @err #PXENV_STATUS_UDP_OPEN          UDP connection already open
141  * @err #PXENV_STATUS_OUT_OF_RESOURCES  Could not open connection
142  *
143  * Prepares the PXE stack for communication using pxenv_udp_write()
144  * and pxenv_udp_read().
145  *
146  * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
147  * recorded and used as the local station's IP address for all further
148  * communication, including communication by means other than
149  * pxenv_udp_write() and pxenv_udp_read().  (If
150  * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
151  * will remain unchanged.)
152  *
153  * You can only have one open UDP connection at a time.  This is not a
154  * meaningful restriction, since pxenv_udp_write() and
155  * pxenv_udp_read() allow you to specify arbitrary local and remote
156  * ports and an arbitrary remote address for each packet.  According
157  * to the PXE specifiation, you cannot have a UDP connection open at
158  * the same time as a TFTP connection; this restriction does not apply
159  * to Etherboot.
160  *
161  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
162  * value before calling this function in protected mode.  You cannot
163  * call this function with a 32-bit stack segment.  (See the relevant
164  * @ref pxe_x86_pmode16 "implementation note" for more details.)
165  *
166  * @note The PXE specification does not make it clear whether the IP
167  * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
168  * for this UDP connection, or retained for all future communication.
169  * The latter seems more consistent with typical PXE stack behaviour.
170  *
171  * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
172  * parameter.
173  *
174  */
175 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
176         struct in_addr new_ip = { .s_addr = pxenv_udp_open->src_ip };
177
178         DBG ( "PXENV_UDP_OPEN" );
179
180         /* Check connection is not already open */
181         if ( pxe_udp.open ) {
182                 pxenv_udp_open->Status = PXENV_STATUS_UDP_OPEN;
183                 return PXENV_EXIT_FAILURE;
184         }
185
186         /* Set IP address if specified */
187         if ( new_ip.s_addr ) {
188                 /* FIXME: actually do something here */
189                 DBG ( " with new IP address %s", inet_ntoa ( new_ip ) );
190         }
191
192         /* Open UDP connection */
193         if ( udp_open ( &pxe_udp.udp, 0 ) != 0 ) {
194                 pxenv_udp_open->Status = PXENV_STATUS_OUT_OF_RESOURCES;
195                 return PXENV_EXIT_FAILURE;
196         }
197         pxe_udp.open = 1;
198
199         pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
200         return PXENV_EXIT_SUCCESS;
201 }
202
203 /**
204  * UDP CLOSE
205  *
206  * @v pxenv_udp_close                   Pointer to a struct s_PXENV_UDP_CLOSE
207  * @ret #PXENV_EXIT_SUCCESS             Always
208  * @ret s_PXENV_UDP_CLOSE::Status       PXE status code
209  * @err None                            -
210  *
211  * Closes a UDP connection opened with pxenv_udp_open().
212  *
213  * You can only have one open UDP connection at a time.  You cannot
214  * have a UDP connection open at the same time as a TFTP connection.
215  * You cannot use pxenv_udp_close() to close a TFTP connection; use
216  * pxenv_tftp_close() instead.
217  *
218  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
219  * value before calling this function in protected mode.  You cannot
220  * call this function with a 32-bit stack segment.  (See the relevant
221  * @ref pxe_x86_pmode16 "implementation note" for more details.)
222  *
223  */
224 PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
225         DBG ( "PXENV_UDP_CLOSE" );
226
227         /* Check connection is open */
228         if ( ! pxe_udp.open ) {
229                 pxenv_udp_close->Status = PXENV_STATUS_UDP_CLOSED;
230                 return PXENV_EXIT_SUCCESS; /* Well, it *is* closed */
231         }
232
233         /* Close UDP connection */
234         udp_close ( &pxe_udp.udp );
235         pxe_udp.open = 0;
236
237         pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
238         return PXENV_EXIT_SUCCESS;
239 }
240
241 /**
242  * UDP WRITE
243  *
244  * @v pxenv_udp_write                   Pointer to a struct s_PXENV_UDP_WRITE
245  * @v s_PXENV_UDP_WRITE::ip             Destination IP address
246  * @v s_PXENV_UDP_WRITE::gw             Relay agent IP address, or 0.0.0.0
247  * @v s_PXENV_UDP_WRITE::src_port       Source UDP port, or 0
248  * @v s_PXENV_UDP_WRITE::dst_port       Destination UDP port
249  * @v s_PXENV_UDP_WRITE::buffer_size    Length of the UDP payload
250  * @v s_PXENV_UDP_WRITE::buffer         Address of the UDP payload
251  * @ret #PXENV_EXIT_SUCCESS             Packet was transmitted successfully
252  * @ret #PXENV_EXIT_FAILURE             Packet could not be transmitted
253  * @ret s_PXENV_UDP_WRITE::Status       PXE status code
254  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
255  * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
256  *
257  * Transmits a single UDP packet.  A valid IP and UDP header will be
258  * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
259  * should not contain precomputed IP and UDP headers, nor should it
260  * contain space allocated for these headers.  The first byte of the
261  * buffer will be transmitted as the first byte following the UDP
262  * header.
263  *
264  * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
265  * place.  See the relevant @ref pxe_routing "implementation note" for
266  * more details.
267  *
268  * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
269  *
270  * You must have opened a UDP connection with pxenv_udp_open() before
271  * calling pxenv_udp_write().
272  *
273  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
274  * value before calling this function in protected mode.  You cannot
275  * call this function with a 32-bit stack segment.  (See the relevant
276  * @ref pxe_x86_pmode16 "implementation note" for more details.)
277  *
278  * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
279  * parameter.
280  *
281  */
282 PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
283         union {
284                 struct sockaddr_in sin;
285                 struct sockaddr_tcpip st;
286         } dest;
287
288         DBG ( "PXENV_UDP_WRITE" );
289
290         /* Check connection is open */
291         if ( ! pxe_udp.open ) {
292                 pxenv_udp_write->Status = PXENV_STATUS_UDP_CLOSED;
293                 return PXENV_EXIT_FAILURE;
294         }
295
296         /* Construct destination socket address */
297         memset ( &dest, 0, sizeof ( dest ) );
298         dest.sin.sin_family = AF_INET;
299         dest.sin.sin_addr.s_addr = pxenv_udp_write->ip;
300         dest.sin.sin_port = pxenv_udp_write->dst_port;
301
302         /* Set local (source) port.  PXE spec says source port is 2069
303          * if not specified.  Really, this ought to be set at UDP open
304          * time but hey, we didn't design this API.
305          */
306         if ( ! pxenv_udp_write->src_port )
307                 pxenv_udp_write->src_port = htons ( 2069 );
308         udp_bind ( &pxe_udp.udp, pxenv_udp_write->src_port );
309
310         /* FIXME: we ignore the gateway specified, since we're
311          * confident of being able to do our own routing.  We should
312          * probably allow for multiple gateways.
313          */
314         
315         /* Transmit packet */
316         if ( udp_senddata ( &pxe_udp.udp ) != 0 ) {
317                 pxenv_udp_write->Status = PXENV_STATUS_UNDI_TRANSMIT_ERROR;
318                 return PXENV_EXIT_FAILURE;
319         }
320
321         pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
322         return PXENV_EXIT_SUCCESS;
323 }
324
325 /**
326  * UDP READ
327  *
328  * @v pxenv_udp_read                    Pointer to a struct s_PXENV_UDP_READ
329  * @v s_PXENV_UDP_READ::dest_ip         Destination IP address, or 0.0.0.0
330  * @v s_PXENV_UDP_READ::d_port          Destination UDP port, or 0
331  * @v s_PXENV_UDP_READ::buffer_size     Size of the UDP payload buffer
332  * @v s_PXENV_UDP_READ::buffer          Address of the UDP payload buffer
333  * @ret #PXENV_EXIT_SUCCESS             A packet has been received
334  * @ret #PXENV_EXIT_FAILURE             No packet has been received
335  * @ret s_PXENV_UDP_READ::Status        PXE status code
336  * @ret s_PXENV_UDP_READ::src_ip        Source IP address
337  * @ret s_PXENV_UDP_READ::dest_ip       Destination IP address
338  * @ret s_PXENV_UDP_READ::s_port        Source UDP port
339  * @ret s_PXENV_UDP_READ::d_port        Destination UDP port
340  * @ret s_PXENV_UDP_READ::buffer_size   Length of UDP payload
341  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
342  * @err #PXENV_STATUS_FAILURE           No packet was ready to read
343  *
344  * Receive a single UDP packet.  This is a non-blocking call; if no
345  * packet is ready to read, the call will return instantly with
346  * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
347  *
348  * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
349  * any IP address will be accepted and may be returned to the caller.
350  *
351  * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
352  * port will be accepted and may be returned to the caller.
353  *
354  * You must have opened a UDP connection with pxenv_udp_open() before
355  * calling pxenv_udp_read().
356  *
357  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
358  * value before calling this function in protected mode.  You cannot
359  * call this function with a 32-bit stack segment.  (See the relevant
360  * @ref pxe_x86_pmode16 "implementation note" for more details.)
361  *
362  * @note The PXE specification (version 2.1) does not state that we
363  * should fill in s_PXENV_UDP_READ::dest_ip and
364  * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
365  * expects us to do so, and will fail if we don't.
366  *
367  */
368 PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
369         struct in_addr dest_ip = { .s_addr = pxenv_udp_read->dest_ip };
370         uint16_t d_port = pxenv_udp_read->d_port;
371
372         DBG ( "PXENV_UDP_READ" );
373
374         /* Check connection is open */
375         if ( ! pxe_udp.open ) {
376                 pxenv_udp_read->Status = PXENV_STATUS_UDP_CLOSED;
377                 return PXENV_EXIT_FAILURE;
378         }
379
380         /* Bind promiscuously; we will do our own filtering */
381         udp_bind_promisc ( &pxe_udp.udp );
382
383         /* Try receiving a packet */
384         pxe_udp.pxenv_udp_read = pxenv_udp_read;
385         step();
386         if ( pxe_udp.pxenv_udp_read ) {
387                 /* No packet received */
388                 pxe_udp.pxenv_udp_read = NULL;
389                 goto no_packet;
390         }
391
392         /* Filter on destination address and/or port */
393         if ( dest_ip.s_addr && ( dest_ip.s_addr != pxenv_udp_read->dest_ip ) )
394                 goto no_packet;
395         if ( d_port && ( d_port != pxenv_udp_read->d_port ) )
396                 goto no_packet;
397
398         pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
399         return PXENV_EXIT_SUCCESS;
400
401  no_packet:
402         pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
403         return PXENV_EXIT_FAILURE;
404 }