10 #include <gpxe/uaccess.h>
11 #include <gpxe/process.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 */
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
);
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()
60 static int pxe_udp_senddata ( struct udp_connection
*conn
, void *data
,
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
;
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
);
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()
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
);
96 if ( ! pxenv_udp_read
) {
97 DBG ( "PXE discarded UDP packet\n" );
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
;
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
,
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
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
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
;
200 pxenv_udp_open
->Status
= PXENV_STATUS_SUCCESS
;
201 return PXENV_EXIT_SUCCESS
;
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
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
);
238 pxenv_udp_close
->Status
= PXENV_STATUS_SUCCESS
;
239 return PXENV_EXIT_SUCCESS
;
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
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
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
283 PXENV_EXIT_t
pxenv_udp_write ( struct s_PXENV_UDP_WRITE
*pxenv_udp_write
) {
285 struct sockaddr_in sin
;
286 struct sockaddr_tcpip st
;
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
;
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
;
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
;
398 if ( pxe_udp
.pxenv_udp_read
) {
399 /* No packet received */
400 pxe_udp
.pxenv_udp_read
= NULL
;
404 /* Filter on destination address and/or port */
405 if ( dest_ip
.s_addr
&& ( dest_ip
.s_addr
!= pxenv_udp_read
->dest_ip
) )
407 if ( d_port
&& ( d_port
!= pxenv_udp_read
->d_port
) )
410 pxenv_udp_read
->Status
= PXENV_STATUS_SUCCESS
;
411 return PXENV_EXIT_SUCCESS
;
414 pxenv_udp_read
->Status
= PXENV_STATUS_FAILURE
;
415 return PXENV_EXIT_FAILURE
;