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,                            /* connection_check */
186   ZERO_NULL,                            /* attach connection */
187   PORT_TFTP,                            /* defport */
188   CURLPROTO_TFTP,                       /* protocol */
189   CURLPROTO_TFTP,                       /* family */
190   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
191 };
192 
193 /**********************************************************
194  *
195  * tftp_set_timeouts -
196  *
197  * Set timeouts based on state machine state.
198  * Use user provided connect timeouts until DATA or ACK
199  * packet is received, then use user-provided transfer timeouts
200  *
201  *
202  **********************************************************/
tftp_set_timeouts(struct tftp_state_data *state)203 static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
204 {
205   time_t maxtime, timeout;
206   timediff_t timeout_ms;
207   bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
208 
209   /* Compute drop-dead time */
210   timeout_ms = Curl_timeleft(state->data, NULL, start);
211 
212   if(timeout_ms < 0) {
213     /* time-out, bail out, go home */
214     failf(state->data, "Connection time-out");
215     return CURLE_OPERATION_TIMEDOUT;
216   }
217 
218   if(timeout_ms > 0)
219     maxtime = (time_t)(timeout_ms + 500) / 1000;
220   else
221     maxtime = 3600; /* use for calculating block timeouts */
222 
223   /* Set per-block timeout to total */
224   timeout = maxtime;
225 
226   /* Average reposting an ACK after 5 seconds */
227   state->retry_max = (int)timeout/5;
228 
229   /* But bound the total number */
230   if(state->retry_max<3)
231     state->retry_max = 3;
232 
233   if(state->retry_max>50)
234     state->retry_max = 50;
235 
236   /* Compute the re-ACK interval to suit the timeout */
237   state->retry_time = (int)(timeout/state->retry_max);
238   if(state->retry_time<1)
239     state->retry_time = 1;
240 
241   infof(state->data,
242         "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
243         ", retry %d maxtry %d",
244         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
245 
246   /* init RX time */
247   time(&state->rx_time);
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 doesn't 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 doesn't 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       state->data->req.upload_fromhere =
456         (char *)state->spacket.data + 4;
457       if(data->state.infilesize != -1)
458         Curl_pgrsSetUploadSize(data, data->state.infilesize);
459     }
460     else {
461       /* If we are downloading, send an RRQ */
462       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
463     }
464     /* As RFC3617 describes the separator slash is not actually part of the
465        file name so we skip the always-present first letter of the path
466        string. */
467     result = Curl_urldecode(&state->data->state.up.path[1], 0,
468                             &filename, NULL, REJECT_ZERO);
469     if(result)
470       return result;
471 
472     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
473       failf(data, "TFTP file name too long");
474       free(filename);
475       return CURLE_TFTP_ILLEGAL; /* too long file name field */
476     }
477 
478     msnprintf((char *)state->spacket.data + 2,
479               state->blksize,
480               "%s%c%s%c", filename, '\0',  mode, '\0');
481     sbytes = 4 + strlen(filename) + strlen(mode);
482 
483     /* optional addition of TFTP options */
484     if(!data->set.tftp_no_options) {
485       char buf[64];
486       /* add tsize option */
487       if(data->state.upload && (data->state.infilesize != -1))
488         msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
489                   data->state.infilesize);
490       else
491         strcpy(buf, "0"); /* the destination is large enough */
492 
493       result = tftp_option_add(state, &sbytes,
494                                (char *)state->spacket.data + sbytes,
495                                TFTP_OPTION_TSIZE);
496       if(result == CURLE_OK)
497         result = tftp_option_add(state, &sbytes,
498                                  (char *)state->spacket.data + sbytes, buf);
499 
500       /* add blksize option */
501       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
502       if(result == CURLE_OK)
503         result = tftp_option_add(state, &sbytes,
504                                  (char *)state->spacket.data + sbytes,
505                                  TFTP_OPTION_BLKSIZE);
506       if(result == CURLE_OK)
507         result = tftp_option_add(state, &sbytes,
508                                  (char *)state->spacket.data + sbytes, buf);
509 
510       /* add timeout option */
511       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
512       if(result == CURLE_OK)
513         result = tftp_option_add(state, &sbytes,
514                                  (char *)state->spacket.data + sbytes,
515                                  TFTP_OPTION_INTERVAL);
516       if(result == CURLE_OK)
517         result = tftp_option_add(state, &sbytes,
518                                  (char *)state->spacket.data + sbytes, buf);
519 
520       if(result != CURLE_OK) {
521         failf(data, "TFTP buffer too small for options");
522         free(filename);
523         return CURLE_TFTP_ILLEGAL;
524       }
525     }
526 
527     /* the typecase for the 3rd argument is mostly for systems that do
528        not have a size_t argument, like older unixes that want an 'int' */
529     senddata = sendto(state->sockfd, (void *)state->spacket.data,
530                       (SEND_TYPE_ARG3)sbytes, 0,
531                       &data->conn->remote_addr->sa_addr,
532                       data->conn->remote_addr->addrlen);
533     if(senddata != (ssize_t)sbytes) {
534       char buffer[STRERROR_LEN];
535       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
536     }
537     free(filename);
538     break;
539 
540   case TFTP_EVENT_OACK:
541     if(data->state.upload) {
542       result = tftp_connect_for_tx(state, event);
543     }
544     else {
545       result = tftp_connect_for_rx(state, event);
546     }
547     break;
548 
549   case TFTP_EVENT_ACK: /* Connected for transmit */
550     result = tftp_connect_for_tx(state, event);
551     break;
552 
553   case TFTP_EVENT_DATA: /* Connected for receive */
554     result = tftp_connect_for_rx(state, event);
555     break;
556 
557   case TFTP_EVENT_ERROR:
558     state->state = TFTP_STATE_FIN;
559     break;
560 
561   default:
562     failf(state->data, "tftp_send_first: internal error");
563     break;
564   }
565 
566   return result;
567 }
568 
569 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
570    boundary */
571 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
572 
573 /**********************************************************
574  *
575  * tftp_rx
576  *
577  * Event handler for the RX state
578  *
579  **********************************************************/
tftp_rx(struct tftp_state_data *state, tftp_event_t event)580 static CURLcode tftp_rx(struct tftp_state_data *state,
581                         tftp_event_t event)
582 {
583   ssize_t sbytes;
584   int rblock;
585   struct Curl_easy *data = state->data;
586   char buffer[STRERROR_LEN];
587 
588   switch(event) {
589 
590   case TFTP_EVENT_DATA:
591     /* Is this the block we expect? */
592     rblock = getrpacketblock(&state->rpacket);
593     if(NEXT_BLOCKNUM(state->block) == rblock) {
594       /* This is the expected block.  Reset counters and ACK it. */
595       state->retries = 0;
596     }
597     else if(state->block == rblock) {
598       /* This is the last recently received block again. Log it and ACK it
599          again. */
600       infof(data, "Received last DATA packet block %d again.", rblock);
601     }
602     else {
603       /* totally unexpected, just log it */
604       infof(data,
605             "Received unexpected DATA packet block %d, expecting block %d",
606             rblock, NEXT_BLOCKNUM(state->block));
607       break;
608     }
609 
610     /* ACK this block. */
611     state->block = (unsigned short)rblock;
612     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
613     setpacketblock(&state->spacket, state->block);
614     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
615                     4, SEND_4TH_ARG,
616                     (struct sockaddr *)&state->remote_addr,
617                     state->remote_addrlen);
618     if(sbytes < 0) {
619       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
620       return CURLE_SEND_ERROR;
621     }
622 
623     /* Check if completed (That is, a less than full packet is received) */
624     if(state->rbytes < (ssize_t)state->blksize + 4) {
625       state->state = TFTP_STATE_FIN;
626     }
627     else {
628       state->state = TFTP_STATE_RX;
629     }
630     time(&state->rx_time);
631     break;
632 
633   case TFTP_EVENT_OACK:
634     /* ACK option acknowledgement so we can move on to data */
635     state->block = 0;
636     state->retries = 0;
637     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
638     setpacketblock(&state->spacket, state->block);
639     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
640                     4, SEND_4TH_ARG,
641                     (struct sockaddr *)&state->remote_addr,
642                     state->remote_addrlen);
643     if(sbytes < 0) {
644       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
645       return CURLE_SEND_ERROR;
646     }
647 
648     /* we're ready to RX data */
649     state->state = TFTP_STATE_RX;
650     time(&state->rx_time);
651     break;
652 
653   case TFTP_EVENT_TIMEOUT:
654     /* Increment the retry count and fail if over the limit */
655     state->retries++;
656     infof(data,
657           "Timeout waiting for block %d ACK.  Retries = %d",
658           NEXT_BLOCKNUM(state->block), state->retries);
659     if(state->retries > state->retry_max) {
660       state->error = TFTP_ERR_TIMEOUT;
661       state->state = TFTP_STATE_FIN;
662     }
663     else {
664       /* Resend the previous ACK */
665       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
666                       4, SEND_4TH_ARG,
667                       (struct sockaddr *)&state->remote_addr,
668                       state->remote_addrlen);
669       if(sbytes<0) {
670         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
671         return CURLE_SEND_ERROR;
672       }
673     }
674     break;
675 
676   case TFTP_EVENT_ERROR:
677     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
678     setpacketblock(&state->spacket, state->block);
679     (void)sendto(state->sockfd, (void *)state->spacket.data,
680                  4, SEND_4TH_ARG,
681                  (struct sockaddr *)&state->remote_addr,
682                  state->remote_addrlen);
683     /* don't bother with the return code, but if the socket is still up we
684      * should be a good TFTP client and let the server know we're done */
685     state->state = TFTP_STATE_FIN;
686     break;
687 
688   default:
689     failf(data, "%s", "tftp_rx: internal error");
690     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
691                                   this */
692   }
693   return CURLE_OK;
694 }
695 
696 /**********************************************************
697  *
698  * tftp_tx
699  *
700  * Event handler for the TX state
701  *
702  **********************************************************/
tftp_tx(struct tftp_state_data *state, tftp_event_t event)703 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
704 {
705   struct Curl_easy *data = state->data;
706   ssize_t sbytes;
707   CURLcode result = CURLE_OK;
708   struct SingleRequest *k = &data->req;
709   size_t cb; /* Bytes currently read */
710   char buffer[STRERROR_LEN];
711 
712   switch(event) {
713 
714   case TFTP_EVENT_ACK:
715   case TFTP_EVENT_OACK:
716     if(event == TFTP_EVENT_ACK) {
717       /* Ack the packet */
718       int rblock = getrpacketblock(&state->rpacket);
719 
720       if(rblock != state->block &&
721          /* There's a bug in tftpd-hpa that causes it to send us an ack for
722           * 65535 when the block number wraps to 0. So when we're expecting
723           * 0, also accept 65535. See
724           * https://www.syslinux.org/archives/2010-September/015612.html
725           * */
726          !(state->block == 0 && rblock == 65535)) {
727         /* This isn't the expected block.  Log it and up the retry counter */
728         infof(data, "Received ACK for block %d, expecting %d",
729               rblock, state->block);
730         state->retries++;
731         /* Bail out if over the maximum */
732         if(state->retries>state->retry_max) {
733           failf(data, "tftp_tx: giving up waiting for block %d ack",
734                 state->block);
735           result = CURLE_SEND_ERROR;
736         }
737         else {
738           /* Re-send the data packet */
739           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
740                           4 + state->sbytes, SEND_4TH_ARG,
741                           (struct sockaddr *)&state->remote_addr,
742                           state->remote_addrlen);
743           /* Check all sbytes were sent */
744           if(sbytes<0) {
745             failf(data, "%s", Curl_strerror(SOCKERRNO,
746                                             buffer, sizeof(buffer)));
747             result = CURLE_SEND_ERROR;
748           }
749         }
750 
751         return result;
752       }
753       /* This is the expected packet.  Reset the counters and send the next
754          block */
755       time(&state->rx_time);
756       state->block++;
757     }
758     else
759       state->block = 1; /* first data block is 1 when using OACK */
760 
761     state->retries = 0;
762     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
763     setpacketblock(&state->spacket, state->block);
764     if(state->block > 1 && state->sbytes < state->blksize) {
765       state->state = TFTP_STATE_FIN;
766       return CURLE_OK;
767     }
768 
769     /* TFTP considers data block size < 512 bytes as an end of session. So
770      * in some cases we must wait for additional data to build full (512 bytes)
771      * data block.
772      * */
773     state->sbytes = 0;
774     state->data->req.upload_fromhere = (char *)state->spacket.data + 4;
775     do {
776       result = Curl_fillreadbuffer(data, state->blksize - state->sbytes, &cb);
777       if(result)
778         return result;
779       state->sbytes += (int)cb;
780       state->data->req.upload_fromhere += cb;
781     } while(state->sbytes < state->blksize && cb);
782 
783     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
784                     4 + state->sbytes, SEND_4TH_ARG,
785                     (struct sockaddr *)&state->remote_addr,
786                     state->remote_addrlen);
787     /* Check all sbytes were sent */
788     if(sbytes<0) {
789       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
790       return CURLE_SEND_ERROR;
791     }
792     /* Update the progress meter */
793     k->writebytecount += state->sbytes;
794     Curl_pgrsSetUploadCounter(data, k->writebytecount);
795     break;
796 
797   case TFTP_EVENT_TIMEOUT:
798     /* Increment the retry counter and log the timeout */
799     state->retries++;
800     infof(data, "Timeout waiting for block %d ACK. "
801           " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
802     /* Decide if we've had enough */
803     if(state->retries > state->retry_max) {
804       state->error = TFTP_ERR_TIMEOUT;
805       state->state = TFTP_STATE_FIN;
806     }
807     else {
808       /* Re-send the data packet */
809       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
810                       4 + state->sbytes, SEND_4TH_ARG,
811                       (struct sockaddr *)&state->remote_addr,
812                       state->remote_addrlen);
813       /* Check all sbytes were sent */
814       if(sbytes<0) {
815         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
816         return CURLE_SEND_ERROR;
817       }
818       /* since this was a re-send, we remain at the still byte position */
819       Curl_pgrsSetUploadCounter(data, k->writebytecount);
820     }
821     break;
822 
823   case TFTP_EVENT_ERROR:
824     state->state = TFTP_STATE_FIN;
825     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
826     setpacketblock(&state->spacket, state->block);
827     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
828                  (struct sockaddr *)&state->remote_addr,
829                  state->remote_addrlen);
830     /* don't bother with the return code, but if the socket is still up we
831      * should be a good TFTP client and let the server know we're done */
832     state->state = TFTP_STATE_FIN;
833     break;
834 
835   default:
836     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
837     break;
838   }
839 
840   return result;
841 }
842 
843 /**********************************************************
844  *
845  * tftp_translate_code
846  *
847  * Translate internal error codes to CURL error codes
848  *
849  **********************************************************/
tftp_translate_code(tftp_error_t error)850 static CURLcode tftp_translate_code(tftp_error_t error)
851 {
852   CURLcode result = CURLE_OK;
853 
854   if(error != TFTP_ERR_NONE) {
855     switch(error) {
856     case TFTP_ERR_NOTFOUND:
857       result = CURLE_TFTP_NOTFOUND;
858       break;
859     case TFTP_ERR_PERM:
860       result = CURLE_TFTP_PERM;
861       break;
862     case TFTP_ERR_DISKFULL:
863       result = CURLE_REMOTE_DISK_FULL;
864       break;
865     case TFTP_ERR_UNDEF:
866     case TFTP_ERR_ILLEGAL:
867       result = CURLE_TFTP_ILLEGAL;
868       break;
869     case TFTP_ERR_UNKNOWNID:
870       result = CURLE_TFTP_UNKNOWNID;
871       break;
872     case TFTP_ERR_EXISTS:
873       result = CURLE_REMOTE_FILE_EXISTS;
874       break;
875     case TFTP_ERR_NOSUCHUSER:
876       result = CURLE_TFTP_NOSUCHUSER;
877       break;
878     case TFTP_ERR_TIMEOUT:
879       result = CURLE_OPERATION_TIMEDOUT;
880       break;
881     case TFTP_ERR_NORESPONSE:
882       result = CURLE_COULDNT_CONNECT;
883       break;
884     default:
885       result = CURLE_ABORTED_BY_CALLBACK;
886       break;
887     }
888   }
889   else
890     result = CURLE_OK;
891 
892   return result;
893 }
894 
895 /**********************************************************
896  *
897  * tftp_state_machine
898  *
899  * The tftp state machine event dispatcher
900  *
901  **********************************************************/
tftp_state_machine(struct tftp_state_data *state, tftp_event_t event)902 static CURLcode tftp_state_machine(struct tftp_state_data *state,
903                                    tftp_event_t event)
904 {
905   CURLcode result = CURLE_OK;
906   struct Curl_easy *data = state->data;
907 
908   switch(state->state) {
909   case TFTP_STATE_START:
910     DEBUGF(infof(data, "TFTP_STATE_START"));
911     result = tftp_send_first(state, event);
912     break;
913   case TFTP_STATE_RX:
914     DEBUGF(infof(data, "TFTP_STATE_RX"));
915     result = tftp_rx(state, event);
916     break;
917   case TFTP_STATE_TX:
918     DEBUGF(infof(data, "TFTP_STATE_TX"));
919     result = tftp_tx(state, event);
920     break;
921   case TFTP_STATE_FIN:
922     infof(data, "%s", "TFTP finished");
923     break;
924   default:
925     DEBUGF(infof(data, "STATE: %d", state->state));
926     failf(data, "%s", "Internal state machine error");
927     result = CURLE_TFTP_ILLEGAL;
928     break;
929   }
930 
931   return result;
932 }
933 
934 /**********************************************************
935  *
936  * tftp_disconnect
937  *
938  * The disconnect callback
939  *
940  **********************************************************/
tftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection)941 static CURLcode tftp_disconnect(struct Curl_easy *data,
942                                 struct connectdata *conn, bool dead_connection)
943 {
944   struct tftp_state_data *state = conn->proto.tftpc;
945   (void) data;
946   (void) dead_connection;
947 
948   /* done, free dynamically allocated pkt buffers */
949   if(state) {
950     Curl_safefree(state->rpacket.data);
951     Curl_safefree(state->spacket.data);
952     free(state);
953   }
954 
955   return CURLE_OK;
956 }
957 
958 /**********************************************************
959  *
960  * tftp_connect
961  *
962  * The connect callback
963  *
964  **********************************************************/
tftp_connect(struct Curl_easy *data, bool *done)965 static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
966 {
967   struct tftp_state_data *state;
968   int blksize;
969   int need_blksize;
970   struct connectdata *conn = data->conn;
971 
972   blksize = TFTP_BLKSIZE_DEFAULT;
973 
974   state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
975   if(!state)
976     return CURLE_OUT_OF_MEMORY;
977 
978   /* alloc pkt buffers based on specified blksize */
979   if(data->set.tftp_blksize)
980     /* range checked when set */
981     blksize = (int)data->set.tftp_blksize;
982 
983   need_blksize = blksize;
984   /* default size is the fallback when no OACK is received */
985   if(need_blksize < TFTP_BLKSIZE_DEFAULT)
986     need_blksize = TFTP_BLKSIZE_DEFAULT;
987 
988   if(!state->rpacket.data) {
989     state->rpacket.data = calloc(1, need_blksize + 2 + 2);
990 
991     if(!state->rpacket.data)
992       return CURLE_OUT_OF_MEMORY;
993   }
994 
995   if(!state->spacket.data) {
996     state->spacket.data = calloc(1, need_blksize + 2 + 2);
997 
998     if(!state->spacket.data)
999       return CURLE_OUT_OF_MEMORY;
1000   }
1001 
1002   /* we don't keep TFTP connections up basically because there's none or very
1003    * little gain for UDP */
1004   connclose(conn, "TFTP");
1005 
1006   state->data = data;
1007   state->sockfd = conn->sock[FIRSTSOCKET];
1008   state->state = TFTP_STATE_START;
1009   state->error = TFTP_ERR_NONE;
1010   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
1011   state->requested_blksize = blksize;
1012 
1013   ((struct sockaddr *)&state->local_addr)->sa_family =
1014     (CURL_SA_FAMILY_T)(conn->remote_addr->family);
1015 
1016   tftp_set_timeouts(state);
1017 
1018   if(!conn->bits.bound) {
1019     /* If not already bound, bind to any interface, random UDP port. If it is
1020      * reused or a custom local port was desired, this has already been done!
1021      *
1022      * We once used the size of the local_addr struct as the third argument
1023      * for bind() to better work with IPv6 or whatever size the struct could
1024      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1025      * size of that argument to match the exact size of a 'sockaddr_in' struct
1026      * when running IPv4-only.
1027      *
1028      * Therefore we use the size from the address we connected to, which we
1029      * assume uses the same IP version and thus hopefully this works for both
1030      * IPv4 and IPv6...
1031      */
1032     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1033                   conn->remote_addr->addrlen);
1034     if(rc) {
1035       char buffer[STRERROR_LEN];
1036       failf(data, "bind() failed; %s",
1037             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1038       return CURLE_COULDNT_CONNECT;
1039     }
1040     conn->bits.bound = TRUE;
1041   }
1042 
1043   Curl_pgrsStartNow(data);
1044 
1045   *done = TRUE;
1046 
1047   return CURLE_OK;
1048 }
1049 
1050 /**********************************************************
1051  *
1052  * tftp_done
1053  *
1054  * The done callback
1055  *
1056  **********************************************************/
tftp_done(struct Curl_easy *data, CURLcode status, bool premature)1057 static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
1058                           bool premature)
1059 {
1060   CURLcode result = CURLE_OK;
1061   struct connectdata *conn = data->conn;
1062   struct tftp_state_data *state = conn->proto.tftpc;
1063 
1064   (void)status; /* unused */
1065   (void)premature; /* not used */
1066 
1067   if(Curl_pgrsDone(data))
1068     return CURLE_ABORTED_BY_CALLBACK;
1069 
1070   /* If we have encountered an error */
1071   if(state)
1072     result = tftp_translate_code(state->error);
1073 
1074   return result;
1075 }
1076 
1077 /**********************************************************
1078  *
1079  * tftp_getsock
1080  *
1081  * The getsock callback
1082  *
1083  **********************************************************/
tftp_getsock(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *socks)1084 static int tftp_getsock(struct Curl_easy *data,
1085                         struct connectdata *conn, curl_socket_t *socks)
1086 {
1087   (void)data;
1088   socks[0] = conn->sock[FIRSTSOCKET];
1089   return GETSOCK_READSOCK(0);
1090 }
1091 
1092 /**********************************************************
1093  *
1094  * tftp_receive_packet
1095  *
1096  * Called once select fires and data is ready on the socket
1097  *
1098  **********************************************************/
tftp_receive_packet(struct Curl_easy *data)1099 static CURLcode tftp_receive_packet(struct Curl_easy *data)
1100 {
1101   struct Curl_sockaddr_storage fromaddr;
1102   curl_socklen_t        fromlen;
1103   CURLcode              result = CURLE_OK;
1104   struct connectdata *conn = data->conn;
1105   struct tftp_state_data *state = conn->proto.tftpc;
1106 
1107   /* Receive the packet */
1108   fromlen = sizeof(fromaddr);
1109   state->rbytes = (int)recvfrom(state->sockfd,
1110                                 (void *)state->rpacket.data,
1111                                 state->blksize + 4,
1112                                 0,
1113                                 (struct sockaddr *)&fromaddr,
1114                                 &fromlen);
1115   if(state->remote_addrlen == 0) {
1116     memcpy(&state->remote_addr, &fromaddr, fromlen);
1117     state->remote_addrlen = fromlen;
1118   }
1119 
1120   /* Sanity check packet length */
1121   if(state->rbytes < 4) {
1122     failf(data, "Received too short packet");
1123     /* Not a timeout, but how best to handle it? */
1124     state->event = TFTP_EVENT_TIMEOUT;
1125   }
1126   else {
1127     /* The event is given by the TFTP packet time */
1128     unsigned short event = getrpacketevent(&state->rpacket);
1129     state->event = (tftp_event_t)event;
1130 
1131     switch(state->event) {
1132     case TFTP_EVENT_DATA:
1133       /* Don't pass to the client empty or retransmitted packets */
1134       if(state->rbytes > 4 &&
1135          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1136         result = Curl_client_write(data, CLIENTWRITE_BODY,
1137                                    (char *)state->rpacket.data + 4,
1138                                    state->rbytes-4);
1139         if(result) {
1140           tftp_state_machine(state, TFTP_EVENT_ERROR);
1141           return result;
1142         }
1143       }
1144       break;
1145     case TFTP_EVENT_ERROR:
1146     {
1147       unsigned short error = getrpacketblock(&state->rpacket);
1148       char *str = (char *)state->rpacket.data + 4;
1149       size_t strn = state->rbytes - 4;
1150       state->error = (tftp_error_t)error;
1151       if(tftp_strnlen(str, strn) < strn)
1152         infof(data, "TFTP error: %s", str);
1153       break;
1154     }
1155     case TFTP_EVENT_ACK:
1156       break;
1157     case TFTP_EVENT_OACK:
1158       result = tftp_parse_option_ack(state,
1159                                      (const char *)state->rpacket.data + 2,
1160                                      state->rbytes-2);
1161       if(result)
1162         return result;
1163       break;
1164     case TFTP_EVENT_RRQ:
1165     case TFTP_EVENT_WRQ:
1166     default:
1167       failf(data, "%s", "Internal error: Unexpected packet");
1168       break;
1169     }
1170 
1171     /* Update the progress meter */
1172     if(Curl_pgrsUpdate(data)) {
1173       tftp_state_machine(state, TFTP_EVENT_ERROR);
1174       return CURLE_ABORTED_BY_CALLBACK;
1175     }
1176   }
1177   return result;
1178 }
1179 
1180 /**********************************************************
1181  *
1182  * tftp_state_timeout
1183  *
1184  * Check if timeouts have been reached
1185  *
1186  **********************************************************/
tftp_state_timeout(struct Curl_easy *data, tftp_event_t *event)1187 static timediff_t tftp_state_timeout(struct Curl_easy *data,
1188                                      tftp_event_t *event)
1189 {
1190   time_t current;
1191   struct connectdata *conn = data->conn;
1192   struct tftp_state_data *state = conn->proto.tftpc;
1193   timediff_t timeout_ms;
1194 
1195   if(event)
1196     *event = TFTP_EVENT_NONE;
1197 
1198   timeout_ms = Curl_timeleft(state->data, NULL,
1199                              (state->state == TFTP_STATE_START));
1200   if(timeout_ms < 0) {
1201     state->error = TFTP_ERR_TIMEOUT;
1202     state->state = TFTP_STATE_FIN;
1203     return 0;
1204   }
1205   time(&current);
1206   if(current > state->rx_time + state->retry_time) {
1207     if(event)
1208       *event = TFTP_EVENT_TIMEOUT;
1209     time(&state->rx_time); /* update even though we received nothing */
1210   }
1211 
1212   return timeout_ms;
1213 }
1214 
1215 /**********************************************************
1216  *
1217  * tftp_multi_statemach
1218  *
1219  * Handle single RX socket event and return
1220  *
1221  **********************************************************/
tftp_multi_statemach(struct Curl_easy *data, bool *done)1222 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1223 {
1224   tftp_event_t event;
1225   CURLcode result = CURLE_OK;
1226   struct connectdata *conn = data->conn;
1227   struct tftp_state_data *state = conn->proto.tftpc;
1228   timediff_t timeout_ms = tftp_state_timeout(data, &event);
1229 
1230   *done = FALSE;
1231 
1232   if(timeout_ms < 0) {
1233     failf(data, "TFTP response timeout");
1234     return CURLE_OPERATION_TIMEDOUT;
1235   }
1236   if(event != TFTP_EVENT_NONE) {
1237     result = tftp_state_machine(state, event);
1238     if(result)
1239       return result;
1240     *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1241     if(*done)
1242       /* Tell curl we're done */
1243       Curl_setup_transfer(data, -1, -1, FALSE, -1);
1244   }
1245   else {
1246     /* no timeouts to handle, check our socket */
1247     int rc = SOCKET_READABLE(state->sockfd, 0);
1248 
1249     if(rc == -1) {
1250       /* bail out */
1251       int error = SOCKERRNO;
1252       char buffer[STRERROR_LEN];
1253       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1254       state->event = TFTP_EVENT_ERROR;
1255     }
1256     else if(rc) {
1257       result = tftp_receive_packet(data);
1258       if(result)
1259         return result;
1260       result = tftp_state_machine(state, state->event);
1261       if(result)
1262         return result;
1263       *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1264       if(*done)
1265         /* Tell curl we're done */
1266         Curl_setup_transfer(data, -1, -1, FALSE, -1);
1267     }
1268     /* if rc == 0, then select() timed out */
1269   }
1270 
1271   return result;
1272 }
1273 
1274 /**********************************************************
1275  *
1276  * tftp_doing
1277  *
1278  * Called from multi.c while DOing
1279  *
1280  **********************************************************/
tftp_doing(struct Curl_easy *data, bool *dophase_done)1281 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1282 {
1283   CURLcode result;
1284   result = tftp_multi_statemach(data, dophase_done);
1285 
1286   if(*dophase_done) {
1287     DEBUGF(infof(data, "DO phase is complete"));
1288   }
1289   else if(!result) {
1290     /* The multi code doesn't have this logic for the DOING state so we
1291        provide it for TFTP since it may do the entire transfer in this
1292        state. */
1293     if(Curl_pgrsUpdate(data))
1294       result = CURLE_ABORTED_BY_CALLBACK;
1295     else
1296       result = Curl_speedcheck(data, Curl_now());
1297   }
1298   return result;
1299 }
1300 
1301 /**********************************************************
1302  *
1303  * tftp_perform
1304  *
1305  * Entry point for transfer from tftp_do, starts state mach
1306  *
1307  **********************************************************/
tftp_perform(struct Curl_easy *data, bool *dophase_done)1308 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1309 {
1310   CURLcode result = CURLE_OK;
1311   struct connectdata *conn = data->conn;
1312   struct tftp_state_data *state = conn->proto.tftpc;
1313 
1314   *dophase_done = FALSE;
1315 
1316   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1317 
1318   if((state->state == TFTP_STATE_FIN) || result)
1319     return result;
1320 
1321   tftp_multi_statemach(data, dophase_done);
1322 
1323   if(*dophase_done)
1324     DEBUGF(infof(data, "DO phase is complete"));
1325 
1326   return result;
1327 }
1328 
1329 
1330 /**********************************************************
1331  *
1332  * tftp_do
1333  *
1334  * The do callback
1335  *
1336  * This callback initiates the TFTP transfer
1337  *
1338  **********************************************************/
1339 
tftp_do(struct Curl_easy *data, bool *done)1340 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1341 {
1342   struct tftp_state_data *state;
1343   CURLcode result;
1344   struct connectdata *conn = data->conn;
1345 
1346   *done = FALSE;
1347 
1348   if(!conn->proto.tftpc) {
1349     result = tftp_connect(data, done);
1350     if(result)
1351       return result;
1352   }
1353 
1354   state = conn->proto.tftpc;
1355   if(!state)
1356     return CURLE_TFTP_ILLEGAL;
1357 
1358   result = tftp_perform(data, done);
1359 
1360   /* If tftp_perform() returned an error, use that for return code. If it
1361      was OK, see if tftp_translate_code() has an error. */
1362   if(!result)
1363     /* If we have encountered an internal tftp error, translate it. */
1364     result = tftp_translate_code(state->error);
1365 
1366   return result;
1367 }
1368 
tftp_setup_connection(struct Curl_easy *data, struct connectdata *conn)1369 static CURLcode tftp_setup_connection(struct Curl_easy *data,
1370                                       struct connectdata *conn)
1371 {
1372   char *type;
1373 
1374   conn->transport = TRNSPRT_UDP;
1375 
1376   /* TFTP URLs support an extension like ";mode=<typecode>" that
1377    * we'll try to get now! */
1378   type = strstr(data->state.up.path, ";mode=");
1379 
1380   if(!type)
1381     type = strstr(conn->host.rawalloc, ";mode=");
1382 
1383   if(type) {
1384     char command;
1385     *type = 0;                   /* it was in the middle of the hostname */
1386     command = Curl_raw_toupper(type[6]);
1387 
1388     switch(command) {
1389     case 'A': /* ASCII mode */
1390     case 'N': /* NETASCII mode */
1391       data->state.prefer_ascii = TRUE;
1392       break;
1393 
1394     case 'O': /* octet mode */
1395     case 'I': /* binary mode */
1396     default:
1397       /* switch off ASCII */
1398       data->state.prefer_ascii = FALSE;
1399       break;
1400     }
1401   }
1402 
1403   return CURLE_OK;
1404 }
1405 #endif
1406