xref: /curl/lib/tftp.c (revision cd2b4520)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #ifndef CURL_DISABLE_TFTP
28 
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #ifdef HAVE_NETDB_H
33 #include <netdb.h>
34 #endif
35 #ifdef HAVE_ARPA_INET_H
36 #include <arpa/inet.h>
37 #endif
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44 
45 #ifdef HAVE_SYS_PARAM_H
46 #include <sys/param.h>
47 #endif
48 
49 #include "urldata.h"
50 #include <curl/curl.h>
51 #include "cf-socket.h"
52 #include "transfer.h"
53 #include "sendf.h"
54 #include "tftp.h"
55 #include "progress.h"
56 #include "connect.h"
57 #include "strerror.h"
58 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
59 #include "multiif.h"
60 #include "url.h"
61 #include "strcase.h"
62 #include "speedcheck.h"
63 #include "select.h"
64 #include "escape.h"
65 
66 /* The last 3 #include files should be in this order */
67 #include "curl_printf.h"
68 #include "curl_memory.h"
69 #include "memdebug.h"
70 
71 /* RFC2348 allows the block size to be negotiated */
72 #define TFTP_BLKSIZE_DEFAULT 512
73 #define TFTP_OPTION_BLKSIZE "blksize"
74 
75 /* from RFC2349: */
76 #define TFTP_OPTION_TSIZE    "tsize"
77 #define TFTP_OPTION_INTERVAL "timeout"
78 
79 typedef enum {
80   TFTP_MODE_NETASCII = 0,
81   TFTP_MODE_OCTET
82 } tftp_mode_t;
83 
84 typedef enum {
85   TFTP_STATE_START = 0,
86   TFTP_STATE_RX,
87   TFTP_STATE_TX,
88   TFTP_STATE_FIN
89 } tftp_state_t;
90 
91 typedef enum {
92   TFTP_EVENT_NONE = -1,
93   TFTP_EVENT_INIT = 0,
94   TFTP_EVENT_RRQ = 1,
95   TFTP_EVENT_WRQ = 2,
96   TFTP_EVENT_DATA = 3,
97   TFTP_EVENT_ACK = 4,
98   TFTP_EVENT_ERROR = 5,
99   TFTP_EVENT_OACK = 6,
100   TFTP_EVENT_TIMEOUT
101 } tftp_event_t;
102 
103 typedef enum {
104   TFTP_ERR_UNDEF = 0,
105   TFTP_ERR_NOTFOUND,
106   TFTP_ERR_PERM,
107   TFTP_ERR_DISKFULL,
108   TFTP_ERR_ILLEGAL,
109   TFTP_ERR_UNKNOWNID,
110   TFTP_ERR_EXISTS,
111   TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
112 
113   /* The remaining error codes are internal to curl */
114   TFTP_ERR_NONE = -100,
115   TFTP_ERR_TIMEOUT,
116   TFTP_ERR_NORESPONSE
117 } tftp_error_t;
118 
119 struct tftp_packet {
120   unsigned char *data;
121 };
122 
123 struct tftp_state_data {
124   tftp_state_t    state;
125   tftp_mode_t     mode;
126   tftp_error_t    error;
127   tftp_event_t    event;
128   struct Curl_easy *data;
129   curl_socket_t   sockfd;
130   int             retries;
131   int             retry_time;
132   int             retry_max;
133   time_t          rx_time;
134   struct Curl_sockaddr_storage   local_addr;
135   struct Curl_sockaddr_storage   remote_addr;
136   curl_socklen_t  remote_addrlen;
137   int             rbytes;
138   int             sbytes;
139   int             blksize;
140   int             requested_blksize;
141   unsigned short  block;
142   struct tftp_packet rpacket;
143   struct tftp_packet spacket;
144 };
145 
146 
147 /* Forward declarations */
148 static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
149 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
150 static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
151 static CURLcode tftp_disconnect(struct Curl_easy *data,
152                                 struct connectdata *conn,
153                                 bool dead_connection);
154 static CURLcode tftp_do(struct Curl_easy *data, bool *done);
155 static CURLcode tftp_done(struct Curl_easy *data,
156                           CURLcode, bool premature);
157 static CURLcode tftp_setup_connection(struct Curl_easy *data,
158                                       struct connectdata *conn);
159 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
160 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
161 static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
162                         curl_socket_t *socks);
163 static CURLcode tftp_translate_code(tftp_error_t error);
164 
165 
166 /*
167  * TFTP protocol handler.
168  */
169 
170 const struct Curl_handler Curl_handler_tftp = {
171   "tftp",                               /* scheme */
172   tftp_setup_connection,                /* setup_connection */
173   tftp_do,                              /* do_it */
174   tftp_done,                            /* done */
175   ZERO_NULL,                            /* do_more */
176   tftp_connect,                         /* connect_it */
177   tftp_multi_statemach,                 /* connecting */
178   tftp_doing,                           /* doing */
179   tftp_getsock,                         /* proto_getsock */
180   tftp_getsock,                         /* doing_getsock */
181   ZERO_NULL,                            /* domore_getsock */
182   ZERO_NULL,                            /* perform_getsock */
183   tftp_disconnect,                      /* disconnect */
184   ZERO_NULL,                            /* write_resp */
185   ZERO_NULL,                            /* write_resp_hd */
186   ZERO_NULL,                            /* connection_check */
187   ZERO_NULL,                            /* attach connection */
188   PORT_TFTP,                            /* defport */
189   CURLPROTO_TFTP,                       /* protocol */
190   CURLPROTO_TFTP,                       /* family */
191   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
192 };
193 
194 /**********************************************************
195  *
196  * tftp_set_timeouts -
197  *
198  * Set timeouts based on state machine state.
199  * Use user provided connect timeouts until DATA or ACK
200  * packet is received, then use user-provided transfer timeouts
201  *
202  *
203  **********************************************************/
tftp_set_timeouts(struct tftp_state_data * state)204 static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
205 {
206   time_t maxtime, timeout;
207   timediff_t timeout_ms;
208   bool start = (state->state == TFTP_STATE_START);
209 
210   /* Compute drop-dead time */
211   timeout_ms = Curl_timeleft(state->data, NULL, start);
212 
213   if(timeout_ms < 0) {
214     /* time-out, bail out, go home */
215     failf(state->data, "Connection time-out");
216     return CURLE_OPERATION_TIMEDOUT;
217   }
218 
219   if(timeout_ms > 0)
220     maxtime = (time_t)(timeout_ms + 500) / 1000;
221   else
222     maxtime = 3600; /* use for calculating block timeouts */
223 
224   /* Set per-block timeout to total */
225   timeout = maxtime;
226 
227   /* Average reposting an ACK after 5 seconds */
228   state->retry_max = (int)timeout/5;
229 
230   /* But bound the total number */
231   if(state->retry_max < 3)
232     state->retry_max = 3;
233 
234   if(state->retry_max > 50)
235     state->retry_max = 50;
236 
237   /* Compute the re-ACK interval to suit the timeout */
238   state->retry_time = (int)(timeout/state->retry_max);
239   if(state->retry_time < 1)
240     state->retry_time = 1;
241 
242   infof(state->data,
243         "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
244         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
245 
246   /* init RX time */
247   state->rx_time = time(NULL);
248 
249   return CURLE_OK;
250 }
251 
252 /**********************************************************
253  *
254  * tftp_set_send_first
255  *
256  * Event handler for the START state
257  *
258  **********************************************************/
259 
setpacketevent(struct tftp_packet * packet,unsigned short num)260 static void setpacketevent(struct tftp_packet *packet, unsigned short num)
261 {
262   packet->data[0] = (unsigned char)(num >> 8);
263   packet->data[1] = (unsigned char)(num & 0xff);
264 }
265 
266 
setpacketblock(struct tftp_packet * packet,unsigned short num)267 static void setpacketblock(struct tftp_packet *packet, unsigned short num)
268 {
269   packet->data[2] = (unsigned char)(num >> 8);
270   packet->data[3] = (unsigned char)(num & 0xff);
271 }
272 
getrpacketevent(const struct tftp_packet * packet)273 static unsigned short getrpacketevent(const struct tftp_packet *packet)
274 {
275   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
276 }
277 
getrpacketblock(const struct tftp_packet * packet)278 static unsigned short getrpacketblock(const struct tftp_packet *packet)
279 {
280   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
281 }
282 
tftp_strnlen(const char * string,size_t maxlen)283 static size_t tftp_strnlen(const char *string, size_t maxlen)
284 {
285   const char *end = memchr(string, '\0', maxlen);
286   return end ? (size_t) (end - string) : maxlen;
287 }
288 
tftp_option_get(const char * buf,size_t len,const char ** option,const char ** value)289 static const char *tftp_option_get(const char *buf, size_t len,
290                                    const char **option, const char **value)
291 {
292   size_t loc;
293 
294   loc = tftp_strnlen(buf, len);
295   loc++; /* NULL term */
296 
297   if(loc >= len)
298     return NULL;
299   *option = buf;
300 
301   loc += tftp_strnlen(buf + loc, len-loc);
302   loc++; /* NULL term */
303 
304   if(loc > len)
305     return NULL;
306   *value = &buf[strlen(*option) + 1];
307 
308   return &buf[loc];
309 }
310 
tftp_parse_option_ack(struct tftp_state_data * state,const char * ptr,int len)311 static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
312                                       const char *ptr, int len)
313 {
314   const char *tmp = ptr;
315   struct Curl_easy *data = state->data;
316 
317   /* if OACK does not contain blksize option, the default (512) must be used */
318   state->blksize = TFTP_BLKSIZE_DEFAULT;
319 
320   while(tmp < ptr + len) {
321     const char *option, *value;
322 
323     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
324     if(!tmp) {
325       failf(data, "Malformed ACK packet, rejecting");
326       return CURLE_TFTP_ILLEGAL;
327     }
328 
329     infof(data, "got option=(%s) value=(%s)", option, value);
330 
331     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
332       long blksize;
333 
334       blksize = strtol(value, NULL, 10);
335 
336       if(!blksize) {
337         failf(data, "invalid blocksize value in OACK packet");
338         return CURLE_TFTP_ILLEGAL;
339       }
340       if(blksize > TFTP_BLKSIZE_MAX) {
341         failf(data, "%s (%d)", "blksize is larger than max supported",
342               TFTP_BLKSIZE_MAX);
343         return CURLE_TFTP_ILLEGAL;
344       }
345       else if(blksize < TFTP_BLKSIZE_MIN) {
346         failf(data, "%s (%d)", "blksize is smaller than min supported",
347               TFTP_BLKSIZE_MIN);
348         return CURLE_TFTP_ILLEGAL;
349       }
350       else if(blksize > state->requested_blksize) {
351         /* could realloc pkt buffers here, but the spec does not call out
352          * support for the server requesting a bigger blksize than the client
353          * requests */
354         failf(data, "%s (%ld)",
355               "server requested blksize larger than allocated", blksize);
356         return CURLE_TFTP_ILLEGAL;
357       }
358 
359       state->blksize = (int)blksize;
360       infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
361             state->blksize, "requested", state->requested_blksize);
362     }
363     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
364       long tsize = 0;
365 
366       tsize = strtol(value, NULL, 10);
367       infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
368 
369       /* tsize should be ignored on upload: Who cares about the size of the
370          remote file? */
371       if(!data->state.upload) {
372         if(!tsize) {
373           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
374           return CURLE_TFTP_ILLEGAL;
375         }
376         Curl_pgrsSetDownloadSize(data, tsize);
377       }
378     }
379   }
380 
381   return CURLE_OK;
382 }
383 
tftp_option_add(struct tftp_state_data * state,size_t * csize,char * buf,const char * option)384 static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
385                                 char *buf, const char *option)
386 {
387   if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
388     return CURLE_TFTP_ILLEGAL;
389   strcpy(buf, option);
390   *csize += strlen(option) + 1;
391   return CURLE_OK;
392 }
393 
tftp_connect_for_tx(struct tftp_state_data * state,tftp_event_t event)394 static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
395                                     tftp_event_t event)
396 {
397   CURLcode result;
398 #ifndef CURL_DISABLE_VERBOSE_STRINGS
399   struct Curl_easy *data = state->data;
400 
401   infof(data, "%s", "Connected for transmit");
402 #endif
403   state->state = TFTP_STATE_TX;
404   result = tftp_set_timeouts(state);
405   if(result)
406     return result;
407   return tftp_tx(state, event);
408 }
409 
tftp_connect_for_rx(struct tftp_state_data * state,tftp_event_t event)410 static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
411                                     tftp_event_t event)
412 {
413   CURLcode result;
414 #ifndef CURL_DISABLE_VERBOSE_STRINGS
415   struct Curl_easy *data = state->data;
416 
417   infof(data, "%s", "Connected for receive");
418 #endif
419   state->state = TFTP_STATE_RX;
420   result = tftp_set_timeouts(state);
421   if(result)
422     return result;
423   return tftp_rx(state, event);
424 }
425 
tftp_send_first(struct tftp_state_data * state,tftp_event_t event)426 static CURLcode tftp_send_first(struct tftp_state_data *state,
427                                 tftp_event_t event)
428 {
429   size_t sbytes;
430   ssize_t senddata;
431   const char *mode = "octet";
432   char *filename;
433   struct Curl_easy *data = state->data;
434   CURLcode result = CURLE_OK;
435 
436   /* Set ASCII mode if -B flag was used */
437   if(data->state.prefer_ascii)
438     mode = "netascii";
439 
440   switch(event) {
441 
442   case TFTP_EVENT_INIT:    /* Send the first packet out */
443   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
444     /* Increment the retry counter, quit if over the limit */
445     state->retries++;
446     if(state->retries > state->retry_max) {
447       state->error = TFTP_ERR_NORESPONSE;
448       state->state = TFTP_STATE_FIN;
449       return result;
450     }
451 
452     if(data->state.upload) {
453       /* If we are uploading, send an WRQ */
454       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
455       if(data->state.infilesize != -1)
456         Curl_pgrsSetUploadSize(data, data->state.infilesize);
457     }
458     else {
459       /* If we are downloading, send an RRQ */
460       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
461     }
462     /* As RFC3617 describes the separator slash is not actually part of the
463        filename so we skip the always-present first letter of the path
464        string. */
465     result = Curl_urldecode(&state->data->state.up.path[1], 0,
466                             &filename, NULL, REJECT_ZERO);
467     if(result)
468       return result;
469 
470     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
471       failf(data, "TFTP filename too long");
472       free(filename);
473       return CURLE_TFTP_ILLEGAL; /* too long filename field */
474     }
475 
476     msnprintf((char *)state->spacket.data + 2,
477               state->blksize,
478               "%s%c%s%c", filename, '\0',  mode, '\0');
479     sbytes = 4 + strlen(filename) + strlen(mode);
480 
481     /* optional addition of TFTP options */
482     if(!data->set.tftp_no_options) {
483       char buf[64];
484       /* add tsize option */
485       msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
486                 data->state.upload && (data->state.infilesize != -1) ?
487                 data->state.infilesize : 0);
488 
489       result = tftp_option_add(state, &sbytes,
490                                (char *)state->spacket.data + sbytes,
491                                TFTP_OPTION_TSIZE);
492       if(result == CURLE_OK)
493         result = tftp_option_add(state, &sbytes,
494                                  (char *)state->spacket.data + sbytes, buf);
495 
496       /* add blksize option */
497       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
498       if(result == CURLE_OK)
499         result = tftp_option_add(state, &sbytes,
500                                  (char *)state->spacket.data + sbytes,
501                                  TFTP_OPTION_BLKSIZE);
502       if(result == CURLE_OK)
503         result = tftp_option_add(state, &sbytes,
504                                  (char *)state->spacket.data + sbytes, buf);
505 
506       /* add timeout option */
507       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
508       if(result == CURLE_OK)
509         result = tftp_option_add(state, &sbytes,
510                                  (char *)state->spacket.data + sbytes,
511                                  TFTP_OPTION_INTERVAL);
512       if(result == CURLE_OK)
513         result = tftp_option_add(state, &sbytes,
514                                  (char *)state->spacket.data + sbytes, buf);
515 
516       if(result != CURLE_OK) {
517         failf(data, "TFTP buffer too small for options");
518         free(filename);
519         return CURLE_TFTP_ILLEGAL;
520       }
521     }
522 
523     /* the typecase for the 3rd argument is mostly for systems that do
524        not have a size_t argument, like older unixes that want an 'int' */
525     senddata = sendto(state->sockfd, (void *)state->spacket.data,
526                       (SEND_TYPE_ARG3)sbytes, 0,
527                       &data->conn->remote_addr->curl_sa_addr,
528                       (curl_socklen_t)data->conn->remote_addr->addrlen);
529     if(senddata != (ssize_t)sbytes) {
530       char buffer[STRERROR_LEN];
531       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
532     }
533     free(filename);
534     break;
535 
536   case TFTP_EVENT_OACK:
537     if(data->state.upload) {
538       result = tftp_connect_for_tx(state, event);
539     }
540     else {
541       result = tftp_connect_for_rx(state, event);
542     }
543     break;
544 
545   case TFTP_EVENT_ACK: /* Connected for transmit */
546     result = tftp_connect_for_tx(state, event);
547     break;
548 
549   case TFTP_EVENT_DATA: /* Connected for receive */
550     result = tftp_connect_for_rx(state, event);
551     break;
552 
553   case TFTP_EVENT_ERROR:
554     state->state = TFTP_STATE_FIN;
555     break;
556 
557   default:
558     failf(state->data, "tftp_send_first: internal error");
559     break;
560   }
561 
562   return result;
563 }
564 
565 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
566    boundary */
567 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
568 
569 /**********************************************************
570  *
571  * tftp_rx
572  *
573  * Event handler for the RX state
574  *
575  **********************************************************/
tftp_rx(struct tftp_state_data * state,tftp_event_t event)576 static CURLcode tftp_rx(struct tftp_state_data *state,
577                         tftp_event_t event)
578 {
579   ssize_t sbytes;
580   int rblock;
581   struct Curl_easy *data = state->data;
582   char buffer[STRERROR_LEN];
583 
584   switch(event) {
585 
586   case TFTP_EVENT_DATA:
587     /* Is this the block we expect? */
588     rblock = getrpacketblock(&state->rpacket);
589     if(NEXT_BLOCKNUM(state->block) == rblock) {
590       /* This is the expected block. Reset counters and ACK it. */
591       state->retries = 0;
592     }
593     else if(state->block == rblock) {
594       /* This is the last recently received block again. Log it and ACK it
595          again. */
596       infof(data, "Received last DATA packet block %d again.", rblock);
597     }
598     else {
599       /* totally unexpected, just log it */
600       infof(data,
601             "Received unexpected DATA packet block %d, expecting block %d",
602             rblock, NEXT_BLOCKNUM(state->block));
603       break;
604     }
605 
606     /* ACK this block. */
607     state->block = (unsigned short)rblock;
608     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
609     setpacketblock(&state->spacket, state->block);
610     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
611                     4, SEND_4TH_ARG,
612                     (struct sockaddr *)&state->remote_addr,
613                     state->remote_addrlen);
614     if(sbytes < 0) {
615       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
616       return CURLE_SEND_ERROR;
617     }
618 
619     /* Check if completed (That is, a less than full packet is received) */
620     if(state->rbytes < (ssize_t)state->blksize + 4) {
621       state->state = TFTP_STATE_FIN;
622     }
623     else {
624       state->state = TFTP_STATE_RX;
625     }
626     state->rx_time = time(NULL);
627     break;
628 
629   case TFTP_EVENT_OACK:
630     /* ACK option acknowledgement so we can move on to data */
631     state->block = 0;
632     state->retries = 0;
633     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
634     setpacketblock(&state->spacket, state->block);
635     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
636                     4, SEND_4TH_ARG,
637                     (struct sockaddr *)&state->remote_addr,
638                     state->remote_addrlen);
639     if(sbytes < 0) {
640       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
641       return CURLE_SEND_ERROR;
642     }
643 
644     /* we are ready to RX data */
645     state->state = TFTP_STATE_RX;
646     state->rx_time = time(NULL);
647     break;
648 
649   case TFTP_EVENT_TIMEOUT:
650     /* Increment the retry count and fail if over the limit */
651     state->retries++;
652     infof(data,
653           "Timeout waiting for block %d ACK. Retries = %d",
654           NEXT_BLOCKNUM(state->block), state->retries);
655     if(state->retries > state->retry_max) {
656       state->error = TFTP_ERR_TIMEOUT;
657       state->state = TFTP_STATE_FIN;
658     }
659     else {
660       /* Resend the previous ACK */
661       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
662                       4, SEND_4TH_ARG,
663                       (struct sockaddr *)&state->remote_addr,
664                       state->remote_addrlen);
665       if(sbytes < 0) {
666         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
667         return CURLE_SEND_ERROR;
668       }
669     }
670     break;
671 
672   case TFTP_EVENT_ERROR:
673     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
674     setpacketblock(&state->spacket, state->block);
675     (void)sendto(state->sockfd, (void *)state->spacket.data,
676                  4, SEND_4TH_ARG,
677                  (struct sockaddr *)&state->remote_addr,
678                  state->remote_addrlen);
679     /* do not bother with the return code, but if the socket is still up we
680      * should be a good TFTP client and let the server know we are done */
681     state->state = TFTP_STATE_FIN;
682     break;
683 
684   default:
685     failf(data, "%s", "tftp_rx: internal error");
686     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
687                                   this */
688   }
689   return CURLE_OK;
690 }
691 
692 /**********************************************************
693  *
694  * tftp_tx
695  *
696  * Event handler for the TX state
697  *
698  **********************************************************/
tftp_tx(struct tftp_state_data * state,tftp_event_t event)699 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
700 {
701   struct Curl_easy *data = state->data;
702   ssize_t sbytes;
703   CURLcode result = CURLE_OK;
704   struct SingleRequest *k = &data->req;
705   size_t cb; /* Bytes currently read */
706   char buffer[STRERROR_LEN];
707   char *bufptr;
708   bool eos;
709 
710   switch(event) {
711 
712   case TFTP_EVENT_ACK:
713   case TFTP_EVENT_OACK:
714     if(event == TFTP_EVENT_ACK) {
715       /* Ack the packet */
716       int rblock = getrpacketblock(&state->rpacket);
717 
718       if(rblock != state->block &&
719          /* There is a bug in tftpd-hpa that causes it to send us an ack for
720           * 65535 when the block number wraps to 0. So when we are expecting
721           * 0, also accept 65535. See
722           * https://www.syslinux.org/archives/2010-September/015612.html
723           * */
724          !(state->block == 0 && rblock == 65535)) {
725         /* This is not the expected block. Log it and up the retry counter */
726         infof(data, "Received ACK for block %d, expecting %d",
727               rblock, state->block);
728         state->retries++;
729         /* Bail out if over the maximum */
730         if(state->retries > state->retry_max) {
731           failf(data, "tftp_tx: giving up waiting for block %d ack",
732                 state->block);
733           result = CURLE_SEND_ERROR;
734         }
735         else {
736           /* Re-send the data packet */
737           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
738                           4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
739                           (struct sockaddr *)&state->remote_addr,
740                           state->remote_addrlen);
741           /* Check all sbytes were sent */
742           if(sbytes < 0) {
743             failf(data, "%s", Curl_strerror(SOCKERRNO,
744                                             buffer, sizeof(buffer)));
745             result = CURLE_SEND_ERROR;
746           }
747         }
748 
749         return result;
750       }
751       /* This is the expected packet. Reset the counters and send the next
752          block */
753       state->rx_time = time(NULL);
754       state->block++;
755     }
756     else
757       state->block = 1; /* first data block is 1 when using OACK */
758 
759     state->retries = 0;
760     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
761     setpacketblock(&state->spacket, state->block);
762     if(state->block > 1 && state->sbytes < state->blksize) {
763       state->state = TFTP_STATE_FIN;
764       return CURLE_OK;
765     }
766 
767     /* TFTP considers data block size < 512 bytes as an end of session. So
768      * in some cases we must wait for additional data to build full (512 bytes)
769      * data block.
770      * */
771     state->sbytes = 0;
772     bufptr = (char *)state->spacket.data + 4;
773     do {
774       result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
775                                 &cb, &eos);
776       if(result)
777         return result;
778       state->sbytes += (int)cb;
779       bufptr += cb;
780     } while(state->sbytes < state->blksize && cb);
781 
782     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
783                     4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
784                     (struct sockaddr *)&state->remote_addr,
785                     state->remote_addrlen);
786     /* Check all sbytes were sent */
787     if(sbytes < 0) {
788       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
789       return CURLE_SEND_ERROR;
790     }
791     /* Update the progress meter */
792     k->writebytecount += state->sbytes;
793     Curl_pgrsSetUploadCounter(data, k->writebytecount);
794     break;
795 
796   case TFTP_EVENT_TIMEOUT:
797     /* Increment the retry counter and log the timeout */
798     state->retries++;
799     infof(data, "Timeout waiting for block %d ACK. "
800           " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
801     /* Decide if we have had enough */
802     if(state->retries > state->retry_max) {
803       state->error = TFTP_ERR_TIMEOUT;
804       state->state = TFTP_STATE_FIN;
805     }
806     else {
807       /* Re-send the data packet */
808       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
809                       4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
810                       (struct sockaddr *)&state->remote_addr,
811                       state->remote_addrlen);
812       /* Check all sbytes were sent */
813       if(sbytes < 0) {
814         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
815         return CURLE_SEND_ERROR;
816       }
817       /* since this was a re-send, we remain at the still byte position */
818       Curl_pgrsSetUploadCounter(data, k->writebytecount);
819     }
820     break;
821 
822   case TFTP_EVENT_ERROR:
823     state->state = TFTP_STATE_FIN;
824     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
825     setpacketblock(&state->spacket, state->block);
826     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
827                  (struct sockaddr *)&state->remote_addr,
828                  state->remote_addrlen);
829     /* do not bother with the return code, but if the socket is still up we
830      * should be a good TFTP client and let the server know we are done */
831     state->state = TFTP_STATE_FIN;
832     break;
833 
834   default:
835     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
836     break;
837   }
838 
839   return result;
840 }
841 
842 /**********************************************************
843  *
844  * tftp_translate_code
845  *
846  * Translate internal error codes to CURL error codes
847  *
848  **********************************************************/
tftp_translate_code(tftp_error_t error)849 static CURLcode tftp_translate_code(tftp_error_t error)
850 {
851   CURLcode result = CURLE_OK;
852 
853   if(error != TFTP_ERR_NONE) {
854     switch(error) {
855     case TFTP_ERR_NOTFOUND:
856       result = CURLE_TFTP_NOTFOUND;
857       break;
858     case TFTP_ERR_PERM:
859       result = CURLE_TFTP_PERM;
860       break;
861     case TFTP_ERR_DISKFULL:
862       result = CURLE_REMOTE_DISK_FULL;
863       break;
864     case TFTP_ERR_UNDEF:
865     case TFTP_ERR_ILLEGAL:
866       result = CURLE_TFTP_ILLEGAL;
867       break;
868     case TFTP_ERR_UNKNOWNID:
869       result = CURLE_TFTP_UNKNOWNID;
870       break;
871     case TFTP_ERR_EXISTS:
872       result = CURLE_REMOTE_FILE_EXISTS;
873       break;
874     case TFTP_ERR_NOSUCHUSER:
875       result = CURLE_TFTP_NOSUCHUSER;
876       break;
877     case TFTP_ERR_TIMEOUT:
878       result = CURLE_OPERATION_TIMEDOUT;
879       break;
880     case TFTP_ERR_NORESPONSE:
881       result = CURLE_COULDNT_CONNECT;
882       break;
883     default:
884       result = CURLE_ABORTED_BY_CALLBACK;
885       break;
886     }
887   }
888   else
889     result = CURLE_OK;
890 
891   return result;
892 }
893 
894 /**********************************************************
895  *
896  * tftp_state_machine
897  *
898  * The tftp state machine event dispatcher
899  *
900  **********************************************************/
tftp_state_machine(struct tftp_state_data * state,tftp_event_t event)901 static CURLcode tftp_state_machine(struct tftp_state_data *state,
902                                    tftp_event_t event)
903 {
904   CURLcode result = CURLE_OK;
905   struct Curl_easy *data = state->data;
906 
907   switch(state->state) {
908   case TFTP_STATE_START:
909     DEBUGF(infof(data, "TFTP_STATE_START"));
910     result = tftp_send_first(state, event);
911     break;
912   case TFTP_STATE_RX:
913     DEBUGF(infof(data, "TFTP_STATE_RX"));
914     result = tftp_rx(state, event);
915     break;
916   case TFTP_STATE_TX:
917     DEBUGF(infof(data, "TFTP_STATE_TX"));
918     result = tftp_tx(state, event);
919     break;
920   case TFTP_STATE_FIN:
921     infof(data, "%s", "TFTP finished");
922     break;
923   default:
924     DEBUGF(infof(data, "STATE: %d", state->state));
925     failf(data, "%s", "Internal state machine error");
926     result = CURLE_TFTP_ILLEGAL;
927     break;
928   }
929 
930   return result;
931 }
932 
933 /**********************************************************
934  *
935  * tftp_disconnect
936  *
937  * The disconnect callback
938  *
939  **********************************************************/
tftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)940 static CURLcode tftp_disconnect(struct Curl_easy *data,
941                                 struct connectdata *conn, bool dead_connection)
942 {
943   struct tftp_state_data *state = conn->proto.tftpc;
944   (void) data;
945   (void) dead_connection;
946 
947   /* done, free dynamically allocated pkt buffers */
948   if(state) {
949     Curl_safefree(state->rpacket.data);
950     Curl_safefree(state->spacket.data);
951     free(state);
952   }
953 
954   return CURLE_OK;
955 }
956 
957 /**********************************************************
958  *
959  * tftp_connect
960  *
961  * The connect callback
962  *
963  **********************************************************/
tftp_connect(struct Curl_easy * data,bool * done)964 static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
965 {
966   struct tftp_state_data *state;
967   int blksize;
968   int need_blksize;
969   struct connectdata *conn = data->conn;
970 
971   blksize = TFTP_BLKSIZE_DEFAULT;
972 
973   state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
974   if(!state)
975     return CURLE_OUT_OF_MEMORY;
976 
977   /* alloc pkt buffers based on specified blksize */
978   if(data->set.tftp_blksize)
979     /* range checked when set */
980     blksize = (int)data->set.tftp_blksize;
981 
982   need_blksize = blksize;
983   /* default size is the fallback when no OACK is received */
984   if(need_blksize < TFTP_BLKSIZE_DEFAULT)
985     need_blksize = TFTP_BLKSIZE_DEFAULT;
986 
987   if(!state->rpacket.data) {
988     state->rpacket.data = calloc(1, need_blksize + 2 + 2);
989 
990     if(!state->rpacket.data)
991       return CURLE_OUT_OF_MEMORY;
992   }
993 
994   if(!state->spacket.data) {
995     state->spacket.data = calloc(1, need_blksize + 2 + 2);
996 
997     if(!state->spacket.data)
998       return CURLE_OUT_OF_MEMORY;
999   }
1000 
1001   /* we do not keep TFTP connections up basically because there is none or
1002    * little gain for UDP */
1003   connclose(conn, "TFTP");
1004 
1005   state->data = data;
1006   state->sockfd = conn->sock[FIRSTSOCKET];
1007   state->state = TFTP_STATE_START;
1008   state->error = TFTP_ERR_NONE;
1009   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
1010   state->requested_blksize = blksize;
1011 
1012   ((struct sockaddr *)&state->local_addr)->sa_family =
1013     (CURL_SA_FAMILY_T)(conn->remote_addr->family);
1014 
1015   tftp_set_timeouts(state);
1016 
1017   if(!conn->bits.bound) {
1018     /* If not already bound, bind to any interface, random UDP port. If it is
1019      * reused or a custom local port was desired, this has already been done!
1020      *
1021      * We once used the size of the local_addr struct as the third argument
1022      * for bind() to better work with IPv6 or whatever size the struct could
1023      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1024      * size of that argument to match the exact size of a 'sockaddr_in' struct
1025      * when running IPv4-only.
1026      *
1027      * Therefore we use the size from the address we connected to, which we
1028      * assume uses the same IP version and thus hopefully this works for both
1029      * IPv4 and IPv6...
1030      */
1031     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1032                   (curl_socklen_t)conn->remote_addr->addrlen);
1033     if(rc) {
1034       char buffer[STRERROR_LEN];
1035       failf(data, "bind() failed; %s",
1036             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1037       return CURLE_COULDNT_CONNECT;
1038     }
1039     conn->bits.bound = TRUE;
1040   }
1041 
1042   Curl_pgrsStartNow(data);
1043 
1044   *done = TRUE;
1045 
1046   return CURLE_OK;
1047 }
1048 
1049 /**********************************************************
1050  *
1051  * tftp_done
1052  *
1053  * The done callback
1054  *
1055  **********************************************************/
tftp_done(struct Curl_easy * data,CURLcode status,bool premature)1056 static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
1057                           bool premature)
1058 {
1059   CURLcode result = CURLE_OK;
1060   struct connectdata *conn = data->conn;
1061   struct tftp_state_data *state = conn->proto.tftpc;
1062 
1063   (void)status; /* unused */
1064   (void)premature; /* not used */
1065 
1066   if(Curl_pgrsDone(data))
1067     return CURLE_ABORTED_BY_CALLBACK;
1068 
1069   /* If we have encountered an error */
1070   if(state)
1071     result = tftp_translate_code(state->error);
1072 
1073   return result;
1074 }
1075 
1076 /**********************************************************
1077  *
1078  * tftp_getsock
1079  *
1080  * The getsock callback
1081  *
1082  **********************************************************/
tftp_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * socks)1083 static int tftp_getsock(struct Curl_easy *data,
1084                         struct connectdata *conn, curl_socket_t *socks)
1085 {
1086   (void)data;
1087   socks[0] = conn->sock[FIRSTSOCKET];
1088   return GETSOCK_READSOCK(0);
1089 }
1090 
1091 /**********************************************************
1092  *
1093  * tftp_receive_packet
1094  *
1095  * Called once select fires and data is ready on the socket
1096  *
1097  **********************************************************/
tftp_receive_packet(struct Curl_easy * data)1098 static CURLcode tftp_receive_packet(struct Curl_easy *data)
1099 {
1100   curl_socklen_t        fromlen;
1101   CURLcode              result = CURLE_OK;
1102   struct connectdata *conn = data->conn;
1103   struct tftp_state_data *state = conn->proto.tftpc;
1104 
1105   /* Receive the packet */
1106   fromlen = sizeof(state->remote_addr);
1107   state->rbytes = (int)recvfrom(state->sockfd,
1108                                 (void *)state->rpacket.data,
1109                                 (RECV_TYPE_ARG3)state->blksize + 4,
1110                                 0,
1111                                 (struct sockaddr *)&state->remote_addr,
1112                                 &fromlen);
1113   state->remote_addrlen = fromlen;
1114 
1115   /* Sanity check packet length */
1116   if(state->rbytes < 4) {
1117     failf(data, "Received too short packet");
1118     /* Not a timeout, but how best to handle it? */
1119     state->event = TFTP_EVENT_TIMEOUT;
1120   }
1121   else {
1122     /* The event is given by the TFTP packet time */
1123     unsigned short event = getrpacketevent(&state->rpacket);
1124     state->event = (tftp_event_t)event;
1125 
1126     switch(state->event) {
1127     case TFTP_EVENT_DATA:
1128       /* Do not pass to the client empty or retransmitted packets */
1129       if(state->rbytes > 4 &&
1130          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1131         result = Curl_client_write(data, CLIENTWRITE_BODY,
1132                                    (char *)state->rpacket.data + 4,
1133                                    state->rbytes-4);
1134         if(result) {
1135           tftp_state_machine(state, TFTP_EVENT_ERROR);
1136           return result;
1137         }
1138       }
1139       break;
1140     case TFTP_EVENT_ERROR:
1141     {
1142       unsigned short error = getrpacketblock(&state->rpacket);
1143       char *str = (char *)state->rpacket.data + 4;
1144       size_t strn = state->rbytes - 4;
1145       state->error = (tftp_error_t)error;
1146       if(tftp_strnlen(str, strn) < strn)
1147         infof(data, "TFTP error: %s", str);
1148       break;
1149     }
1150     case TFTP_EVENT_ACK:
1151       break;
1152     case TFTP_EVENT_OACK:
1153       result = tftp_parse_option_ack(state,
1154                                      (const char *)state->rpacket.data + 2,
1155                                      state->rbytes-2);
1156       if(result)
1157         return result;
1158       break;
1159     case TFTP_EVENT_RRQ:
1160     case TFTP_EVENT_WRQ:
1161     default:
1162       failf(data, "%s", "Internal error: Unexpected packet");
1163       break;
1164     }
1165 
1166     /* Update the progress meter */
1167     if(Curl_pgrsUpdate(data)) {
1168       tftp_state_machine(state, TFTP_EVENT_ERROR);
1169       return CURLE_ABORTED_BY_CALLBACK;
1170     }
1171   }
1172   return result;
1173 }
1174 
1175 /**********************************************************
1176  *
1177  * tftp_state_timeout
1178  *
1179  * Check if timeouts have been reached
1180  *
1181  **********************************************************/
tftp_state_timeout(struct Curl_easy * data,tftp_event_t * event)1182 static timediff_t tftp_state_timeout(struct Curl_easy *data,
1183                                      tftp_event_t *event)
1184 {
1185   time_t current;
1186   struct connectdata *conn = data->conn;
1187   struct tftp_state_data *state = conn->proto.tftpc;
1188   timediff_t timeout_ms;
1189 
1190   if(event)
1191     *event = TFTP_EVENT_NONE;
1192 
1193   timeout_ms = Curl_timeleft(state->data, NULL,
1194                              (state->state == TFTP_STATE_START));
1195   if(timeout_ms < 0) {
1196     state->error = TFTP_ERR_TIMEOUT;
1197     state->state = TFTP_STATE_FIN;
1198     return 0;
1199   }
1200   current = time(NULL);
1201   if(current > state->rx_time + state->retry_time) {
1202     if(event)
1203       *event = TFTP_EVENT_TIMEOUT;
1204     state->rx_time = time(NULL); /* update even though we received nothing */
1205   }
1206 
1207   return timeout_ms;
1208 }
1209 
1210 /**********************************************************
1211  *
1212  * tftp_multi_statemach
1213  *
1214  * Handle single RX socket event and return
1215  *
1216  **********************************************************/
tftp_multi_statemach(struct Curl_easy * data,bool * done)1217 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1218 {
1219   tftp_event_t event;
1220   CURLcode result = CURLE_OK;
1221   struct connectdata *conn = data->conn;
1222   struct tftp_state_data *state = conn->proto.tftpc;
1223   timediff_t timeout_ms = tftp_state_timeout(data, &event);
1224 
1225   *done = FALSE;
1226 
1227   if(timeout_ms < 0) {
1228     failf(data, "TFTP response timeout");
1229     return CURLE_OPERATION_TIMEDOUT;
1230   }
1231   if(event != TFTP_EVENT_NONE) {
1232     result = tftp_state_machine(state, event);
1233     if(result)
1234       return result;
1235     *done = (state->state == TFTP_STATE_FIN);
1236     if(*done)
1237       /* Tell curl we are done */
1238       Curl_xfer_setup_nop(data);
1239   }
1240   else {
1241     /* no timeouts to handle, check our socket */
1242     int rc = SOCKET_READABLE(state->sockfd, 0);
1243 
1244     if(rc == -1) {
1245       /* bail out */
1246       int error = SOCKERRNO;
1247       char buffer[STRERROR_LEN];
1248       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1249       state->event = TFTP_EVENT_ERROR;
1250     }
1251     else if(rc) {
1252       result = tftp_receive_packet(data);
1253       if(result)
1254         return result;
1255       result = tftp_state_machine(state, state->event);
1256       if(result)
1257         return result;
1258       *done = (state->state == TFTP_STATE_FIN);
1259       if(*done)
1260         /* Tell curl we are done */
1261         Curl_xfer_setup_nop(data);
1262     }
1263     /* if rc == 0, then select() timed out */
1264   }
1265 
1266   return result;
1267 }
1268 
1269 /**********************************************************
1270  *
1271  * tftp_doing
1272  *
1273  * Called from multi.c while DOing
1274  *
1275  **********************************************************/
tftp_doing(struct Curl_easy * data,bool * dophase_done)1276 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1277 {
1278   CURLcode result;
1279   result = tftp_multi_statemach(data, dophase_done);
1280 
1281   if(*dophase_done) {
1282     DEBUGF(infof(data, "DO phase is complete"));
1283   }
1284   else if(!result) {
1285     /* The multi code does not have this logic for the DOING state so we
1286        provide it for TFTP since it may do the entire transfer in this
1287        state. */
1288     if(Curl_pgrsUpdate(data))
1289       result = CURLE_ABORTED_BY_CALLBACK;
1290     else
1291       result = Curl_speedcheck(data, Curl_now());
1292   }
1293   return result;
1294 }
1295 
1296 /**********************************************************
1297  *
1298  * tftp_perform
1299  *
1300  * Entry point for transfer from tftp_do, starts state mach
1301  *
1302  **********************************************************/
tftp_perform(struct Curl_easy * data,bool * dophase_done)1303 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1304 {
1305   CURLcode result = CURLE_OK;
1306   struct connectdata *conn = data->conn;
1307   struct tftp_state_data *state = conn->proto.tftpc;
1308 
1309   *dophase_done = FALSE;
1310 
1311   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1312 
1313   if((state->state == TFTP_STATE_FIN) || result)
1314     return result;
1315 
1316   tftp_multi_statemach(data, dophase_done);
1317 
1318   if(*dophase_done)
1319     DEBUGF(infof(data, "DO phase is complete"));
1320 
1321   return result;
1322 }
1323 
1324 
1325 /**********************************************************
1326  *
1327  * tftp_do
1328  *
1329  * The do callback
1330  *
1331  * This callback initiates the TFTP transfer
1332  *
1333  **********************************************************/
1334 
tftp_do(struct Curl_easy * data,bool * done)1335 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1336 {
1337   struct tftp_state_data *state;
1338   CURLcode result;
1339   struct connectdata *conn = data->conn;
1340 
1341   *done = FALSE;
1342 
1343   if(!conn->proto.tftpc) {
1344     result = tftp_connect(data, done);
1345     if(result)
1346       return result;
1347   }
1348 
1349   state = conn->proto.tftpc;
1350   if(!state)
1351     return CURLE_TFTP_ILLEGAL;
1352 
1353   result = tftp_perform(data, done);
1354 
1355   /* If tftp_perform() returned an error, use that for return code. If it
1356      was OK, see if tftp_translate_code() has an error. */
1357   if(!result)
1358     /* If we have encountered an internal tftp error, translate it. */
1359     result = tftp_translate_code(state->error);
1360 
1361   return result;
1362 }
1363 
tftp_setup_connection(struct Curl_easy * data,struct connectdata * conn)1364 static CURLcode tftp_setup_connection(struct Curl_easy *data,
1365                                       struct connectdata *conn)
1366 {
1367   char *type;
1368 
1369   conn->transport = TRNSPRT_UDP;
1370 
1371   /* TFTP URLs support an extension like ";mode=<typecode>" that
1372    * we will try to get now! */
1373   type = strstr(data->state.up.path, ";mode=");
1374 
1375   if(!type)
1376     type = strstr(conn->host.rawalloc, ";mode=");
1377 
1378   if(type) {
1379     char command;
1380     *type = 0;                   /* it was in the middle of the hostname */
1381     command = Curl_raw_toupper(type[6]);
1382 
1383     switch(command) {
1384     case 'A': /* ASCII mode */
1385     case 'N': /* NETASCII mode */
1386       data->state.prefer_ascii = TRUE;
1387       break;
1388 
1389     case 'O': /* octet mode */
1390     case 'I': /* binary mode */
1391     default:
1392       /* switch off ASCII */
1393       data->state.prefer_ascii = FALSE;
1394       break;
1395     }
1396   }
1397 
1398   return CURLE_OK;
1399 }
1400 #endif
1401