]> git.proxmox.com Git - grub2.git/blame - grub-core/net/tftp.c
Write ChangeLog.
[grub2.git] / grub-core / net / tftp.c
CommitLineData
7bb47706
MA
1#include <grub/misc.h>
2#include <grub/net/tftp.h>
3#include <grub/net/udp.h>
4#include <grub/net/ip.h>
5#include <grub/net/ethernet.h>
6#include <grub/net/netbuff.h>
7bb47706
MA
7#include <grub/net.h>
8#include <grub/mm.h>
9#include <grub/dl.h>
10#include <grub/file.h>
11
48ac061a
MA
12GRUB_MOD_LICENSE ("GPLv3+");
13
7bb47706
MA
14static grub_err_t
15tftp_open (struct grub_file *file, const char *filename)
16{
17 struct tftphdr *tftph;
18 char *rrq;
25f1579b 19 int i;
7bb47706 20 int rrqlen;
25f1579b
MRA
21 int hdrlen;
22 char open_data[1500];
23 struct grub_net_buff nb;
eea84144 24 tftp_data_t data;
7bb47706 25 grub_err_t err;
eea84144
VS
26
27 data = grub_malloc (sizeof *data);
28 if (!data)
29 return grub_errno;
25f1579b
MRA
30
31 file->device->net->socket->data = (void *) data;
32 nb.head = open_data;
33 nb.end = open_data + sizeof (open_data);
34 grub_netbuff_clear (&nb);
7bb47706 35
25f1579b
MRA
36 grub_netbuff_reserve (&nb,1500);
37 grub_netbuff_push (&nb,sizeof (*tftph));
04d22ddd 38
25f1579b 39 tftph = (struct tftphdr *) nb.data;
7bb47706
MA
40
41 rrq = (char *) tftph->u.rrq;
42 rrqlen = 0;
43
04d22ddd 44 tftph->opcode = grub_cpu_to_be16 (TFTP_RRQ);
7bb47706
MA
45 grub_strcpy (rrq, filename);
46 rrqlen += grub_strlen (filename) + 1;
47 rrq += grub_strlen (filename) + 1;
7bb47706
MA
48
49 grub_strcpy (rrq,"octet");
50 rrqlen += grub_strlen ("octet") + 1;
51 rrq += grub_strlen ("octet") + 1;
52
7bb47706
MA
53 grub_strcpy (rrq,"blksize");
54 rrqlen += grub_strlen("blksize") + 1;
55 rrq += grub_strlen ("blksize") + 1;
56
57 grub_strcpy (rrq,"1024");
58 rrqlen += grub_strlen ("1024") + 1;
59 rrq += grub_strlen ("1024") + 1;
60
61 grub_strcpy (rrq,"tsize");
62 rrqlen += grub_strlen ("tsize") + 1;
63 rrq += grub_strlen ("tsize") + 1;
64
65 grub_strcpy (rrq,"0");
66 rrqlen += grub_strlen ("0") + 1;
04d22ddd 67 rrq += grub_strlen ("0") + 1;
7bb47706
MA
68 hdrlen = sizeof (tftph->opcode) + rrqlen;
69
25f1579b
MRA
70 grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen));
71
72 file->device->net->socket->out_port = TFTP_SERVER_PORT;
04d22ddd 73
25f1579b 74 err = grub_net_send_udp_packet (file->device->net->socket, &nb);
04d22ddd
VS
75 if (err)
76 return err;
77
25f1579b
MRA
78 /* Receive OACK packet. */
79 for ( i = 0; i < 3; i++)
04d22ddd 80 {
eea84144 81 grub_net_poll_cards (100);
25f1579b
MRA
82 if (grub_errno)
83 return grub_errno;
84 if (file->device->net->socket->status != 0)
85 break;
86 /* Retry. */
423a1849
MRA
87 /*err = grub_net_send_udp_packet (file->device->net->socket, &nb);
88 if (err)
89 return err;*/
04d22ddd 90 }
7bb47706 91
25f1579b
MRA
92 if (file->device->net->socket->status == 0)
93 return grub_error (GRUB_ERR_TIMEOUT,"Time out opening tftp.");
94 file->size = data->file_size;
7bb47706 95
04d22ddd 96 return GRUB_ERR_NONE;
7bb47706
MA
97}
98
25f1579b
MRA
99static grub_err_t
100tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
7bb47706
MA
101{
102 struct tftphdr *tftph;
25f1579b
MRA
103 char nbdata[128];
104 tftp_data_t data = sock->data;
7bb47706 105 grub_err_t err;
25f1579b
MRA
106 char *ptr;
107 struct grub_net_buff nb_ack;
108
109 nb_ack.head = nbdata;
110 nb_ack.end = nbdata + sizeof (nbdata);
7bb47706 111
7bb47706 112
25f1579b 113 tftph = (struct tftphdr *) nb->data;
04d22ddd 114 switch (grub_be_to_cpu16 (tftph->opcode))
7bb47706 115 {
25f1579b 116 case TFTP_OACK:
eea84144 117 for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail; )
25f1579b
MRA
118 {
119 if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
eea84144
VS
120 {
121 data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
122 0, 0);
123 }
25f1579b
MRA
124 while (ptr < nb->tail && *ptr)
125 ptr++;
126 ptr++;
127 }
128 sock->status = 1;
129 data->block = 0;
130 grub_netbuff_clear(nb);
131 break;
7bb47706 132 case TFTP_DATA:
25f1579b
MRA
133 grub_netbuff_pull (nb,sizeof (tftph->opcode) + sizeof (tftph->u.data.block));
134
135 if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
136 {
137 data->block++;
0696f08f
MRA
138 unsigned size = nb->tail - nb->data;
139 if (size < 1024)
25f1579b 140 sock->status = 2;
0696f08f
MRA
141 /* Prevent garbage in broken cards. */
142 if (size > 1024)
143 grub_netbuff_unput (nb, size - 1024);
25f1579b
MRA
144 }
145 else
146 grub_netbuff_clear(nb);
147
148 break;
7bb47706 149 case TFTP_ERROR:
25f1579b 150 grub_netbuff_clear (nb);
04d22ddd 151 return grub_error (GRUB_ERR_IO, (char *)tftph->u.err.errmsg);
25f1579b 152 break;
7bb47706 153 }
25f1579b
MRA
154 grub_netbuff_clear (&nb_ack);
155 grub_netbuff_reserve (&nb_ack,128);
156 grub_netbuff_push (&nb_ack,sizeof (tftph->opcode) + sizeof (tftph->u.ack.block));
7bb47706 157
25f1579b 158 tftph = (struct tftphdr *) nb_ack.data;
04d22ddd 159 tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
eea84144 160 tftph->u.ack.block = grub_cpu_to_be16 (data->block);
7bb47706 161
25f1579b
MRA
162 err = grub_net_send_udp_packet (sock, &nb_ack);
163 return err;
7bb47706
MA
164}
165
166static grub_err_t
167tftp_close (struct grub_file *file __attribute__ ((unused)))
168{
31b5172b
MRA
169 grub_free (file->device->net->socket->data);
170 return GRUB_ERR_NONE;
7bb47706
MA
171}
172
25f1579b 173static struct grub_net_app_protocol grub_tftp_protocol =
7bb47706
MA
174{
175 .name = "tftp",
176 .open = tftp_open,
177 .read = tftp_receive,
178 .close = tftp_close
179};
180
181GRUB_MOD_INIT (tftp)
182{
183 grub_net_app_level_register (&grub_tftp_protocol);
184}
185
186GRUB_MOD_FINI (tftp)
187{
188 grub_net_app_level_unregister (&grub_tftp_protocol);
189}