176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TFTP data output backend 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/pxe.h> 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/config.h> 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <netinet/in.h> 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/times.h> 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "upload_backend.h" 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum tftp_opcode { 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TFTP_RRQ = 1, 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TFTP_WRQ = 2, 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TFTP_DATA = 3, 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TFTP_ACK = 4, 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TFTP_ERROR = 5, 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct tftp_error { 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t opcode; 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t errcode; 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char errmsg[0]; 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} __attribute__ (( packed )); 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct tftp_state { 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t my_ip; 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t srv_ip; 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t srv_gw; 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t my_port; 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t srv_port; 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t seq; 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst char *tftp_string_error_message[]={ 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"", 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"File not found", 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Access Denied", 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Disk Full", 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Illegal Operation", 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Unknown Transfert ID", 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"File already exists", 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Unknown User", 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Negociation failed", 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Unable to resolve hostname", // not in RFC 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"Unable to connect", // not in RFC 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman"No Error", 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RCV_BUF 2048 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int send_ack_packet(struct tftp_state *tftp, 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const void *pkt, size_t len) 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman t_PXENV_UDP_WRITE *uw; 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman t_PXENV_UDP_READ *ur; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman clock_t start; 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static const clock_t timeouts[] = { 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman }; 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const clock_t *timeout; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err = -1; 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw = lmalloc(sizeof *uw + len); 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur = lmalloc(sizeof *ur + RCV_BUF); 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (timeout = timeouts ; *timeout ; timeout++) { 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(uw, 0, sizeof *uw); 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(uw+1, pkt, len); 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->ip = tftp->srv_ip; 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->gw = tftp->srv_gw; 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->src_port = tftp->my_port; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->dst_port = tftp->srv_port ? tftp->srv_port : htons(69); 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->buffer_size = len; 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uw->buffer = FAR_PTR(uw+1); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pxe_call(PXENV_UDP_WRITE, uw); 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman start = times(NULL); 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(ur, 0, sizeof *ur); 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->src_ip = tftp->srv_ip; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->dest_ip = tftp->my_ip; 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->s_port = tftp->srv_port; 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->d_port = tftp->my_port; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->buffer_size = RCV_BUF; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ur->buffer = FAR_PTR(ur+1); 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = pxe_call(PXENV_UDP_READ, ur); 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!err && ur->status == PXENV_STATUS_SUCCESS && 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp->srv_ip == ur->src_ip && 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (tftp->srv_port == 0 || 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp->srv_port == ur->s_port)) { 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t *xb = (uint16_t *)(ur+1); 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ntohs(xb[0]) == TFTP_ACK && 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntohs(xb[1]) == tftp->seq) { 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp->srv_port = ur->s_port; 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = TFTP_OK; /* All good! */ 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (ntohs(xb[0]) == TFTP_ERROR) { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct tftp_error *te = (struct tftp_error *)(ur+1); 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (te->errcode == TFTP_ERR_UNKNOWN_ERROR) { 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp_string_error_message[TFTP_ERR_UNKNOWN_ERROR]=strdup(te->errmsg); 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err=-ntohs(te->errcode); // Return the associated error code 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ((clock_t)(times(NULL) - start) < *timeout); 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lfree(ur); 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lfree(uw); 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int upload_tftp_write(struct upload_backend *be) 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static uint16_t local_port = 0x4000; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct tftp_state tftp; 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char buffer[512+4+6]; 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int nlen; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err=TFTP_OK; 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const union syslinux_derivative_info *sdi = 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_derivative_info(); 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *data = be->outbuf; 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t len = be->zbytes; 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t chunk; 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.my_ip = sdi->pxe.myip; 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.my_port = htons(local_port++); 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.srv_gw = ((tftp.srv_ip ^ tftp.my_ip) & sdi->pxe.ipinfo->netmask) 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ? sdi->pxe.ipinfo->gateway : 0; 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.srv_port = 0; 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.seq = 0; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (be->argv[1]) { 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.srv_ip = pxe_dns(be->argv[1]); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!tftp.srv_ip) { 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// printf("\nUnable to resolve hostname: %s\n", be->argv[1]); 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -TFTP_ERR_UNABLE_TO_RESOLVE; 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tftp.srv_ip = sdi->pxe.ipinfo->serverip; 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!tftp.srv_ip) { 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// printf("\nNo server IP address\n"); 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -TFTP_ERR_UNABLE_TO_CONNECT; 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* printf("server %u.%u.%u.%u... ", 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)&tftp.srv_ip)[0], 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)&tftp.srv_ip)[1], 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)&tftp.srv_ip)[2], 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)&tftp.srv_ip)[3]);*/ 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buffer[0] = 0; 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buffer[1] = TFTP_WRQ; 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman nlen = strlcpy(buffer+2, be->argv[0], 512); 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(buffer+3+nlen, "octet", 6); 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((err=send_ack_packet(&tftp, buffer, 2+nlen+1+6))!=TFTP_OK) 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk = len >= 512 ? 512 : len; 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buffer[1] = TFTP_DATA; 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *((uint16_t *)(buffer+2)) = htons(++tftp.seq); 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(buffer+4, data, chunk); 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data += chunk; 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len -= chunk; 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((err=send_ack_packet(&tftp, buffer, chunk+4))!=TFTP_OK) 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (chunk == 512); 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return TFTP_OK; 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct upload_backend upload_tftp = { 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .name = "tftp", 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .helpmsg = "filename [tftp_server]", 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .minargs = 1, 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .write = upload_tftp_write, 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 193