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