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>
33 static int send_ack_packet(struct tftp_state
*tftp
,
34 const void *pkt
, size_t len
)
36 com32sys_t ireg
, oreg
;
37 t_PXENV_UDP_WRITE
*uw
;
40 static const clock_t timeouts
[] = {
41 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31,
42 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0
44 const clock_t *timeout
;
47 uw
= lmalloc(sizeof *uw
+ len
);
48 ur
= lmalloc(sizeof *ur
+ RCV_BUF
);
50 memset(&ireg
, 0, sizeof ireg
);
51 ireg
.eax
.w
[0] = 0x0009;
53 for (timeout
= timeouts
; *timeout
; timeout
++) {
54 memset(uw
, 0, sizeof uw
);
55 memcpy(uw
+1, pkt
, len
);
56 uw
->ip
= tftp
->srv_ip
;
57 uw
->gw
= tftp
->srv_gw
;
58 uw
->src_port
= tftp
->my_port
;
59 uw
->dst_port
= tftp
->srv_port
? tftp
->srv_port
: htons(69);
60 uw
->buffer_size
= len
;
61 uw
->buffer
= FAR_PTR(uw
+1);
63 ireg
.ebx
.w
[0] = PXENV_UDP_WRITE
;
65 ireg
.edi
.w
[0] = OFFS(uw
);
67 __intcall(0x22, &ireg
, &oreg
);
72 memset(ur
, 0, sizeof ur
);
73 ur
->src_ip
= tftp
->srv_ip
;
74 ur
->dest_ip
= tftp
->my_ip
;
75 ur
->s_port
= tftp
->srv_port
;
76 ur
->d_port
= tftp
->my_port
;
77 ur
->buffer_size
= RCV_BUF
;
78 ur
->buffer
= FAR_PTR(ur
+1);
80 ireg
.ebx
.w
[0] = PXENV_UDP_READ
;
82 ireg
.edi
.w
[0] = OFFS(ur
);
83 __intcall(0x22, &ireg
, &oreg
);
85 if (!(oreg
.eflags
.l
& EFLAGS_CF
) &&
86 ur
->status
== PXENV_STATUS_SUCCESS
&&
87 tftp
->srv_ip
== ur
->src_ip
&&
88 (tftp
->srv_port
== 0 ||
89 tftp
->srv_port
== ur
->s_port
)) {
90 uint16_t *xb
= (uint16_t *)(ur
+1);
91 if (ntohs(xb
[0]) == TFTP_ACK
&&
92 ntohs(xb
[1]) == tftp
->seq
) {
93 tftp
->srv_port
= ur
->s_port
;
94 err
= 0; /* All good! */
96 } else if (ntohs(xb
[1]) == TFTP_ERROR
) {
100 } while ((clock_t)(times(NULL
) - start
) < *timeout
);
110 static int be_tftp_write(struct backend
*be
)
112 static uint16_t local_port
= 0x4000;
113 struct tftp_state tftp
;
114 char buffer
[512+4+6];
116 const union syslinux_derivative_info
*sdi
=
117 syslinux_derivative_info();
118 const char *data
= be
->outbuf
;
119 size_t len
= be
->zbytes
;
122 tftp
.my_ip
= sdi
->pxe
.myip
;
123 tftp
.my_port
= htons(local_port
++);
124 tftp
.srv_gw
= ((tftp
.srv_ip
^ tftp
.my_ip
) & sdi
->pxe
.ipinfo
->netmask
)
125 ? sdi
->pxe
.ipinfo
->gateway
: 0;
130 tftp
.srv_ip
= pxe_dns(be
->argv
[1]);
132 printf("\nUnable to resolve hostname: %s\n", be
->argv
[1]);
136 tftp
.srv_ip
= sdi
->pxe
.ipinfo
->serverip
;
138 printf("\nNo server IP address\n");
143 printf("server %u.%u.%u.%u... ",
144 ((uint8_t *)&tftp
.srv_ip
)[0],
145 ((uint8_t *)&tftp
.srv_ip
)[1],
146 ((uint8_t *)&tftp
.srv_ip
)[2],
147 ((uint8_t *)&tftp
.srv_ip
)[3]);
150 buffer
[1] = TFTP_WRQ
;
151 nlen
= strlcpy(buffer
+2, be
->argv
[0], 512);
152 memcpy(buffer
+3+nlen
, "octet", 6);
154 if (send_ack_packet(&tftp
, buffer
, 2+nlen
+1+6))
158 chunk
= len
>= 512 ? 512 : len
;
160 buffer
[1] = TFTP_DATA
;
161 *((uint16_t *)(buffer
+2)) = htons(++tftp
.seq
);
162 memcpy(buffer
+4, data
, chunk
);
166 if (send_ack_packet(&tftp
, buffer
, chunk
+4))
168 } while (chunk
== 512);
173 struct backend be_tftp
= {
175 .helpmsg
= "filename [tftp_server]",
177 .write
= be_tftp_write
,