• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   ZERO_NULL,                            /* follow */
189   PORT_TFTP,                            /* defport */
190   CURLPROTO_TFTP,                       /* protocol */
191   CURLPROTO_TFTP,                       /* family */
192   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
193 };
194 
195 /**********************************************************
196  *
197  * tftp_set_timeouts -
198  *
199  * Set timeouts based on state machine state.
200  * Use user provided connect timeouts until DATA or ACK
201  * packet is received, then use user-provided transfer timeouts
202  *
203  *
204  **********************************************************/
tftp_set_timeouts(struct tftp_state_data * state)205 static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
206 {
207   time_t maxtime, timeout;
208   timediff_t timeout_ms;
209   bool start = (state->state == TFTP_STATE_START);
210 
211   /* Compute drop-dead time */
212   timeout_ms = Curl_timeleft(state->data, NULL, start);
213 
214   if(timeout_ms < 0) {
215     /* time-out, bail out, go home */
216     failf(state->data, "Connection time-out");
217     return CURLE_OPERATION_TIMEDOUT;
218   }
219 
220   if(timeout_ms > 0)
221     maxtime = (time_t)(timeout_ms + 500) / 1000;
222   else
223     maxtime = 3600; /* use for calculating block timeouts */
224 
225   /* Set per-block timeout to total */
226   timeout = maxtime;
227 
228   /* Average reposting an ACK after 5 seconds */
229   state->retry_max = (int)timeout/5;
230 
231   /* But bound the total number */
232   if(state->retry_max < 3)
233     state->retry_max = 3;
234 
235   if(state->retry_max > 50)
236     state->retry_max = 50;
237 
238   /* Compute the re-ACK interval to suit the timeout */
239   state->retry_time = (int)(timeout/state->retry_max);
240   if(state->retry_time < 1)
241     state->retry_time = 1;
242 
243   infof(state->data,
244         "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
245         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
246 
247   /* init RX time */
248   state->rx_time = time(NULL);
249 
250   return CURLE_OK;
251 }
252 
253 /**********************************************************
254  *
255  * tftp_set_send_first
256  *
257  * Event handler for the START state
258  *
259  **********************************************************/
260 
setpacketevent(struct tftp_packet * packet,unsigned short num)261 static void setpacketevent(struct tftp_packet *packet, unsigned short num)
262 {
263   packet->data[0] = (unsigned char)(num >> 8);
264   packet->data[1] = (unsigned char)(num & 0xff);
265 }
266 
267 
setpacketblock(struct tftp_packet * packet,unsigned short num)268 static void setpacketblock(struct tftp_packet *packet, unsigned short num)
269 {
270   packet->data[2] = (unsigned char)(num >> 8);
271   packet->data[3] = (unsigned char)(num & 0xff);
272 }
273 
getrpacketevent(const struct tftp_packet * packet)274 static unsigned short getrpacketevent(const struct tftp_packet *packet)
275 {
276   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
277 }
278 
getrpacketblock(const struct tftp_packet * packet)279 static unsigned short getrpacketblock(const struct tftp_packet *packet)
280 {
281   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
282 }
283 
tftp_strnlen(const char * string,size_t maxlen)284 static size_t tftp_strnlen(const char *string, size_t maxlen)
285 {
286   const char *end = memchr(string, '\0', maxlen);
287   return end ? (size_t) (end - string) : maxlen;
288 }
289 
tftp_option_get(const char * buf,size_t len,const char ** option,const char ** value)290 static const char *tftp_option_get(const char *buf, size_t len,
291                                    const char **option, const char **value)
292 {
293   size_t loc;
294 
295   loc = tftp_strnlen(buf, len);
296   loc++; /* NULL term */
297 
298   if(loc >= len)
299     return NULL;
300   *option = buf;
301 
302   loc += tftp_strnlen(buf + loc, len-loc);
303   loc++; /* NULL term */
304 
305   if(loc > len)
306     return NULL;
307   *value = &buf[strlen(*option) + 1];
308 
309   return &buf[loc];
310 }
311 
tftp_parse_option_ack(struct tftp_state_data * state,const char * ptr,int len)312 static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
313                                       const char *ptr, int len)
314 {
315   const char *tmp = ptr;
316   struct Curl_easy *data = state->data;
317 
318   /* if OACK does not contain blksize option, the default (512) must be used */
319   state->blksize = TFTP_BLKSIZE_DEFAULT;
320 
321   while(tmp < ptr + len) {
322     const char *option, *value;
323 
324     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
325     if(!tmp) {
326       failf(data, "Malformed ACK packet, rejecting");
327       return CURLE_TFTP_ILLEGAL;
328     }
329 
330     infof(data, "got option=(%s) value=(%s)", option, value);
331 
332     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
333       long blksize;
334 
335       blksize = strtol(value, NULL, 10);
336 
337       if(!blksize) {
338         failf(data, "invalid blocksize value in OACK packet");
339         return CURLE_TFTP_ILLEGAL;
340       }
341       if(blksize > TFTP_BLKSIZE_MAX) {
342         failf(data, "%s (%d)", "blksize is larger than max supported",
343               TFTP_BLKSIZE_MAX);
344         return CURLE_TFTP_ILLEGAL;
345       }
346       else if(blksize < TFTP_BLKSIZE_MIN) {
347         failf(data, "%s (%d)", "blksize is smaller than min supported",
348               TFTP_BLKSIZE_MIN);
349         return CURLE_TFTP_ILLEGAL;
350       }
351       else if(blksize > state->requested_blksize) {
352         /* could realloc pkt buffers here, but the spec does not call out
353          * support for the server requesting a bigger blksize than the client
354          * requests */
355         failf(data, "%s (%ld)",
356               "server requested blksize larger than allocated", blksize);
357         return CURLE_TFTP_ILLEGAL;
358       }
359 
360       state->blksize = (int)blksize;
361       infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
362             state->blksize, "requested", state->requested_blksize);
363     }
364     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
365       long tsize = 0;
366 
367       tsize = strtol(value, NULL, 10);
368       infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
369 
370       /* tsize should be ignored on upload: Who cares about the size of the
371          remote file? */
372       if(!data->state.upload) {
373         if(!tsize) {
374           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
375           return CURLE_TFTP_ILLEGAL;
376         }
377         Curl_pgrsSetDownloadSize(data, tsize);
378       }
379     }
380   }
381 
382   return CURLE_OK;
383 }
384 
tftp_option_add(struct tftp_state_data * state,size_t * csize,char * buf,const char * option)385 static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
386                                 char *buf, const char *option)
387 {
388   if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
389     return CURLE_TFTP_ILLEGAL;
390   strcpy(buf, option);
391   *csize += strlen(option) + 1;
392   return CURLE_OK;
393 }
394 
tftp_connect_for_tx(struct tftp_state_data * state,tftp_event_t event)395 static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
396                                     tftp_event_t event)
397 {
398   CURLcode result;
399 #ifndef CURL_DISABLE_VERBOSE_STRINGS
400   struct Curl_easy *data = state->data;
401 
402   infof(data, "%s", "Connected for transmit");
403 #endif
404   state->state = TFTP_STATE_TX;
405   result = tftp_set_timeouts(state);
406   if(result)
407     return result;
408   return tftp_tx(state, event);
409 }
410 
tftp_connect_for_rx(struct tftp_state_data * state,tftp_event_t event)411 static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
412                                     tftp_event_t event)
413 {
414   CURLcode result;
415 #ifndef CURL_DISABLE_VERBOSE_STRINGS
416   struct Curl_easy *data = state->data;
417 
418   infof(data, "%s", "Connected for receive");
419 #endif
420   state->state = TFTP_STATE_RX;
421   result = tftp_set_timeouts(state);
422   if(result)
423     return result;
424   return tftp_rx(state, event);
425 }
426 
tftp_send_first(struct tftp_state_data * state,tftp_event_t event)427 static CURLcode tftp_send_first(struct tftp_state_data *state,
428                                 tftp_event_t event)
429 {
430   size_t sbytes;
431   ssize_t senddata;
432   const char *mode = "octet";
433   char *filename;
434   struct Curl_easy *data = state->data;
435   CURLcode result = CURLE_OK;
436 
437   /* Set ASCII mode if -B flag was used */
438   if(data->state.prefer_ascii)
439     mode = "netascii";
440 
441   switch(event) {
442 
443   case TFTP_EVENT_INIT:    /* Send the first packet out */
444   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
445     /* Increment the retry counter, quit if over the limit */
446     state->retries++;
447     if(state->retries > state->retry_max) {
448       state->error = TFTP_ERR_NORESPONSE;
449       state->state = TFTP_STATE_FIN;
450       return result;
451     }
452 
453     if(data->state.upload) {
454       /* If we are uploading, send an WRQ */
455       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
456       if(data->state.infilesize != -1)
457         Curl_pgrsSetUploadSize(data, data->state.infilesize);
458     }
459     else {
460       /* If we are downloading, send an RRQ */
461       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
462     }
463     /* As RFC3617 describes the separator slash is not actually part of the
464        filename so we skip the always-present first letter of the path
465        string. */
466     result = Curl_urldecode(&state->data->state.up.path[1], 0,
467                             &filename, NULL, REJECT_ZERO);
468     if(result)
469       return result;
470 
471     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
472       failf(data, "TFTP filename too long");
473       free(filename);
474       return CURLE_TFTP_ILLEGAL; /* too long filename field */
475     }
476 
477     msnprintf((char *)state->spacket.data + 2,
478               state->blksize,
479               "%s%c%s%c", filename, '\0',  mode, '\0');
480     sbytes = 4 + strlen(filename) + strlen(mode);
481 
482     /* optional addition of TFTP options */
483     if(!data->set.tftp_no_options) {
484       char buf[64];
485       /* add tsize option */
486       msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
487                 data->state.upload && (data->state.infilesize != -1) ?
488                 data->state.infilesize : 0);
489 
490       result = tftp_option_add(state, &sbytes,
491                                (char *)state->spacket.data + sbytes,
492                                TFTP_OPTION_TSIZE);
493       if(result == CURLE_OK)
494         result = tftp_option_add(state, &sbytes,
495                                  (char *)state->spacket.data + sbytes, buf);
496 
497       /* add blksize option */
498       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
499       if(result == CURLE_OK)
500         result = tftp_option_add(state, &sbytes,
501                                  (char *)state->spacket.data + sbytes,
502                                  TFTP_OPTION_BLKSIZE);
503       if(result == CURLE_OK)
504         result = tftp_option_add(state, &sbytes,
505                                  (char *)state->spacket.data + sbytes, buf);
506 
507       /* add timeout option */
508       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
509       if(result == CURLE_OK)
510         result = tftp_option_add(state, &sbytes,
511                                  (char *)state->spacket.data + sbytes,
512                                  TFTP_OPTION_INTERVAL);
513       if(result == CURLE_OK)
514         result = tftp_option_add(state, &sbytes,
515                                  (char *)state->spacket.data + sbytes, buf);
516 
517       if(result != CURLE_OK) {
518         failf(data, "TFTP buffer too small for options");
519         free(filename);
520         return CURLE_TFTP_ILLEGAL;
521       }
522     }
523 
524     /* the typecase for the 3rd argument is mostly for systems that do
525        not have a size_t argument, like older unixes that want an 'int' */
526     senddata = sendto(state->sockfd, (void *)state->spacket.data,
527                       (SEND_TYPE_ARG3)sbytes, 0,
528                      (struct sockaddr *)&data->conn->remote_addr->curl_sa_addr,
529                       (curl_socklen_t)data->conn->remote_addr->addrlen);
530     if(senddata != (ssize_t)sbytes) {
531       char buffer[STRERROR_LEN];
532       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
533     }
534     free(filename);
535     break;
536 
537   case TFTP_EVENT_OACK:
538     if(data->state.upload) {
539       result = tftp_connect_for_tx(state, event);
540     }
541     else {
542       result = tftp_connect_for_rx(state, event);
543     }
544     break;
545 
546   case TFTP_EVENT_ACK: /* Connected for transmit */
547     result = tftp_connect_for_tx(state, event);
548     break;
549 
550   case TFTP_EVENT_DATA: /* Connected for receive */
551     result = tftp_connect_for_rx(state, event);
552     break;
553 
554   case TFTP_EVENT_ERROR:
555     state->state = TFTP_STATE_FIN;
556     break;
557 
558   default:
559     failf(state->data, "tftp_send_first: internal error");
560     break;
561   }
562 
563   return result;
564 }
565 
566 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
567    boundary */
568 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
569 
570 /**********************************************************
571  *
572  * tftp_rx
573  *
574  * Event handler for the RX state
575  *
576  **********************************************************/
tftp_rx(struct tftp_state_data * state,tftp_event_t event)577 static CURLcode tftp_rx(struct tftp_state_data *state,
578                         tftp_event_t event)
579 {
580   ssize_t sbytes;
581   int rblock;
582   struct Curl_easy *data = state->data;
583   char buffer[STRERROR_LEN];
584 
585   switch(event) {
586 
587   case TFTP_EVENT_DATA:
588     /* Is this the block we expect? */
589     rblock = getrpacketblock(&state->rpacket);
590     if(NEXT_BLOCKNUM(state->block) == rblock) {
591       /* This is the expected block. Reset counters and ACK it. */
592       state->retries = 0;
593     }
594     else if(state->block == rblock) {
595       /* This is the last recently received block again. Log it and ACK it
596          again. */
597       infof(data, "Received last DATA packet block %d again.", rblock);
598     }
599     else {
600       /* totally unexpected, just log it */
601       infof(data,
602             "Received unexpected DATA packet block %d, expecting block %d",
603             rblock, NEXT_BLOCKNUM(state->block));
604       break;
605     }
606 
607     /* ACK this block. */
608     state->block = (unsigned short)rblock;
609     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
610     setpacketblock(&state->spacket, state->block);
611     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
612                     4, SEND_4TH_ARG,
613                     (struct sockaddr *)&state->remote_addr,
614                     state->remote_addrlen);
615     if(sbytes < 0) {
616       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
617       return CURLE_SEND_ERROR;
618     }
619 
620     /* Check if completed (That is, a less than full packet is received) */
621     if(state->rbytes < (ssize_t)state->blksize + 4) {
622       state->state = TFTP_STATE_FIN;
623     }
624     else {
625       state->state = TFTP_STATE_RX;
626     }
627     state->rx_time = time(NULL);
628     break;
629 
630   case TFTP_EVENT_OACK:
631     /* ACK option acknowledgement so we can move on to data */
632     state->block = 0;
633     state->retries = 0;
634     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
635     setpacketblock(&state->spacket, state->block);
636     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
637                     4, SEND_4TH_ARG,
638                     (struct sockaddr *)&state->remote_addr,
639                     state->remote_addrlen);
640     if(sbytes < 0) {
641       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
642       return CURLE_SEND_ERROR;
643     }
644 
645     /* we are ready to RX data */
646     state->state = TFTP_STATE_RX;
647     state->rx_time = time(NULL);
648     break;
649 
650   case TFTP_EVENT_TIMEOUT:
651     /* Increment the retry count and fail if over the limit */
652     state->retries++;
653     infof(data,
654           "Timeout waiting for block %d ACK. Retries = %d",
655           NEXT_BLOCKNUM(state->block), state->retries);
656     if(state->retries > state->retry_max) {
657       state->error = TFTP_ERR_TIMEOUT;
658       state->state = TFTP_STATE_FIN;
659     }
660     else {
661       /* Resend the previous ACK */
662       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
663                       4, SEND_4TH_ARG,
664                       (struct sockaddr *)&state->remote_addr,
665                       state->remote_addrlen);
666       if(sbytes < 0) {
667         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
668         return CURLE_SEND_ERROR;
669       }
670     }
671     break;
672 
673   case TFTP_EVENT_ERROR:
674     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
675     setpacketblock(&state->spacket, state->block);
676     (void)sendto(state->sockfd, (void *)state->spacket.data,
677                  4, SEND_4TH_ARG,
678                  (struct sockaddr *)&state->remote_addr,
679                  state->remote_addrlen);
680     /* do not bother with the return code, but if the socket is still up we
681      * should be a good TFTP client and let the server know we are done */
682     state->state = TFTP_STATE_FIN;
683     break;
684 
685   default:
686     failf(data, "%s", "tftp_rx: internal error");
687     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
688                                   this */
689   }
690   return CURLE_OK;
691 }
692 
693 /**********************************************************
694  *
695  * tftp_tx
696  *
697  * Event handler for the TX state
698  *
699  **********************************************************/
tftp_tx(struct tftp_state_data * state,tftp_event_t event)700 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
701 {
702   struct Curl_easy *data = state->data;
703   ssize_t sbytes;
704   CURLcode result = CURLE_OK;
705   struct SingleRequest *k = &data->req;
706   size_t cb; /* Bytes currently read */
707   char buffer[STRERROR_LEN];
708   char *bufptr;
709   bool eos;
710 
711   switch(event) {
712 
713   case TFTP_EVENT_ACK:
714   case TFTP_EVENT_OACK:
715     if(event == TFTP_EVENT_ACK) {
716       /* Ack the packet */
717       int rblock = getrpacketblock(&state->rpacket);
718 
719       if(rblock != state->block &&
720          /* There is a bug in tftpd-hpa that causes it to send us an ack for
721           * 65535 when the block number wraps to 0. So when we are expecting
722           * 0, also accept 65535. See
723           * https://www.syslinux.org/archives/2010-September/015612.html
724           * */
725          !(state->block == 0 && rblock == 65535)) {
726         /* This is not the expected block. Log it and up the retry counter */
727         infof(data, "Received ACK for block %d, expecting %d",
728               rblock, state->block);
729         state->retries++;
730         /* Bail out if over the maximum */
731         if(state->retries > state->retry_max) {
732           failf(data, "tftp_tx: giving up waiting for block %d ack",
733                 state->block);
734           result = CURLE_SEND_ERROR;
735         }
736         else {
737           /* Re-send the data packet */
738           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
739                           4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
740                           (struct sockaddr *)&state->remote_addr,
741                           state->remote_addrlen);
742           /* Check all sbytes were sent */
743           if(sbytes < 0) {
744             failf(data, "%s", Curl_strerror(SOCKERRNO,
745                                             buffer, sizeof(buffer)));
746             result = CURLE_SEND_ERROR;
747           }
748         }
749 
750         return result;
751       }
752       /* This is the expected packet. Reset the counters and send the next
753          block */
754       state->rx_time = time(NULL);
755       state->block++;
756     }
757     else
758       state->block = 1; /* first data block is 1 when using OACK */
759 
760     state->retries = 0;
761     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
762     setpacketblock(&state->spacket, state->block);
763     if(state->block > 1 && state->sbytes < state->blksize) {
764       state->state = TFTP_STATE_FIN;
765       return CURLE_OK;
766     }
767 
768     /* TFTP considers data block size < 512 bytes as an end of session. So
769      * in some cases we must wait for additional data to build full (512 bytes)
770      * data block.
771      * */
772     state->sbytes = 0;
773     bufptr = (char *)state->spacket.data + 4;
774     do {
775       result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
776                                 &cb, &eos);
777       if(result)
778         return result;
779       state->sbytes += (int)cb;
780       bufptr += cb;
781     } while(state->sbytes < state->blksize && cb);
782 
783     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
784                     4 + (SEND_TYPE_ARG3)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 have 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 + (SEND_TYPE_ARG3)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     /* do not 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 are 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 do not keep TFTP connections up basically because there is none or
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                   (curl_socklen_t)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   curl_socklen_t        fromlen;
1102   CURLcode              result = CURLE_OK;
1103   struct connectdata *conn = data->conn;
1104   struct tftp_state_data *state = conn->proto.tftpc;
1105 
1106   /* Receive the packet */
1107   fromlen = sizeof(state->remote_addr);
1108   state->rbytes = (int)recvfrom(state->sockfd,
1109                                 (void *)state->rpacket.data,
1110                                 (RECV_TYPE_ARG3)state->blksize + 4,
1111                                 0,
1112                                 (struct sockaddr *)&state->remote_addr,
1113                                 &fromlen);
1114   state->remote_addrlen = fromlen;
1115 
1116   /* Sanity check packet length */
1117   if(state->rbytes < 4) {
1118     failf(data, "Received too short packet");
1119     /* Not a timeout, but how best to handle it? */
1120     state->event = TFTP_EVENT_TIMEOUT;
1121   }
1122   else {
1123     /* The event is given by the TFTP packet time */
1124     unsigned short event = getrpacketevent(&state->rpacket);
1125     state->event = (tftp_event_t)event;
1126 
1127     switch(state->event) {
1128     case TFTP_EVENT_DATA:
1129       /* Do not pass to the client empty or retransmitted packets */
1130       if(state->rbytes > 4 &&
1131          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1132         result = Curl_client_write(data, CLIENTWRITE_BODY,
1133                                    (char *)state->rpacket.data + 4,
1134                                    state->rbytes-4);
1135         if(result) {
1136           tftp_state_machine(state, TFTP_EVENT_ERROR);
1137           return result;
1138         }
1139       }
1140       break;
1141     case TFTP_EVENT_ERROR:
1142     {
1143       unsigned short error = getrpacketblock(&state->rpacket);
1144       char *str = (char *)state->rpacket.data + 4;
1145       size_t strn = state->rbytes - 4;
1146       state->error = (tftp_error_t)error;
1147       if(tftp_strnlen(str, strn) < strn)
1148         infof(data, "TFTP error: %s", str);
1149       break;
1150     }
1151     case TFTP_EVENT_ACK:
1152       break;
1153     case TFTP_EVENT_OACK:
1154       result = tftp_parse_option_ack(state,
1155                                      (const char *)state->rpacket.data + 2,
1156                                      state->rbytes-2);
1157       if(result)
1158         return result;
1159       break;
1160     case TFTP_EVENT_RRQ:
1161     case TFTP_EVENT_WRQ:
1162     default:
1163       failf(data, "%s", "Internal error: Unexpected packet");
1164       break;
1165     }
1166 
1167     /* Update the progress meter */
1168     if(Curl_pgrsUpdate(data)) {
1169       tftp_state_machine(state, TFTP_EVENT_ERROR);
1170       return CURLE_ABORTED_BY_CALLBACK;
1171     }
1172   }
1173   return result;
1174 }
1175 
1176 /**********************************************************
1177  *
1178  * tftp_state_timeout
1179  *
1180  * Check if timeouts have been reached
1181  *
1182  **********************************************************/
tftp_state_timeout(struct Curl_easy * data,tftp_event_t * event)1183 static timediff_t tftp_state_timeout(struct Curl_easy *data,
1184                                      tftp_event_t *event)
1185 {
1186   time_t current;
1187   struct connectdata *conn = data->conn;
1188   struct tftp_state_data *state = conn->proto.tftpc;
1189   timediff_t timeout_ms;
1190 
1191   if(event)
1192     *event = TFTP_EVENT_NONE;
1193 
1194   timeout_ms = Curl_timeleft(state->data, NULL,
1195                              (state->state == TFTP_STATE_START));
1196   if(timeout_ms < 0) {
1197     state->error = TFTP_ERR_TIMEOUT;
1198     state->state = TFTP_STATE_FIN;
1199     return 0;
1200   }
1201   current = time(NULL);
1202   if(current > state->rx_time + state->retry_time) {
1203     if(event)
1204       *event = TFTP_EVENT_TIMEOUT;
1205     state->rx_time = time(NULL); /* update even though we received nothing */
1206   }
1207 
1208   return timeout_ms;
1209 }
1210 
1211 /**********************************************************
1212  *
1213  * tftp_multi_statemach
1214  *
1215  * Handle single RX socket event and return
1216  *
1217  **********************************************************/
tftp_multi_statemach(struct Curl_easy * data,bool * done)1218 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1219 {
1220   tftp_event_t event;
1221   CURLcode result = CURLE_OK;
1222   struct connectdata *conn = data->conn;
1223   struct tftp_state_data *state = conn->proto.tftpc;
1224   timediff_t timeout_ms = tftp_state_timeout(data, &event);
1225 
1226   *done = FALSE;
1227 
1228   if(timeout_ms < 0) {
1229     failf(data, "TFTP response timeout");
1230     return CURLE_OPERATION_TIMEDOUT;
1231   }
1232   if(event != TFTP_EVENT_NONE) {
1233     result = tftp_state_machine(state, event);
1234     if(result)
1235       return result;
1236     *done = (state->state == TFTP_STATE_FIN);
1237     if(*done)
1238       /* Tell curl we are done */
1239       Curl_xfer_setup_nop(data);
1240   }
1241   else {
1242     /* no timeouts to handle, check our socket */
1243     int rc = SOCKET_READABLE(state->sockfd, 0);
1244 
1245     if(rc == -1) {
1246       /* bail out */
1247       int error = SOCKERRNO;
1248       char buffer[STRERROR_LEN];
1249       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1250       state->event = TFTP_EVENT_ERROR;
1251     }
1252     else if(rc) {
1253       result = tftp_receive_packet(data);
1254       if(result)
1255         return result;
1256       result = tftp_state_machine(state, state->event);
1257       if(result)
1258         return result;
1259       *done = (state->state == TFTP_STATE_FIN);
1260       if(*done)
1261         /* Tell curl we are done */
1262         Curl_xfer_setup_nop(data);
1263     }
1264     /* if rc == 0, then select() timed out */
1265   }
1266 
1267   return result;
1268 }
1269 
1270 /**********************************************************
1271  *
1272  * tftp_doing
1273  *
1274  * Called from multi.c while DOing
1275  *
1276  **********************************************************/
tftp_doing(struct Curl_easy * data,bool * dophase_done)1277 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1278 {
1279   CURLcode result;
1280   result = tftp_multi_statemach(data, dophase_done);
1281 
1282   if(*dophase_done) {
1283     DEBUGF(infof(data, "DO phase is complete"));
1284   }
1285   else if(!result) {
1286     /* The multi code does not have this logic for the DOING state so we
1287        provide it for TFTP since it may do the entire transfer in this
1288        state. */
1289     if(Curl_pgrsUpdate(data))
1290       result = CURLE_ABORTED_BY_CALLBACK;
1291     else
1292       result = Curl_speedcheck(data, Curl_now());
1293   }
1294   return result;
1295 }
1296 
1297 /**********************************************************
1298  *
1299  * tftp_perform
1300  *
1301  * Entry point for transfer from tftp_do, starts state mach
1302  *
1303  **********************************************************/
tftp_perform(struct Curl_easy * data,bool * dophase_done)1304 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1305 {
1306   CURLcode result = CURLE_OK;
1307   struct connectdata *conn = data->conn;
1308   struct tftp_state_data *state = conn->proto.tftpc;
1309 
1310   *dophase_done = FALSE;
1311 
1312   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1313 
1314   if((state->state == TFTP_STATE_FIN) || result)
1315     return result;
1316 
1317   tftp_multi_statemach(data, dophase_done);
1318 
1319   if(*dophase_done)
1320     DEBUGF(infof(data, "DO phase is complete"));
1321 
1322   return result;
1323 }
1324 
1325 
1326 /**********************************************************
1327  *
1328  * tftp_do
1329  *
1330  * The do callback
1331  *
1332  * This callback initiates the TFTP transfer
1333  *
1334  **********************************************************/
1335 
tftp_do(struct Curl_easy * data,bool * done)1336 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1337 {
1338   struct tftp_state_data *state;
1339   CURLcode result;
1340   struct connectdata *conn = data->conn;
1341 
1342   *done = FALSE;
1343 
1344   if(!conn->proto.tftpc) {
1345     result = tftp_connect(data, done);
1346     if(result)
1347       return result;
1348   }
1349 
1350   state = conn->proto.tftpc;
1351   if(!state)
1352     return CURLE_TFTP_ILLEGAL;
1353 
1354   result = tftp_perform(data, done);
1355 
1356   /* If tftp_perform() returned an error, use that for return code. If it
1357      was OK, see if tftp_translate_code() has an error. */
1358   if(!result)
1359     /* If we have encountered an internal tftp error, translate it. */
1360     result = tftp_translate_code(state->error);
1361 
1362   return result;
1363 }
1364 
tftp_setup_connection(struct Curl_easy * data,struct connectdata * conn)1365 static CURLcode tftp_setup_connection(struct Curl_easy *data,
1366                                       struct connectdata *conn)
1367 {
1368   char *type;
1369 
1370   conn->transport = TRNSPRT_UDP;
1371 
1372   /* TFTP URLs support an extension like ";mode=<typecode>" that
1373    * we will try to get now! */
1374   type = strstr(data->state.up.path, ";mode=");
1375 
1376   if(!type)
1377     type = strstr(conn->host.rawalloc, ";mode=");
1378 
1379   if(type) {
1380     char command;
1381     *type = 0;                   /* it was in the middle of the hostname */
1382     command = Curl_raw_toupper(type[6]);
1383 
1384     switch(command) {
1385     case 'A': /* ASCII mode */
1386     case 'N': /* NETASCII mode */
1387       data->state.prefer_ascii = TRUE;
1388       break;
1389 
1390     case 'O': /* octet mode */
1391     case 'I': /* binary mode */
1392     default:
1393       /* switch off ASCII */
1394       data->state.prefer_ascii = FALSE;
1395       break;
1396     }
1397   }
1398 
1399   return CURLE_OK;
1400 }
1401 #endif
1402