Переглянути джерело

Provide individually cached constructed copies of DHCP packets via

PXENV_GET_CACHED_INFO.  If we dont do this, Altiris' NBP screws up; it
relies on being able to grab pointers to each of the three packets and
then read them at will later.
tags/v0.9.3
Michael Brown 16 роки тому
джерело
коміт
838ecba131
1 змінених файлів з 109 додано та 86 видалено
  1. 109
    86
      src/interface/pxe/pxe_preboot.c

+ 109
- 86
src/interface/pxe/pxe_preboot.c Переглянути файл

@@ -32,22 +32,42 @@
32 32
 #include <gpxe/netdevice.h>
33 33
 #include <gpxe/isapnp.h>
34 34
 #include <gpxe/init.h>
35
+#include <gpxe/if_ether.h>
35 36
 #include <basemem_packet.h>
36 37
 #include "pxe.h"
37 38
 #include "pxe_call.h"
38 39
 
39
-/** Filename used for last TFTP request
40
- *
41
- * This is a bug-for-bug compatibility hack needed in order to work
42
- * with Microsoft Remote Installation Services (RIS).  The filename
43
- * used in a call to PXENV_RESTART_TFTP must be returned as the DHCP
44
- * filename in subsequent calls to PXENV_GET_CACHED_INFO.
45
- */
46
-static char *pxe_ris_filename = NULL;
47
-
48 40
 /* Avoid dragging in isapnp.o unnecessarily */
49 41
 uint16_t isapnp_read_port;
50 42
 
43
+/** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */
44
+enum pxe_cached_info_indices {
45
+	CACHED_INFO_DHCPDISCOVER = ( PXENV_PACKET_TYPE_DHCP_DISCOVER - 1 ),
46
+	CACHED_INFO_DHCPACK = ( PXENV_PACKET_TYPE_DHCP_ACK - 1 ),
47
+	CACHED_INFO_BINL = ( PXENV_PACKET_TYPE_CACHED_REPLY - 1 ),
48
+	NUM_CACHED_INFOS
49
+};
50
+
51
+/** A cached DHCP packet */
52
+union pxe_cached_info {
53
+	struct dhcphdr dhcphdr;
54
+	char raw[ETH_FRAME_LEN];
55
+};
56
+
57
+/* The case in which the caller doesn't supply a buffer is really
58
+ * awkward to support given that we have multiple sources of options,
59
+ * and that we don't actually store the DHCP packets.  (We may not
60
+ * even have performed DHCP; we may have obtained all configuration
61
+ * from non-volatile stored options or from the command line.)
62
+ *
63
+ * Some NBPs rely on the buffers we provide being persistent, so we
64
+ * can't just use the temporary packet buffer.  4.5kB of base memory
65
+ * always wasted just because some clients are too lazy to provide
66
+ * their own buffers...
67
+ */
68
+static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] );
69
+#define cached_info __use_data16 ( cached_info )
70
+
51 71
 /**
52 72
  * UNLOAD BASE CODE STACK
53 73
  *
@@ -72,8 +92,8 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
72 92
 	int ( * dhcp_packet_creator ) ( struct net_device *, int,
73 93
 					struct dhcp_option_block *, void *,
74 94
 					size_t, struct dhcp_packet * );
95
+	unsigned int idx;
75 96
 	unsigned int msgtype;
76
-	void *data = NULL;
77 97
 	size_t len;
78 98
 	userptr_t buffer;
79 99
 	int rc;
@@ -83,88 +103,86 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
83 103
 	DBG ( " to %04x:%04x+%x", get_cached_info->Buffer.segment,
84 104
 	      get_cached_info->Buffer.offset, get_cached_info->BufferSize );
85 105
 
86
-	/* The case in which the caller doesn't supply a buffer is
87
-	 * really awkward to support given that we have multiple
88
-	 * sources of options, and that we don't actually store the
89
-	 * DHCP packets.  (We may not even have performed DHCP; we may
90
-	 * have obtained all configuration from non-volatile stored
91
-	 * options or from the command line.)  We provide the caller
92
-	 * with our base-memory temporary packet buffer and construct
93
-	 * the packet in there.
94
-	 *
95
-	 * To add to the fun, Intel decided at some point in the
96
-	 * evolution of the PXE specification to add the BufferLimit
97
-	 * field, which we are meant to fill in with the length of our
98
-	 * packet buffer, so that the caller can safely modify the
99
-	 * boot server reply packet stored therein.  However, this
100
-	 * field was not present in earlier versions of the PXE spec,
101
-	 * and there is at least one PXE NBP (Altiris) which allocates
102
-	 * only exactly enough space for this earlier, shorter version
103
-	 * of the structure.  If we actually fill in the BufferLimit
104
-	 * field, we therefore risk trashing random areas of the
105
-	 * caller's memory.  If we *don't* fill it in, then the caller
106
-	 * is at liberty to assume that whatever random value happened
107
-	 * to be in that location represents the length of the buffer
108
-	 * we've just passed back to it.
109
-	 *
110
-	 * Since older PXE stacks won't fill this field in anyway,
111
-	 * it's probably safe to assume that no callers actually rely
112
-	 * on it, so we choose to not fill it in.
113
-	 */
106
+	/* Sanity check */
107
+        idx = ( get_cached_info->PacketType - 1 );
108
+	if ( idx >= ( sizeof ( cached_info ) / sizeof ( cached_info[0] ) ) ) {
109
+		DBG ( " bad PacketType" );
110
+		goto err;
111
+	}
112
+
113
+	/* Construct cached version of packet, if not already constructed. */
114
+	if ( ! cached_info[idx].dhcphdr.op ) {
115
+		/* Construct DHCP packet */
116
+		if ( get_cached_info->PacketType ==
117
+		     PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
118
+			dhcp_packet_creator = create_dhcp_request;
119
+			msgtype = DHCPDISCOVER;
120
+		} else {
121
+			dhcp_packet_creator = create_dhcp_response;
122
+			msgtype = DHCPACK;
123
+		}
124
+		if ( ( rc = dhcp_packet_creator ( pxe_netdev, msgtype,
125
+						  NULL, &cached_info[idx],
126
+						  sizeof ( cached_info[idx] ),
127
+						  &dhcppkt ) ) != 0 ) {
128
+			DBG ( " failed to build packet" );
129
+			goto err;
130
+		}
131
+	}
132
+
114 133
 	len = get_cached_info->BufferSize;
115 134
 	if ( len == 0 ) {
116
-		len = sizeof ( basemem_packet );
135
+		/* Point client at our cached buffer.
136
+		 *
137
+		 * To add to the fun, Intel decided at some point in
138
+		 * the evolution of the PXE specification to add the
139
+		 * BufferLimit field, which we are meant to fill in
140
+		 * with the length of our packet buffer, so that the
141
+		 * caller can safely modify the boot server reply
142
+		 * packet stored therein.  However, this field was not
143
+		 * present in earlier versions of the PXE spec, and
144
+		 * there is at least one PXE NBP (Altiris) which
145
+		 * allocates only exactly enough space for this
146
+		 * earlier, shorter version of the structure.  If we
147
+		 * actually fill in the BufferLimit field, we
148
+		 * therefore risk trashing random areas of the
149
+		 * caller's memory.  If we *don't* fill it in, then
150
+		 * the caller is at liberty to assume that whatever
151
+		 * random value happened to be in that location
152
+		 * represents the length of the buffer we've just
153
+		 * passed back to it.
154
+		 *
155
+		 * Since older PXE stacks won't fill this field in
156
+		 * anyway, it's probably safe to assume that no
157
+		 * callers actually rely on it, so we choose to not
158
+		 * fill it in.
159
+		 */
117 160
 		get_cached_info->Buffer.segment = rm_ds;
118 161
 		get_cached_info->Buffer.offset =
119
-			( unsigned int ) ( & __from_data16 ( basemem_packet ) );
120
-		DBG ( " using %04x:%04x+'%x'", get_cached_info->Buffer.segment,
162
+			( unsigned ) ( & __from_data16 ( cached_info[idx] ) );
163
+		get_cached_info->BufferSize = sizeof ( cached_info[idx] );
164
+		DBG ( " returning %04x:%04x+%04x['%x']",
165
+		      get_cached_info->Buffer.segment,
121 166
 		      get_cached_info->Buffer.offset,
167
+		      get_cached_info->BufferSize,
122 168
 		      get_cached_info->BufferLimit );
123
-	}
124
-
125
-	/* Allocate space for temporary copy */
126
-	data = malloc ( len );
127
-	if ( ! data ) {
128
-		DBG ( " out of memory" );
129
-		goto err;
130
-	}
131
-
132
-	/* Construct DHCP packet */
133
-	if ( get_cached_info->PacketType == PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
134
-		dhcp_packet_creator = create_dhcp_request;
135
-		msgtype = DHCPDISCOVER;
136 169
 	} else {
137
-		dhcp_packet_creator = create_dhcp_response;
138
-		msgtype = DHCPACK;
139
-	}
140
-	if ( ( rc = dhcp_packet_creator ( pxe_netdev, msgtype, NULL,
141
-					  data, len, &dhcppkt ) ) != 0 ) {
142
-		DBG ( " failed to build packet" );
143
-		goto err;
170
+		/* Copy packet to client buffer */
171
+		if ( len < sizeof ( cached_info[idx] ) ) {
172
+			DBG ( " buffer too short" );
173
+			goto err;
174
+		}
175
+		buffer = real_to_user ( get_cached_info->Buffer.segment,
176
+					get_cached_info->Buffer.offset );
177
+		copy_to_user ( buffer, 0, &cached_info[idx],
178
+			       sizeof ( cached_info[idx] ) );
179
+		get_cached_info->BufferSize = sizeof ( cached_info[idx] );
144 180
 	}
145 181
 
146
-	/* Overwrite filename to work around Microsoft RIS bug */
147
-	if ( pxe_ris_filename ) {
148
-		DBG ( " applying RIS hack" );
149
-		strncpy ( dhcppkt.dhcphdr->file, pxe_ris_filename,
150
-			  sizeof ( dhcppkt.dhcphdr->file ) );
151
-	}
152
-
153
-	/* Copy packet to client buffer */
154
-	buffer = real_to_user ( get_cached_info->Buffer.segment,
155
-				get_cached_info->Buffer.offset );
156
-	len = dhcppkt.len;
157
-	DBG ( " length %x", len );
158
-	copy_to_user ( buffer, 0, data, len );
159
-	get_cached_info->BufferSize = len;
160
-
161
-	free ( data );
162 182
 	get_cached_info->Status = PXENV_STATUS_SUCCESS;
163 183
 	return PXENV_EXIT_SUCCESS;
164 184
 
165 185
  err:
166
-	if ( data )
167
-		free ( data );
168 186
 	get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES;
169 187
 	return PXENV_EXIT_FAILURE;
170 188
 }
@@ -179,13 +197,18 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
179 197
 
180 198
 	DBG ( "PXENV_RESTART_TFTP " );
181 199
 
182
-	/* Work around Microsoft RIS bug */
183
-	free ( pxe_ris_filename );
184
-	pxe_ris_filename = strdup ( ( char * ) restart_tftp->FileName );
185
-	if ( ! pxe_ris_filename ) {
186
-		restart_tftp->Status = PXENV_STATUS_OUT_OF_RESOURCES;
187
-		return PXENV_EXIT_FAILURE;
188
-	}
200
+	/* This is a bug-for-bug compatibility hack needed in order to
201
+	 * work with Microsoft Remote Installation Services (RIS).
202
+	 * The filename used in a call to PXENV_RESTART_TFTP must be
203
+	 * returned as the DHCP filename in subsequent calls to
204
+	 * PXENV_GET_CACHED_INFO.
205
+	 */
206
+	memcpy ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file,
207
+		 restart_tftp->FileName,
208
+		 sizeof ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file ) );
209
+	memcpy ( cached_info[CACHED_INFO_BINL].dhcphdr.file,
210
+		 restart_tftp->FileName,
211
+		 sizeof ( cached_info[CACHED_INFO_BINL].dhcphdr.file ) );
189 212
 
190 213
 	/* Words cannot describe the complete mismatch between the PXE
191 214
 	 * specification and any possible version of reality...

Завантаження…
Відмінити
Зберегти