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,