2 * TFTP data output backend
6 #include <syslinux/pxe.h>
7 #include <syslinux/config.h>
8 #include <netinet/in.h>
32 static int send_ack_packet(struct tftp_state
*tftp
,
33 const void *pkt
, size_t len
)
35 com32sys_t ireg
, oreg
;
36 t_PXENV_UDP_WRITE
*uw
;
39 static const clock_t timeouts
[] = {
40 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31,
41 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0
43 const clock_t *timeout
;
46 uw
= lmalloc(sizeof *uw
+ len
);
47 ur
= lmalloc(sizeof *ur
+ RCV_BUF
);
49 memset(&ireg
, 0, sizeof ireg
);
50 ireg
.eax
.w
[0] = 0x0009;
52 for (timeout
= timeouts
; *timeout
; timeout
++) {
53 memset(uw
, 0, sizeof uw
);
54 memcpy(uw
+1, pkt
, len
);
55 uw
->ip
= tftp
->srv_ip
;
56 uw
->gw
= tftp
->srv_gw
;
57 uw
->src_port
= tftp
->my_port
;
58 uw
->dst_port
= tftp
->srv_port
? tftp
->srv_port
: htons(69);
59 uw
->buffer_size
= len
;
60 uw
->buffer
= FAR_PTR(uw
+1);
62 ireg
.ebx
.w
[0] = PXENV_UDP_WRITE
;
64 ireg
.edi
.w
[0] = OFFS(uw
);
66 __intcall(0x22, &ireg
, &oreg
);
71 memset(ur
, 0, sizeof ur
);
72 ur
->src_ip
= tftp
->srv_ip
;
73 ur
->dest_ip
= tftp
->my_ip
;
74 ur
->s_port
= tftp
->srv_port
;
75 ur
->d_port
= tftp
->my_port
;
76 ur
->buffer_size
= RCV_BUF
;
77 ur
->buffer
= FAR_PTR(ur
+1);
79 ireg
.ebx
.w
[0] = PXENV_UDP_READ
;
81 ireg
.edi
.w
[0] = OFFS(ur
);
82 __intcall(0x22, &ireg
, &oreg
);
84 if (!(oreg
.eflags
.l
& EFLAGS_CF
) &&
85 ur
->status
== PXENV_STATUS_SUCCESS
&&
86 tftp
->srv_ip
== ur
->src_ip
&&
87 (tftp
->srv_port
== 0 ||
88 tftp
->srv_port
== ur
->s_port
)) {
89 uint16_t *xb
= (uint16_t *)(ur
+1);
90 if (ntohs(xb
[0]) == TFTP_ACK
&&
91 ntohs(xb
[1]) == tftp
->seq
) {
92 tftp
->srv_port
= ur
->s_port
;
93 err
= 0; /* All good! */
95 } else if (ntohs(xb
[1]) == TFTP_ERROR
) {
99 } while ((clock_t)(times(NULL
) - start
) < *timeout
);
109 static int be_tftp_write(struct backend
*be
)
111 static uint16_t local_port
= 0x4000;
112 struct tftp_state tftp
;
113 char buffer
[512+4+6];
115 const union syslinux_derivative_info
*sdi
=
116 syslinux_derivative_info();
117 const char *data
= be
->outbuf
;
118 size_t len
= be
->zbytes
;
121 tftp
.my_ip
= sdi
->pxe
.myip
;
122 tftp
.my_port
= htons(local_port
++);
123 tftp
.srv_ip
= pxe_dns(be
->argv
[1]);
124 tftp
.srv_gw
= ((tftp
.srv_ip
^ tftp
.my_ip
) & sdi
->pxe
.ipinfo
->netmask
)
125 ? sdi
->pxe
.ipinfo
->gateway
: 0;
130 buffer
[1] = TFTP_WRQ
;
131 nlen
= strlcpy(buffer
+2, be
->argv
[0], 512);
132 memcpy(buffer
+3+nlen
, "octet", 6);
134 if (send_ack_packet(&tftp
, buffer
, 2+nlen
+1+6))
138 chunk
= len
>= 512 ? 512 : len
;
140 buffer
[1] = TFTP_DATA
;
141 *((uint16_t *)(buffer
+2)) = htons(++tftp
.seq
);
142 memcpy(buffer
+4, data
, chunk
);
146 if (send_ack_packet(&tftp
, buffer
, chunk
+4))
148 } while (chunk
== 512);
153 struct backend be_tftp
= {
155 .helpmsg
= "filename tftp_server",
157 .write
= be_tftp_write
,