Annotation of src/usr.bin/tftp/tftp.c, Revision 1.23
1.23 ! gsoares 1: /* $OpenBSD: tftp.c,v 1.22 2009/10/27 23:59:44 deraadt Exp $ */
1.1 deraadt 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.
1.12 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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
1.17 mglocker 35: *
36: * This version includes many modifications by Jim Guyton <guyton@rand-unix>
1.1 deraadt 37: */
1.16 claudio 38:
1.1 deraadt 39: #include <sys/types.h>
40: #include <sys/socket.h>
41: #include <sys/time.h>
1.19 mglocker 42: #include <sys/stat.h>
1.1 deraadt 43:
44: #include <netinet/in.h>
45: #include <arpa/tftp.h>
46:
1.17 mglocker 47: #include <err.h>
1.1 deraadt 48: #include <errno.h>
1.16 claudio 49: #include <poll.h>
1.1 deraadt 50: #include <signal.h>
51: #include <stdio.h>
1.11 henning 52: #include <stddef.h>
1.19 mglocker 53: #include <stdlib.h>
1.1 deraadt 54: #include <string.h>
55: #include <unistd.h>
1.23 ! gsoares 56: #include <netdb.h>
1.1 deraadt 57:
58: #include "extern.h"
59: #include "tftpsubs.h"
60:
1.23 ! gsoares 61: static int cmpport(struct sockaddr *, struct sockaddr *);
1.17 mglocker 62: static int makerequest(int, const char *, struct tftphdr *, const char *);
1.23 ! gsoares 63: static void nak(int, struct sockaddr *);
1.17 mglocker 64: static void tpacket(const char *, struct tftphdr *, int);
65: static void startclock(void);
66: static void stopclock(void);
67: static void printstats(const char *, unsigned long);
68: static void printtimeout(void);
1.19 mglocker 69: static void oack(struct tftphdr *, int, int);
70: static int oack_set(const char *, const char *);
1.17 mglocker 71:
1.23 ! gsoares 72: extern struct sockaddr_storage peeraddr; /* filled in by main */
1.17 mglocker 73: extern int f; /* the opened socket */
74: extern int trace;
75: extern int verbose;
76: extern int rexmtval;
77: extern int maxtimeout;
1.16 claudio 78: extern FILE *file;
1.17 mglocker 79: extern volatile sig_atomic_t intrflag;
1.19 mglocker 80: extern char *ackbuf;
81: extern int has_options;
82: extern int opt_tsize;
83: extern int opt_tout;
84: extern int opt_blksize;
1.16 claudio 85:
86: struct timeval tstart;
87: struct timeval tstop;
1.19 mglocker 88: unsigned int segment_size = SEGSIZE;
89: unsigned int packet_size = SEGSIZE + 4;
1.16 claudio 90:
91: struct errmsg {
1.17 mglocker 92: int e_code;
1.16 claudio 93: char *e_msg;
94: } errmsgs[] = {
95: { EUNDEF, "Undefined error code" },
96: { ENOTFOUND, "File not found" },
97: { EACCESS, "Access violation" },
98: { ENOSPACE, "Disk full or allocation exceeded" },
99: { EBADOP, "Illegal TFTP operation" },
100: { EBADID, "Unknown transfer ID" },
101: { EEXISTS, "File already exists" },
102: { ENOUSER, "No such user" },
1.19 mglocker 103: { EOPTNEG, "Option negotiation failed" },
1.16 claudio 104: { -1, NULL }
105: };
106:
1.19 mglocker 107: struct options {
108: const char *o_type;
109: } options[] = {
110: { "tsize" },
111: { "timeout" },
112: { "blksize" },
113: { NULL }
114: };
115:
116: enum opt_enum {
117: OPT_TSIZE = 0,
118: OPT_TIMEOUT,
119: OPT_BLKSIZE
120: };
121:
1.1 deraadt 122: /*
123: * Send the requested file.
124: */
125: void
1.14 deraadt 126: sendfile(int fd, char *name, char *mode)
1.1 deraadt 127: {
1.17 mglocker 128: struct tftphdr *dp, *ap; /* data and ack packets */
1.23 ! gsoares 129: struct sockaddr_storage from, peer;
! 130: struct sockaddr_storage serv; /* valid server port number */
1.17 mglocker 131: struct pollfd pfd[1];
132: unsigned long amount;
1.21 ray 133: socklen_t fromlen;
1.17 mglocker 134: int convert; /* true if converting crlf -> lf */
1.21 ray 135: int n, nfds, error, timeouts, block, size;
1.1 deraadt 136:
137: startclock(); /* start stat's clock */
138: dp = r_init(); /* reset fillbuf/read-ahead code */
139: ap = (struct tftphdr *)ackbuf;
140: file = fdopen(fd, "r");
141: convert = !strcmp(mode, "netascii");
142: block = 0;
143: amount = 0;
1.23 ! gsoares 144: memcpy(&peer, &peeraddr, peeraddr.ss_len);
! 145: memset(&serv, 0, sizeof(serv));
1.1 deraadt 146:
147: do {
1.16 claudio 148: /* read data from file */
149: if (!block)
1.1 deraadt 150: size = makerequest(WRQ, name, dp, mode) - 4;
151: else {
1.19 mglocker 152: size = readit(file, &dp, convert, segment_size);
1.1 deraadt 153: if (size < 0) {
1.23 ! gsoares 154: nak(errno + 100, (struct sockaddr *)&peer);
1.1 deraadt 155: break;
156: }
157: dp->th_opcode = htons((u_short)DATA);
158: dp->th_block = htons((u_short)block);
159: }
1.16 claudio 160:
161: /* send data to server and wait for server ACK */
162: for (timeouts = 0, error = 0; !intrflag;) {
1.20 mglocker 163: if (timeouts >= maxtimeout) {
1.16 claudio 164: printtimeout();
165: goto abort;
166: }
167:
168: if (!error) {
169: if (trace)
170: tpacket("sent", dp, size + 4);
171: if (sendto(f, dp, size + 4, 0,
1.23 ! gsoares 172: (struct sockaddr *)&peer,
! 173: peer.ss_len) != size + 4) {
1.16 claudio 174: warn("sendto");
175: goto abort;
176: }
1.19 mglocker 177: if (block > 0)
178: read_ahead(file, convert, segment_size);
1.16 claudio 179: }
180: error = 0;
181:
182: pfd[0].fd = f;
183: pfd[0].events = POLLIN;
184: nfds = poll(pfd, 1, rexmtval * 1000);
185: if (nfds == 0) {
1.20 mglocker 186: timeouts += rexmtval;
1.16 claudio 187: continue;
188: }
189: if (nfds == -1) {
190: error = 1;
191: if (errno == EINTR)
192: continue;
193: warn("poll");
194: goto abort;
195: }
196: fromlen = sizeof(from);
1.19 mglocker 197: n = recvfrom(f, ackbuf, packet_size, 0,
1.16 claudio 198: (struct sockaddr *)&from, &fromlen);
199: if (n == 0) {
200: warn("recvfrom");
201: goto abort;
202: }
203: if (n == -1) {
204: error = 1;
205: if (errno == EINTR)
206: continue;
1.7 mickey 207: warn("recvfrom");
1.1 deraadt 208: goto abort;
209: }
1.23 ! gsoares 210: if (!serv.ss_family)
! 211: serv = from;
! 212: else if (!cmpport((struct sockaddr *)&serv,
! 213: (struct sockaddr *)&from)) {
! 214: warn("server port mismatch");
! 215: goto abort;
! 216: }
! 217: peer = from;
1.1 deraadt 218: if (trace)
219: tpacket("received", ap, n);
1.19 mglocker 220:
1.1 deraadt 221: ap->th_opcode = ntohs(ap->th_opcode);
1.19 mglocker 222:
223: if (ap->th_opcode == OACK) {
224: oack(ap, n, 0);
225: break;
226: }
227:
1.1 deraadt 228: ap->th_block = ntohs(ap->th_block);
1.16 claudio 229:
1.1 deraadt 230: if (ap->th_opcode == ERROR) {
1.16 claudio 231: printf("Error code %d: %s\n",
232: ap->th_code, ap->th_msg);
1.1 deraadt 233: goto abort;
234: }
235: if (ap->th_opcode == ACK) {
236: int j;
1.16 claudio 237: if (ap->th_block == block)
1.1 deraadt 238: break;
1.16 claudio 239: /* re-synchronize with other side */
1.1 deraadt 240: j = synchnet(f);
1.15 deraadt 241: if (j && trace)
242: printf("discarded %d packets\n", j);
1.16 claudio 243: if (ap->th_block == (block - 1))
244: continue;
1.1 deraadt 245: }
1.16 claudio 246: error = 1; /* received packet does not match */
1.1 deraadt 247: }
1.16 claudio 248:
1.1 deraadt 249: if (block > 0)
250: amount += size;
251: block++;
1.19 mglocker 252: } while ((size == segment_size || block == 1) && !intrflag);
1.16 claudio 253:
1.1 deraadt 254: abort:
255: fclose(file);
256: stopclock();
1.16 claudio 257: if (amount > 0) {
258: if (intrflag)
259: putchar('\n');
1.1 deraadt 260: printstats("Sent", amount);
1.16 claudio 261: }
1.1 deraadt 262: }
263:
264: /*
265: * Receive a file.
266: */
267: void
1.14 deraadt 268: recvfile(int fd, char *name, char *mode)
1.1 deraadt 269: {
1.17 mglocker 270: struct tftphdr *dp, *ap; /* data and ack packets */
1.23 ! gsoares 271: struct sockaddr_storage from, peer;
! 272: struct sockaddr_storage serv; /* valid server port number */
1.17 mglocker 273: struct pollfd pfd[1];
274: unsigned long amount;
1.21 ray 275: socklen_t fromlen;
1.17 mglocker 276: int convert; /* true if converting crlf -> lf */
1.21 ray 277: int n, nfds, error, timeouts, block, size;
1.17 mglocker 278: int firsttrip;
1.1 deraadt 279:
1.16 claudio 280: startclock(); /* start stat's clock */
281: dp = w_init(); /* reset fillbuf/read-ahead code */
1.1 deraadt 282: ap = (struct tftphdr *)ackbuf;
283: file = fdopen(fd, "w");
284: convert = !strcmp(mode, "netascii");
1.16 claudio 285: n = 0;
1.1 deraadt 286: block = 1;
1.16 claudio 287: amount = 0;
1.1 deraadt 288: firsttrip = 1;
1.23 ! gsoares 289: memcpy(&peer, &peeraddr, peeraddr.ss_len);
! 290: memset(&serv, 0, sizeof(serv));
1.1 deraadt 291:
1.19 mglocker 292: options:
1.1 deraadt 293: do {
1.16 claudio 294: /* create new ACK packet */
1.1 deraadt 295: if (firsttrip) {
296: size = makerequest(RRQ, name, ap, mode);
297: firsttrip = 0;
298: } else {
299: ap->th_opcode = htons((u_short)ACK);
300: ap->th_block = htons((u_short)(block));
301: size = 4;
302: block++;
303: }
1.16 claudio 304:
305: /* send ACK to server and wait for server data */
306: for (timeouts = 0, error = 0; !intrflag;) {
1.20 mglocker 307: if (timeouts >= maxtimeout) {
1.16 claudio 308: printtimeout();
309: goto abort;
310: }
311:
312: if (!error) {
313: if (trace)
314: tpacket("sent", ap, size);
315: if (sendto(f, ackbuf, size, 0,
1.23 ! gsoares 316: (struct sockaddr *)&peer,
! 317: peer.ss_len) != size) {
1.16 claudio 318: warn("sendto");
319: goto abort;
320: }
321: write_behind(file, convert);
322: }
323: error = 0;
324:
325: pfd[0].fd = f;
326: pfd[0].events = POLLIN;
327: nfds = poll(pfd, 1, rexmtval * 1000);
328: if (nfds == 0) {
1.20 mglocker 329: timeouts += rexmtval;
1.16 claudio 330: continue;
331: }
332: if (nfds == -1) {
333: error = 1;
334: if (errno == EINTR)
335: continue;
336: warn("poll");
337: goto abort;
338: }
339: fromlen = sizeof(from);
1.19 mglocker 340: n = recvfrom(f, dp, packet_size, 0,
1.16 claudio 341: (struct sockaddr *)&from, &fromlen);
342: if (n == 0) {
343: warn("recvfrom");
344: goto abort;
345: }
346: if (n == -1) {
347: error = 1;
348: if (errno == EINTR)
349: continue;
1.7 mickey 350: warn("recvfrom");
1.1 deraadt 351: goto abort;
352: }
1.23 ! gsoares 353: if (!serv.ss_family)
! 354: serv = from;
! 355: else if (!cmpport((struct sockaddr *)&serv,
! 356: (struct sockaddr *)&from)) {
! 357: warn("server port mismatch");
! 358: goto abort;
! 359: }
! 360: peer = from;
1.1 deraadt 361: if (trace)
362: tpacket("received", dp, n);
1.19 mglocker 363:
1.1 deraadt 364: dp->th_opcode = ntohs(dp->th_opcode);
1.19 mglocker 365:
366: if (dp->th_opcode == OACK) {
367: oack(dp, n, 0);
368: block = 0;
369: goto options;
370: }
371:
1.1 deraadt 372: dp->th_block = ntohs(dp->th_block);
1.16 claudio 373:
1.1 deraadt 374: if (dp->th_opcode == ERROR) {
1.16 claudio 375: printf("Error code %d: %s\n",
376: dp->th_code, dp->th_msg);
1.1 deraadt 377: goto abort;
378: }
379: if (dp->th_opcode == DATA) {
380: int j;
1.16 claudio 381: if (dp->th_block == block)
382: break;
383: /* re-synchronize with other side */
1.1 deraadt 384: j = synchnet(f);
1.15 deraadt 385: if (j && trace)
1.1 deraadt 386: printf("discarded %d packets\n", j);
1.16 claudio 387: if (dp->th_block == (block - 1))
388: continue;
1.1 deraadt 389: }
1.16 claudio 390: error = 1; /* received packet does not match */
1.1 deraadt 391: }
1.16 claudio 392:
393: /* write data to file */
1.1 deraadt 394: size = writeit(file, &dp, n - 4, convert);
395: if (size < 0) {
1.23 ! gsoares 396: nak(errno + 100, (struct sockaddr *)&peer);
1.1 deraadt 397: break;
398: }
399: amount += size;
1.19 mglocker 400: } while (size == segment_size && !intrflag);
1.16 claudio 401:
402: abort:
403: /* ok to ack, since user has seen err msg */
404: ap->th_opcode = htons((u_short)ACK);
1.1 deraadt 405: ap->th_block = htons((u_short)block);
1.23 ! gsoares 406: (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
! 407: peer.ss_len);
1.16 claudio 408: write_behind(file, convert); /* flush last buffer */
409:
1.1 deraadt 410: fclose(file);
411: stopclock();
1.16 claudio 412: if (amount > 0) {
413: if (intrflag)
414: putchar('\n');
1.1 deraadt 415: printstats("Received", amount);
1.16 claudio 416: }
1.1 deraadt 417: }
418:
419: static int
1.23 ! gsoares 420: cmpport(struct sockaddr *sa, struct sockaddr *sb)
! 421: {
! 422: char a[NI_MAXSERV], b[NI_MAXSERV];
! 423: if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV))
! 424: return (0);
! 425: if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV))
! 426: return (0);
! 427: if (strcmp(a, b) != 0)
! 428: return (0);
! 429:
! 430: return (1);
! 431: }
! 432:
! 433: static int
1.14 deraadt 434: makerequest(int request, const char *name, struct tftphdr *tp,
435: const char *mode)
1.1 deraadt 436: {
1.19 mglocker 437: char *cp;
438: int len, pktlen;
439: off_t fsize = 0;
440: struct stat st;
1.1 deraadt 441:
442: tp->th_opcode = htons((u_short)request);
443: cp = tp->th_stuff;
1.19 mglocker 444: pktlen = packet_size - offsetof(struct tftphdr, th_stuff);
1.11 henning 445: len = strlen(name) + 1;
446: strlcpy(cp, name, pktlen);
447: strlcpy(cp + len, mode, pktlen - len);
448: len += strlen(mode) + 1;
1.17 mglocker 449:
1.19 mglocker 450: if (opt_tsize) {
451: if (request == WRQ) {
452: stat(name, &st);
453: fsize = st.st_size;
454: }
455: len += snprintf(cp + len, pktlen - len, "%s%c%lld%c",
456: options[OPT_TSIZE].o_type, 0, fsize, 0);
457: }
458: if (opt_tout)
459: len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
460: options[OPT_TIMEOUT].o_type, 0, rexmtval, 0);
461: if (opt_blksize)
462: len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
463: options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0);
464:
1.11 henning 465: return (cp + len - (char *)tp);
1.1 deraadt 466: }
467:
468: /*
469: * Send a nak packet (error message).
470: * Error code passed in is one of the
471: * standard TFTP codes, or a UNIX errno
472: * offset by 100.
473: */
474: static void
1.23 ! gsoares 475: nak(int error, struct sockaddr *peer)
1.1 deraadt 476: {
1.17 mglocker 477: struct errmsg *pe;
478: struct tftphdr *tp;
479: int length;
1.1 deraadt 480:
481: tp = (struct tftphdr *)ackbuf;
482: tp->th_opcode = htons((u_short)ERROR);
483: tp->th_code = htons((u_short)error);
484: for (pe = errmsgs; pe->e_code >= 0; pe++)
485: if (pe->e_code == error)
486: break;
487: if (pe->e_code < 0) {
488: pe->e_msg = strerror(error - 100);
489: tp->th_code = EUNDEF;
490: }
1.19 mglocker 491: length = strlcpy(tp->th_msg, pe->e_msg, packet_size) + 5;
492: if (length > packet_size)
493: length = packet_size;
1.1 deraadt 494: if (trace)
495: tpacket("sent", tp, length);
1.23 ! gsoares 496: if (sendto(f, ackbuf, length, 0, peer,
! 497: peer->sa_len) != length)
1.7 mickey 498: warn("nak");
1.1 deraadt 499: }
500:
501: static void
1.14 deraadt 502: tpacket(const char *s, struct tftphdr *tp, int n)
1.1 deraadt 503: {
1.17 mglocker 504: char *cp, *file;
505: static char *opcodes[] =
1.19 mglocker 506: { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
1.17 mglocker 507:
1.1 deraadt 508: u_short op = ntohs(tp->th_opcode);
509:
1.19 mglocker 510: if (op < RRQ || op > OACK)
1.1 deraadt 511: printf("%s opcode=%x ", s, op);
512: else
513: printf("%s %s ", s, opcodes[op]);
1.16 claudio 514:
1.1 deraadt 515: switch (op) {
516: case RRQ:
517: case WRQ:
518: n -= 2;
519: file = cp = tp->th_stuff;
1.3 millert 520: cp = strchr(cp, '\0');
1.19 mglocker 521: printf("<file=%s, mode=%s", file, cp + 1);
522: if (has_options)
523: oack(tp, n, 1);
524: printf(">\n");
1.1 deraadt 525: break;
526: case DATA:
527: printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
528: break;
529: case ACK:
530: printf("<block=%d>\n", ntohs(tp->th_block));
531: break;
532: case ERROR:
533: printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
534: break;
1.19 mglocker 535: case OACK:
536: printf("<");
537: oack(tp, n, 1);
538: printf(">\n");
539: break;
1.1 deraadt 540: }
541: }
542:
543: static void
1.13 deraadt 544: startclock(void)
1.1 deraadt 545: {
1.17 mglocker 546: (void)gettimeofday(&tstart, NULL);
1.1 deraadt 547: }
548:
549: static void
1.13 deraadt 550: stopclock(void)
1.1 deraadt 551: {
1.17 mglocker 552: (void)gettimeofday(&tstop, NULL);
1.1 deraadt 553: }
554:
555: static void
1.14 deraadt 556: printstats(const char *direction, unsigned long amount)
1.1 deraadt 557: {
1.17 mglocker 558: double delta;
1.15 deraadt 559:
560: /* compute delta in 1/10's second units */
1.16 claudio 561: delta = ((tstop.tv_sec * 10.) + (tstop.tv_usec / 100000)) -
562: ((tstart.tv_sec * 10.) + (tstart.tv_usec / 100000));
563: delta = delta / 10.; /* back to seconds */
1.6 deraadt 564: printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
1.1 deraadt 565: if (verbose)
1.16 claudio 566: printf(" [%.0f bits/sec]", (amount * 8.) / delta);
1.1 deraadt 567: putchar('\n');
568: }
569:
570: static void
1.16 claudio 571: printtimeout(void)
1.1 deraadt 572: {
1.16 claudio 573: printf("Transfer timed out.\n");
1.19 mglocker 574: }
575:
576: static void
577: oack(struct tftphdr *tp, int size, int trace)
578: {
579: int i, len, off;
580: char *opt, *val;
581:
582: u_short op = ntohs(tp->th_opcode);
583:
584: opt = tp->th_u.tu_stuff;
585: val = tp->th_u.tu_stuff;
586:
587: if (op == RRQ || op == WRQ) {
588: len = strlen(opt) + 1;
589: opt = strchr(opt, '\0');
590: opt++;
591: len += strlen(opt) + 1;
592: opt = strchr(opt, '\0');
593: opt++;
594: val = opt;
595: off = len;
596: if (trace)
597: printf(", ");
598: } else
599: off = 2;
600:
601: for (i = off, len = 0; i < size - 1; i++) {
602: if (*val != '\0') {
603: val++;
604: continue;
605: }
606: /* got option and value */
607: val++;
608: if (trace)
609: printf("%s=%s", opt, val);
610: else
611: if (oack_set(opt, val) == -1)
612: break;
613: len = strlen(val) + 1;
614: val += len;
615: opt = val;
616: i += len;
617: if (trace && i < size - 1)
618: printf(", ");
619: }
620: }
621:
622: int
623: oack_set(const char *option, const char *value)
624: {
625: int i, n;
626: const char *errstr;
1.23 ! gsoares 627: struct sockaddr_storage peer;
! 628: memcpy(&peer, &peeraddr, peeraddr.ss_len);
1.19 mglocker 629:
630: for (i = 0; options[i].o_type != NULL; i++) {
631: if (!strcasecmp(options[i].o_type, option)) {
632: if (i == OPT_TSIZE) {
633: /* XXX verify OACK response */
634: }
635: if (i == OPT_TIMEOUT) {
636: /* verify OACK response */
1.20 mglocker 637: n = strtonum(value, TIMEOUT_MIN, TIMEOUT_MAX,
638: &errstr);
1.19 mglocker 639: if (errstr || rexmtval != n ||
640: opt_tout == 0) {
1.23 ! gsoares 641: nak(EOPTNEG, (struct sockaddr *)&peer);
1.19 mglocker 642: intrflag = 1;
643: return (-1);
644: }
645: /* OK */
646: }
647: if (i == OPT_BLKSIZE) {
648: /* verify OACK response */
649: n = strtonum(value, SEGSIZE_MIN, SEGSIZE_MAX,
650: &errstr);
651: if (errstr || opt_blksize != n ||
652: opt_blksize == 0) {
1.23 ! gsoares 653: nak(EOPTNEG, (struct sockaddr *)&peer);
1.19 mglocker 654: intrflag = 1;
655: return (-1);
656: }
657: /* OK, set option */
658: segment_size = n;
659: packet_size = segment_size + 4;
660: }
661: }
662: }
663:
664: return (1);
1.1 deraadt 665: }