2 * TFTP data output backend
7 #include <syslinux/pxe.h>
8 #include <syslinux/config.h>
9 #include <netinet/in.h>
10 #include <sys/times.h>
11 #include "upload_backend.h"
25 } __attribute__ (( packed
));
36 const char *tftp_string_error_message
[]={
42 "Unknown Transfert ID",
43 "File already exists",
46 "Unable to resolve hostname", // not in RFC
47 "Unable to connect", // not in RFC
53 static int send_ack_packet(struct tftp_state
*tftp
,
54 const void *pkt
, size_t len
)
56 t_PXENV_UDP_WRITE
*uw
;
59 static const clock_t timeouts
[] = {
60 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31,
61 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0
63 const clock_t *timeout
;
66 uw
= lmalloc(sizeof *uw
+ len
);
67 ur
= lmalloc(sizeof *ur
+ RCV_BUF
);
69 for (timeout
= timeouts
; *timeout
; timeout
++) {
70 memset(uw
, 0, sizeof *uw
);
71 memcpy(uw
+1, pkt
, len
);
72 uw
->ip
= tftp
->srv_ip
;
73 uw
->gw
= tftp
->srv_gw
;
74 uw
->src_port
= tftp
->my_port
;
75 uw
->dst_port
= tftp
->srv_port
? tftp
->srv_port
: htons(69);
76 uw
->buffer_size
= len
;
77 uw
->buffer
= FAR_PTR(uw
+1);
79 pxe_call(PXENV_UDP_WRITE
, uw
);
84 memset(ur
, 0, sizeof *ur
);
85 ur
->src_ip
= tftp
->srv_ip
;
86 ur
->dest_ip
= tftp
->my_ip
;
87 ur
->s_port
= tftp
->srv_port
;
88 ur
->d_port
= tftp
->my_port
;
89 ur
->buffer_size
= RCV_BUF
;
90 ur
->buffer
= FAR_PTR(ur
+1);
92 err
= pxe_call(PXENV_UDP_READ
, ur
);
94 if (!err
&& ur
->status
== PXENV_STATUS_SUCCESS
&&
95 tftp
->srv_ip
== ur
->src_ip
&&
96 (tftp
->srv_port
== 0 ||
97 tftp
->srv_port
== ur
->s_port
)) {
98 uint16_t *xb
= (uint16_t *)(ur
+1);
99 if (ntohs(xb
[0]) == TFTP_ACK
&&
100 ntohs(xb
[1]) == tftp
->seq
) {
101 tftp
->srv_port
= ur
->s_port
;
102 err
= TFTP_OK
; /* All good! */
104 } else if (ntohs(xb
[0]) == TFTP_ERROR
) {
105 struct tftp_error
*te
= (struct tftp_error
*)(ur
+1);
106 if (te
->errcode
== TFTP_ERR_UNKNOWN_ERROR
) {
107 tftp_string_error_message
[TFTP_ERR_UNKNOWN_ERROR
]=strdup(te
->errmsg
);
109 err
=-ntohs(te
->errcode
); // Return the associated error code
113 } while ((clock_t)(times(NULL
) - start
) < *timeout
);
123 static int upload_tftp_write(struct upload_backend
*be
)
125 static uint16_t local_port
= 0x4000;
126 struct tftp_state tftp
;
127 char buffer
[512+4+6];
130 const union syslinux_derivative_info
*sdi
=
131 syslinux_derivative_info();
132 const char *data
= be
->outbuf
;
133 size_t len
= be
->zbytes
;
136 tftp
.my_ip
= sdi
->pxe
.myip
;
137 tftp
.my_port
= htons(local_port
++);
138 tftp
.srv_gw
= ((tftp
.srv_ip
^ tftp
.my_ip
) & sdi
->pxe
.ipinfo
->netmask
)
139 ? sdi
->pxe
.ipinfo
->gateway
: 0;
144 tftp
.srv_ip
= pxe_dns(be
->argv
[1]);
146 // printf("\nUnable to resolve hostname: %s\n", be->argv[1]);
147 return -TFTP_ERR_UNABLE_TO_RESOLVE
;
150 tftp
.srv_ip
= sdi
->pxe
.ipinfo
->serverip
;
152 // printf("\nNo server IP address\n");
153 return -TFTP_ERR_UNABLE_TO_CONNECT
;
157 /* printf("server %u.%u.%u.%u... ",
158 ((uint8_t *)&tftp.srv_ip)[0],
159 ((uint8_t *)&tftp.srv_ip)[1],
160 ((uint8_t *)&tftp.srv_ip)[2],
161 ((uint8_t *)&tftp.srv_ip)[3]);*/
164 buffer
[1] = TFTP_WRQ
;
165 nlen
= strlcpy(buffer
+2, be
->argv
[0], 512);
166 memcpy(buffer
+3+nlen
, "octet", 6);
168 if ((err
=send_ack_packet(&tftp
, buffer
, 2+nlen
+1+6))!=TFTP_OK
)
172 chunk
= len
>= 512 ? 512 : len
;
174 buffer
[1] = TFTP_DATA
;
175 *((uint16_t *)(buffer
+2)) = htons(++tftp
.seq
);
176 memcpy(buffer
+4, data
, chunk
);
180 if ((err
=send_ack_packet(&tftp
, buffer
, chunk
+4))!=TFTP_OK
)
182 } while (chunk
== 512);
187 struct upload_backend upload_tftp
= {
189 .helpmsg
= "filename [tftp_server]",
191 .write
= upload_tftp_write
,