File: | src/usr.bin/tftp/tftp.c |
Warning: | line 607, column 16 Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: tftp.c,v 1.25 2017/09/10 07:29:39 tb Exp $ */ |
2 | /* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1983, 1993 |
6 | * The Regents of the University of California. All rights reserved. |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the name of the University nor the names of its contributors |
17 | * may be used to endorse or promote products derived from this software |
18 | * without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 | * SUCH DAMAGE. |
31 | */ |
32 | |
33 | /* |
34 | * TFTP User Program -- Protocol Machines |
35 | * |
36 | * This version includes many modifications by Jim Guyton <guyton@rand-unix> |
37 | */ |
38 | |
39 | #include <sys/types.h> |
40 | #include <sys/socket.h> |
41 | #include <sys/time.h> |
42 | #include <sys/stat.h> |
43 | |
44 | #include <netinet/in.h> |
45 | #include <arpa/tftp.h> |
46 | |
47 | #include <err.h> |
48 | #include <errno(*__errno()).h> |
49 | #include <poll.h> |
50 | #include <signal.h> |
51 | #include <stdio.h> |
52 | #include <stddef.h> |
53 | #include <stdlib.h> |
54 | #include <string.h> |
55 | #include <time.h> |
56 | #include <unistd.h> |
57 | #include <netdb.h> |
58 | |
59 | #include "extern.h" |
60 | #include "tftpsubs.h" |
61 | |
62 | static int cmpport(struct sockaddr *, struct sockaddr *); |
63 | static int makerequest(int, const char *, struct tftphdr *, const char *); |
64 | static void nak(int, struct sockaddr *); |
65 | static void tpacket(const char *, struct tftphdr *, int); |
66 | static void startclock(void); |
67 | static void stopclock(void); |
68 | static void printstats(const char *, unsigned long); |
69 | static void printtimeout(void); |
70 | static void oack(struct tftphdr *, int, int); |
71 | static int oack_set(const char *, const char *); |
72 | |
73 | extern struct sockaddr_storage peeraddr; /* filled in by main */ |
74 | extern int f; /* the opened socket */ |
75 | extern int trace; |
76 | extern int verbose; |
77 | extern int rexmtval; |
78 | extern int maxtimeout; |
79 | extern FILE *file; |
80 | extern volatile sig_atomic_t intrflag; |
81 | extern char *ackbuf; |
82 | extern int has_options; |
83 | extern int opt_tsize; |
84 | extern int opt_tout; |
85 | extern int opt_blksize; |
86 | |
87 | struct timespec tstart; |
88 | struct timespec tstop; |
89 | unsigned int segment_size = SEGSIZE512; |
90 | unsigned int packet_size = SEGSIZE512 + 4; |
91 | |
92 | struct errmsg { |
93 | int e_code; |
94 | char *e_msg; |
95 | } errmsgs[] = { |
96 | { EUNDEF0, "Undefined error code" }, |
97 | { ENOTFOUND1, "File not found" }, |
98 | { EACCESS2, "Access violation" }, |
99 | { ENOSPACE3, "Disk full or allocation exceeded" }, |
100 | { EBADOP4, "Illegal TFTP operation" }, |
101 | { EBADID5, "Unknown transfer ID" }, |
102 | { EEXISTS6, "File already exists" }, |
103 | { ENOUSER7, "No such user" }, |
104 | { EOPTNEG8, "Option negotiation failed" }, |
105 | { -1, NULL((void*)0) } |
106 | }; |
107 | |
108 | struct options { |
109 | const char *o_type; |
110 | } options[] = { |
111 | { "tsize" }, |
112 | { "timeout" }, |
113 | { "blksize" }, |
114 | { NULL((void*)0) } |
115 | }; |
116 | |
117 | enum opt_enum { |
118 | OPT_TSIZE = 0, |
119 | OPT_TIMEOUT, |
120 | OPT_BLKSIZE |
121 | }; |
122 | |
123 | /* |
124 | * Send the requested file. |
125 | */ |
126 | void |
127 | sendfile(int fd, char *name, char *mode) |
128 | { |
129 | struct tftphdr *dp, *ap; /* data and ack packets */ |
130 | struct sockaddr_storage from, peer; |
131 | struct sockaddr_storage serv; /* valid server port number */ |
132 | struct pollfd pfd[1]; |
133 | unsigned long amount; |
134 | socklen_t fromlen; |
135 | int convert; /* true if converting crlf -> lf */ |
136 | int n, nfds, error, timeouts, size; |
137 | uint16_t block = 0; |
138 | int firsttrip = 1; |
139 | |
140 | startclock(); /* start stat's clock */ |
141 | dp = r_init(); /* reset fillbuf/read-ahead code */ |
142 | ap = (struct tftphdr *)ackbuf; |
143 | file = fdopen(fd, "r"); |
144 | convert = !strcmp(mode, "netascii"); |
145 | amount = 0; |
146 | memcpy(&peer, &peeraddr, peeraddr.ss_len); |
147 | memset(&serv, 0, sizeof(serv)); |
148 | |
149 | do { |
150 | /* read data from file */ |
151 | if (firsttrip) |
152 | size = makerequest(WRQ02, name, dp, mode) - 4; |
153 | else { |
154 | size = readit(file, &dp, convert, segment_size); |
155 | if (size < 0) { |
156 | nak(errno(*__errno()) + 100, (struct sockaddr *)&peer); |
157 | break; |
158 | } |
159 | dp->th_opcode = htons((u_short)DATA)(__uint16_t)(__builtin_constant_p((u_short)03) ? (__uint16_t) (((__uint16_t)((u_short)03) & 0xffU) << 8 | ((__uint16_t )((u_short)03) & 0xff00U) >> 8) : __swap16md((u_short )03)); |
160 | dp->th_blockth_u.tu_block = htons(block)(__uint16_t)(__builtin_constant_p(block) ? (__uint16_t)(((__uint16_t )(block) & 0xffU) << 8 | ((__uint16_t)(block) & 0xff00U) >> 8) : __swap16md(block)); |
161 | } |
162 | |
163 | /* send data to server and wait for server ACK */ |
164 | for (timeouts = 0, error = 0; !intrflag;) { |
165 | if (timeouts >= maxtimeout) { |
166 | printtimeout(); |
167 | goto abort; |
168 | } |
169 | |
170 | if (!error) { |
171 | if (trace) |
172 | tpacket("sent", dp, size + 4); |
173 | if (sendto(f, dp, size + 4, 0, |
174 | (struct sockaddr *)&peer, |
175 | peer.ss_len) != size + 4) { |
176 | warn("sendto"); |
177 | goto abort; |
178 | } |
179 | if (!firsttrip) |
180 | read_ahead(file, convert, segment_size); |
181 | } |
182 | error = 0; |
183 | |
184 | pfd[0].fd = f; |
185 | pfd[0].events = POLLIN0x0001; |
186 | nfds = poll(pfd, 1, rexmtval * 1000); |
187 | if (nfds == 0) { |
188 | timeouts += rexmtval; |
189 | continue; |
190 | } |
191 | if (nfds == -1) { |
192 | error = 1; |
193 | if (errno(*__errno()) == EINTR4) |
194 | continue; |
195 | warn("poll"); |
196 | goto abort; |
197 | } |
198 | fromlen = sizeof(from); |
199 | n = recvfrom(f, ackbuf, packet_size, 0, |
200 | (struct sockaddr *)&from, &fromlen); |
201 | if (n == 0) { |
202 | warn("recvfrom"); |
203 | goto abort; |
204 | } |
205 | if (n == -1) { |
206 | error = 1; |
207 | if (errno(*__errno()) == EINTR4) |
208 | continue; |
209 | warn("recvfrom"); |
210 | goto abort; |
211 | } |
212 | if (!serv.ss_family) |
213 | serv = from; |
214 | else if (!cmpport((struct sockaddr *)&serv, |
215 | (struct sockaddr *)&from)) { |
216 | warn("server port mismatch"); |
217 | goto abort; |
218 | } |
219 | peer = from; |
220 | if (trace) |
221 | tpacket("received", ap, n); |
222 | |
223 | ap->th_opcode = ntohs(ap->th_opcode)(__uint16_t)(__builtin_constant_p(ap->th_opcode) ? (__uint16_t )(((__uint16_t)(ap->th_opcode) & 0xffU) << 8 | ( (__uint16_t)(ap->th_opcode) & 0xff00U) >> 8) : __swap16md (ap->th_opcode)); |
224 | |
225 | if (ap->th_opcode == OACK06) { |
226 | oack(ap, n, 0); |
227 | break; |
228 | } |
229 | |
230 | ap->th_blockth_u.tu_block = ntohs(ap->th_block)(__uint16_t)(__builtin_constant_p(ap->th_u.tu_block) ? (__uint16_t )(((__uint16_t)(ap->th_u.tu_block) & 0xffU) << 8 | ((__uint16_t)(ap->th_u.tu_block) & 0xff00U) >> 8) : __swap16md(ap->th_u.tu_block)); |
231 | |
232 | if (ap->th_opcode == ERROR05) { |
233 | printf("Error code %d: %s\n", |
234 | ap->th_codeth_u.tu_code, ap->th_msgth_data); |
235 | goto abort; |
236 | } |
237 | if (ap->th_opcode == ACK04) { |
238 | int j; |
239 | if (ap->th_blockth_u.tu_block == block) |
240 | break; |
241 | /* re-synchronize with other side */ |
242 | j = synchnet(f); |
243 | if (j && trace) |
244 | printf("discarded %d packets\n", j); |
245 | if (ap->th_blockth_u.tu_block == (block - 1)) |
246 | continue; |
247 | } |
248 | error = 1; /* received packet does not match */ |
249 | } |
250 | |
251 | if (firsttrip) { |
252 | size = segment_size; |
253 | firsttrip = 0; |
254 | } else |
255 | amount += size; |
256 | block++; |
257 | } while ((size == segment_size) && !intrflag); |
258 | |
259 | abort: |
260 | fclose(file); |
261 | stopclock(); |
262 | if (amount > 0) { |
263 | if (intrflag) |
264 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); |
265 | printstats("Sent", amount); |
266 | } |
267 | } |
268 | |
269 | /* |
270 | * Receive a file. |
271 | */ |
272 | void |
273 | recvfile(int fd, char *name, char *mode) |
274 | { |
275 | struct tftphdr *dp, *ap; /* data and ack packets */ |
276 | struct sockaddr_storage from, peer; |
277 | struct sockaddr_storage serv; /* valid server port number */ |
278 | struct pollfd pfd[1]; |
279 | unsigned long amount; |
280 | socklen_t fromlen; |
281 | int convert; /* true if converting crlf -> lf */ |
282 | int n, nfds, error, timeouts, size; |
283 | int firsttrip; |
284 | uint16_t block; |
285 | |
286 | startclock(); /* start stat's clock */ |
287 | dp = w_init(); /* reset fillbuf/read-ahead code */ |
288 | ap = (struct tftphdr *)ackbuf; |
289 | file = fdopen(fd, "w"); |
290 | convert = !strcmp(mode, "netascii"); |
291 | n = 0; |
292 | block = 1; |
293 | amount = 0; |
294 | firsttrip = 1; |
295 | memcpy(&peer, &peeraddr, peeraddr.ss_len); |
296 | memset(&serv, 0, sizeof(serv)); |
297 | |
298 | options: |
299 | do { |
300 | /* create new ACK packet */ |
301 | if (firsttrip) { |
302 | size = makerequest(RRQ01, name, ap, mode); |
303 | firsttrip = 0; |
304 | } else { |
305 | ap->th_opcode = htons((u_short)ACK)(__uint16_t)(__builtin_constant_p((u_short)04) ? (__uint16_t) (((__uint16_t)((u_short)04) & 0xffU) << 8 | ((__uint16_t )((u_short)04) & 0xff00U) >> 8) : __swap16md((u_short )04)); |
306 | ap->th_blockth_u.tu_block = htons(block)(__uint16_t)(__builtin_constant_p(block) ? (__uint16_t)(((__uint16_t )(block) & 0xffU) << 8 | ((__uint16_t)(block) & 0xff00U) >> 8) : __swap16md(block)); |
307 | size = 4; |
308 | block++; |
309 | } |
310 | |
311 | /* send ACK to server and wait for server data */ |
312 | for (timeouts = 0, error = 0; !intrflag;) { |
313 | if (timeouts >= maxtimeout) { |
314 | printtimeout(); |
315 | goto abort; |
316 | } |
317 | |
318 | if (!error) { |
319 | if (trace) |
320 | tpacket("sent", ap, size); |
321 | if (sendto(f, ackbuf, size, 0, |
322 | (struct sockaddr *)&peer, |
323 | peer.ss_len) != size) { |
324 | warn("sendto"); |
325 | goto abort; |
326 | } |
327 | write_behind(file, convert); |
328 | } |
329 | error = 0; |
330 | |
331 | pfd[0].fd = f; |
332 | pfd[0].events = POLLIN0x0001; |
333 | nfds = poll(pfd, 1, rexmtval * 1000); |
334 | if (nfds == 0) { |
335 | timeouts += rexmtval; |
336 | continue; |
337 | } |
338 | if (nfds == -1) { |
339 | error = 1; |
340 | if (errno(*__errno()) == EINTR4) |
341 | continue; |
342 | warn("poll"); |
343 | goto abort; |
344 | } |
345 | fromlen = sizeof(from); |
346 | n = recvfrom(f, dp, packet_size, 0, |
347 | (struct sockaddr *)&from, &fromlen); |
348 | if (n == 0) { |
349 | warn("recvfrom"); |
350 | goto abort; |
351 | } |
352 | if (n == -1) { |
353 | error = 1; |
354 | if (errno(*__errno()) == EINTR4) |
355 | continue; |
356 | warn("recvfrom"); |
357 | goto abort; |
358 | } |
359 | if (!serv.ss_family) |
360 | serv = from; |
361 | else if (!cmpport((struct sockaddr *)&serv, |
362 | (struct sockaddr *)&from)) { |
363 | warn("server port mismatch"); |
364 | goto abort; |
365 | } |
366 | peer = from; |
367 | if (trace) |
368 | tpacket("received", dp, n); |
369 | |
370 | dp->th_opcode = ntohs(dp->th_opcode)(__uint16_t)(__builtin_constant_p(dp->th_opcode) ? (__uint16_t )(((__uint16_t)(dp->th_opcode) & 0xffU) << 8 | ( (__uint16_t)(dp->th_opcode) & 0xff00U) >> 8) : __swap16md (dp->th_opcode)); |
371 | |
372 | if (dp->th_opcode == OACK06) { |
373 | oack(dp, n, 0); |
374 | block = 0; |
375 | goto options; |
376 | } |
377 | |
378 | dp->th_blockth_u.tu_block = ntohs(dp->th_block)(__uint16_t)(__builtin_constant_p(dp->th_u.tu_block) ? (__uint16_t )(((__uint16_t)(dp->th_u.tu_block) & 0xffU) << 8 | ((__uint16_t)(dp->th_u.tu_block) & 0xff00U) >> 8) : __swap16md(dp->th_u.tu_block)); |
379 | |
380 | if (dp->th_opcode == ERROR05) { |
381 | printf("Error code %d: %s\n", |
382 | dp->th_codeth_u.tu_code, dp->th_msgth_data); |
383 | goto abort; |
384 | } |
385 | if (dp->th_opcode == DATA03) { |
386 | int j; |
387 | if (dp->th_blockth_u.tu_block == block) |
388 | break; |
389 | /* re-synchronize with other side */ |
390 | j = synchnet(f); |
391 | if (j && trace) |
392 | printf("discarded %d packets\n", j); |
393 | if (dp->th_blockth_u.tu_block == (block - 1)) |
394 | continue; |
395 | } |
396 | error = 1; /* received packet does not match */ |
397 | } |
398 | |
399 | /* write data to file */ |
400 | size = writeit(file, &dp, n - 4, convert); |
401 | if (size < 0) { |
402 | nak(errno(*__errno()) + 100, (struct sockaddr *)&peer); |
403 | break; |
404 | } |
405 | amount += size; |
406 | } while (size == segment_size && !intrflag); |
407 | |
408 | abort: |
409 | /* ok to ack, since user has seen err msg */ |
410 | ap->th_opcode = htons((u_short)ACK)(__uint16_t)(__builtin_constant_p((u_short)04) ? (__uint16_t) (((__uint16_t)((u_short)04) & 0xffU) << 8 | ((__uint16_t )((u_short)04) & 0xff00U) >> 8) : __swap16md((u_short )04)); |
411 | ap->th_blockth_u.tu_block = htons(block)(__uint16_t)(__builtin_constant_p(block) ? (__uint16_t)(((__uint16_t )(block) & 0xffU) << 8 | ((__uint16_t)(block) & 0xff00U) >> 8) : __swap16md(block)); |
412 | (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, |
413 | peer.ss_len); |
414 | write_behind(file, convert); /* flush last buffer */ |
415 | |
416 | fclose(file); |
417 | stopclock(); |
418 | if (amount > 0) { |
419 | if (intrflag) |
420 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); |
421 | printstats("Received", amount); |
422 | } |
423 | } |
424 | |
425 | static int |
426 | cmpport(struct sockaddr *sa, struct sockaddr *sb) |
427 | { |
428 | char a[NI_MAXSERV32], b[NI_MAXSERV32]; |
429 | if (getnameinfo(sa, sa->sa_len, NULL((void*)0), 0, a, sizeof(a), NI_NUMERICSERV2)) |
430 | return (0); |
431 | if (getnameinfo(sb, sb->sa_len, NULL((void*)0), 0, b, sizeof(b), NI_NUMERICSERV2)) |
432 | return (0); |
433 | if (strcmp(a, b) != 0) |
434 | return (0); |
435 | |
436 | return (1); |
437 | } |
438 | |
439 | static int |
440 | makerequest(int request, const char *name, struct tftphdr *tp, |
441 | const char *mode) |
442 | { |
443 | char *cp; |
444 | int len, pktlen; |
445 | off_t fsize = 0; |
446 | struct stat st; |
447 | |
448 | tp->th_opcode = htons((u_short)request)(__uint16_t)(__builtin_constant_p((u_short)request) ? (__uint16_t )(((__uint16_t)((u_short)request) & 0xffU) << 8 | ( (__uint16_t)((u_short)request) & 0xff00U) >> 8) : __swap16md ((u_short)request)); |
449 | cp = tp->th_stuffth_u.tu_stuff; |
450 | pktlen = packet_size - offsetof(struct tftphdr, th_stuff)__builtin_offsetof(struct tftphdr, th_u.tu_stuff); |
451 | len = strlen(name) + 1; |
452 | strlcpy(cp, name, pktlen); |
453 | strlcpy(cp + len, mode, pktlen - len); |
454 | len += strlen(mode) + 1; |
455 | |
456 | if (opt_tsize) { |
457 | if (request == WRQ02) { |
458 | stat(name, &st); |
459 | fsize = st.st_size; |
460 | } |
461 | len += snprintf(cp + len, pktlen - len, "%s%c%lld%c", |
462 | options[OPT_TSIZE].o_type, 0, fsize, 0); |
463 | } |
464 | if (opt_tout) |
465 | len += snprintf(cp + len, pktlen - len, "%s%c%d%c", |
466 | options[OPT_TIMEOUT].o_type, 0, rexmtval, 0); |
467 | if (opt_blksize) |
468 | len += snprintf(cp + len, pktlen - len, "%s%c%d%c", |
469 | options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0); |
470 | |
471 | return (cp + len - (char *)tp); |
472 | } |
473 | |
474 | /* |
475 | * Send a nak packet (error message). |
476 | * Error code passed in is one of the |
477 | * standard TFTP codes, or a UNIX errno |
478 | * offset by 100. |
479 | */ |
480 | static void |
481 | nak(int error, struct sockaddr *peer) |
482 | { |
483 | struct errmsg *pe; |
484 | struct tftphdr *tp; |
485 | int length; |
486 | |
487 | tp = (struct tftphdr *)ackbuf; |
488 | tp->th_opcode = htons((u_short)ERROR)(__uint16_t)(__builtin_constant_p((u_short)05) ? (__uint16_t) (((__uint16_t)((u_short)05) & 0xffU) << 8 | ((__uint16_t )((u_short)05) & 0xff00U) >> 8) : __swap16md((u_short )05)); |
489 | tp->th_codeth_u.tu_code = htons((u_short)error)(__uint16_t)(__builtin_constant_p((u_short)error) ? (__uint16_t )(((__uint16_t)((u_short)error) & 0xffU) << 8 | ((__uint16_t )((u_short)error) & 0xff00U) >> 8) : __swap16md((u_short )error)); |
490 | for (pe = errmsgs; pe->e_code >= 0; pe++) |
491 | if (pe->e_code == error) |
492 | break; |
493 | if (pe->e_code < 0) { |
494 | pe->e_msg = strerror(error - 100); |
495 | tp->th_codeth_u.tu_code = EUNDEF0; |
496 | } |
497 | length = strlcpy(tp->th_msgth_data, pe->e_msg, packet_size) + 5; |
498 | if (length > packet_size) |
499 | length = packet_size; |
500 | if (trace) |
501 | tpacket("sent", tp, length); |
502 | if (sendto(f, ackbuf, length, 0, peer, |
503 | peer->sa_len) != length) |
504 | warn("nak"); |
505 | } |
506 | |
507 | static void |
508 | tpacket(const char *s, struct tftphdr *tp, int n) |
509 | { |
510 | char *cp, *file; |
511 | static char *opcodes[] = |
512 | { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; |
513 | |
514 | u_short op = ntohs(tp->th_opcode)(__uint16_t)(__builtin_constant_p(tp->th_opcode) ? (__uint16_t )(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ( (__uint16_t)(tp->th_opcode) & 0xff00U) >> 8) : __swap16md (tp->th_opcode)); |
515 | |
516 | if (op < RRQ01 || op > OACK06) |
517 | printf("%s opcode=%x ", s, op); |
518 | else |
519 | printf("%s %s ", s, opcodes[op]); |
520 | |
521 | switch (op) { |
522 | case RRQ01: |
523 | case WRQ02: |
524 | n -= 2; |
525 | file = cp = tp->th_stuffth_u.tu_stuff; |
526 | cp = strchr(cp, '\0'); |
527 | printf("<file=%s, mode=%s", file, cp + 1); |
528 | if (has_options) |
529 | oack(tp, n, 1); |
530 | printf(">\n"); |
531 | break; |
532 | case DATA03: |
533 | printf("<block=%d, %d bytes>\n", ntohs(tp->th_block)(__uint16_t)(__builtin_constant_p(tp->th_u.tu_block) ? (__uint16_t )(((__uint16_t)(tp->th_u.tu_block) & 0xffU) << 8 | ((__uint16_t)(tp->th_u.tu_block) & 0xff00U) >> 8) : __swap16md(tp->th_u.tu_block)), n - 4); |
534 | break; |
535 | case ACK04: |
536 | printf("<block=%d>\n", ntohs(tp->th_block)(__uint16_t)(__builtin_constant_p(tp->th_u.tu_block) ? (__uint16_t )(((__uint16_t)(tp->th_u.tu_block) & 0xffU) << 8 | ((__uint16_t)(tp->th_u.tu_block) & 0xff00U) >> 8) : __swap16md(tp->th_u.tu_block))); |
537 | break; |
538 | case ERROR05: |
539 | printf("<code=%d, msg=%s>\n", ntohs(tp->th_code)(__uint16_t)(__builtin_constant_p(tp->th_u.tu_code) ? (__uint16_t )(((__uint16_t)(tp->th_u.tu_code) & 0xffU) << 8 | ((__uint16_t)(tp->th_u.tu_code) & 0xff00U) >> 8 ) : __swap16md(tp->th_u.tu_code)), tp->th_msgth_data); |
540 | break; |
541 | case OACK06: |
542 | printf("<"); |
543 | oack(tp, n, 1); |
544 | printf(">\n"); |
545 | break; |
546 | } |
547 | } |
548 | |
549 | static void |
550 | startclock(void) |
551 | { |
552 | clock_gettime(CLOCK_MONOTONIC3, &tstart); |
553 | } |
554 | |
555 | static void |
556 | stopclock(void) |
557 | { |
558 | clock_gettime(CLOCK_MONOTONIC3, &tstop); |
559 | } |
560 | |
561 | static void |
562 | printstats(const char *direction, unsigned long amount) |
563 | { |
564 | double delta; |
565 | |
566 | /* compute delta in 1/10's second units */ |
567 | delta = ((tstop.tv_sec * 10.) + (tstop.tv_nsec / 100000000)) - |
568 | ((tstart.tv_sec * 10.) + (tstart.tv_nsec / 100000000)); |
569 | delta = delta / 10.; /* back to seconds */ |
570 | printf("%s %lu bytes in %.1f seconds", direction, amount, delta); |
571 | if (verbose) |
572 | printf(" [%.0f bits/sec]", (amount * 8.) / delta); |
573 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); |
574 | } |
575 | |
576 | static void |
577 | printtimeout(void) |
578 | { |
579 | printf("Transfer timed out.\n"); |
580 | } |
581 | |
582 | static void |
583 | oack(struct tftphdr *tp, int size, int trace) |
584 | { |
585 | int i, len, off; |
586 | char *opt, *val; |
587 | |
588 | u_short op = ntohs(tp->th_opcode)(__uint16_t)(__builtin_constant_p(tp->th_opcode) ? (__uint16_t )(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ( (__uint16_t)(tp->th_opcode) & 0xff00U) >> 8) : __swap16md (tp->th_opcode)); |
589 | |
590 | opt = tp->th_u.tu_stuff; |
591 | val = tp->th_u.tu_stuff; |
592 | |
593 | if (op == RRQ01 || op == WRQ02) { |
594 | len = strlen(opt) + 1; |
595 | opt = strchr(opt, '\0'); |
596 | opt++; |
597 | len += strlen(opt) + 1; |
598 | opt = strchr(opt, '\0'); |
599 | opt++; |
600 | val = opt; |
601 | off = len; |
602 | if (trace) |
603 | printf(", "); |
604 | } else |
605 | off = 2; |
606 | |
607 | for (i = off, len = 0; i < size - 1; i++) { |
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len' | |
608 | if (*val != '\0') { |
609 | val++; |
610 | continue; |
611 | } |
612 | /* got option and value */ |
613 | val++; |
614 | if (trace) |
615 | printf("%s=%s", opt, val); |
616 | else |
617 | if (oack_set(opt, val) == -1) |
618 | break; |
619 | len = strlen(val) + 1; |
620 | val += len; |
621 | opt = val; |
622 | i += len; |
623 | if (trace && i < size - 1) |
624 | printf(", "); |
625 | } |
626 | } |
627 | |
628 | int |
629 | oack_set(const char *option, const char *value) |
630 | { |
631 | int i, n; |
632 | const char *errstr; |
633 | struct sockaddr_storage peer; |
634 | memcpy(&peer, &peeraddr, peeraddr.ss_len); |
635 | |
636 | for (i = 0; options[i].o_type != NULL((void*)0); i++) { |
637 | if (!strcasecmp(options[i].o_type, option)) { |
638 | if (i == OPT_TSIZE) { |
639 | /* XXX verify OACK response */ |
640 | } |
641 | if (i == OPT_TIMEOUT) { |
642 | /* verify OACK response */ |
643 | n = strtonum(value, TIMEOUT_MIN1, TIMEOUT_MAX255, |
644 | &errstr); |
645 | if (errstr || rexmtval != n || |
646 | opt_tout == 0) { |
647 | nak(EOPTNEG8, (struct sockaddr *)&peer); |
648 | intrflag = 1; |
649 | return (-1); |
650 | } |
651 | /* OK */ |
652 | } |
653 | if (i == OPT_BLKSIZE) { |
654 | /* verify OACK response */ |
655 | n = strtonum(value, SEGSIZE_MIN8, SEGSIZE_MAX65464, |
656 | &errstr); |
657 | if (errstr || opt_blksize != n || |
658 | opt_blksize == 0) { |
659 | nak(EOPTNEG8, (struct sockaddr *)&peer); |
660 | intrflag = 1; |
661 | return (-1); |
662 | } |
663 | /* OK, set option */ |
664 | segment_size = n; |
665 | packet_size = segment_size + 4; |
666 | } |
667 | } |
668 | } |
669 | |
670 | return (1); |
671 | } |