[BACK]Return to tftp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tftp

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: }