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