Browse Source

Implement enough of PXENV_GET_CACHED_INFO to support pxelinux.

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
f018da8215
1 changed files with 58 additions and 59 deletions
  1. 58
    59
      src/interface/pxe/pxe_preboot.c

+ 58
- 59
src/interface/pxe/pxe_preboot.c View File

@@ -23,6 +23,11 @@
23 23
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 24
  */
25 25
 
26
+#include <stdint.h>
27
+#include <string.h>
28
+#include <malloc.h>
29
+#include <gpxe/uaccess.h>
30
+#include <gpxe/dhcp.h>
26 31
 #include "pxe.h"
27 32
 #include "pxe_callbacks.h"
28 33
 
@@ -34,8 +39,6 @@
34 39
  *
35 40
  */
36 41
 PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
37
-	int success;
38
-
39 42
 	DBG ( "PXENV_UNLOAD_STACK" );
40 43
 
41 44
 #if 0
@@ -68,68 +71,67 @@ PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
68 71
  */
69 72
 PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
70 73
 				     *get_cached_info ) {
71
-	DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
74
+	struct dhcp_packet dhcppkt;
75
+	void *data = NULL;
76
+	size_t len;
77
+	int msgtype;
78
+	struct dhcp_option_block *options;
79
+	userptr_t buffer;
80
+	int rc;
72 81
 
73
-#if 0
74
-	/* Fill in cached_info structure in our pxe_stack */
82
+	DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
75 83
 
76
-	/* I don't think there's actually any way we can be called in
77
-	 * the middle of a DHCP request... 
78
-	 */
79
-	cached_info->opcode = BOOTP_REP;
80
-	/* We only have Ethernet drivers */
81
-	cached_info->Hardware = ETHER_TYPE;
82
-	cached_info->Hardlen = ETH_ALEN;
83
-	/* PXESPEC: "Client sets" says the spec, but who's filling in
84
-	 * this structure?  It ain't the client.
84
+	/* This is really, really awkward to support with our multiple
85
+	 * sources of options.
85 86
 	 */
86
-	cached_info->Gatehops = 0;
87
-	cached_info->ident = 0;
88
-	cached_info->seconds = 0;
89
-	cached_info->Flags = BOOTP_BCAST;
90
-	/* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
91
-	cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
92
-	cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
93
-	cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
94
-	/* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
95
-	cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
96
-	memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
97
-	/* Nullify server name */
98
-	cached_info->Sname[0] = '\0';
99
-	memcpy ( cached_info->bootfile, KERNEL_BUF,
100
-		 sizeof(cached_info->bootfile) );
101
-	/* Copy DHCP vendor options */
102
-	memcpy ( &cached_info->vendor.d, bootp_data.bootp_reply.bp_vend,
103
-		 sizeof(cached_info->vendor.d) );
104
-	
105
-	/* Copy to user-specified buffer, or set pointer to our buffer */
106
-	get_cached_info->BufferLimit = sizeof(*cached_info);
107
-	/* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
108
-	 * 0, but what are we supposed to do with a null buffer of
109
-	 * non-zero size?!
110
-	 */
111
-	if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
112
-		/* Point back to our buffer */
113
-		PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
114
-		get_cached_info->BufferSize = sizeof(*cached_info);
87
+	if ( get_cached_info->BufferLimit == 0 ) {
88
+		DBG ( " without an external buffer.  Aargh." );
89
+		goto err;
90
+	}
91
+
92
+	DBG ( " to %04x:%04x+%x\n", get_cached_info->Buffer.segment,
93
+	      get_cached_info->Buffer.offset, get_cached_info->BufferLimit );
94
+
95
+	/* Allocate space for temporary copy */
96
+	len = get_cached_info->BufferLimit;
97
+	data = malloc ( len );
98
+	if ( ! data ) {
99
+		DBG ( " out of memory" );
100
+		goto err;
101
+	}
102
+
103
+	/* Construct DHCP packet */
104
+	if ( get_cached_info->PacketType == PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
105
+		msgtype = DHCPDISCOVER;
106
+		options = &dhcp_request_options;
115 107
 	} else {
116
-		/* Copy to user buffer */
117
-		size_t size = sizeof(*cached_info);
118
-		void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
119
-		if ( get_cached_info->BufferSize < size )
120
-			size = get_cached_info->BufferSize;
121
-		DBG ( " to %x", virt_to_phys ( buffer ) );
122
-		memcpy ( buffer, cached_info, size );
123
-		/* PXESPEC: Should we return an error if the user
124
-		 * buffer is too small?  We do return the actual size
125
-		 * of the buffer via BufferLimit, so the user does
126
-		 * have a way to detect this already.
127
-		 */
108
+		msgtype = DHCPACK;
109
+		options = NULL;
110
+	}
111
+	if ( ( rc = create_dhcp_packet ( pxe_netdev, msgtype, data, len,
112
+					 &dhcppkt ) ) != 0 ) {
113
+		DBG ( " failed to build packet" );
114
+		goto err;
115
+	}
116
+	if ( ( rc = copy_dhcp_packet_options ( &dhcppkt, options ) ) != 0 ) {
117
+		DBG ( " failed to copy options" );
118
+		goto err;
128 119
 	}
129
-#endif
130 120
 
121
+	/* Copy packet to client buffer */
122
+	buffer = real_to_user ( get_cached_info->Buffer.segment,
123
+				get_cached_info->Buffer.offset );
124
+	copy_to_user ( buffer, 0, data, len );
125
+
126
+	free ( data );
131 127
 	get_cached_info->Status = PXENV_STATUS_SUCCESS;
132 128
 	return PXENV_EXIT_SUCCESS;
129
+
130
+ err:
131
+	if ( data )
132
+		free ( data );
133
+	get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES;
134
+	return PXENV_EXIT_FAILURE;
133 135
 }
134 136
 
135 137
 /* PXENV_RESTART_TFTP
@@ -138,8 +140,6 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
138 140
  */
139 141
 PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
140 142
 				  *restart_tftp ) {
141
-	PXENV_EXIT_t tftp_exit;
142
-
143 143
 	DBG ( "PXENV_RESTART_TFTP" );
144 144
 
145 145
 #if 0
@@ -168,7 +168,6 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
168 168
  * Status: working
169 169
  */
170 170
 PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
171
-	unsigned char bus, devfn;
172 171
 
173 172
 	DBG ( "PXENV_START_UNDI" );
174 173
 

Loading…
Cancel
Save