2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/misc.h>
20 #include <grub/net/udp.h>
21 #include <grub/net/ip.h>
22 #include <grub/net/ethernet.h>
23 #include <grub/net/netbuff.h>
27 #include <grub/file.h>
28 #include <grub/priority_queue.h>
29 #include <grub/i18n.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
33 /* IP port for the MTFTP server used for Intel's PXE */
36 MTFTP_SERVER_PORT
= 75,
37 MTFTP_CLIENT_PORT
= 76,
38 /* IP port for the TFTP server */
44 TFTP_DEFAULTSIZE_PACKET
= 512,
68 TFTP_EUNDEF
= 0, /* not defined */
69 TFTP_ENOTFOUND
= 1, /* file not found */
70 TFTP_EACCESS
= 2, /* access violation */
71 TFTP_ENOSPACE
= 3, /* disk full or allocation exceeded */
72 TFTP_EBADOP
= 4, /* illegal TFTP operation */
73 TFTP_EBADID
= 5, /* unknown transfer ID */
74 TFTP_EEXISTS
= 6, /* file already exists */
75 TFTP_ENOUSER
= 7 /* no such user */
81 grub_int8_t rrq
[TFTP_DEFAULTSIZE_PACKET
];
84 grub_int8_t download
[0];
90 grub_uint16_t errcode
;
91 grub_int8_t errmsg
[TFTP_DEFAULTSIZE_PACKET
];
94 grub_int8_t data
[TFTP_DEFAULTSIZE_PACKET
+2];
97 } __attribute__ ((packed
)) ;
100 typedef struct tftp_data
102 grub_uint64_t file_size
;
104 grub_uint32_t block_size
;
105 grub_uint32_t ack_sent
;
107 struct grub_error_saved save_err
;
108 grub_net_udp_socket_t sock
;
109 grub_priority_queue_t pq
;
113 cmp (const void *a__
, const void *b__
)
115 struct grub_net_buff
*a_
= *(struct grub_net_buff
**) a__
;
116 struct grub_net_buff
*b_
= *(struct grub_net_buff
**) b__
;
117 struct tftphdr
*a
= (struct tftphdr
*) a_
->data
;
118 struct tftphdr
*b
= (struct tftphdr
*) b_
->data
;
119 /* We want the first elements to be on top. */
120 if (grub_be_to_cpu16 (a
->u
.data
.block
) < grub_be_to_cpu16 (b
->u
.data
.block
))
122 if (grub_be_to_cpu16 (a
->u
.data
.block
) > grub_be_to_cpu16 (b
->u
.data
.block
))
128 ack (tftp_data_t data
, grub_uint16_t block
)
130 struct tftphdr
*tftph_ack
;
131 grub_uint8_t nbdata
[512];
132 struct grub_net_buff nb_ack
;
135 nb_ack
.head
= nbdata
;
136 nb_ack
.end
= nbdata
+ sizeof (nbdata
);
137 grub_netbuff_clear (&nb_ack
);
138 grub_netbuff_reserve (&nb_ack
, 512);
139 err
= grub_netbuff_push (&nb_ack
, sizeof (tftph_ack
->opcode
)
140 + sizeof (tftph_ack
->u
.ack
.block
));
144 tftph_ack
= (struct tftphdr
*) nb_ack
.data
;
145 tftph_ack
->opcode
= grub_cpu_to_be16 (TFTP_ACK
);
146 tftph_ack
->u
.ack
.block
= block
;
148 err
= grub_net_send_udp_packet (data
->sock
, &nb_ack
);
151 data
->ack_sent
= block
;
152 return GRUB_ERR_NONE
;
156 tftp_receive (grub_net_udp_socket_t sock
__attribute__ ((unused
)),
157 struct grub_net_buff
*nb
,
160 grub_file_t file
= f
;
161 struct tftphdr
*tftph
= (void *) nb
->data
;
162 tftp_data_t data
= file
->data
;
166 if (nb
->tail
- nb
->data
< (grub_ssize_t
) sizeof (tftph
->opcode
))
168 grub_dprintf ("tftp", "TFTP packet too small\n");
169 return GRUB_ERR_NONE
;
172 tftph
= (struct tftphdr
*) nb
->data
;
173 switch (grub_be_to_cpu16 (tftph
->opcode
))
176 data
->block_size
= TFTP_DEFAULTSIZE_PACKET
;
178 for (ptr
= nb
->data
+ sizeof (tftph
->opcode
); ptr
< nb
->tail
;)
180 if (grub_memcmp (ptr
, "tsize\0", sizeof ("tsize\0") - 1) == 0)
181 data
->file_size
= grub_strtoul ((char *) ptr
+ sizeof ("tsize\0")
183 if (grub_memcmp (ptr
, "blksize\0", sizeof ("blksize\0") - 1) == 0)
184 data
->block_size
= grub_strtoul ((char *) ptr
+ sizeof ("blksize\0")
186 while (ptr
< nb
->tail
&& *ptr
)
191 grub_netbuff_free (nb
);
193 grub_error_save (&data
->save_err
);
194 return GRUB_ERR_NONE
;
196 if (nb
->tail
- nb
->data
< (grub_ssize_t
) (sizeof (tftph
->opcode
)
197 + sizeof (tftph
->u
.data
.block
)))
199 grub_dprintf ("tftp", "TFTP packet too small\n");
200 return GRUB_ERR_NONE
;
203 err
= grub_priority_queue_push (data
->pq
, &nb
);
208 struct grub_net_buff
**nb_top_p
, *nb_top
;
211 nb_top_p
= grub_priority_queue_top (data
->pq
);
213 return GRUB_ERR_NONE
;
215 tftph
= (struct tftphdr
*) nb_top
->data
;
216 if (grub_be_to_cpu16 (tftph
->u
.data
.block
) >= data
->block
+ 1)
218 grub_netbuff_free (nb_top
);
219 grub_priority_queue_pop (data
->pq
);
221 if (grub_be_to_cpu16 (tftph
->u
.data
.block
) == data
->block
+ 1)
225 grub_priority_queue_pop (data
->pq
);
227 if (file
->device
->net
->packs
.count
< 50)
228 err
= ack (data
, tftph
->u
.data
.block
);
231 file
->device
->net
->stall
= 1;
237 err
= grub_netbuff_pull (nb_top
, sizeof (tftph
->opcode
) +
238 sizeof (tftph
->u
.data
.block
));
241 size
= nb_top
->tail
- nb_top
->data
;
244 if (size
< data
->block_size
)
246 file
->device
->net
->eof
= 1;
247 file
->device
->net
->stall
= 1;
248 grub_net_udp_close (data
->sock
);
251 /* Prevent garbage in broken cards. Is it still necessary
252 given that IP implementation has been fixed?
254 if (size
> data
->block_size
)
256 err
= grub_netbuff_unput (nb_top
, size
- data
->block_size
);
260 /* If there is data, puts packet in socket list. */
261 if ((nb_top
->tail
- nb_top
->data
) > 0)
262 grub_net_put_packet (&file
->device
->net
->packs
, nb_top
);
264 grub_netbuff_free (nb_top
);
267 return GRUB_ERR_NONE
;
270 grub_netbuff_free (nb
);
271 grub_error (GRUB_ERR_IO
, (char *) tftph
->u
.err
.errmsg
);
272 grub_error_save (&data
->save_err
);
273 return GRUB_ERR_NONE
;
275 grub_netbuff_free (nb
);
276 return GRUB_ERR_NONE
;
281 destroy_pq (tftp_data_t data
)
283 struct grub_net_buff
**nb_p
;
284 while ((nb_p
= grub_priority_queue_top (data
->pq
)))
286 grub_netbuff_free (*nb_p
);
287 grub_priority_queue_pop (data
->pq
);
290 grub_priority_queue_destroy (data
->pq
);
294 tftp_open (struct grub_file
*file
, const char *filename
)
296 struct tftphdr
*tftph
;
301 grub_uint8_t open_data
[1500];
302 struct grub_net_buff nb
;
306 grub_net_network_level_address_t addr
;
308 data
= grub_zalloc (sizeof (*data
));
313 nb
.end
= open_data
+ sizeof (open_data
);
314 grub_netbuff_clear (&nb
);
316 grub_netbuff_reserve (&nb
, 1500);
317 err
= grub_netbuff_push (&nb
, sizeof (*tftph
));
321 tftph
= (struct tftphdr
*) nb
.data
;
323 rrq
= (char *) tftph
->u
.rrq
;
326 tftph
->opcode
= grub_cpu_to_be16 (TFTP_RRQ
);
327 grub_strcpy (rrq
, filename
);
328 rrqlen
+= grub_strlen (filename
) + 1;
329 rrq
+= grub_strlen (filename
) + 1;
331 grub_strcpy (rrq
, "octet");
332 rrqlen
+= grub_strlen ("octet") + 1;
333 rrq
+= grub_strlen ("octet") + 1;
335 grub_strcpy (rrq
, "blksize");
336 rrqlen
+= grub_strlen ("blksize") + 1;
337 rrq
+= grub_strlen ("blksize") + 1;
339 grub_strcpy (rrq
, "1024");
340 rrqlen
+= grub_strlen ("1024") + 1;
341 rrq
+= grub_strlen ("1024") + 1;
343 grub_strcpy (rrq
, "tsize");
344 rrqlen
+= grub_strlen ("tsize") + 1;
345 rrq
+= grub_strlen ("tsize") + 1;
347 grub_strcpy (rrq
, "0");
348 rrqlen
+= grub_strlen ("0") + 1;
349 rrq
+= grub_strlen ("0") + 1;
350 hdrlen
= sizeof (tftph
->opcode
) + rrqlen
;
352 err
= grub_netbuff_unput (&nb
, nb
.tail
- (nb
.data
+ hdrlen
));
356 file
->not_easily_seekable
= 1;
359 data
->pq
= grub_priority_queue_new (sizeof (struct grub_net_buff
*), cmp
);
363 err
= grub_net_resolve_address (file
->device
->net
->server
, &addr
);
370 data
->sock
= grub_net_udp_open (addr
,
371 TFTP_SERVER_PORT
, tftp_receive
,
379 /* Receive OACK packet. */
381 for (i
= 0; i
< GRUB_NET_TRIES
; i
++)
384 err
= grub_net_send_udp_packet (data
->sock
, &nb
);
387 grub_net_udp_close (data
->sock
);
391 grub_net_poll_cards (GRUB_NET_INTERVAL
, &data
->have_oack
);
396 if (!data
->have_oack
)
397 grub_error (GRUB_ERR_TIMEOUT
, N_("time out opening `%s'"), filename
);
399 grub_error_load (&data
->save_err
);
402 grub_net_udp_close (data
->sock
);
407 file
->size
= data
->file_size
;
409 return GRUB_ERR_NONE
;
413 tftp_close (struct grub_file
*file
)
415 tftp_data_t data
= file
->data
;
419 grub_uint8_t nbdata
[512];
421 struct grub_net_buff nb_err
;
422 struct tftphdr
*tftph
;
424 nb_err
.head
= nbdata
;
425 nb_err
.end
= nbdata
+ sizeof (nbdata
);
427 grub_netbuff_clear (&nb_err
);
428 grub_netbuff_reserve (&nb_err
, 512);
429 err
= grub_netbuff_push (&nb_err
, sizeof (tftph
->opcode
)
430 + sizeof (tftph
->u
.err
.errcode
)
431 + sizeof ("closed"));
434 tftph
= (struct tftphdr
*) nb_err
.data
;
435 tftph
->opcode
= grub_cpu_to_be16 (TFTP_ERROR
);
436 tftph
->u
.err
.errcode
= grub_cpu_to_be16 (TFTP_EUNDEF
);
437 grub_memcpy (tftph
->u
.err
.errmsg
, "closed", sizeof ("closed"));
439 err
= grub_net_send_udp_packet (data
->sock
, &nb_err
);
443 grub_net_udp_close (data
->sock
);
447 return GRUB_ERR_NONE
;
451 tftp_packets_pulled (struct grub_file
*file
)
453 tftp_data_t data
= file
->data
;
454 if (file
->device
->net
->packs
.count
>= 50)
457 if (!file
->device
->net
->eof
)
458 file
->device
->net
->stall
= 0;
459 if (data
->ack_sent
>= data
->block
)
461 return ack (data
, data
->block
);
464 static struct grub_net_app_protocol grub_tftp_protocol
=
469 .packets_pulled
= tftp_packets_pulled
474 grub_net_app_level_register (&grub_tftp_protocol
);
479 grub_net_app_level_unregister (&grub_tftp_protocol
);