xref: /aosp_15_r20/external/toybox/toys/pending/tftp.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* tftp.c - TFTP client.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2012 Madhur Verma <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2015 Sameer Prakash Pradhan <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker  *
6*cf5a6c84SAndroid Build Coastguard Worker  * No Standard.
7*cf5a6c84SAndroid Build Coastguard Worker 
8*cf5a6c84SAndroid Build Coastguard Worker USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
9*cf5a6c84SAndroid Build Coastguard Worker 
10*cf5a6c84SAndroid Build Coastguard Worker config TFTP
11*cf5a6c84SAndroid Build Coastguard Worker   bool "tftp"
12*cf5a6c84SAndroid Build Coastguard Worker   default n
13*cf5a6c84SAndroid Build Coastguard Worker   help
14*cf5a6c84SAndroid Build Coastguard Worker     usage: tftp [OPTIONS] HOST [PORT]
15*cf5a6c84SAndroid Build Coastguard Worker 
16*cf5a6c84SAndroid Build Coastguard Worker     Transfer file from/to tftp server.
17*cf5a6c84SAndroid Build Coastguard Worker 
18*cf5a6c84SAndroid Build Coastguard Worker     -l FILE Local FILE
19*cf5a6c84SAndroid Build Coastguard Worker     -r FILE Remote FILE
20*cf5a6c84SAndroid Build Coastguard Worker     -g    Get file
21*cf5a6c84SAndroid Build Coastguard Worker     -p    Put file
22*cf5a6c84SAndroid Build Coastguard Worker     -b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)
23*cf5a6c84SAndroid Build Coastguard Worker */
24*cf5a6c84SAndroid Build Coastguard Worker #define FOR_tftp
25*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
26*cf5a6c84SAndroid Build Coastguard Worker 
GLOBALS(char * local_file;char * remote_file;long block_size;struct sockaddr_storage inaddr;int af;)27*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
28*cf5a6c84SAndroid Build Coastguard Worker   char *local_file;
29*cf5a6c84SAndroid Build Coastguard Worker   char *remote_file;
30*cf5a6c84SAndroid Build Coastguard Worker   long block_size;
31*cf5a6c84SAndroid Build Coastguard Worker 
32*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage inaddr;
33*cf5a6c84SAndroid Build Coastguard Worker   int af;
34*cf5a6c84SAndroid Build Coastguard Worker )
35*cf5a6c84SAndroid Build Coastguard Worker 
36*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_BLKSIZE    512
37*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_RETRIES    3
38*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_DATAHEADERSIZE 4
39*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_MAXPACKETSIZE  (TFTP_DATAHEADERSIZE + TFTP_BLKSIZE)
40*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_PACKETSIZE    TFTP_MAXPACKETSIZE
41*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_DATASIZE    (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE)
42*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_IOBUFSIZE    (TFTP_PACKETSIZE+8)
43*cf5a6c84SAndroid Build Coastguard Worker 
44*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_RRQ      1  /* Read Request      RFC 1350, RFC 2090 */
45*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_WRQ      2  /* Write Request     RFC 1350 */
46*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_DATA    3  /* Data chunk      RFC 1350 */
47*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_ACK      4  /* Acknowledgement     RFC 1350 */
48*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_ERR      5  /* Error Message     RFC 1350 */
49*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_OACK    6  /* Option acknowledgment RFC 2347 */
50*cf5a6c84SAndroid Build Coastguard Worker 
51*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ER_ILLEGALOP  4  /* Illegal TFTP operation */
52*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ER_UNKID    5  /* Unknown transfer ID */
53*cf5a6c84SAndroid Build Coastguard Worker 
54*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_NOSUCHFILE  "File not found"
55*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_ACCESS    "Access violation"
56*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_FULL    "Disk full or allocation exceeded"
57*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_ILLEGALOP  "Illegal TFTP operation"
58*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_UNKID    "Unknown transfer ID"
59*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_EXISTS    "File already exists"
60*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_UNKUSER    "No such user"
61*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_NEGOTIATE  "Terminate transfer due to option negotiation"
62*cf5a6c84SAndroid Build Coastguard Worker 
63*cf5a6c84SAndroid Build Coastguard Worker // Initializes SERVER with ADDR and returns socket.
64*cf5a6c84SAndroid Build Coastguard Worker static int init_tftp(struct sockaddr_storage *server)
65*cf5a6c84SAndroid Build Coastguard Worker {
66*cf5a6c84SAndroid Build Coastguard Worker   struct timeval to = { .tv_sec = 10, //Time out
67*cf5a6c84SAndroid Build Coastguard Worker                         .tv_usec = 0 };
68*cf5a6c84SAndroid Build Coastguard Worker   const int set = 1;
69*cf5a6c84SAndroid Build Coastguard Worker   int port = 69, sd = xsocket(TT.af, SOCK_DGRAM, IPPROTO_UDP);
70*cf5a6c84SAndroid Build Coastguard Worker 
71*cf5a6c84SAndroid Build Coastguard Worker   xsetsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&to, sizeof(struct timeval));
72*cf5a6c84SAndroid Build Coastguard Worker   xsetsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set));
73*cf5a6c84SAndroid Build Coastguard Worker 
74*cf5a6c84SAndroid Build Coastguard Worker   if(toys.optc == 2) port = atolx_range(toys.optargs[1], 1, 65535);
75*cf5a6c84SAndroid Build Coastguard Worker   memset(server, 0, sizeof(struct sockaddr_storage));
76*cf5a6c84SAndroid Build Coastguard Worker   if (TT.af == AF_INET6) {
77*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in6 *)server)->sin6_family = AF_INET6;
78*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in6 *)server)->sin6_addr =
79*cf5a6c84SAndroid Build Coastguard Worker         ((struct sockaddr_in6 *)&TT.inaddr)->sin6_addr;
80*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in6 *)server)->sin6_port = htons(port);
81*cf5a6c84SAndroid Build Coastguard Worker   }
82*cf5a6c84SAndroid Build Coastguard Worker   else {
83*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in *)server)->sin_family = AF_INET;
84*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in *)server)->sin_addr.s_addr =
85*cf5a6c84SAndroid Build Coastguard Worker         ((struct sockaddr_in *)&TT.inaddr)->sin_addr.s_addr;
86*cf5a6c84SAndroid Build Coastguard Worker       ((struct sockaddr_in *)server)->sin_port = htons(port);
87*cf5a6c84SAndroid Build Coastguard Worker   }
88*cf5a6c84SAndroid Build Coastguard Worker   return sd;
89*cf5a6c84SAndroid Build Coastguard Worker }
90*cf5a6c84SAndroid Build Coastguard Worker 
91*cf5a6c84SAndroid Build Coastguard Worker /*
92*cf5a6c84SAndroid Build Coastguard Worker  * Makes a request packet in BUFFER with OPCODE and file PATH of MODE
93*cf5a6c84SAndroid Build Coastguard Worker  * and returns length of packet.
94*cf5a6c84SAndroid Build Coastguard Worker  */
mkpkt_request(uint8_t * buffer,int opcode,char * path,int mode)95*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_request(uint8_t *buffer, int opcode, char *path, int mode)
96*cf5a6c84SAndroid Build Coastguard Worker {
97*cf5a6c84SAndroid Build Coastguard Worker   buffer[0] = opcode >> 8;
98*cf5a6c84SAndroid Build Coastguard Worker   buffer[1] = opcode & 0xff;
99*cf5a6c84SAndroid Build Coastguard Worker   if(strlen(path) > TFTP_BLKSIZE) error_exit("path too long");
100*cf5a6c84SAndroid Build Coastguard Worker   return sprintf((char*) &buffer[2], "%s%c%s", path, 0,
101*cf5a6c84SAndroid Build Coastguard Worker     (mode ? "octet" : "netascii")) + 3;
102*cf5a6c84SAndroid Build Coastguard Worker }
103*cf5a6c84SAndroid Build Coastguard Worker 
104*cf5a6c84SAndroid Build Coastguard Worker /*
105*cf5a6c84SAndroid Build Coastguard Worker  * Makes an acknowledgement packet in BUFFER of BLOCNO
106*cf5a6c84SAndroid Build Coastguard Worker  * and returns packet length.
107*cf5a6c84SAndroid Build Coastguard Worker  */
mkpkt_ack(uint8_t * buffer,uint16_t blockno)108*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_ack(uint8_t *buffer, uint16_t blockno)
109*cf5a6c84SAndroid Build Coastguard Worker {
110*cf5a6c84SAndroid Build Coastguard Worker   buffer[0] = TFTP_OP_ACK >> 8;
111*cf5a6c84SAndroid Build Coastguard Worker   buffer[1] = TFTP_OP_ACK & 0xff;
112*cf5a6c84SAndroid Build Coastguard Worker   buffer[2] = blockno >> 8;
113*cf5a6c84SAndroid Build Coastguard Worker   buffer[3] = blockno & 0xff;
114*cf5a6c84SAndroid Build Coastguard Worker   return 4;
115*cf5a6c84SAndroid Build Coastguard Worker }
116*cf5a6c84SAndroid Build Coastguard Worker 
117*cf5a6c84SAndroid Build Coastguard Worker /*
118*cf5a6c84SAndroid Build Coastguard Worker  * Makes an error packet in BUFFER with ERRORCODE and ERRORMSG.
119*cf5a6c84SAndroid Build Coastguard Worker  * and returns packet length.
120*cf5a6c84SAndroid Build Coastguard Worker  */
mkpkt_err(uint8_t * buffer,uint16_t errorcode,char * errormsg)121*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_err(uint8_t *buffer, uint16_t errorcode, char *errormsg)
122*cf5a6c84SAndroid Build Coastguard Worker {
123*cf5a6c84SAndroid Build Coastguard Worker   buffer[0] = TFTP_OP_ERR >> 8;
124*cf5a6c84SAndroid Build Coastguard Worker   buffer[1] = TFTP_OP_ERR & 0xff;
125*cf5a6c84SAndroid Build Coastguard Worker   buffer[2] = errorcode >> 8;
126*cf5a6c84SAndroid Build Coastguard Worker   buffer[3] = errorcode & 0xff;
127*cf5a6c84SAndroid Build Coastguard Worker   strcpy((char*) &buffer[4], errormsg);
128*cf5a6c84SAndroid Build Coastguard Worker   return strlen(errormsg) + 5;
129*cf5a6c84SAndroid Build Coastguard Worker }
130*cf5a6c84SAndroid Build Coastguard Worker 
131*cf5a6c84SAndroid Build Coastguard Worker /*
132*cf5a6c84SAndroid Build Coastguard Worker  * Recieves data from server in BUFF with socket SD and updates FROM
133*cf5a6c84SAndroid Build Coastguard Worker  * and returns read length.
134*cf5a6c84SAndroid Build Coastguard Worker  */
read_server(int sd,void * buf,int len,struct sockaddr_storage * from)135*cf5a6c84SAndroid Build Coastguard Worker static int read_server(int sd, void *buf, int len,
136*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage *from)
137*cf5a6c84SAndroid Build Coastguard Worker {
138*cf5a6c84SAndroid Build Coastguard Worker   socklen_t alen;
139*cf5a6c84SAndroid Build Coastguard Worker   ssize_t nb;
140*cf5a6c84SAndroid Build Coastguard Worker 
141*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
142*cf5a6c84SAndroid Build Coastguard Worker     memset(buf, 0, len);
143*cf5a6c84SAndroid Build Coastguard Worker     alen = sizeof(struct sockaddr_storage);
144*cf5a6c84SAndroid Build Coastguard Worker     nb = recvfrom(sd, buf, len, 0, (struct sockaddr *) from, &alen);
145*cf5a6c84SAndroid Build Coastguard Worker     if (nb < 0) {
146*cf5a6c84SAndroid Build Coastguard Worker       if (errno == EAGAIN) {
147*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("server read timed out");
148*cf5a6c84SAndroid Build Coastguard Worker         return nb;
149*cf5a6c84SAndroid Build Coastguard Worker       }else if (errno != EINTR) {
150*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("server read failed");
151*cf5a6c84SAndroid Build Coastguard Worker         return nb;
152*cf5a6c84SAndroid Build Coastguard Worker       }
153*cf5a6c84SAndroid Build Coastguard Worker     }else return nb;
154*cf5a6c84SAndroid Build Coastguard Worker   }
155*cf5a6c84SAndroid Build Coastguard Worker   return nb;
156*cf5a6c84SAndroid Build Coastguard Worker }
157*cf5a6c84SAndroid Build Coastguard Worker 
158*cf5a6c84SAndroid Build Coastguard Worker /*
159*cf5a6c84SAndroid Build Coastguard Worker  * sends data to server TO from BUFF of length LEN through socket SD
160*cf5a6c84SAndroid Build Coastguard Worker  * and returns successfully send bytes number.
161*cf5a6c84SAndroid Build Coastguard Worker  */
write_server(int sd,void * buf,size_t len,struct sockaddr_storage * to)162*cf5a6c84SAndroid Build Coastguard Worker static ssize_t write_server(int sd, void *buf, size_t len,
163*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage *to)
164*cf5a6c84SAndroid Build Coastguard Worker {
165*cf5a6c84SAndroid Build Coastguard Worker   ssize_t nb;
166*cf5a6c84SAndroid Build Coastguard Worker 
167*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
168*cf5a6c84SAndroid Build Coastguard Worker     nb = sendto(sd, buf, len, 0, (struct sockaddr *)to,
169*cf5a6c84SAndroid Build Coastguard Worker             sizeof(struct sockaddr_storage));
170*cf5a6c84SAndroid Build Coastguard Worker     if (nb < 0) {
171*cf5a6c84SAndroid Build Coastguard Worker       if (errno != EINTR) {
172*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("server write failed");
173*cf5a6c84SAndroid Build Coastguard Worker         return nb;
174*cf5a6c84SAndroid Build Coastguard Worker       }
175*cf5a6c84SAndroid Build Coastguard Worker     } else return nb;
176*cf5a6c84SAndroid Build Coastguard Worker   }
177*cf5a6c84SAndroid Build Coastguard Worker   return nb;
178*cf5a6c84SAndroid Build Coastguard Worker }
179*cf5a6c84SAndroid Build Coastguard Worker 
180*cf5a6c84SAndroid Build Coastguard Worker // checks packet for data and updates block no
check_data(uint8_t * packet,uint16_t * opcode,uint16_t * blockno)181*cf5a6c84SAndroid Build Coastguard Worker static inline int check_data( uint8_t *packet, uint16_t *opcode,
182*cf5a6c84SAndroid Build Coastguard Worker   uint16_t *blockno)
183*cf5a6c84SAndroid Build Coastguard Worker {
184*cf5a6c84SAndroid Build Coastguard Worker   *opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
185*cf5a6c84SAndroid Build Coastguard Worker   if (*opcode == TFTP_OP_DATA) {
186*cf5a6c84SAndroid Build Coastguard Worker     *blockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
187*cf5a6c84SAndroid Build Coastguard Worker     return 0;
188*cf5a6c84SAndroid Build Coastguard Worker   }
189*cf5a6c84SAndroid Build Coastguard Worker   return -1;
190*cf5a6c84SAndroid Build Coastguard Worker }
191*cf5a6c84SAndroid Build Coastguard Worker 
192*cf5a6c84SAndroid Build Coastguard Worker // Makes data packet through FD from file OFFSET in buffer PACKET of BLOCKNO
mkpkt_data(int fd,off_t offset,uint8_t * packet,uint16_t blockno)193*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_data(int fd, off_t offset, uint8_t *packet, uint16_t blockno)
194*cf5a6c84SAndroid Build Coastguard Worker {
195*cf5a6c84SAndroid Build Coastguard Worker   off_t tmp;
196*cf5a6c84SAndroid Build Coastguard Worker   int nbytesread;
197*cf5a6c84SAndroid Build Coastguard Worker 
198*cf5a6c84SAndroid Build Coastguard Worker   packet[0] = TFTP_OP_DATA >> 8;
199*cf5a6c84SAndroid Build Coastguard Worker   packet[1] = TFTP_OP_DATA & 0xff;
200*cf5a6c84SAndroid Build Coastguard Worker   packet[2] = blockno >> 8;
201*cf5a6c84SAndroid Build Coastguard Worker   packet[3] = blockno & 0xff;
202*cf5a6c84SAndroid Build Coastguard Worker   tmp = lseek(fd, offset, SEEK_SET);
203*cf5a6c84SAndroid Build Coastguard Worker   if (tmp == (off_t) -1) {
204*cf5a6c84SAndroid Build Coastguard Worker     perror_msg("lseek failed");
205*cf5a6c84SAndroid Build Coastguard Worker     return -1;
206*cf5a6c84SAndroid Build Coastguard Worker   }
207*cf5a6c84SAndroid Build Coastguard Worker   nbytesread = readall(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE);
208*cf5a6c84SAndroid Build Coastguard Worker   if (nbytesread < 0) return -1;
209*cf5a6c84SAndroid Build Coastguard Worker   return nbytesread + TFTP_DATAHEADERSIZE;
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker 
212*cf5a6c84SAndroid Build Coastguard Worker // Receives ACK responses from server and updates blockno
read_ack(int sd,uint8_t * packet,struct sockaddr_storage * server,uint16_t * port,uint16_t * blockno)213*cf5a6c84SAndroid Build Coastguard Worker static int read_ack(int sd, uint8_t *packet, struct sockaddr_storage *server,
214*cf5a6c84SAndroid Build Coastguard Worker   uint16_t *port, uint16_t *blockno)
215*cf5a6c84SAndroid Build Coastguard Worker {
216*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage from;
217*cf5a6c84SAndroid Build Coastguard Worker   int nbytes;
218*cf5a6c84SAndroid Build Coastguard Worker   uint16_t opcode, rblockno;
219*cf5a6c84SAndroid Build Coastguard Worker   int packetlen, retry;
220*cf5a6c84SAndroid Build Coastguard Worker 
221*cf5a6c84SAndroid Build Coastguard Worker   for (retry = 0; retry < TFTP_RETRIES; retry++) {
222*cf5a6c84SAndroid Build Coastguard Worker     for (;;) {
223*cf5a6c84SAndroid Build Coastguard Worker       nbytes = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
224*cf5a6c84SAndroid Build Coastguard Worker       if (nbytes < 4) { // Ack headersize = 4
225*cf5a6c84SAndroid Build Coastguard Worker         if (nbytes == 0) error_msg("Connection lost.");
226*cf5a6c84SAndroid Build Coastguard Worker         else if (nbytes > 0) error_msg("Short packet: %d bytes", nbytes);
227*cf5a6c84SAndroid Build Coastguard Worker         else error_msg("Server read ACK failure.");
228*cf5a6c84SAndroid Build Coastguard Worker         break;
229*cf5a6c84SAndroid Build Coastguard Worker       } else {
230*cf5a6c84SAndroid Build Coastguard Worker         if (!*port) {
231*cf5a6c84SAndroid Build Coastguard Worker           *port = ((struct sockaddr_in *)&from)->sin_port;
232*cf5a6c84SAndroid Build Coastguard Worker           ((struct sockaddr_in *)server)->sin_port =
233*cf5a6c84SAndroid Build Coastguard Worker                   ((struct sockaddr_in *)&from)->sin_port;
234*cf5a6c84SAndroid Build Coastguard Worker         }
235*cf5a6c84SAndroid Build Coastguard Worker         if (((struct sockaddr_in *)server)->sin_addr.s_addr !=
236*cf5a6c84SAndroid Build Coastguard Worker                 ((struct sockaddr_in *)&from)->sin_addr.s_addr) {
237*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Invalid address in DATA.");
238*cf5a6c84SAndroid Build Coastguard Worker           continue;
239*cf5a6c84SAndroid Build Coastguard Worker         }
240*cf5a6c84SAndroid Build Coastguard Worker         if (*port != ((struct sockaddr_in *)server)->sin_port) {
241*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Invalid port in DATA.");
242*cf5a6c84SAndroid Build Coastguard Worker           packetlen = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
243*cf5a6c84SAndroid Build Coastguard Worker           (void) write_server(sd, packet, packetlen, server);
244*cf5a6c84SAndroid Build Coastguard Worker           continue;
245*cf5a6c84SAndroid Build Coastguard Worker         }
246*cf5a6c84SAndroid Build Coastguard Worker         opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
247*cf5a6c84SAndroid Build Coastguard Worker         rblockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
248*cf5a6c84SAndroid Build Coastguard Worker 
249*cf5a6c84SAndroid Build Coastguard Worker         if (opcode != TFTP_OP_ACK) {
250*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Bad opcode.");
251*cf5a6c84SAndroid Build Coastguard Worker           if (opcode > 5) {
252*cf5a6c84SAndroid Build Coastguard Worker             packetlen = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
253*cf5a6c84SAndroid Build Coastguard Worker             (void) write_server(sd, packet, packetlen, server);
254*cf5a6c84SAndroid Build Coastguard Worker           }
255*cf5a6c84SAndroid Build Coastguard Worker           break;
256*cf5a6c84SAndroid Build Coastguard Worker         }
257*cf5a6c84SAndroid Build Coastguard Worker         if (blockno) *blockno = rblockno;
258*cf5a6c84SAndroid Build Coastguard Worker         return 0;
259*cf5a6c84SAndroid Build Coastguard Worker       }
260*cf5a6c84SAndroid Build Coastguard Worker     }
261*cf5a6c84SAndroid Build Coastguard Worker   }
262*cf5a6c84SAndroid Build Coastguard Worker   error_msg("Timeout, Waiting for ACK.");
263*cf5a6c84SAndroid Build Coastguard Worker   return -1;
264*cf5a6c84SAndroid Build Coastguard Worker }
265*cf5a6c84SAndroid Build Coastguard Worker 
266*cf5a6c84SAndroid Build Coastguard Worker // receives file from server.
file_get(void)267*cf5a6c84SAndroid Build Coastguard Worker static int file_get(void)
268*cf5a6c84SAndroid Build Coastguard Worker {
269*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage server, from;
270*cf5a6c84SAndroid Build Coastguard Worker   uint8_t *packet;
271*cf5a6c84SAndroid Build Coastguard Worker   uint16_t blockno = 0, opcode, rblockno = 0;
272*cf5a6c84SAndroid Build Coastguard Worker   int len, sd, fd, retry, nbytesrecvd = 0, ndatabytes, ret, result = -1;
273*cf5a6c84SAndroid Build Coastguard Worker 
274*cf5a6c84SAndroid Build Coastguard Worker   sd = init_tftp(&server);
275*cf5a6c84SAndroid Build Coastguard Worker 
276*cf5a6c84SAndroid Build Coastguard Worker   packet = (uint8_t*) xzalloc(TFTP_IOBUFSIZE);
277*cf5a6c84SAndroid Build Coastguard Worker   fd = xcreate(TT.local_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
278*cf5a6c84SAndroid Build Coastguard Worker 
279*cf5a6c84SAndroid Build Coastguard Worker   len = mkpkt_request(packet, TFTP_OP_RRQ, TT.remote_file, 1);
280*cf5a6c84SAndroid Build Coastguard Worker   ret = write_server(sd, packet, len, &server);
281*cf5a6c84SAndroid Build Coastguard Worker   if (ret != len){
282*cf5a6c84SAndroid Build Coastguard Worker     unlink(TT.local_file);
283*cf5a6c84SAndroid Build Coastguard Worker     goto errout_with_sd;
284*cf5a6c84SAndroid Build Coastguard Worker   }
285*cf5a6c84SAndroid Build Coastguard Worker   if (TT.af == AF_INET6) ((struct sockaddr_in6 *)&server)->sin6_port = 0;
286*cf5a6c84SAndroid Build Coastguard Worker   else ((struct sockaddr_in *)&server)->sin_port = 0;
287*cf5a6c84SAndroid Build Coastguard Worker 
288*cf5a6c84SAndroid Build Coastguard Worker   do {
289*cf5a6c84SAndroid Build Coastguard Worker     blockno++;
290*cf5a6c84SAndroid Build Coastguard Worker     for (retry = 0 ; retry < TFTP_RETRIES; retry++) {
291*cf5a6c84SAndroid Build Coastguard Worker       nbytesrecvd = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
292*cf5a6c84SAndroid Build Coastguard Worker       if (nbytesrecvd > 0) {
293*cf5a6c84SAndroid Build Coastguard Worker         if ( ((TT.af == AF_INET) &&
294*cf5a6c84SAndroid Build Coastguard Worker                 memcmp(&((struct sockaddr_in *)&server)->sin_addr,
295*cf5a6c84SAndroid Build Coastguard Worker                 &((struct sockaddr_in *)&from)->sin_addr,
296*cf5a6c84SAndroid Build Coastguard Worker                 sizeof(struct in_addr))) ||
297*cf5a6c84SAndroid Build Coastguard Worker              ((TT.af == AF_INET6) &&
298*cf5a6c84SAndroid Build Coastguard Worker                 memcmp(&((struct sockaddr_in6 *)&server)->sin6_addr,
299*cf5a6c84SAndroid Build Coastguard Worker                 &((struct sockaddr_in6 *)&from)->sin6_addr,
300*cf5a6c84SAndroid Build Coastguard Worker                 sizeof(struct in6_addr)))) {
301*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Invalid address in DATA.");
302*cf5a6c84SAndroid Build Coastguard Worker           retry--;
303*cf5a6c84SAndroid Build Coastguard Worker           continue;
304*cf5a6c84SAndroid Build Coastguard Worker         }
305*cf5a6c84SAndroid Build Coastguard Worker         if ( ((TT.af == AF_INET) && ((struct sockaddr_in *)&server)->sin_port
306*cf5a6c84SAndroid Build Coastguard Worker                 && (((struct sockaddr_in *)&server)->sin_port !=
307*cf5a6c84SAndroid Build Coastguard Worker                 ((struct sockaddr_in *)&from)->sin_port)) ||
308*cf5a6c84SAndroid Build Coastguard Worker              ((TT.af == AF_INET6) && ((struct sockaddr_in6 *)&server)->sin6_port
309*cf5a6c84SAndroid Build Coastguard Worker                 && (((struct sockaddr_in6 *)&server)->sin6_port !=
310*cf5a6c84SAndroid Build Coastguard Worker                 ((struct sockaddr_in6 *)&from)->sin6_port))) {
311*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Invalid port in DATA.");
312*cf5a6c84SAndroid Build Coastguard Worker           len = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
313*cf5a6c84SAndroid Build Coastguard Worker           ret = write_server(sd, packet, len, &from);
314*cf5a6c84SAndroid Build Coastguard Worker           retry--;
315*cf5a6c84SAndroid Build Coastguard Worker           continue;
316*cf5a6c84SAndroid Build Coastguard Worker         }
317*cf5a6c84SAndroid Build Coastguard Worker         if (nbytesrecvd < TFTP_DATAHEADERSIZE) {
318*cf5a6c84SAndroid Build Coastguard Worker           error_msg("Tiny data packet ignored.");
319*cf5a6c84SAndroid Build Coastguard Worker           continue;
320*cf5a6c84SAndroid Build Coastguard Worker         }
321*cf5a6c84SAndroid Build Coastguard Worker         if (check_data(packet, &opcode, &rblockno) != 0
322*cf5a6c84SAndroid Build Coastguard Worker             || blockno != rblockno) {
323*cf5a6c84SAndroid Build Coastguard Worker 
324*cf5a6c84SAndroid Build Coastguard Worker         if (opcode == TFTP_OP_ERR) {
325*cf5a6c84SAndroid Build Coastguard Worker           char *message = "DATA Check failure.";
326*cf5a6c84SAndroid Build Coastguard Worker             char *arr[] = {TFTP_ES_NOSUCHFILE, TFTP_ES_ACCESS,
327*cf5a6c84SAndroid Build Coastguard Worker               TFTP_ES_FULL, TFTP_ES_ILLEGALOP,
328*cf5a6c84SAndroid Build Coastguard Worker               TFTP_ES_UNKID, TFTP_ES_EXISTS,
329*cf5a6c84SAndroid Build Coastguard Worker               TFTP_ES_UNKUSER, TFTP_ES_NEGOTIATE};
330*cf5a6c84SAndroid Build Coastguard Worker             if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
331*cf5a6c84SAndroid Build Coastguard Worker             error_msg_raw(message);
332*cf5a6c84SAndroid Build Coastguard Worker         }
333*cf5a6c84SAndroid Build Coastguard Worker         else if (blockno == 1 && opcode == TFTP_OP_OACK) {
334*cf5a6c84SAndroid Build Coastguard Worker           len = mkpkt_ack(packet, 0);
335*cf5a6c84SAndroid Build Coastguard Worker           ret = write_server(sd, packet, len, &from);
336*cf5a6c84SAndroid Build Coastguard Worker           if (ret != len){
337*cf5a6c84SAndroid Build Coastguard Worker             unlink(TT.local_file);
338*cf5a6c84SAndroid Build Coastguard Worker             goto errout_with_sd;
339*cf5a6c84SAndroid Build Coastguard Worker           }
340*cf5a6c84SAndroid Build Coastguard Worker         }
341*cf5a6c84SAndroid Build Coastguard Worker         else if (opcode > 5) {
342*cf5a6c84SAndroid Build Coastguard Worker           len = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
343*cf5a6c84SAndroid Build Coastguard Worker           ret = write_server(sd, packet, len, &from);
344*cf5a6c84SAndroid Build Coastguard Worker         }
345*cf5a6c84SAndroid Build Coastguard Worker         continue;
346*cf5a6c84SAndroid Build Coastguard Worker         }
347*cf5a6c84SAndroid Build Coastguard Worker         if ((TT.af == AF_INET6) && !((struct sockaddr_in6 *)&server)->sin6_port)
348*cf5a6c84SAndroid Build Coastguard Worker           ((struct sockaddr_in6 *)&server)->sin6_port =
349*cf5a6c84SAndroid Build Coastguard Worker             ((struct sockaddr_in6 *)&from)->sin6_port;
350*cf5a6c84SAndroid Build Coastguard Worker         else if ((TT.af == AF_INET) && !((struct sockaddr_in *)&server)->sin_port)
351*cf5a6c84SAndroid Build Coastguard Worker           ((struct sockaddr_in *)&server)->sin_port =
352*cf5a6c84SAndroid Build Coastguard Worker             ((struct sockaddr_in *)&from)->sin_port;
353*cf5a6c84SAndroid Build Coastguard Worker         break;
354*cf5a6c84SAndroid Build Coastguard Worker       }
355*cf5a6c84SAndroid Build Coastguard Worker     }
356*cf5a6c84SAndroid Build Coastguard Worker     if (retry == TFTP_RETRIES) {
357*cf5a6c84SAndroid Build Coastguard Worker       error_msg("Retry limit exceeded.");
358*cf5a6c84SAndroid Build Coastguard Worker       unlink(TT.local_file);
359*cf5a6c84SAndroid Build Coastguard Worker       goto errout_with_sd;
360*cf5a6c84SAndroid Build Coastguard Worker     }
361*cf5a6c84SAndroid Build Coastguard Worker     ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE;
362*cf5a6c84SAndroid Build Coastguard Worker     if (writeall(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0){
363*cf5a6c84SAndroid Build Coastguard Worker       unlink(TT.local_file);
364*cf5a6c84SAndroid Build Coastguard Worker       goto errout_with_sd;
365*cf5a6c84SAndroid Build Coastguard Worker     }
366*cf5a6c84SAndroid Build Coastguard Worker     len = mkpkt_ack(packet, blockno);
367*cf5a6c84SAndroid Build Coastguard Worker     ret = write_server(sd, packet, len, &server);
368*cf5a6c84SAndroid Build Coastguard Worker     if (ret != len){
369*cf5a6c84SAndroid Build Coastguard Worker       unlink(TT.local_file);
370*cf5a6c84SAndroid Build Coastguard Worker       goto errout_with_sd;
371*cf5a6c84SAndroid Build Coastguard Worker     }
372*cf5a6c84SAndroid Build Coastguard Worker   } while (ndatabytes >= TFTP_DATASIZE);
373*cf5a6c84SAndroid Build Coastguard Worker 
374*cf5a6c84SAndroid Build Coastguard Worker   result = 0;
375*cf5a6c84SAndroid Build Coastguard Worker 
376*cf5a6c84SAndroid Build Coastguard Worker errout_with_sd: xclose(sd);
377*cf5a6c84SAndroid Build Coastguard Worker   free(packet);
378*cf5a6c84SAndroid Build Coastguard Worker   return result;
379*cf5a6c84SAndroid Build Coastguard Worker }
380*cf5a6c84SAndroid Build Coastguard Worker 
381*cf5a6c84SAndroid Build Coastguard Worker // Sends file to server.
file_put(void)382*cf5a6c84SAndroid Build Coastguard Worker int file_put(void)
383*cf5a6c84SAndroid Build Coastguard Worker {
384*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_storage server;
385*cf5a6c84SAndroid Build Coastguard Worker   uint8_t *packet;
386*cf5a6c84SAndroid Build Coastguard Worker   off_t offset = 0;
387*cf5a6c84SAndroid Build Coastguard Worker   uint16_t blockno = 1, rblockno, port = 0;
388*cf5a6c84SAndroid Build Coastguard Worker   int packetlen, sd, fd, retry = 0, ret, result = -1;
389*cf5a6c84SAndroid Build Coastguard Worker 
390*cf5a6c84SAndroid Build Coastguard Worker   sd = init_tftp(&server);
391*cf5a6c84SAndroid Build Coastguard Worker   packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE);
392*cf5a6c84SAndroid Build Coastguard Worker   fd = xopenro(TT.local_file);
393*cf5a6c84SAndroid Build Coastguard Worker 
394*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {  //first loop for request send and confirmation from server.
395*cf5a6c84SAndroid Build Coastguard Worker     packetlen = mkpkt_request(packet, TFTP_OP_WRQ, TT.remote_file, 1);
396*cf5a6c84SAndroid Build Coastguard Worker     ret = write_server(sd, packet, packetlen, &server);
397*cf5a6c84SAndroid Build Coastguard Worker     if (ret != packetlen) goto errout_with_sd;
398*cf5a6c84SAndroid Build Coastguard Worker     if (read_ack(sd, packet, &server, &port, NULL) == 0) break;
399*cf5a6c84SAndroid Build Coastguard Worker     if (++retry > TFTP_RETRIES) {
400*cf5a6c84SAndroid Build Coastguard Worker       error_msg("Retry count exceeded.");
401*cf5a6c84SAndroid Build Coastguard Worker       goto errout_with_sd;
402*cf5a6c84SAndroid Build Coastguard Worker     }
403*cf5a6c84SAndroid Build Coastguard Worker   }
404*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {  // loop for data sending and receving ack from server.
405*cf5a6c84SAndroid Build Coastguard Worker     packetlen = mkpkt_data(fd, offset, packet, blockno);
406*cf5a6c84SAndroid Build Coastguard Worker     if (packetlen < 0) goto errout_with_sd;
407*cf5a6c84SAndroid Build Coastguard Worker 
408*cf5a6c84SAndroid Build Coastguard Worker     ret = write_server(sd, packet, packetlen, &server);
409*cf5a6c84SAndroid Build Coastguard Worker     if (ret != packetlen) goto errout_with_sd;
410*cf5a6c84SAndroid Build Coastguard Worker 
411*cf5a6c84SAndroid Build Coastguard Worker     if (read_ack(sd, packet, &server, &port, &rblockno) == 0) {
412*cf5a6c84SAndroid Build Coastguard Worker       if (rblockno == blockno) {
413*cf5a6c84SAndroid Build Coastguard Worker         if (packetlen < TFTP_PACKETSIZE) break;
414*cf5a6c84SAndroid Build Coastguard Worker         blockno++;
415*cf5a6c84SAndroid Build Coastguard Worker         offset += TFTP_DATASIZE;
416*cf5a6c84SAndroid Build Coastguard Worker         retry = 0;
417*cf5a6c84SAndroid Build Coastguard Worker         continue;
418*cf5a6c84SAndroid Build Coastguard Worker       }
419*cf5a6c84SAndroid Build Coastguard Worker     }
420*cf5a6c84SAndroid Build Coastguard Worker     if (++retry > TFTP_RETRIES) {
421*cf5a6c84SAndroid Build Coastguard Worker       error_msg("Retry count exceeded.");
422*cf5a6c84SAndroid Build Coastguard Worker       goto errout_with_sd;
423*cf5a6c84SAndroid Build Coastguard Worker     }
424*cf5a6c84SAndroid Build Coastguard Worker   }
425*cf5a6c84SAndroid Build Coastguard Worker   result = 0;
426*cf5a6c84SAndroid Build Coastguard Worker 
427*cf5a6c84SAndroid Build Coastguard Worker errout_with_sd: close(sd);
428*cf5a6c84SAndroid Build Coastguard Worker   free(packet);
429*cf5a6c84SAndroid Build Coastguard Worker   return result;
430*cf5a6c84SAndroid Build Coastguard Worker }
431*cf5a6c84SAndroid Build Coastguard Worker 
tftp_main(void)432*cf5a6c84SAndroid Build Coastguard Worker void tftp_main(void)
433*cf5a6c84SAndroid Build Coastguard Worker {
434*cf5a6c84SAndroid Build Coastguard Worker   struct addrinfo *info, rp, *res=0;
435*cf5a6c84SAndroid Build Coastguard Worker   int ret;
436*cf5a6c84SAndroid Build Coastguard Worker 
437*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(r)) {
438*cf5a6c84SAndroid Build Coastguard Worker     if (!FLAG(l)) {
439*cf5a6c84SAndroid Build Coastguard Worker       char *slash = strrchr(TT.remote_file, '/');
440*cf5a6c84SAndroid Build Coastguard Worker       TT.local_file = (slash) ? slash + 1 : TT.remote_file;
441*cf5a6c84SAndroid Build Coastguard Worker     }
442*cf5a6c84SAndroid Build Coastguard Worker   } else if (FLAG(l)) TT.remote_file = TT.local_file;
443*cf5a6c84SAndroid Build Coastguard Worker   else error_exit("Please provide some files.");
444*cf5a6c84SAndroid Build Coastguard Worker 
445*cf5a6c84SAndroid Build Coastguard Worker   memset(&rp, 0, sizeof(rp));
446*cf5a6c84SAndroid Build Coastguard Worker   rp.ai_family = AF_UNSPEC;
447*cf5a6c84SAndroid Build Coastguard Worker   rp.ai_socktype = SOCK_STREAM;
448*cf5a6c84SAndroid Build Coastguard Worker   ret = getaddrinfo(toys.optargs[0], toys.optargs[1], &rp, &info);
449*cf5a6c84SAndroid Build Coastguard Worker   if (!ret) {
450*cf5a6c84SAndroid Build Coastguard Worker     for (res = info; res; res = res->ai_next)
451*cf5a6c84SAndroid Build Coastguard Worker     if ( (res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) break;
452*cf5a6c84SAndroid Build Coastguard Worker   }
453*cf5a6c84SAndroid Build Coastguard Worker   if (!res)
454*cf5a6c84SAndroid Build Coastguard Worker     error_exit("bad address '%s' : %s", toys.optargs[0], gai_strerror(ret));
455*cf5a6c84SAndroid Build Coastguard Worker   TT.af = info->ai_family;
456*cf5a6c84SAndroid Build Coastguard Worker 
457*cf5a6c84SAndroid Build Coastguard Worker   memcpy((void *)&TT.inaddr, info->ai_addr, info->ai_addrlen);
458*cf5a6c84SAndroid Build Coastguard Worker   freeaddrinfo(info);
459*cf5a6c84SAndroid Build Coastguard Worker 
460*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(g)) file_get();
461*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(p)) file_put();
462*cf5a6c84SAndroid Build Coastguard Worker }
463