Bläddra i källkod

Updated PXE UDP implementation to use the new Etherboot UDP API.

Updated PXE API dispatcher to use copy_{to,from}_user, and moved to
arch/i386 since the implementation is quite architecture-dependent.
(The individual PXE API calls can be largely
architecture-independent.)
tags/v0.9.3
Michael Brown 18 år sedan
förälder
incheckning
a0a872f7f1

+ 1
- 0
src/arch/i386/Makefile Visa fil

@@ -7,6 +7,7 @@ SRCDIRS		+= arch/i386/drivers/bus
7 7
 SRCDIRS		+= arch/i386/drivers/net
8 8
 SRCDIRS		+= arch/i386/drivers/disk
9 9
 SRCDIRS		+= arch/i386/interface/pcbios
10
+SRCDIRS		+= arch/i386/interface/pxe
10 11
 
11 12
 # The various xxx_loader.c files are #included into core/loader.c and
12 13
 # should not be compiled directly.

+ 290
- 0
src/arch/i386/interface/pxe/pxe_call.c Visa fil

@@ -0,0 +1,290 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <gpxe/uaccess.h>
20
+#include <registers.h>
21
+#include <pxe.h>
22
+
23
+/** @file
24
+ *
25
+ * PXE API entry point
26
+ */
27
+
28
+/** A function pointer to hold any PXE API call
29
+ *
30
+ * Used by pxe_api_call() to avoid large swathes of duplicated code.
31
+ */
32
+union pxenv_call {
33
+	PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * );
34
+	PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * );
35
+	PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * );
36
+	PXENV_EXIT_t ( * get_cached_info )
37
+			( struct s_PXENV_GET_CACHED_INFO * );
38
+	PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * );
39
+	PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * );
40
+	PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * );
41
+	PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * );
42
+	PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * );
43
+	PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * );
44
+	PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * );
45
+	PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * );
46
+	PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * );
47
+	PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * );
48
+	PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * );
49
+	PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * );
50
+	PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * );
51
+	PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * );
52
+	PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * );
53
+	PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * );
54
+	PXENV_EXIT_t ( * undi_initialize )
55
+			( struct s_PXENV_UNDI_INITIALIZE * );
56
+	PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * );
57
+	PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * );
58
+	PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * );
59
+	PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * );
60
+	PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * );
61
+	PXENV_EXIT_t ( * undi_set_mcast_address )
62
+			( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * );
63
+	PXENV_EXIT_t ( * undi_set_station_address )
64
+			( struct s_PXENV_UNDI_SET_STATION_ADDRESS * );
65
+	PXENV_EXIT_t ( * undi_set_packet_filter )
66
+			( struct s_PXENV_UNDI_SET_PACKET_FILTER * );
67
+	PXENV_EXIT_t ( * undi_get_information )
68
+			( struct s_PXENV_UNDI_GET_INFORMATION * );
69
+	PXENV_EXIT_t ( * undi_get_statistics )
70
+			( struct s_PXENV_UNDI_GET_STATISTICS * );
71
+	PXENV_EXIT_t ( * undi_clear_statistics )
72
+			( struct s_PXENV_UNDI_CLEAR_STATISTICS * );
73
+	PXENV_EXIT_t ( * undi_initiate_diags )
74
+			( struct s_PXENV_UNDI_INITIATE_DIAGS * );
75
+	PXENV_EXIT_t ( * undi_force_interrupt )
76
+			( struct s_PXENV_UNDI_FORCE_INTERRUPT * );
77
+	PXENV_EXIT_t ( * undi_get_mcast_address )
78
+			( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * );
79
+	PXENV_EXIT_t ( * undi_get_nic_type )
80
+			( struct s_PXENV_UNDI_GET_NIC_TYPE * );
81
+	PXENV_EXIT_t ( * undi_get_iface_info )
82
+			( struct s_PXENV_UNDI_GET_IFACE_INFO * );
83
+	PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
84
+	PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
85
+};
86
+
87
+/**
88
+ * Handle an unknown PXE API call
89
+ *
90
+ * @v pxenv_unknown 			Pointer to a struct s_PXENV_UNKNOWN
91
+ * @ret #PXENV_EXIT_FAILURE		Always
92
+ * @err #PXENV_STATUS_UNSUPPORTED	Always
93
+ */
94
+static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
95
+	pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED;
96
+	return PXENV_EXIT_FAILURE;
97
+}
98
+
99
+/**
100
+ * Dispatch PXE API call
101
+ *
102
+ * @v bx		PXE opcode
103
+ * @v es:di		Address of PXE parameter block
104
+ * @ret ax		PXE exit code
105
+ */
106
+void pxe_api_call ( struct i386_all_regs *ix86 ) {
107
+	int opcode = ix86->regs.bx;
108
+	userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
109
+	size_t param_len;
110
+	union u_PXENV_ANY pxenv_any;
111
+	union pxenv_call pxenv_call;
112
+	PXENV_EXIT_t ret;
113
+
114
+	switch ( opcode ) {
115
+	case PXENV_UNLOAD_STACK:
116
+		pxenv_call.unload_stack = pxenv_unload_stack;
117
+		param_len = sizeof ( pxenv_any.unload_stack );
118
+		break;
119
+	case PXENV_GET_CACHED_INFO:
120
+		pxenv_call.get_cached_info = pxenv_get_cached_info;
121
+		param_len = sizeof ( pxenv_any.get_cached_info );
122
+		break;
123
+	case PXENV_RESTART_TFTP:
124
+		pxenv_call.restart_tftp = pxenv_restart_tftp;
125
+		param_len = sizeof ( pxenv_any.restart_tftp );
126
+		break;
127
+	case PXENV_START_UNDI:
128
+		pxenv_call.start_undi = pxenv_start_undi;
129
+		param_len = sizeof ( pxenv_any.start_undi );
130
+		break;
131
+	case PXENV_STOP_UNDI:
132
+		pxenv_call.stop_undi = pxenv_stop_undi;
133
+		param_len = sizeof ( pxenv_any.stop_undi );
134
+		break;
135
+	case PXENV_START_BASE:
136
+		pxenv_call.start_base = pxenv_start_base;
137
+		param_len = sizeof ( pxenv_any.start_base );
138
+		break;
139
+	case PXENV_STOP_BASE:
140
+		pxenv_call.stop_base = pxenv_stop_base;
141
+		param_len = sizeof ( pxenv_any.stop_base );
142
+		break;
143
+	case PXENV_TFTP_OPEN:
144
+		pxenv_call.tftp_open = pxenv_tftp_open;
145
+		param_len = sizeof ( pxenv_any.tftp_open );
146
+		break;
147
+	case PXENV_TFTP_CLOSE:
148
+		pxenv_call.tftp_close = pxenv_tftp_close;
149
+		param_len = sizeof ( pxenv_any.tftp_close );
150
+		break;
151
+	case PXENV_TFTP_READ:
152
+		pxenv_call.tftp_read = pxenv_tftp_read;
153
+		param_len = sizeof ( pxenv_any.tftp_read );
154
+		break;
155
+	case PXENV_TFTP_READ_FILE:
156
+		pxenv_call.tftp_read_file = pxenv_tftp_read_file;
157
+		param_len = sizeof ( pxenv_any.tftp_read_file );
158
+		break;
159
+	case PXENV_TFTP_GET_FSIZE:
160
+		pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize;
161
+		param_len = sizeof ( pxenv_any.tftp_get_fsize );
162
+		break;
163
+	case PXENV_UDP_OPEN:
164
+		pxenv_call.udp_open = pxenv_udp_open;
165
+		param_len = sizeof ( pxenv_any.udp_open );
166
+		break;
167
+	case PXENV_UDP_CLOSE:
168
+		pxenv_call.udp_close = pxenv_udp_close;
169
+		param_len = sizeof ( pxenv_any.udp_close );
170
+		break;
171
+	case PXENV_UDP_WRITE:
172
+		pxenv_call.udp_write = pxenv_udp_write;
173
+		param_len = sizeof ( pxenv_any.udp_write );
174
+		break;
175
+	case PXENV_UDP_READ:
176
+		pxenv_call.udp_read = pxenv_udp_read;
177
+		param_len = sizeof ( pxenv_any.udp_read );
178
+		break;
179
+	case PXENV_UNDI_STARTUP:
180
+		pxenv_call.undi_startup = pxenv_undi_startup;
181
+		param_len = sizeof ( pxenv_any.undi_startup );
182
+		break;
183
+	case PXENV_UNDI_CLEANUP:
184
+		pxenv_call.undi_cleanup = pxenv_undi_cleanup;
185
+		param_len = sizeof ( pxenv_any.undi_cleanup );
186
+		break;
187
+	case PXENV_UNDI_INITIALIZE:
188
+		pxenv_call.undi_initialize = pxenv_undi_initialize;
189
+		param_len = sizeof ( pxenv_any.undi_initialize );
190
+		break;
191
+	case PXENV_UNDI_RESET_ADAPTER:
192
+		pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter;
193
+		param_len = sizeof ( pxenv_any.undi_reset_adapter );
194
+		break;
195
+	case PXENV_UNDI_SHUTDOWN:
196
+		pxenv_call.undi_shutdown = pxenv_undi_shutdown;
197
+		param_len = sizeof ( pxenv_any.undi_shutdown );
198
+		break;
199
+	case PXENV_UNDI_OPEN:
200
+		pxenv_call.undi_open = pxenv_undi_open;
201
+		param_len = sizeof ( pxenv_any.undi_open );
202
+		break;
203
+	case PXENV_UNDI_CLOSE:
204
+		pxenv_call.undi_close = pxenv_undi_close;
205
+		param_len = sizeof ( pxenv_any.undi_close );
206
+		break;
207
+	case PXENV_UNDI_TRANSMIT:
208
+		pxenv_call.undi_transmit = pxenv_undi_transmit;
209
+		param_len = sizeof ( pxenv_any.undi_transmit );
210
+		break;
211
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
212
+		pxenv_call.undi_set_mcast_address =
213
+			pxenv_undi_set_mcast_address;
214
+		param_len = sizeof ( pxenv_any.undi_set_mcast_address );
215
+		break;
216
+	case PXENV_UNDI_SET_STATION_ADDRESS:
217
+		pxenv_call.undi_set_station_address =
218
+			pxenv_undi_set_station_address;
219
+		param_len = sizeof ( pxenv_any.undi_set_station_address );
220
+		break;
221
+	case PXENV_UNDI_SET_PACKET_FILTER:
222
+		pxenv_call.undi_set_packet_filter =
223
+			pxenv_undi_set_packet_filter;
224
+		param_len = sizeof ( pxenv_any.undi_set_packet_filter );
225
+		break;
226
+	case PXENV_UNDI_GET_INFORMATION:
227
+		pxenv_call.undi_get_information = pxenv_undi_get_information;
228
+		param_len = sizeof ( pxenv_any.undi_get_information );
229
+		break;
230
+	case PXENV_UNDI_GET_STATISTICS:
231
+		pxenv_call.undi_get_statistics = pxenv_undi_get_statistics;
232
+		param_len = sizeof ( pxenv_any.undi_get_statistics );
233
+		break;
234
+	case PXENV_UNDI_CLEAR_STATISTICS:
235
+		pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics;
236
+		param_len = sizeof ( pxenv_any.undi_clear_statistics );
237
+		break;
238
+	case PXENV_UNDI_INITIATE_DIAGS:
239
+		pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags;
240
+		param_len = sizeof ( pxenv_any.undi_initiate_diags );
241
+		break;
242
+	case PXENV_UNDI_FORCE_INTERRUPT:
243
+		pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt;
244
+		param_len = sizeof ( pxenv_any.undi_force_interrupt );
245
+		break;
246
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
247
+		pxenv_call.undi_get_mcast_address =
248
+			pxenv_undi_get_mcast_address;
249
+		param_len = sizeof ( pxenv_any.undi_get_mcast_address );
250
+		break;
251
+	case PXENV_UNDI_GET_NIC_TYPE:
252
+		pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type;
253
+		param_len = sizeof ( pxenv_any.undi_get_nic_type );
254
+		break;
255
+	case PXENV_UNDI_GET_IFACE_INFO:
256
+		pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info;
257
+		param_len = sizeof ( pxenv_any.undi_get_iface_info );
258
+		break;
259
+	case PXENV_UNDI_ISR:
260
+		pxenv_call.undi_isr = pxenv_undi_isr;
261
+		param_len = sizeof ( pxenv_any.undi_isr );
262
+		break;
263
+	default:
264
+		DBG ( "PXENV_UNKNOWN_%hx", opcode );
265
+		pxenv_call.unknown = pxenv_unknown;
266
+		param_len = sizeof ( pxenv_any.unknown );
267
+		break;
268
+	}
269
+
270
+	/* Copy parameter block from caller */
271
+	copy_from_user ( &pxenv_any, parameters, 0, param_len );
272
+
273
+	/* Set default status in case child routine fails to do so */
274
+	pxenv_any.Status = PXENV_STATUS_FAILURE;
275
+
276
+	/* Hand off to relevant API routine */
277
+	DBG ( "[" );
278
+	ret = pxenv_call.any ( &pxenv_any );
279
+	if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) {
280
+		DBG ( " %02x", pxenv_any.Status );
281
+	}
282
+	if ( ret != PXENV_EXIT_SUCCESS ) {
283
+		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
284
+	}
285
+	DBG ( "]" );
286
+	
287
+	/* Copy modified parameter block back to caller and return */
288
+	copy_to_user ( parameters, 0, &pxenv_any, param_len );
289
+	ix86->regs.ax = ret;
290
+}

+ 5
- 0
src/include/gpxe/udp.h Visa fil

@@ -64,6 +64,9 @@ struct udp_operations {
64 64
 	 * @v conn	UDP connection
65 65
 	 * @v data	Data
66 66
 	 * @v len	Length of data
67
+	 * @v st_src	Source address
68
+	 * @v st_dest	Destination address
69
+	 * @ret rc	Return status code
67 70
 	 */
68 71
 	int ( * newdata ) ( struct udp_connection *conn, void *data,
69 72
 			    size_t len, struct sockaddr_tcpip *st_src,
@@ -92,8 +95,10 @@ struct udp_connection {
92 95
  */
93 96
 
94 97
 extern int udp_bind ( struct udp_connection *conn, uint16_t local_port );
98
+extern void udp_bind_promisc ( struct udp_connection *conn );
95 99
 extern void udp_connect ( struct udp_connection *conn,
96 100
 			  struct sockaddr_tcpip *peer );
101
+extern void udp_connect_promisc ( struct udp_connection *conn );
97 102
 extern int udp_open ( struct udp_connection *conn, uint16_t local_port );
98 103
 extern void udp_close ( struct udp_connection *conn );
99 104
 

+ 9
- 21
src/include/pxe.h Visa fil

@@ -3,8 +3,13 @@
3 3
 
4 4
 #include "pxe_types.h"
5 5
 #include "pxe_api.h"
6
-#include "etherboot.h"
7
-#include "tftp.h"
6
+
7
+/* Parameter block for pxenv_unknown() */
8
+struct s_PXENV_UNKNOWN {
9
+	PXENV_STATUS_t Status;			/**< PXE status code */
10
+} PACKED;
11
+
12
+typedef struct s_PXENV_UNKNOWN PXENV_UNKNOWN_t;
8 13
 
9 14
 /* Union used for PXE API calls; we don't know the type of the
10 15
  * structure until we interpret the opcode.  Also, Status is available
@@ -14,6 +19,7 @@
14 19
 union u_PXENV_ANY {
15 20
 	/* Make it easy to read status for any operation */
16 21
 	PXENV_STATUS_t				Status;
22
+	struct s_PXENV_UNKNOWN			unknown;
17 23
 	struct s_PXENV_UNLOAD_STACK		unload_stack;
18 24
 	struct s_PXENV_GET_CACHED_INFO		get_cached_info;
19 25
 	struct s_PXENV_TFTP_READ_FILE		restart_tftp;
@@ -81,29 +87,11 @@ typedef enum {
81 87
 typedef struct pxe_stack {
82 88
 	struct s_PXE		pxe	__attribute__ ((aligned(16)));
83 89
 	struct s_PXENV		pxenv	__attribute__ ((aligned(16)));
84
-	pxe_stack_state_t state;
85
-	union {
86
-		BOOTPLAYER_t	cached_info;
87
-		char		packet[ETH_FRAME_LEN];
88
-		struct {
89
-			uint32_t magic_cookie;
90
-			unsigned int len;
91
-			int eof;
92
-			char data[TFTP_MAX_BLKSIZE];
93
-		} tftpdata;
94
-		struct {
95
-			char *buffer;
96
-			uint32_t offset;
97
-			uint32_t bufferlen;
98
-		} readfile;
99
-	};
100
-	struct {}	arch_data __attribute__ ((aligned(16)));
90
+	pxe_stack_state_t	state;
101 91
 } pxe_stack_t;
102 92
 
103 93
 extern int ensure_pxe_state ( pxe_stack_state_t wanted );
104 94
 
105 95
 extern pxe_stack_t *pxe_stack;
106 96
 
107
-extern PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any );
108
-
109 97
 #endif /* PXE_H */

+ 3
- 148
src/interface/pxe/pxe.c Visa fil

@@ -25,6 +25,8 @@
25 25
 #include "dev.h"
26 26
 #include "pxe.h"
27 27
 
28
+#if 0
29
+
28 30
 /* Global pointer to currently installed PXE stack */
29 31
 pxe_stack_t *pxe_stack = NULL;
30 32
 
@@ -162,151 +164,4 @@ int ensure_pxe_state ( pxe_stack_state_t wanted ) {
162 164
 	return success;
163 165
 }
164 166
 
165
-/* API call dispatcher
166
- *
167
- * Status: complete
168
- */
169
-PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
170
-	PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
171
-
172
-	/* Set default status in case child routine fails to do so */
173
-	any->Status = PXENV_STATUS_FAILURE;
174
-
175
-	DBG ( "[" );
176
-
177
-	/* Hand off to relevant API routine */
178
-	switch ( opcode ) {
179
-	case PXENV_START_UNDI:
180
-		ret = pxenv_start_undi ( &any->start_undi );
181
-		break;
182
-	case PXENV_UNDI_STARTUP:
183
-		ret = pxenv_undi_startup ( &any->undi_startup );
184
-		break;
185
-	case PXENV_UNDI_CLEANUP:
186
-		ret = pxenv_undi_cleanup ( &any->undi_cleanup );
187
-		break;
188
-	case PXENV_UNDI_INITIALIZE:
189
-		ret = pxenv_undi_initialize ( &any->undi_initialize );
190
-		break;
191
-	case PXENV_UNDI_RESET_ADAPTER:
192
-		ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
193
-		break;
194
-	case PXENV_UNDI_SHUTDOWN:
195
-		ret = pxenv_undi_shutdown ( &any->undi_shutdown );
196
-		break;
197
-	case PXENV_UNDI_OPEN:
198
-		ret = pxenv_undi_open ( &any->undi_open );
199
-		break;
200
-	case PXENV_UNDI_CLOSE:
201
-		ret = pxenv_undi_close ( &any->undi_close );
202
-		break;
203
-	case PXENV_UNDI_TRANSMIT:
204
-		ret = pxenv_undi_transmit ( &any->undi_transmit );
205
-		break;
206
-	case PXENV_UNDI_SET_MCAST_ADDRESS:
207
-		ret = pxenv_undi_set_mcast_address (
208
-						&any->undi_set_mcast_address );
209
-		break;
210
-	case PXENV_UNDI_SET_STATION_ADDRESS:
211
-		ret = pxenv_undi_set_station_address (
212
-					      &any->undi_set_station_address );
213
-		break;
214
-	case PXENV_UNDI_SET_PACKET_FILTER:
215
-		ret = pxenv_undi_set_packet_filter (
216
-						&any->undi_set_packet_filter );
217
-		break;
218
-	case PXENV_UNDI_GET_INFORMATION:
219
-		ret = pxenv_undi_get_information (
220
-					       &any->undi_get_information );
221
-		break;
222
-	case PXENV_UNDI_GET_STATISTICS:
223
-		ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
224
-		break;
225
-	case PXENV_UNDI_CLEAR_STATISTICS:
226
-		ret = pxenv_undi_clear_statistics (
227
-						 &any->undi_clear_statistics );
228
-		break;
229
-	case PXENV_UNDI_INITIATE_DIAGS:
230
-		ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
231
-						 
232
-		break;
233
-	case PXENV_UNDI_FORCE_INTERRUPT:
234
-		ret = pxenv_undi_force_interrupt (
235
-					       &any->undi_force_interrupt );
236
-		break;
237
-	case PXENV_UNDI_GET_MCAST_ADDRESS:
238
-		ret = pxenv_undi_get_mcast_address (
239
-					     &any->undi_get_mcast_address );
240
-		break;
241
-	case PXENV_UNDI_GET_NIC_TYPE:
242
-		ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
243
-		break;
244
-	case PXENV_UNDI_GET_IFACE_INFO:
245
-		ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
246
-		break;
247
-	case PXENV_UNDI_ISR:
248
-		ret = pxenv_undi_isr ( &any->undi_isr );
249
-		break;
250
-	case PXENV_STOP_UNDI:
251
-		ret = pxenv_stop_undi ( &any->stop_undi );
252
-		break;
253
-	case PXENV_TFTP_OPEN:
254
-		ret = pxenv_tftp_open ( &any->tftp_open );
255
-		break;
256
-	case PXENV_TFTP_CLOSE:
257
-		ret = pxenv_tftp_close ( &any->tftp_close );
258
-		break;
259
-	case PXENV_TFTP_READ:
260
-		ret = pxenv_tftp_read ( &any->tftp_read );
261
-		break;
262
-	case PXENV_TFTP_READ_FILE:
263
-		ret = pxenv_tftp_read_file ( &any->tftp_read_file );
264
-		break;
265
-	case PXENV_TFTP_GET_FSIZE:
266
-		ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
267
-		break;
268
-	case PXENV_UDP_OPEN:
269
-		ret = pxenv_udp_open ( &any->udp_open );
270
-		break;
271
-	case PXENV_UDP_CLOSE:
272
-		ret = pxenv_udp_close ( &any->udp_close );
273
-		break;
274
-	case PXENV_UDP_READ:
275
-		ret = pxenv_udp_read ( &any->udp_read );
276
-		break;
277
-	case PXENV_UDP_WRITE:
278
-		ret = pxenv_udp_write ( &any->udp_write );
279
-		break;
280
-	case PXENV_UNLOAD_STACK:
281
-		ret = pxenv_unload_stack ( &any->unload_stack );
282
-		break;
283
-	case PXENV_GET_CACHED_INFO:
284
-		ret = pxenv_get_cached_info ( &any->get_cached_info );
285
-		break;
286
-	case PXENV_RESTART_TFTP:
287
-		ret = pxenv_restart_tftp ( &any->restart_tftp );
288
-		break;
289
-	case PXENV_START_BASE:
290
-		ret = pxenv_start_base ( &any->start_base );
291
-		break;
292
-	case PXENV_STOP_BASE:
293
-		ret = pxenv_stop_base ( &any->stop_base );
294
-		break;
295
-		
296
-	default:
297
-		DBG ( "PXENV_UNKNOWN_%hx", opcode );
298
-		any->Status = PXENV_STATUS_UNSUPPORTED;
299
-		ret = PXENV_EXIT_FAILURE;
300
-		break;
301
-	}
302
-
303
-	if ( any->Status != PXENV_STATUS_SUCCESS ) {
304
-		DBG ( " %hx", any->Status );
305
-	}
306
-	if ( ret != PXENV_EXIT_SUCCESS ) {
307
-		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
308
-	}
309
-	DBG ( "]" );
310
-
311
-	return ret;
312
-}
167
+#endif

+ 4
- 0
src/interface/pxe/pxe_preboot.c Visa fil

@@ -23,6 +23,8 @@
23 23
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 24
  */
25 25
 
26
+#if 0
27
+
26 28
 #include "pxe.h"
27 29
 #include "pxe_callbacks.h"
28 30
 
@@ -247,3 +249,5 @@ PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
247 249
 	stop_base->Status = PXENV_STATUS_SUCCESS;
248 250
 	return PXENV_EXIT_SUCCESS;
249 251
 }
252
+
253
+#endif

+ 4
- 0
src/interface/pxe/pxe_tftp.c Visa fil

@@ -22,6 +22,8 @@
22 22
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 23
  */
24 24
 
25
+#if 0
26
+
25 27
 #include "pxe.h"
26 28
 
27 29
 static int pxe_tftp_read_block ( unsigned char *data, unsigned int block,
@@ -621,3 +623,5 @@ Note to future API designers at Intel: try to understand the
621 623
 underlying network protocol first!
622 624
 
623 625
 */
626
+
627
+#endif

+ 226
- 154
src/interface/pxe/pxe_udp.c Visa fil

@@ -4,9 +4,12 @@
4 4
  *
5 5
  */
6 6
 
7
-#include "pxe.h"
8
-#include "io.h"
9
-#include "string.h"
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>
10 13
 
11 14
 /*
12 15
  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
@@ -26,14 +29,116 @@
26 29
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 30
  */
28 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
+
29 133
 /**
30 134
  * UDP OPEN
31 135
  *
32
- * @v udp_open				Pointer to a struct s_PXENV_UDP_OPEN
136
+ * @v pxenv_udp_open			Pointer to a struct s_PXENV_UDP_OPEN
33 137
  * @v s_PXENV_UDP_OPEN::src_ip		IP address of this station, or 0.0.0.0
34 138
  * @ret #PXENV_EXIT_SUCCESS		Always
35 139
  * @ret s_PXENV_UDP_OPEN::Status	PXE status code
36
- * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
140
+ * @err #PXENV_STATUS_UDP_OPEN		UDP connection already open
141
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES	Could not open connection
37 142
  *
38 143
  * Prepares the PXE stack for communication using pxenv_udp_write()
39 144
  * and pxenv_udp_read().
@@ -45,10 +150,13 @@
45 150
  * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
46 151
  * will remain unchanged.)
47 152
  *
48
- * You can only have one open UDP connection at a time.  You cannot
49
- * have a UDP connection open at the same time as a TFTP connection.
50
- * (This is not strictly true for Etherboot; see the relevant @ref
51
- * pxe_note_udp "implementation note" for more details.)
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.
52 160
  *
53 161
  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
54 162
  * value before calling this function in protected mode.  You cannot
@@ -60,38 +168,52 @@
60 168
  * for this UDP connection, or retained for all future communication.
61 169
  * The latter seems more consistent with typical PXE stack behaviour.
62 170
  *
171
+ * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
172
+ * parameter.
173
+ *
63 174
  */
64
-PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
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
+
65 178
 	DBG ( "PXENV_UDP_OPEN" );
66
-	ENSURE_READY ( udp_open );
67 179
 
68
-	if ( udp_open->src_ip &&
69
-	     udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
70
-		/* Overwrite our IP address */
71
-		DBG ( " with new IP %@", udp_open->src_ip );
72
-		arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
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;
73 196
 	}
197
+	pxe_udp.open = 1;
74 198
 
75
-	udp_open->Status = PXENV_STATUS_SUCCESS;
199
+	pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
76 200
 	return PXENV_EXIT_SUCCESS;
77 201
 }
78 202
 
79 203
 /**
80 204
  * UDP CLOSE
81 205
  *
82
- * @v udp_close				Pointer to a struct s_PXENV_UDP_CLOSE
206
+ * @v pxenv_udp_close			Pointer to a struct s_PXENV_UDP_CLOSE
83 207
  * @ret #PXENV_EXIT_SUCCESS		Always
84 208
  * @ret s_PXENV_UDP_CLOSE::Status	PXE status code
85 209
  * @err None				-
86 210
  *
87
- * Closes a UDP "connection" opened with pxenv_udp_open().
211
+ * Closes a UDP connection opened with pxenv_udp_open().
88 212
  *
89 213
  * You can only have one open UDP connection at a time.  You cannot
90 214
  * have a UDP connection open at the same time as a TFTP connection.
91 215
  * You cannot use pxenv_udp_close() to close a TFTP connection; use
92
- * pxenv_tftp_close() instead.  (This is not strictly true for
93
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
94
- * for more details.)
216
+ * pxenv_tftp_close() instead.
95 217
  *
96 218
  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
97 219
  * value before calling this function in protected mode.  You cannot
@@ -99,16 +221,27 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
99 221
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
100 222
  *
101 223
  */
102
-PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
224
+PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
103 225
 	DBG ( "PXENV_UDP_CLOSE" );
104
-	udp_close->Status = PXENV_STATUS_SUCCESS;
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;
105 238
 	return PXENV_EXIT_SUCCESS;
106 239
 }
107 240
 
108 241
 /**
109 242
  * UDP WRITE
110 243
  *
111
- * @v udp_write				Pointer to a struct s_PXENV_UDP_WRITE
244
+ * @v pxenv_udp_write			Pointer to a struct s_PXENV_UDP_WRITE
112 245
  * @v s_PXENV_UDP_WRITE::ip		Destination IP address
113 246
  * @v s_PXENV_UDP_WRITE::gw		Relay agent IP address, or 0.0.0.0
114 247
  * @v s_PXENV_UDP_WRITE::src_port	Source UDP port, or 0
@@ -118,9 +251,8 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
118 251
  * @ret #PXENV_EXIT_SUCCESS		Packet was transmitted successfully
119 252
  * @ret #PXENV_EXIT_FAILURE		Packet could not be transmitted
120 253
  * @ret s_PXENV_UDP_WRITE::Status	PXE status code
121
- * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
122
- * @err #PXENV_STATUS_OUT_OF_RESOURCES	Packet was too large to transmit
123
- * @err other				Any error from pxenv_undi_transmit()
254
+ * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
255
+ * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
124 256
  *
125 257
  * Transmits a single UDP packet.  A valid IP and UDP header will be
126 258
  * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
@@ -136,116 +268,64 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
136 268
  * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
137 269
  *
138 270
  * You must have opened a UDP connection with pxenv_udp_open() before
139
- * calling pxenv_udp_write().  (This is not strictly true for
140
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
141
- * for more details.)
271
+ * calling pxenv_udp_write().
142 272
  *
143 273
  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
144 274
  * value before calling this function in protected mode.  You cannot
145 275
  * call this function with a 32-bit stack segment.  (See the relevant
146 276
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
147 277
  *
278
+ * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
279
+ * parameter.
280
+ *
148 281
  */
149
-PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write ) {
150
-	uint16_t src_port;
151
-	uint16_t dst_port;
152
-	struct udppacket *packet = (struct udppacket *)nic.packet;
153
-	int packet_size;
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;
154 287
 
155 288
 	DBG ( "PXENV_UDP_WRITE" );
156
-	ENSURE_READY ( udp_write );
157
-
158
-	/* PXE spec says source port is 2069 if not specified */
159
-	src_port = ntohs(udp_write->src_port);
160
-	if ( src_port == 0 ) src_port = 2069;
161
-	dst_port = ntohs(udp_write->dst_port);
162
-	DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
163
-	      udp_write->buffer_size );
164
-	
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
+
165 310
 	/* FIXME: we ignore the gateway specified, since we're
166 311
 	 * confident of being able to do our own routing.  We should
167 312
 	 * probably allow for multiple gateways.
168 313
 	 */
169 314
 	
170
-	/* Copy payload to packet buffer */
171
-	packet_size = ( (void*)&packet->payload - (void*)packet )
172
-		+ udp_write->buffer_size;
173
-	if ( packet_size > ETH_FRAME_LEN ) {
174
-		udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
175
-		return PXENV_EXIT_FAILURE;
176
-	}
177
-	memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
178
-		 udp_write->buffer_size );
179
-
180 315
 	/* Transmit packet */
181
-	if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
182
-			      packet_size, packet ) ) {
183
-		udp_write->Status = errno;
316
+	if ( udp_senddata ( &pxe_udp.udp ) != 0 ) {
317
+		pxenv_udp_write->Status = PXENV_STATUS_UNDI_TRANSMIT_ERROR;
184 318
 		return PXENV_EXIT_FAILURE;
185 319
 	}
186 320
 
187
-	udp_write->Status = PXENV_STATUS_SUCCESS;
321
+	pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
188 322
 	return PXENV_EXIT_SUCCESS;
189 323
 }
190 324
 
191
-/* Utility function for pxenv_udp_read() */
192
-static int await_pxe_udp ( int ival __unused, void *ptr,
193
-			   unsigned short ptype __unused,
194
-			   struct iphdr *ip, struct udphdr *udp,
195
-			   struct tcphdr *tcp __unused ) {
196
-	struct s_PXENV_UDP_READ *udp_read = (struct s_PXENV_UDP_READ*)ptr;
197
-	uint16_t d_port;
198
-	size_t size;
199
-
200
-	/* Ignore non-UDP packets */
201
-	if ( !udp ) {
202
-		DBG ( " non-UDP" );
203
-		return 0;
204
-	}
205
-	
206
-	/* Check dest_ip */
207
-	if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
208
-		DBG ( " wrong dest IP (got %@, wanted %@)",
209
-		      ip->dest.s_addr, udp_read->dest_ip );
210
-		return 0;
211
-	}
212
-
213
-	/* Check dest_port */
214
-	d_port = ntohs ( udp_read->d_port );
215
-	if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
216
-		DBG ( " wrong dest port (got %d, wanted %d)",
217
-		      ntohs(udp->dest), d_port );
218
-		return 0;
219
-	}
220
-
221
-	/* Copy packet to buffer and fill in information */
222
-	udp_read->src_ip = ip->src.s_addr;
223
-	udp_read->s_port = udp->src; /* Both in network order */
224
-	size = ntohs(udp->len) - sizeof(*udp);
225
-	/* Workaround: NTLDR expects us to fill these in, even though
226
-	 * PXESPEC clearly defines them as input parameters.
227
-	 */
228
-	udp_read->dest_ip = ip->dest.s_addr;
229
-	udp_read->d_port = udp->dest;
230
-	DBG ( " %@:%d->%@:%d (%d)",
231
-	      udp_read->src_ip, ntohs(udp_read->s_port),
232
-	      udp_read->dest_ip, ntohs(udp_read->d_port), size );
233
-	if ( udp_read->buffer_size < size ) {
234
-		/* PXESPEC: what error code should we actually return? */
235
-		DBG ( " buffer too small (%d)", udp_read->buffer_size );
236
-		udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
237
-		return 0;
238
-	}
239
-	memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
240
-	udp_read->buffer_size = size;
241
-
242
-	return 1;
243
-}
244
-
245 325
 /**
246 326
  * UDP READ
247 327
  *
248
- * @v udp_read				Pointer to a struct s_PXENV_UDP_READ
328
+ * @v pxenv_udp_read			Pointer to a struct s_PXENV_UDP_READ
249 329
  * @v s_PXENV_UDP_READ::dest_ip		Destination IP address, or 0.0.0.0
250 330
  * @v s_PXENV_UDP_READ::d_port		Destination UDP port, or 0
251 331
  * @v s_PXENV_UDP_READ::buffer_size	Size of the UDP payload buffer
@@ -258,8 +338,7 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
258 338
  * @ret s_PXENV_UDP_READ::s_port	Source UDP port
259 339
  * @ret s_PXENV_UDP_READ::d_port	Destination UDP port
260 340
  * @ret s_PXENV_UDP_READ::buffer_size	Length of UDP payload
261
- * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
262
- * @err #PXENV_STATUS_OUT_OF_RESOURCES	Buffer was too small for payload
341
+ * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
263 342
  * @err #PXENV_STATUS_FAILURE		No packet was ready to read
264 343
  *
265 344
  * Receive a single UDP packet.  This is a non-blocking call; if no
@@ -273,9 +352,7 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
273 352
  * port will be accepted and may be returned to the caller.
274 353
  *
275 354
  * You must have opened a UDP connection with pxenv_udp_open() before
276
- * calling pxenv_udp_read().  (This is not strictly true for
277
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
278
- * for more details.)
355
+ * calling pxenv_udp_read().
279 356
  *
280 357
  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
281 358
  * value before calling this function in protected mode.  You cannot
@@ -288,45 +365,40 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
288 365
  * expects us to do so, and will fail if we don't.
289 366
  *
290 367
  */
291
-PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ) {
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
+
292 372
 	DBG ( "PXENV_UDP_READ" );
293
-	ENSURE_READY ( udp_read );
294 373
 
295
-	/* Use await_reply with a timeout of zero */
296
-	/* Allow await_reply to change Status if necessary */
297
-	udp_read->Status = PXENV_STATUS_FAILURE;
298
-	if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
374
+	/* Check connection is open */
375
+	if ( ! pxe_udp.open ) {
376
+		pxenv_udp_read->Status = PXENV_STATUS_UDP_CLOSED;
299 377
 		return PXENV_EXIT_FAILURE;
300 378
 	}
301 379
 
302
-	udp_read->Status = PXENV_STATUS_SUCCESS;
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;
303 399
 	return PXENV_EXIT_SUCCESS;
304
-}
305 400
 
306
-/** @page pxe_notes Etherboot PXE implementation notes
307
-
308
-@section pxe_note_udp The connectionless nature of UDP
309
-
310
-The PXE specification states that it is possible to have only one open
311
-UDP or TFTP connection at any one time.  Etherboot does not
312
-rigourously enforce this restriction, on the UNIX principle that the
313
-code should not prevent the user from doing stupid things, because
314
-that would also prevent the user from doing clever things.  Since UDP
315
-is a connectionless protocol, it is perfectly possible to have
316
-multiple concurrent UDP "connections" open, provided that you take the
317
-multiplicity of connections into account when calling
318
-pxenv_udp_read().  Similarly, there is no technical reason that
319
-prevents you from calling pxenv_udp_write() in the middle of a TFTP
320
-download.
321
-
322
-Etherboot will therefore never return error codes indicating "a
323
-connection is already open", such as #PXENV_STATUS_UDP_OPEN.  If you
324
-want to have multiple concurrent connections, go for it (but don't
325
-expect your perfectly sensible code to work with any other PXE stack).
326
-
327
-Since Etherboot treats UDP as the connectionless protocol that it
328
-really is, pxenv_udp_close() is actually a no-op, and there is no need
329
-to call pxenv_udp_open() before using pxenv_udp_write() or
330
-pxenv_udp_read().
331
-
332
-*/
401
+ no_packet:
402
+	pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
403
+	return PXENV_EXIT_FAILURE;
404
+}

+ 4
- 0
src/interface/pxe/pxe_undi.c Visa fil

@@ -22,6 +22,8 @@
22 22
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 23
  */
24 24
 
25
+#if 0
26
+
25 27
 #include "pxe.h"
26 28
 
27 29
 typedef struct {
@@ -536,3 +538,5 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
536 538
 	undi_isr->Status = PXENV_STATUS_SUCCESS;
537 539
 	return PXENV_EXIT_SUCCESS;
538 540
 }
541
+
542
+#endif

+ 12
- 0
src/net/udp.c Visa fil

@@ -66,6 +66,18 @@ void udp_connect ( struct udp_connection *conn, struct sockaddr_tcpip *peer ) {
66 66
 	memcpy ( &conn->peer, peer, sizeof ( conn->peer ) );
67 67
 }
68 68
 
69
+/**
70
+ * Connect UDP connection to all remote hosts and ports
71
+ *
72
+ * @v conn		UDP connection
73
+ *
74
+ * This undoes the effect of a call to udp_connect(), i.e. allows the
75
+ * connection to receive packets from all remote hosts and ports.
76
+ */
77
+void udp_connect_promisc ( struct udp_connection *conn ) {
78
+	memset ( &conn->peer, 0, sizeof ( conn->peer ) );
79
+}
80
+
69 81
 /**
70 82
  * Open a local port
71 83
  *

Laddar…
Avbryt
Spara