|
@@ -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
|
|