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 com32sys_t ireg
, oreg
;
57 t_PXENV_UDP_WRITE
*uw
;
60 static const clock_t timeouts
[] = {
61 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31,
62 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0
64 const clock_t *timeout
;
67 uw
= lmalloc(sizeof *uw
+ len
);
68 ur
= lmalloc(sizeof *ur
+ RCV_BUF
);
70 memset(&ireg
, 0, sizeof ireg
);
71 ireg
.eax
.w
[0] = 0x0009;
73 for (timeout
= timeouts
; *timeout
; timeout
++) {
74 memset(uw
, 0, sizeof *uw
);
75 memcpy(uw
+1, pkt
, len
);
76 uw
->ip
= tftp
->srv_ip
;
77 uw
->gw
= tftp
->srv_gw
;
78 uw
->src_port
= tftp
->my_port
;
79 uw
->dst_port
= tftp
->srv_port
? tftp
->srv_port
: htons(69);
80 uw
->buffer_size
= len
;
81 uw
->buffer
= FAR_PTR(uw
+1);
83 ireg
.ebx
.w
[0] = PXENV_UDP_WRITE
;
85 ireg
.edi
.w
[0] = OFFS(uw
);
87 __intcall(0x22, &ireg
, &oreg
);
92 memset(ur
, 0, sizeof *ur
);
93 ur
->src_ip
= tftp
->srv_ip
;
94 ur
->dest_ip
= tftp
->my_ip
;
95 ur
->s_port
= tftp
->srv_port
;
96 ur
->d_port
= tftp
->my_port
;
97 ur
->buffer_size
= RCV_BUF
;
98 ur
->buffer
= FAR_PTR(ur
+1);
100 ireg
.ebx
.w
[0] = PXENV_UDP_READ
;
102 ireg
.edi
.w
[0] = OFFS(ur
);
103 __intcall(0x22, &ireg
, &oreg
);
105 if (!(oreg
.eflags
.l
& EFLAGS_CF
) &&
106 ur
->status
== PXENV_STATUS_SUCCESS
&&
107 tftp
->srv_ip
== ur
->src_ip
&&
108 (tftp
->srv_port
== 0 ||
109 tftp
->srv_port
== ur
->s_port
)) {
110 uint16_t *xb
= (uint16_t *)(ur
+1);
111 if (ntohs(xb
[0]) == TFTP_ACK
&&
112 ntohs(xb
[1]) == tftp
->seq
) {
113 tftp
->srv_port
= ur
->s_port
;
114 err
= TFTP_OK
; /* All good! */
116 } else if (ntohs(xb
[0]) == TFTP_ERROR
) {
117 struct tftp_error
*te
= (struct tftp_error
*)(ur
+1);
118 if (te
->errcode
== TFTP_ERR_UNKNOWN_ERROR
) {
119 tftp_string_error_message
[TFTP_ERR_UNKNOWN_ERROR
]=strdup(te
->errmsg
);
121 err
=-ntohs(te
->errcode
); // Return the associated error code
125 } while ((clock_t)(times(NULL
) - start
) < *timeout
);
135 static int upload_tftp_write(struct upload_backend
*be
)
137 static uint16_t local_port
= 0x4000;
138 struct tftp_state tftp
;
139 char buffer
[512+4+6];
142 const union syslinux_derivative_info
*sdi
=
143 syslinux_derivative_info();
144 const char *data
= be
->outbuf
;
145 size_t len
= be
->zbytes
;
148 tftp
.my_ip
= sdi
->pxe
.myip
;
149 tftp
.my_port
= htons(local_port
++);
150 tftp
.srv_gw
= ((tftp
.srv_ip
^ tftp
.my_ip
) & sdi
->pxe
.ipinfo
->netmask
)
151 ? sdi
->pxe
.ipinfo
->gateway
: 0;
156 tftp
.srv_ip
= pxe_dns(be
->argv
[1]);
158 // printf("\nUnable to resolve hostname: %s\n", be->argv[1]);
159 return -TFTP_ERR_UNABLE_TO_RESOLVE
;
162 tftp
.srv_ip
= sdi
->pxe
.ipinfo
->serverip
;
164 // printf("\nNo server IP address\n");
165 return -TFTP_ERR_UNABLE_TO_CONNECT
;
169 /* printf("server %u.%u.%u.%u... ",
170 ((uint8_t *)&tftp.srv_ip)[0],
171 ((uint8_t *)&tftp.srv_ip)[1],
172 ((uint8_t *)&tftp.srv_ip)[2],
173 ((uint8_t *)&tftp.srv_ip)[3]);*/
176 buffer
[1] = TFTP_WRQ
;
177 nlen
= strlcpy(buffer
+2, be
->argv
[0], 512);
178 memcpy(buffer
+3+nlen
, "octet", 6);
180 if ((err
=send_ack_packet(&tftp
, buffer
, 2+nlen
+1+6))!=TFTP_OK
)
184 chunk
= len
>= 512 ? 512 : len
;
186 buffer
[1] = TFTP_DATA
;
187 *((uint16_t *)(buffer
+2)) = htons(++tftp
.seq
);
188 memcpy(buffer
+4, data
, chunk
);
192 if ((err
=send_ack_packet(&tftp
, buffer
, chunk
+4))!=TFTP_OK
)
194 } while (chunk
== 512);
199 struct upload_backend upload_tftp
= {
201 .helpmsg
= "filename [tftp_server]",
203 .write
= upload_tftp_write
,