From 62f63cb7706974eba2c34dbea425bf2e9ede0f9e Mon Sep 17 00:00:00 2001 From: Erwan Velu Date: Wed, 2 Sep 2015 20:52:30 +0200 Subject: libupload: Reworking tftp support to use core functions The libupload was using the pxe_call() directly for doing the tftp uploading stuff. This was only working with pxelinux. Since we do have lpxelinux, the libupload should use the core functions to get rid of thoses direct PXE calls. This patch does - add a tftp_put() function which supports core functions. - implement the call from libupload making the code much more simplier As a result {l}pxelinux can upload data to a tftp server is a similar way. HDT is getting the benefit of such code. --- com32/libupload/upload_tftp.c | 179 ++++++++---------------------------------- 1 file changed, 32 insertions(+), 147 deletions(-) (limited to 'com32') diff --git a/com32/libupload/upload_tftp.c b/com32/libupload/upload_tftp.c index 6a0dacb7..387113ba 100644 --- a/com32/libupload/upload_tftp.c +++ b/com32/libupload/upload_tftp.c @@ -8,33 +8,12 @@ #include #include #include +#include +#include #include "upload_backend.h" -enum tftp_opcode { - TFTP_RRQ = 1, - TFTP_WRQ = 2, - TFTP_DATA = 3, - TFTP_ACK = 4, - TFTP_ERROR = 5, -}; - -struct tftp_error { - uint16_t opcode; - uint16_t errcode; - char errmsg[0]; -} __attribute__ (( packed )); - -struct tftp_state { - uint32_t my_ip; - uint32_t srv_ip; - uint32_t srv_gw; - uint16_t my_port; - uint16_t srv_port; - uint16_t seq; -}; - const char *tftp_string_error_message[]={ -"", +"Unknown error", "File not found", "Access Denied", "Disk Full", @@ -48,140 +27,46 @@ const char *tftp_string_error_message[]={ "No Error", }; -#define RCV_BUF 2048 - -static int send_ack_packet(struct tftp_state *tftp, - const void *pkt, size_t len) -{ - t_PXENV_UDP_WRITE *uw; - t_PXENV_UDP_READ *ur; - clock_t start; - static const clock_t timeouts[] = { - 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, - 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0 - }; - const clock_t *timeout; - int err = -1; - - uw = lmalloc(sizeof *uw + len); - ur = lmalloc(sizeof *ur + RCV_BUF); - - for (timeout = timeouts ; *timeout ; timeout++) { - memset(uw, 0, sizeof *uw); - memcpy(uw+1, pkt, len); - uw->ip = tftp->srv_ip; - uw->gw = tftp->srv_gw; - uw->src_port = tftp->my_port; - uw->dst_port = tftp->srv_port ? tftp->srv_port : htons(69); - uw->buffer_size = len; - uw->buffer = FAR_PTR(uw+1); - - pxe_call(PXENV_UDP_WRITE, uw); - - start = times(NULL); - - do { - memset(ur, 0, sizeof *ur); - ur->src_ip = tftp->srv_ip; - ur->dest_ip = tftp->my_ip; - ur->s_port = tftp->srv_port; - ur->d_port = tftp->my_port; - ur->buffer_size = RCV_BUF; - ur->buffer = FAR_PTR(ur+1); - - err = pxe_call(PXENV_UDP_READ, ur); - - if (!err && ur->status == PXENV_STATUS_SUCCESS && - tftp->srv_ip == ur->src_ip && - (tftp->srv_port == 0 || - tftp->srv_port == ur->s_port)) { - uint16_t *xb = (uint16_t *)(ur+1); - if (ntohs(xb[0]) == TFTP_ACK && - ntohs(xb[1]) == tftp->seq) { - tftp->srv_port = ur->s_port; - err = TFTP_OK; /* All good! */ - goto done; - } else if (ntohs(xb[0]) == TFTP_ERROR) { - struct tftp_error *te = (struct tftp_error *)(ur+1); - if (te->errcode == TFTP_ERR_UNKNOWN_ERROR) { - tftp_string_error_message[TFTP_ERR_UNKNOWN_ERROR]=strdup(te->errmsg); - } - err=-ntohs(te->errcode); // Return the associated error code - goto done; - } - } - } while ((clock_t)(times(NULL) - start) < *timeout); - } - -done: - lfree(ur); - lfree(uw); - - return err; -} - -static int upload_tftp_write(struct upload_backend *be) -{ - static uint16_t local_port = 0x4000; - struct tftp_state tftp; - char buffer[512+4+6]; - int nlen; - int err=TFTP_OK; +static int upload_tftp_write(struct upload_backend *be) { const union syslinux_derivative_info *sdi = syslinux_derivative_info(); - const char *data = be->outbuf; - size_t len = be->zbytes; - size_t chunk; - - tftp.my_ip = sdi->pxe.myip; - tftp.my_port = htons(local_port++); - tftp.srv_gw = ((tftp.srv_ip ^ tftp.my_ip) & sdi->pxe.ipinfo->netmask) - ? sdi->pxe.ipinfo->gateway : 0; - tftp.srv_port = 0; - tftp.seq = 0; + struct url_info url; + struct inode inode; + char url_path[255] = {0}; + uint32_t ip; + int err; if (be->argv[1]) { - tftp.srv_ip = pxe_dns(be->argv[1]); - if (!tftp.srv_ip) { -// printf("\nUnable to resolve hostname: %s\n", be->argv[1]); - return -TFTP_ERR_UNABLE_TO_RESOLVE; - } + ip = pxe_dns(be->argv[1]); + if (!ip) { + dprintf("\nUnable to resolve hostname: %s\n", be->argv[1]); + return -TFTP_ERR_UNABLE_TO_RESOLVE; + } } else { - tftp.srv_ip = sdi->pxe.ipinfo->serverip; - if (!tftp.srv_ip) { -// printf("\nNo server IP address\n"); - return -TFTP_ERR_UNABLE_TO_CONNECT; - } + ip = sdi->pxe.ipinfo->serverip; + if (!ip) { + dprintf("\nNo server IP address\n"); + return -TFTP_ERR_UNABLE_TO_CONNECT; + } } -/* printf("server %u.%u.%u.%u... ", - ((uint8_t *)&tftp.srv_ip)[0], - ((uint8_t *)&tftp.srv_ip)[1], - ((uint8_t *)&tftp.srv_ip)[2], - ((uint8_t *)&tftp.srv_ip)[3]);*/ - - buffer[0] = 0; - buffer[1] = TFTP_WRQ; - nlen = strlcpy(buffer+2, be->argv[0], 512); - memcpy(buffer+3+nlen, "octet", 6); - - if ((err=send_ack_packet(&tftp, buffer, 2+nlen+1+6))!=TFTP_OK) - return err; + snprintf(url_path, sizeof(url_path), "tftp://%u.%u.%u.%u/%s", + ((uint8_t *)&ip)[0], + ((uint8_t *)&ip)[1], + ((uint8_t *)&ip)[2], + ((uint8_t *)&ip)[3], + be->argv[0]); - do { - chunk = len >= 512 ? 512 : len; + parse_url(&url, url_path); + url.ip = ip; - buffer[1] = TFTP_DATA; - *((uint16_t *)(buffer+2)) = htons(++tftp.seq); - memcpy(buffer+4, data, chunk); - data += chunk; - len -= chunk; + dprintf("Connecting to %s to send %s\n", url.host, url.path); + err = tftp_put(&url, 0, &inode, NULL, be->outbuf, be->zbytes); - if ((err=send_ack_packet(&tftp, buffer, chunk+4))!=TFTP_OK) - return err; - } while (chunk == 512); + if (-err != TFTP_OK) + printf("upload_tftp_write: TFTP server returned error %d : %s\n", err, tftp_string_error_message[-err]); - return TFTP_OK; + return -err; } struct upload_backend upload_tftp = { -- cgit v1.2.3