Annotation of qemu/roms/ipxe/src/net/udp/tftp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stdint.h>
        !            22: #include <stdlib.h>
        !            23: #include <stdio.h>
        !            24: #include <string.h>
        !            25: #include <strings.h>
        !            26: #include <byteswap.h>
        !            27: #include <errno.h>
        !            28: #include <assert.h>
        !            29: #include <ipxe/refcnt.h>
        !            30: #include <ipxe/iobuf.h>
        !            31: #include <ipxe/xfer.h>
        !            32: #include <ipxe/open.h>
        !            33: #include <ipxe/uri.h>
        !            34: #include <ipxe/tcpip.h>
        !            35: #include <ipxe/retry.h>
        !            36: #include <ipxe/features.h>
        !            37: #include <ipxe/bitmap.h>
        !            38: #include <ipxe/settings.h>
        !            39: #include <ipxe/dhcp.h>
        !            40: #include <ipxe/uri.h>
        !            41: #include <ipxe/tftp.h>
        !            42: 
        !            43: /** @file
        !            44:  *
        !            45:  * TFTP protocol
        !            46:  *
        !            47:  */
        !            48: 
        !            49: FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
        !            50: 
        !            51: /* TFTP-specific error codes */
        !            52: #define EINVAL_BLKSIZE         __einfo_error ( EINFO_EINVAL_BLKSIZE )
        !            53: #define EINFO_EINVAL_BLKSIZE __einfo_uniqify \
        !            54:        ( EINFO_EINVAL, 0x01, "Invalid blksize" )
        !            55: #define EINVAL_TSIZE __einfo_error ( EINFO_EINVAL_TSIZE )
        !            56: #define EINFO_EINVAL_TSIZE __einfo_uniqify \
        !            57:        ( EINFO_EINVAL, 0x02, "Invalid tsize" )
        !            58: #define EINVAL_MC_NO_PORT __einfo_error ( EINFO_EINVAL_MC_NO_PORT )
        !            59: #define EINFO_EINVAL_MC_NO_PORT __einfo_uniqify \
        !            60:        ( EINFO_EINVAL, 0x03, "Missing multicast port" )
        !            61: #define EINVAL_MC_NO_MC __einfo_error ( EINFO_EINVAL_MC_NO_MC )
        !            62: #define EINFO_EINVAL_MC_NO_MC __einfo_uniqify \
        !            63:        ( EINFO_EINVAL, 0x04, "Missing multicast mc" )
        !            64: #define EINVAL_MC_INVALID_MC __einfo_error ( EINFO_EINVAL_MC_INVALID_MC )
        !            65: #define EINFO_EINVAL_MC_INVALID_MC __einfo_uniqify \
        !            66:        ( EINFO_EINVAL, 0x05, "Missing multicast IP" )
        !            67: #define EINVAL_MC_INVALID_IP __einfo_error ( EINFO_EINVAL_MC_INVALID_IP )
        !            68: #define EINFO_EINVAL_MC_INVALID_IP __einfo_uniqify \
        !            69:        ( EINFO_EINVAL, 0x06, "Invalid multicast IP" )
        !            70: #define EINVAL_MC_INVALID_PORT __einfo_error ( EINFO_EINVAL_MC_INVALID_PORT )
        !            71: #define EINFO_EINVAL_MC_INVALID_PORT __einfo_uniqify \
        !            72:        ( EINFO_EINVAL, 0x07, "Invalid multicast port" )
        !            73: 
        !            74: /**
        !            75:  * A TFTP request
        !            76:  *
        !            77:  * This data structure holds the state for an ongoing TFTP transfer.
        !            78:  */
        !            79: struct tftp_request {
        !            80:        /** Reference count */
        !            81:        struct refcnt refcnt;
        !            82:        /** Data transfer interface */
        !            83:        struct interface xfer;
        !            84: 
        !            85:        /** URI being fetched */
        !            86:        struct uri *uri;
        !            87:        /** Transport layer interface */
        !            88:        struct interface socket;
        !            89:        /** Multicast transport layer interface */
        !            90:        struct interface mc_socket;
        !            91: 
        !            92:        /** Data block size
        !            93:         *
        !            94:         * This is the "blksize" option negotiated with the TFTP
        !            95:         * server.  (If the TFTP server does not support TFTP options,
        !            96:         * this will default to 512).
        !            97:         */
        !            98:        unsigned int blksize;
        !            99:        /** File size
        !           100:         *
        !           101:         * This is the value returned in the "tsize" option from the
        !           102:         * TFTP server.  If the TFTP server does not support the
        !           103:         * "tsize" option, this value will be zero.
        !           104:         */
        !           105:        unsigned long tsize;
        !           106:        
        !           107:        /** Server port
        !           108:         *
        !           109:         * This is the port to which RRQ packets are sent.
        !           110:         */
        !           111:        unsigned int port;
        !           112:        /** Peer address
        !           113:         *
        !           114:         * The peer address is determined by the first response
        !           115:         * received to the TFTP RRQ.
        !           116:         */
        !           117:        struct sockaddr_tcpip peer;
        !           118:        /** Request flags */
        !           119:        unsigned int flags;
        !           120:        /** MTFTP timeout count */
        !           121:        unsigned int mtftp_timeouts;
        !           122: 
        !           123:        /** Block bitmap */
        !           124:        struct bitmap bitmap;
        !           125:        /** Maximum known length
        !           126:         *
        !           127:         * We don't always know the file length in advance.  In
        !           128:         * particular, if the TFTP server doesn't support the tsize
        !           129:         * option, or we are using MTFTP, then we don't know the file
        !           130:         * length until we see the end-of-file block (which, in the
        !           131:         * case of MTFTP, may not be the last block we see).
        !           132:         *
        !           133:         * This value is updated whenever we obtain information about
        !           134:         * the file length.
        !           135:         */
        !           136:        size_t filesize;
        !           137:        /** Retransmission timer */
        !           138:        struct retry_timer timer;
        !           139: };
        !           140: 
        !           141: /** TFTP request flags */
        !           142: enum {
        !           143:        /** Send ACK packets */
        !           144:        TFTP_FL_SEND_ACK = 0x0001,
        !           145:        /** Request blksize and tsize options */
        !           146:        TFTP_FL_RRQ_SIZES = 0x0002,
        !           147:        /** Request multicast option */
        !           148:        TFTP_FL_RRQ_MULTICAST = 0x0004,
        !           149:        /** Perform MTFTP recovery on timeout */
        !           150:        TFTP_FL_MTFTP_RECOVERY = 0x0008,
        !           151:        /** Only get filesize and then abort the transfer */
        !           152:        TFTP_FL_SIZEONLY = 0x0010,
        !           153: };
        !           154: 
        !           155: /** Maximum number of MTFTP open requests before falling back to TFTP */
        !           156: #define MTFTP_MAX_TIMEOUTS 3
        !           157: 
        !           158: /**
        !           159:  * Free TFTP request
        !           160:  *
        !           161:  * @v refcnt           Reference counter
        !           162:  */
        !           163: static void tftp_free ( struct refcnt *refcnt ) {
        !           164:        struct tftp_request *tftp =
        !           165:                container_of ( refcnt, struct tftp_request, refcnt );
        !           166: 
        !           167:        uri_put ( tftp->uri );
        !           168:        bitmap_free ( &tftp->bitmap );
        !           169:        free ( tftp );
        !           170: }
        !           171: 
        !           172: /**
        !           173:  * Mark TFTP request as complete
        !           174:  *
        !           175:  * @v tftp             TFTP connection
        !           176:  * @v rc               Return status code
        !           177:  */
        !           178: static void tftp_done ( struct tftp_request *tftp, int rc ) {
        !           179: 
        !           180:        DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
        !           181:               tftp, rc, strerror ( rc ) );
        !           182: 
        !           183:        /* Stop the retry timer */
        !           184:        stop_timer ( &tftp->timer );
        !           185: 
        !           186:        /* Close all data transfer interfaces */
        !           187:        intf_shutdown ( &tftp->socket, rc );
        !           188:        intf_shutdown ( &tftp->mc_socket, rc );
        !           189:        intf_shutdown ( &tftp->xfer, rc );
        !           190: }
        !           191: 
        !           192: /**
        !           193:  * Reopen TFTP socket
        !           194:  *
        !           195:  * @v tftp             TFTP connection
        !           196:  * @ret rc             Return status code
        !           197:  */
        !           198: static int tftp_reopen ( struct tftp_request *tftp ) {
        !           199:        struct sockaddr_tcpip server;
        !           200:        int rc;
        !           201: 
        !           202:        /* Close socket */
        !           203:        intf_restart ( &tftp->socket, 0 );
        !           204: 
        !           205:        /* Disable ACK sending. */
        !           206:        tftp->flags &= ~TFTP_FL_SEND_ACK;
        !           207: 
        !           208:        /* Reset peer address */
        !           209:        memset ( &tftp->peer, 0, sizeof ( tftp->peer ) );
        !           210: 
        !           211:        /* Open socket */
        !           212:        memset ( &server, 0, sizeof ( server ) );
        !           213:        server.st_port = htons ( tftp->port );
        !           214:        if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
        !           215:                                             ( struct sockaddr * ) &server,
        !           216:                                             tftp->uri->host, NULL ) ) != 0 ) {
        !           217:                DBGC ( tftp, "TFTP %p could not open socket: %s\n",
        !           218:                       tftp, strerror ( rc ) );
        !           219:                return rc;
        !           220:        }
        !           221: 
        !           222:        return 0;
        !           223: }
        !           224: 
        !           225: /**
        !           226:  * Reopen TFTP multicast socket
        !           227:  *
        !           228:  * @v tftp             TFTP connection
        !           229:  * @v local            Local socket address
        !           230:  * @ret rc             Return status code
        !           231:  */
        !           232: static int tftp_reopen_mc ( struct tftp_request *tftp,
        !           233:                            struct sockaddr *local ) {
        !           234:        int rc;
        !           235: 
        !           236:        /* Close multicast socket */
        !           237:        intf_restart ( &tftp->mc_socket, 0 );
        !           238: 
        !           239:        /* Open multicast socket.  We never send via this socket, so
        !           240:         * use the local address as the peer address (since the peer
        !           241:         * address cannot be NULL).
        !           242:         */
        !           243:        if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
        !           244:                                       local, local ) ) != 0 ) {
        !           245:                DBGC ( tftp, "TFTP %p could not open multicast "
        !           246:                       "socket: %s\n", tftp, strerror ( rc ) );
        !           247:                return rc;
        !           248:        }
        !           249: 
        !           250:        return 0;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * Presize TFTP receive buffers and block bitmap
        !           255:  *
        !           256:  * @v tftp             TFTP connection
        !           257:  * @v filesize         Known minimum file size
        !           258:  * @ret rc             Return status code
        !           259:  */
        !           260: static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
        !           261:        unsigned int num_blocks;
        !           262:        int rc;
        !           263: 
        !           264:        /* Do nothing if we are already large enough */
        !           265:        if ( filesize <= tftp->filesize )
        !           266:                return 0;
        !           267: 
        !           268:        /* Record filesize */
        !           269:        tftp->filesize = filesize;
        !           270: 
        !           271:        /* Notify recipient of file size */
        !           272:        xfer_seek ( &tftp->xfer, filesize );
        !           273:        xfer_seek ( &tftp->xfer, 0 );
        !           274: 
        !           275:        /* Calculate expected number of blocks.  Note that files whose
        !           276:         * length is an exact multiple of the blocksize will have a
        !           277:         * trailing zero-length block, which must be included.
        !           278:         */
        !           279:        num_blocks = ( ( filesize / tftp->blksize ) + 1 );
        !           280:        if ( ( rc = bitmap_resize ( &tftp->bitmap, num_blocks ) ) != 0 ) {
        !           281:                DBGC ( tftp, "TFTP %p could not resize bitmap to %d blocks: "
        !           282:                       "%s\n", tftp, num_blocks, strerror ( rc ) );
        !           283:                return rc;
        !           284:        }
        !           285: 
        !           286:        return 0;
        !           287: }
        !           288: 
        !           289: /**
        !           290:  * TFTP requested blocksize
        !           291:  *
        !           292:  * This is treated as a global configuration parameter.
        !           293:  */
        !           294: static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
        !           295: 
        !           296: /**
        !           297:  * Set TFTP request blocksize
        !           298:  *
        !           299:  * @v blksize          Requested block size
        !           300:  */
        !           301: void tftp_set_request_blksize ( unsigned int blksize ) {
        !           302:        if ( blksize < TFTP_DEFAULT_BLKSIZE )
        !           303:                blksize = TFTP_DEFAULT_BLKSIZE;
        !           304:        tftp_request_blksize = blksize;
        !           305: }
        !           306: 
        !           307: /**
        !           308:  * MTFTP multicast receive address
        !           309:  *
        !           310:  * This is treated as a global configuration parameter.
        !           311:  */
        !           312: static struct sockaddr_in tftp_mtftp_socket = {
        !           313:        .sin_family = AF_INET,
        !           314:        .sin_addr.s_addr = htonl ( 0xefff0101 ),
        !           315:        .sin_port = htons ( 3001 ),
        !           316: };
        !           317: 
        !           318: /**
        !           319:  * Set MTFTP multicast address
        !           320:  *
        !           321:  * @v address          Multicast IPv4 address
        !           322:  */
        !           323: void tftp_set_mtftp_address ( struct in_addr address ) {
        !           324:        tftp_mtftp_socket.sin_addr = address;
        !           325: }
        !           326: 
        !           327: /**
        !           328:  * Set MTFTP multicast port
        !           329:  *
        !           330:  * @v port             Multicast port
        !           331:  */
        !           332: void tftp_set_mtftp_port ( unsigned int port ) {
        !           333:        tftp_mtftp_socket.sin_port = htons ( port );
        !           334: }
        !           335: 
        !           336: /**
        !           337:  * Transmit RRQ
        !           338:  *
        !           339:  * @v tftp             TFTP connection
        !           340:  * @ret rc             Return status code
        !           341:  */
        !           342: static int tftp_send_rrq ( struct tftp_request *tftp ) {
        !           343:        struct tftp_rrq *rrq;
        !           344:        const char *path;
        !           345:        size_t len;
        !           346:        struct io_buffer *iobuf;
        !           347: 
        !           348:        /* Strip initial '/' if present.  If we were opened via the
        !           349:         * URI interface, then there will be an initial '/', since a
        !           350:         * full tftp:// URI provides no way to specify a non-absolute
        !           351:         * path.  However, many TFTP servers (particularly Windows
        !           352:         * TFTP servers) complain about having an initial '/', and it
        !           353:         * violates user expectations to have a '/' silently added to
        !           354:         * the DHCP-specified filename.
        !           355:         */
        !           356:        path = tftp->uri->path;
        !           357:        if ( *path == '/' )
        !           358:                path++;
        !           359: 
        !           360:        DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
        !           361: 
        !           362:        /* Allocate buffer */
        !           363:        len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
        !           364:                + 5 + 1 /* "octet" + NUL */
        !           365:                + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
        !           366:                + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ 
        !           367:                + 9 + 1 + 1 /* "multicast" + NUL + NUL */ );
        !           368:        iobuf = xfer_alloc_iob ( &tftp->socket, len );
        !           369:        if ( ! iobuf )
        !           370:                return -ENOMEM;
        !           371: 
        !           372:        /* Build request */
        !           373:        rrq = iob_put ( iobuf, sizeof ( *rrq ) );
        !           374:        rrq->opcode = htons ( TFTP_RRQ );
        !           375:        iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ),
        !           376:                                    "%s%coctet", path, 0 ) + 1 );
        !           377:        if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
        !           378:                iob_put ( iobuf, snprintf ( iobuf->tail,
        !           379:                                            iob_tailroom ( iobuf ),
        !           380:                                            "blksize%c%d%ctsize%c0", 0,
        !           381:                                            tftp_request_blksize, 0, 0 ) + 1 );
        !           382:        }
        !           383:        if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
        !           384:                iob_put ( iobuf, snprintf ( iobuf->tail,
        !           385:                                            iob_tailroom ( iobuf ),
        !           386:                                            "multicast%c", 0 ) + 1 );
        !           387:        }
        !           388: 
        !           389:        /* RRQ always goes to the address specified in the initial
        !           390:         * xfer_open() call
        !           391:         */
        !           392:        return xfer_deliver_iob ( &tftp->socket, iobuf );
        !           393: }
        !           394: 
        !           395: /**
        !           396:  * Transmit ACK
        !           397:  *
        !           398:  * @v tftp             TFTP connection
        !           399:  * @ret rc             Return status code
        !           400:  */
        !           401: static int tftp_send_ack ( struct tftp_request *tftp ) {
        !           402:        struct tftp_ack *ack;
        !           403:        struct io_buffer *iobuf;
        !           404:        struct xfer_metadata meta = {
        !           405:                .dest = ( struct sockaddr * ) &tftp->peer,
        !           406:        };
        !           407:        unsigned int block;
        !           408: 
        !           409:        /* Determine next required block number */
        !           410:        block = bitmap_first_gap ( &tftp->bitmap );
        !           411:        DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n", tftp, block );
        !           412: 
        !           413:        /* Allocate buffer */
        !           414:        iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
        !           415:        if ( ! iobuf )
        !           416:                return -ENOMEM;
        !           417: 
        !           418:        /* Build ACK */
        !           419:        ack = iob_put ( iobuf, sizeof ( *ack ) );
        !           420:        ack->opcode = htons ( TFTP_ACK );
        !           421:        ack->block = htons ( block );
        !           422: 
        !           423:        /* ACK always goes to the peer recorded from the RRQ response */
        !           424:        return xfer_deliver ( &tftp->socket, iobuf, &meta );
        !           425: }
        !           426: 
        !           427: /**
        !           428:  * Transmit ERROR (Abort)
        !           429:  *
        !           430:  * @v tftp             TFTP connection
        !           431:  * @v errcode          TFTP error code
        !           432:  * @v errmsg           Error message string
        !           433:  * @ret rc             Return status code
        !           434:  */
        !           435: static int tftp_send_error ( struct tftp_request *tftp, int errcode,
        !           436:                             const char *errmsg ) {
        !           437:        struct tftp_error *err;
        !           438:        struct io_buffer *iobuf;
        !           439:        struct xfer_metadata meta = {
        !           440:                .dest = ( struct sockaddr * ) &tftp->peer,
        !           441:        };
        !           442:        size_t msglen;
        !           443: 
        !           444:        DBGC2 ( tftp, "TFTP %p sending ERROR %d: %s\n", tftp, errcode,
        !           445:                errmsg );
        !           446: 
        !           447:        /* Allocate buffer */
        !           448:        msglen = sizeof ( *err ) + strlen ( errmsg ) + 1 /* NUL */;
        !           449:        iobuf = xfer_alloc_iob ( &tftp->socket, msglen );
        !           450:        if ( ! iobuf )
        !           451:                return -ENOMEM;
        !           452: 
        !           453:        /* Build ERROR */
        !           454:        err = iob_put ( iobuf, msglen );
        !           455:        err->opcode = htons ( TFTP_ERROR );
        !           456:        err->errcode = htons ( errcode );
        !           457:        strcpy ( err->errmsg, errmsg );
        !           458: 
        !           459:        /* ERR always goes to the peer recorded from the RRQ response */
        !           460:        return xfer_deliver ( &tftp->socket, iobuf, &meta );
        !           461: }
        !           462: 
        !           463: /**
        !           464:  * Transmit next relevant packet
        !           465:  *
        !           466:  * @v tftp             TFTP connection
        !           467:  * @ret rc             Return status code
        !           468:  */
        !           469: static int tftp_send_packet ( struct tftp_request *tftp ) {
        !           470: 
        !           471:        /* Update retransmission timer.  While name resolution takes place the
        !           472:         * window is zero.  Avoid unnecessary delay after name resolution
        !           473:         * completes by retrying immediately.
        !           474:         */
        !           475:        stop_timer ( &tftp->timer );
        !           476:        if ( xfer_window ( &tftp->socket ) ) {
        !           477:                start_timer ( &tftp->timer );
        !           478:        } else {
        !           479:                start_timer_nodelay ( &tftp->timer );
        !           480:        }
        !           481: 
        !           482:        /* Send RRQ or ACK as appropriate */
        !           483:        if ( ! tftp->peer.st_family ) {
        !           484:                return tftp_send_rrq ( tftp );
        !           485:        } else {
        !           486:                if ( tftp->flags & TFTP_FL_SEND_ACK ) {
        !           487:                        return tftp_send_ack ( tftp );
        !           488:                } else {
        !           489:                        return 0;
        !           490:                }
        !           491:        }
        !           492: }
        !           493: 
        !           494: /**
        !           495:  * Handle TFTP retransmission timer expiry
        !           496:  *
        !           497:  * @v timer            Retry timer
        !           498:  * @v fail             Failure indicator
        !           499:  */
        !           500: static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
        !           501:        struct tftp_request *tftp =
        !           502:                container_of ( timer, struct tftp_request, timer );
        !           503:        int rc;
        !           504: 
        !           505:        /* If we are doing MTFTP, attempt the various recovery strategies */
        !           506:        if ( tftp->flags & TFTP_FL_MTFTP_RECOVERY ) {
        !           507:                if ( tftp->peer.st_family ) {
        !           508:                        /* If we have received any response from the server,
        !           509:                         * try resending the RRQ to restart the download.
        !           510:                         */
        !           511:                        DBGC ( tftp, "TFTP %p attempting reopen\n", tftp );
        !           512:                        if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
        !           513:                                goto err;
        !           514:                } else {
        !           515:                        /* Fall back to plain TFTP after several attempts */
        !           516:                        tftp->mtftp_timeouts++;
        !           517:                        DBGC ( tftp, "TFTP %p timeout %d waiting for MTFTP "
        !           518:                               "open\n", tftp, tftp->mtftp_timeouts );
        !           519: 
        !           520:                        if ( tftp->mtftp_timeouts > MTFTP_MAX_TIMEOUTS ) {
        !           521:                                DBGC ( tftp, "TFTP %p falling back to plain "
        !           522:                                       "TFTP\n", tftp );
        !           523:                                tftp->flags = TFTP_FL_RRQ_SIZES;
        !           524: 
        !           525:                                /* Close multicast socket */
        !           526:                                intf_restart ( &tftp->mc_socket, 0 );
        !           527: 
        !           528:                                /* Reset retry timer */
        !           529:                                start_timer_nodelay ( &tftp->timer );
        !           530: 
        !           531:                                /* The blocksize may change: discard
        !           532:                                 * the block bitmap
        !           533:                                 */
        !           534:                                bitmap_free ( &tftp->bitmap );
        !           535:                                memset ( &tftp->bitmap, 0,
        !           536:                                         sizeof ( tftp->bitmap ) );
        !           537: 
        !           538:                                /* Reopen on standard TFTP port */
        !           539:                                tftp->port = TFTP_PORT;
        !           540:                                if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
        !           541:                                        goto err;
        !           542:                        }
        !           543:                }
        !           544:        } else {
        !           545:                /* Not doing MTFTP (or have fallen back to plain
        !           546:                 * TFTP); fail as per normal.
        !           547:                 */
        !           548:                if ( fail ) {
        !           549:                        rc = -ETIMEDOUT;
        !           550:                        goto err;
        !           551:                }
        !           552:        }
        !           553:        tftp_send_packet ( tftp );
        !           554:        return;
        !           555: 
        !           556:  err:
        !           557:        tftp_done ( tftp, rc );
        !           558: }
        !           559: 
        !           560: /**
        !           561:  * Process TFTP "blksize" option
        !           562:  *
        !           563:  * @v tftp             TFTP connection
        !           564:  * @v value            Option value
        !           565:  * @ret rc             Return status code
        !           566:  */
        !           567: static int tftp_process_blksize ( struct tftp_request *tftp,
        !           568:                                  const char *value ) {
        !           569:        char *end;
        !           570: 
        !           571:        tftp->blksize = strtoul ( value, &end, 10 );
        !           572:        if ( *end ) {
        !           573:                DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
        !           574:                       tftp, value );
        !           575:                return -EINVAL_BLKSIZE;
        !           576:        }
        !           577:        DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
        !           578: 
        !           579:        return 0;
        !           580: }
        !           581: 
        !           582: /**
        !           583:  * Process TFTP "tsize" option
        !           584:  *
        !           585:  * @v tftp             TFTP connection
        !           586:  * @v value            Option value
        !           587:  * @ret rc             Return status code
        !           588:  */
        !           589: static int tftp_process_tsize ( struct tftp_request *tftp,
        !           590:                                const char *value ) {
        !           591:        char *end;
        !           592: 
        !           593:        tftp->tsize = strtoul ( value, &end, 10 );
        !           594:        if ( *end ) {
        !           595:                DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
        !           596:                       tftp, value );
        !           597:                return -EINVAL_TSIZE;
        !           598:        }
        !           599:        DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
        !           600: 
        !           601:        return 0;
        !           602: }
        !           603: 
        !           604: /**
        !           605:  * Process TFTP "multicast" option
        !           606:  *
        !           607:  * @v tftp             TFTP connection
        !           608:  * @v value            Option value
        !           609:  * @ret rc             Return status code
        !           610:  */
        !           611: static int tftp_process_multicast ( struct tftp_request *tftp,
        !           612:                                    const char *value ) {
        !           613:        union {
        !           614:                struct sockaddr sa;
        !           615:                struct sockaddr_in sin;
        !           616:        } socket;
        !           617:        char buf[ strlen ( value ) + 1 ];
        !           618:        char *addr;
        !           619:        char *port;
        !           620:        char *port_end;
        !           621:        char *mc;
        !           622:        char *mc_end;
        !           623:        int rc;
        !           624: 
        !           625:        /* Split value into "addr,port,mc" fields */
        !           626:        memcpy ( buf, value, sizeof ( buf ) );
        !           627:        addr = buf;
        !           628:        port = strchr ( addr, ',' );
        !           629:        if ( ! port ) {
        !           630:                DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
        !           631:                return -EINVAL_MC_NO_PORT;
        !           632:        }
        !           633:        *(port++) = '\0';
        !           634:        mc = strchr ( port, ',' );
        !           635:        if ( ! mc ) {
        !           636:                DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
        !           637:                return -EINVAL_MC_NO_MC;
        !           638:        }
        !           639:        *(mc++) = '\0';
        !           640: 
        !           641:        /* Parse parameters */
        !           642:        if ( strtoul ( mc, &mc_end, 0 ) == 0 )
        !           643:                tftp->flags &= ~TFTP_FL_SEND_ACK;
        !           644:        if ( *mc_end ) {
        !           645:                DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
        !           646:                return -EINVAL_MC_INVALID_MC;
        !           647:        }
        !           648:        DBGC ( tftp, "TFTP %p is%s the master client\n",
        !           649:               tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
        !           650:        if ( *addr && *port ) {
        !           651:                socket.sin.sin_family = AF_INET;
        !           652:                if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
        !           653:                        DBGC ( tftp, "TFTP %p multicast invalid IP address "
        !           654:                               "%s\n", tftp, addr );
        !           655:                        return -EINVAL_MC_INVALID_IP;
        !           656:                }
        !           657:                DBGC ( tftp, "TFTP %p multicast IP address %s\n",
        !           658:                       tftp, inet_ntoa ( socket.sin.sin_addr ) );
        !           659:                socket.sin.sin_port = htons ( strtoul ( port, &port_end, 0 ) );
        !           660:                if ( *port_end ) {
        !           661:                        DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
        !           662:                               tftp, port );
        !           663:                        return -EINVAL_MC_INVALID_PORT;
        !           664:                }
        !           665:                DBGC ( tftp, "TFTP %p multicast port %d\n",
        !           666:                       tftp, ntohs ( socket.sin.sin_port ) );
        !           667:                if ( ( rc = tftp_reopen_mc ( tftp, &socket.sa ) ) != 0 )
        !           668:                        return rc;
        !           669:        }
        !           670: 
        !           671:        return 0;
        !           672: }
        !           673: 
        !           674: /** A TFTP option */
        !           675: struct tftp_option {
        !           676:        /** Option name */
        !           677:        const char *name;
        !           678:        /** Option processor
        !           679:         *
        !           680:         * @v tftp      TFTP connection
        !           681:         * @v value     Option value
        !           682:         * @ret rc      Return status code
        !           683:         */
        !           684:        int ( * process ) ( struct tftp_request *tftp, const char *value );
        !           685: };
        !           686: 
        !           687: /** Recognised TFTP options */
        !           688: static struct tftp_option tftp_options[] = {
        !           689:        { "blksize", tftp_process_blksize },
        !           690:        { "tsize", tftp_process_tsize },
        !           691:        { "multicast", tftp_process_multicast },
        !           692:        { NULL, NULL }
        !           693: };
        !           694: 
        !           695: /**
        !           696:  * Process TFTP option
        !           697:  *
        !           698:  * @v tftp             TFTP connection
        !           699:  * @v name             Option name
        !           700:  * @v value            Option value
        !           701:  * @ret rc             Return status code
        !           702:  */
        !           703: static int tftp_process_option ( struct tftp_request *tftp,
        !           704:                                 const char *name, const char *value ) {
        !           705:        struct tftp_option *option;
        !           706: 
        !           707:        for ( option = tftp_options ; option->name ; option++ ) {
        !           708:                if ( strcasecmp ( name, option->name ) == 0 )
        !           709:                        return option->process ( tftp, value );
        !           710:        }
        !           711: 
        !           712:        DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
        !           713:               tftp, name, value );
        !           714: 
        !           715:        /* Unknown options should be silently ignored */
        !           716:        return 0;
        !           717: }
        !           718: 
        !           719: /**
        !           720:  * Receive OACK
        !           721:  *
        !           722:  * @v tftp             TFTP connection
        !           723:  * @v buf              Temporary data buffer
        !           724:  * @v len              Length of temporary data buffer
        !           725:  * @ret rc             Return status code
        !           726:  */
        !           727: static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
        !           728:        struct tftp_oack *oack = buf;
        !           729:        char *end = buf + len;
        !           730:        char *name;
        !           731:        char *value;
        !           732:        char *next;
        !           733:        int rc = 0;
        !           734: 
        !           735:        /* Sanity check */
        !           736:        if ( len < sizeof ( *oack ) ) {
        !           737:                DBGC ( tftp, "TFTP %p received underlength OACK packet "
        !           738:                       "length %zd\n", tftp, len );
        !           739:                rc = -EINVAL;
        !           740:                goto done;
        !           741:        }
        !           742: 
        !           743:        /* Process each option in turn */
        !           744:        for ( name = oack->data ; name < end ; name = next ) {
        !           745: 
        !           746:                /* Parse option name and value
        !           747:                 *
        !           748:                 * We treat parsing errors as non-fatal, because there
        !           749:                 * exists at least one TFTP server (IBM Tivoli PXE
        !           750:                 * Server 5.1.0.3) that has been observed to send
        !           751:                 * malformed OACKs containing trailing garbage bytes.
        !           752:                 */
        !           753:                value = ( name + strnlen ( name, ( end - name ) ) + 1 );
        !           754:                if ( value > end ) {
        !           755:                        DBGC ( tftp, "TFTP %p received OACK with malformed "
        !           756:                               "option name:\n", tftp );
        !           757:                        DBGC_HD ( tftp, oack, len );
        !           758:                        break;
        !           759:                }
        !           760:                if ( value == end ) {
        !           761:                        DBGC ( tftp, "TFTP %p received OACK missing value "
        !           762:                               "for option \"%s\"\n", tftp, name );
        !           763:                        DBGC_HD ( tftp, oack, len );
        !           764:                        break;
        !           765:                }
        !           766:                next = ( value + strnlen ( value, ( end - value ) ) + 1 );
        !           767:                if ( next > end ) {
        !           768:                        DBGC ( tftp, "TFTP %p received OACK with malformed "
        !           769:                               "value for option \"%s\":\n", tftp, name );
        !           770:                        DBGC_HD ( tftp, oack, len );
        !           771:                        break;
        !           772:                }
        !           773: 
        !           774:                /* Process option */
        !           775:                if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
        !           776:                        goto done;
        !           777:        }
        !           778: 
        !           779:        /* Process tsize information, if available */
        !           780:        if ( tftp->tsize ) {
        !           781:                if ( ( rc = tftp_presize ( tftp, tftp->tsize ) ) != 0 )
        !           782:                        goto done;
        !           783:        }
        !           784: 
        !           785:        /* Abort request if only trying to determine file size */
        !           786:        if ( tftp->flags & TFTP_FL_SIZEONLY ) {
        !           787:                rc = 0;
        !           788:                tftp_send_error ( tftp, 0, "TFTP Aborted" );
        !           789:                tftp_done ( tftp, rc );
        !           790:                return rc;
        !           791:        }
        !           792: 
        !           793:        /* Request next data block */
        !           794:        tftp_send_packet ( tftp );
        !           795: 
        !           796:  done:
        !           797:        if ( rc )
        !           798:                tftp_done ( tftp, rc );
        !           799:        return rc;
        !           800: }
        !           801: 
        !           802: /**
        !           803:  * Receive DATA
        !           804:  *
        !           805:  * @v tftp             TFTP connection
        !           806:  * @v iobuf            I/O buffer
        !           807:  * @ret rc             Return status code
        !           808:  *
        !           809:  * Takes ownership of I/O buffer.
        !           810:  */
        !           811: static int tftp_rx_data ( struct tftp_request *tftp,
        !           812:                          struct io_buffer *iobuf ) {
        !           813:        struct tftp_data *data = iobuf->data;
        !           814:        struct xfer_metadata meta;
        !           815:        unsigned int block;
        !           816:        off_t offset;
        !           817:        size_t data_len;
        !           818:        int rc;
        !           819: 
        !           820:        if ( tftp->flags & TFTP_FL_SIZEONLY ) {
        !           821:                /* If we get here then server doesn't support SIZE option */
        !           822:                rc = -ENOTSUP;
        !           823:                tftp_send_error ( tftp, 0, "TFTP Aborted" );
        !           824:                goto done;
        !           825:        }
        !           826: 
        !           827:        /* Sanity check */
        !           828:        if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
        !           829:                DBGC ( tftp, "TFTP %p received underlength DATA packet "
        !           830:                       "length %zd\n", tftp, iob_len ( iobuf ) );
        !           831:                rc = -EINVAL;
        !           832:                goto done;
        !           833:        }
        !           834: 
        !           835:        /* Calculate block number */
        !           836:        block = ( ( bitmap_first_gap ( &tftp->bitmap ) + 1 ) & ~0xffff );
        !           837:        if ( data->block == 0 && block == 0 ) {
        !           838:                DBGC ( tftp, "TFTP %p received data block 0\n", tftp );
        !           839:                rc = -EINVAL;
        !           840:                goto done;
        !           841:        }
        !           842:        block += ( ntohs ( data->block ) - 1 );
        !           843: 
        !           844:        /* Extract data */
        !           845:        offset = ( block * tftp->blksize );
        !           846:        iob_pull ( iobuf, sizeof ( *data ) );
        !           847:        data_len = iob_len ( iobuf );
        !           848:        if ( data_len > tftp->blksize ) {
        !           849:                DBGC ( tftp, "TFTP %p received overlength DATA packet "
        !           850:                       "length %zd\n", tftp, data_len );
        !           851:                rc = -EINVAL;
        !           852:                goto done;
        !           853:        }
        !           854: 
        !           855:        /* Deliver data */
        !           856:        memset ( &meta, 0, sizeof ( meta ) );
        !           857:        meta.flags = XFER_FL_ABS_OFFSET;
        !           858:        meta.offset = offset;
        !           859:        if ( ( rc = xfer_deliver ( &tftp->xfer, iob_disown ( iobuf ),
        !           860:                                   &meta ) ) != 0 ) {
        !           861:                DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
        !           862:                       tftp, strerror ( rc ) );
        !           863:                goto done;
        !           864:        }
        !           865: 
        !           866:        /* Ensure block bitmap is ready */
        !           867:        if ( ( rc = tftp_presize ( tftp, ( offset + data_len ) ) ) != 0 )
        !           868:                goto done;
        !           869: 
        !           870:        /* Mark block as received */
        !           871:        bitmap_set ( &tftp->bitmap, block );
        !           872: 
        !           873:        /* Acknowledge block */
        !           874:        tftp_send_packet ( tftp );
        !           875: 
        !           876:        /* If all blocks have been received, finish. */
        !           877:        if ( bitmap_full ( &tftp->bitmap ) )
        !           878:                tftp_done ( tftp, 0 );
        !           879: 
        !           880:  done:
        !           881:        free_iob ( iobuf );
        !           882:        if ( rc )
        !           883:                tftp_done ( tftp, rc );
        !           884:        return rc;
        !           885: }
        !           886: 
        !           887: /**
        !           888:  * Convert TFTP error code to return status code
        !           889:  *
        !           890:  * @v errcode          TFTP error code
        !           891:  * @ret rc             Return status code
        !           892:  */
        !           893: static int tftp_errcode_to_rc ( unsigned int errcode ) {
        !           894:        switch ( errcode ) {
        !           895:        case TFTP_ERR_FILE_NOT_FOUND:   return -ENOENT;
        !           896:        case TFTP_ERR_ACCESS_DENIED:    return -EACCES;
        !           897:        case TFTP_ERR_ILLEGAL_OP:       return -ENOTTY;
        !           898:        default:                        return -ENOTSUP;
        !           899:        }
        !           900: }
        !           901: 
        !           902: /**
        !           903:  * Receive ERROR
        !           904:  *
        !           905:  * @v tftp             TFTP connection
        !           906:  * @v buf              Temporary data buffer
        !           907:  * @v len              Length of temporary data buffer
        !           908:  * @ret rc             Return status code
        !           909:  */
        !           910: static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
        !           911:        struct tftp_error *error = buf;
        !           912:        int rc;
        !           913: 
        !           914:        /* Sanity check */
        !           915:        if ( len < sizeof ( *error ) ) {
        !           916:                DBGC ( tftp, "TFTP %p received underlength ERROR packet "
        !           917:                       "length %zd\n", tftp, len );
        !           918:                return -EINVAL;
        !           919:        }
        !           920: 
        !           921:        DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
        !           922:               "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
        !           923:        
        !           924:        /* Determine final operation result */
        !           925:        rc = tftp_errcode_to_rc ( ntohs ( error->errcode ) );
        !           926: 
        !           927:        /* Close TFTP request */
        !           928:        tftp_done ( tftp, rc );
        !           929: 
        !           930:        return 0;
        !           931: }
        !           932: 
        !           933: /**
        !           934:  * Receive new data
        !           935:  *
        !           936:  * @v tftp             TFTP connection
        !           937:  * @v iobuf            I/O buffer
        !           938:  * @v meta             Transfer metadata
        !           939:  * @ret rc             Return status code
        !           940:  */
        !           941: static int tftp_rx ( struct tftp_request *tftp,
        !           942:                     struct io_buffer *iobuf,
        !           943:                     struct xfer_metadata *meta ) {
        !           944:        struct sockaddr_tcpip *st_src;
        !           945:        struct tftp_common *common = iobuf->data;
        !           946:        size_t len = iob_len ( iobuf );
        !           947:        int rc = -EINVAL;
        !           948:        
        !           949:        /* Sanity checks */
        !           950:        if ( len < sizeof ( *common ) ) {
        !           951:                DBGC ( tftp, "TFTP %p received underlength packet length "
        !           952:                       "%zd\n", tftp, len );
        !           953:                goto done;
        !           954:        }
        !           955:        if ( ! meta->src ) {
        !           956:                DBGC ( tftp, "TFTP %p received packet without source port\n",
        !           957:                       tftp );
        !           958:                goto done;
        !           959:        }
        !           960: 
        !           961:        /* Filter by TID.  Set TID on first response received */
        !           962:        st_src = ( struct sockaddr_tcpip * ) meta->src;
        !           963:        if ( ! tftp->peer.st_family ) {
        !           964:                memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
        !           965:                DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
        !           966:                       ntohs ( tftp->peer.st_port ) );
        !           967:        } else if ( memcmp ( &tftp->peer, st_src,
        !           968:                             sizeof ( tftp->peer ) ) != 0 ) {
        !           969:                DBGC ( tftp, "TFTP %p received packet from wrong source (got "
        !           970:                       "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
        !           971:                       ntohs ( tftp->peer.st_port ) );
        !           972:                goto done;
        !           973:        }
        !           974: 
        !           975:        switch ( common->opcode ) {
        !           976:        case htons ( TFTP_OACK ):
        !           977:                rc = tftp_rx_oack ( tftp, iobuf->data, len );
        !           978:                break;
        !           979:        case htons ( TFTP_DATA ):
        !           980:                rc = tftp_rx_data ( tftp, iob_disown ( iobuf ) );
        !           981:                break;
        !           982:        case htons ( TFTP_ERROR ):
        !           983:                rc = tftp_rx_error ( tftp, iobuf->data, len );
        !           984:                break;
        !           985:        default:
        !           986:                DBGC ( tftp, "TFTP %p received strange packet type %d\n",
        !           987:                       tftp, ntohs ( common->opcode ) );
        !           988:                break;
        !           989:        };
        !           990: 
        !           991:  done:
        !           992:        free_iob ( iobuf );
        !           993:        return rc;
        !           994: }
        !           995: 
        !           996: /**
        !           997:  * Receive new data via socket
        !           998:  *
        !           999:  * @v tftp             TFTP connection
        !          1000:  * @v iobuf            I/O buffer
        !          1001:  * @v meta             Transfer metadata
        !          1002:  * @ret rc             Return status code
        !          1003:  */
        !          1004: static int tftp_socket_deliver ( struct tftp_request *tftp,
        !          1005:                                 struct io_buffer *iobuf,
        !          1006:                                 struct xfer_metadata *meta ) {
        !          1007: 
        !          1008:        /* Enable sending ACKs when we receive a unicast packet.  This
        !          1009:         * covers three cases:
        !          1010:         *
        !          1011:         * 1. Standard TFTP; we should always send ACKs, and will
        !          1012:         *    always receive a unicast packet before we need to send the
        !          1013:         *    first ACK.
        !          1014:         *
        !          1015:         * 2. RFC2090 multicast TFTP; the only unicast packets we will
        !          1016:          *    receive are the OACKs; enable sending ACKs here (before
        !          1017:          *    processing the OACK) and disable it when processing the
        !          1018:          *    multicast option if we are not the master client.
        !          1019:         *
        !          1020:         * 3. MTFTP; receiving a unicast datagram indicates that we
        !          1021:         *    are the "master client" and should send ACKs.
        !          1022:         */
        !          1023:        tftp->flags |= TFTP_FL_SEND_ACK;
        !          1024: 
        !          1025:        return tftp_rx ( tftp, iobuf, meta );
        !          1026: }
        !          1027: 
        !          1028: /** TFTP socket operations */
        !          1029: static struct interface_operation tftp_socket_operations[] = {
        !          1030:        INTF_OP ( xfer_deliver, struct tftp_request *, tftp_socket_deliver ),
        !          1031: };
        !          1032: 
        !          1033: /** TFTP socket interface descriptor */
        !          1034: static struct interface_descriptor tftp_socket_desc =
        !          1035:        INTF_DESC ( struct tftp_request, socket, tftp_socket_operations );
        !          1036: 
        !          1037: /** TFTP multicast socket operations */
        !          1038: static struct interface_operation tftp_mc_socket_operations[] = {
        !          1039:        INTF_OP ( xfer_deliver, struct tftp_request *, tftp_rx ),
        !          1040: };
        !          1041: 
        !          1042: /** TFTP multicast socket interface descriptor */
        !          1043: static struct interface_descriptor tftp_mc_socket_desc =
        !          1044:        INTF_DESC ( struct tftp_request, mc_socket, tftp_mc_socket_operations );
        !          1045: 
        !          1046: /**
        !          1047:  * Check flow control window
        !          1048:  *
        !          1049:  * @v tftp             TFTP connection
        !          1050:  * @ret len            Length of window
        !          1051:  */
        !          1052: static size_t tftp_xfer_window ( struct tftp_request *tftp ) {
        !          1053: 
        !          1054:        /* We abuse this data-xfer method to convey the blocksize to
        !          1055:         * the caller.  This really should be done using some kind of
        !          1056:         * stat() method, but we don't yet have the facility to do
        !          1057:         * that.
        !          1058:         */
        !          1059:        return tftp->blksize;
        !          1060: }
        !          1061: 
        !          1062: /** TFTP data transfer interface operations */
        !          1063: static struct interface_operation tftp_xfer_operations[] = {
        !          1064:        INTF_OP ( xfer_window, struct tftp_request *, tftp_xfer_window ),
        !          1065:        INTF_OP ( intf_close, struct tftp_request *, tftp_done ),
        !          1066: };
        !          1067: 
        !          1068: /** TFTP data transfer interface descriptor */
        !          1069: static struct interface_descriptor tftp_xfer_desc =
        !          1070:        INTF_DESC ( struct tftp_request, xfer, tftp_xfer_operations );
        !          1071: 
        !          1072: /**
        !          1073:  * Initiate TFTP/TFTM/MTFTP download
        !          1074:  *
        !          1075:  * @v xfer             Data transfer interface
        !          1076:  * @v uri              Uniform Resource Identifier
        !          1077:  * @ret rc             Return status code
        !          1078:  */
        !          1079: static int tftp_core_open ( struct interface *xfer, struct uri *uri,
        !          1080:                            unsigned int default_port,
        !          1081:                            struct sockaddr *multicast,
        !          1082:                            unsigned int flags ) {
        !          1083:        struct tftp_request *tftp;
        !          1084:        int rc;
        !          1085: 
        !          1086:        /* Sanity checks */
        !          1087:        if ( ! uri->host )
        !          1088:                return -EINVAL;
        !          1089:        if ( ! uri->path )
        !          1090:                return -EINVAL;
        !          1091: 
        !          1092:        /* Allocate and populate TFTP structure */
        !          1093:        tftp = zalloc ( sizeof ( *tftp ) );
        !          1094:        if ( ! tftp )
        !          1095:                return -ENOMEM;
        !          1096:        ref_init ( &tftp->refcnt, tftp_free );
        !          1097:        intf_init ( &tftp->xfer, &tftp_xfer_desc, &tftp->refcnt );
        !          1098:        intf_init ( &tftp->socket, &tftp_socket_desc, &tftp->refcnt );
        !          1099:        intf_init ( &tftp->mc_socket, &tftp_mc_socket_desc, &tftp->refcnt );
        !          1100:        timer_init ( &tftp->timer, tftp_timer_expired, &tftp->refcnt );
        !          1101:        tftp->uri = uri_get ( uri );
        !          1102:        tftp->blksize = TFTP_DEFAULT_BLKSIZE;
        !          1103:        tftp->flags = flags;
        !          1104: 
        !          1105:        /* Open socket */
        !          1106:        tftp->port = uri_port ( tftp->uri, default_port );
        !          1107:        if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
        !          1108:                goto err;
        !          1109: 
        !          1110:        /* Open multicast socket */
        !          1111:        if ( multicast ) {
        !          1112:                if ( ( rc = tftp_reopen_mc ( tftp, multicast ) ) != 0 )
        !          1113:                        goto err;
        !          1114:        }
        !          1115: 
        !          1116:        /* Start timer to initiate RRQ */
        !          1117:        start_timer_nodelay ( &tftp->timer );
        !          1118: 
        !          1119:        /* Attach to parent interface, mortalise self, and return */
        !          1120:        intf_plug_plug ( &tftp->xfer, xfer );
        !          1121:        ref_put ( &tftp->refcnt );
        !          1122:        return 0;
        !          1123: 
        !          1124:  err:
        !          1125:        DBGC ( tftp, "TFTP %p could not create request: %s\n",
        !          1126:               tftp, strerror ( rc ) );
        !          1127:        tftp_done ( tftp, rc );
        !          1128:        ref_put ( &tftp->refcnt );
        !          1129:        return rc;
        !          1130: }
        !          1131: 
        !          1132: /**
        !          1133:  * Initiate TFTP download
        !          1134:  *
        !          1135:  * @v xfer             Data transfer interface
        !          1136:  * @v uri              Uniform Resource Identifier
        !          1137:  * @ret rc             Return status code
        !          1138:  */
        !          1139: static int tftp_open ( struct interface *xfer, struct uri *uri ) {
        !          1140:        return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
        !          1141:                                TFTP_FL_RRQ_SIZES );
        !          1142: 
        !          1143: }
        !          1144: 
        !          1145: /** TFTP URI opener */
        !          1146: struct uri_opener tftp_uri_opener __uri_opener = {
        !          1147:        .scheme = "tftp",
        !          1148:        .open   = tftp_open,
        !          1149: };
        !          1150: 
        !          1151: /**
        !          1152:  * Initiate TFTP-size request
        !          1153:  *
        !          1154:  * @v xfer             Data transfer interface
        !          1155:  * @v uri              Uniform Resource Identifier
        !          1156:  * @ret rc             Return status code
        !          1157:  */
        !          1158: static int tftpsize_open ( struct interface *xfer, struct uri *uri ) {
        !          1159:        return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
        !          1160:                                ( TFTP_FL_RRQ_SIZES |
        !          1161:                                  TFTP_FL_SIZEONLY ) );
        !          1162: 
        !          1163: }
        !          1164: 
        !          1165: /** TFTP URI opener */
        !          1166: struct uri_opener tftpsize_uri_opener __uri_opener = {
        !          1167:        .scheme = "tftpsize",
        !          1168:        .open   = tftpsize_open,
        !          1169: };
        !          1170: 
        !          1171: /**
        !          1172:  * Initiate TFTM download
        !          1173:  *
        !          1174:  * @v xfer             Data transfer interface
        !          1175:  * @v uri              Uniform Resource Identifier
        !          1176:  * @ret rc             Return status code
        !          1177:  */
        !          1178: static int tftm_open ( struct interface *xfer, struct uri *uri ) {
        !          1179:        return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
        !          1180:                                ( TFTP_FL_RRQ_SIZES |
        !          1181:                                  TFTP_FL_RRQ_MULTICAST ) );
        !          1182: 
        !          1183: }
        !          1184: 
        !          1185: /** TFTM URI opener */
        !          1186: struct uri_opener tftm_uri_opener __uri_opener = {
        !          1187:        .scheme = "tftm",
        !          1188:        .open   = tftm_open,
        !          1189: };
        !          1190: 
        !          1191: /**
        !          1192:  * Initiate MTFTP download
        !          1193:  *
        !          1194:  * @v xfer             Data transfer interface
        !          1195:  * @v uri              Uniform Resource Identifier
        !          1196:  * @ret rc             Return status code
        !          1197:  */
        !          1198: static int mtftp_open ( struct interface *xfer, struct uri *uri ) {
        !          1199:        return tftp_core_open ( xfer, uri, MTFTP_PORT,
        !          1200:                                ( struct sockaddr * ) &tftp_mtftp_socket,
        !          1201:                                TFTP_FL_MTFTP_RECOVERY );
        !          1202: }
        !          1203: 
        !          1204: /** MTFTP URI opener */
        !          1205: struct uri_opener mtftp_uri_opener __uri_opener = {
        !          1206:        .scheme = "mtftp",
        !          1207:        .open   = mtftp_open,
        !          1208: };
        !          1209: 
        !          1210: /******************************************************************************
        !          1211:  *
        !          1212:  * Settings
        !          1213:  *
        !          1214:  ******************************************************************************
        !          1215:  */
        !          1216: 
        !          1217: /** TFTP server setting */
        !          1218: struct setting next_server_setting __setting ( SETTING_BOOT ) = {
        !          1219:        .name = "next-server",
        !          1220:        .description = "TFTP server",
        !          1221:        .tag = DHCP_EB_SIADDR,
        !          1222:        .type = &setting_type_ipv4,
        !          1223: };
        !          1224: 
        !          1225: /**
        !          1226:  * Apply TFTP configuration settings
        !          1227:  *
        !          1228:  * @ret rc             Return status code
        !          1229:  */
        !          1230: static int tftp_apply_settings ( void ) {
        !          1231:        static struct in_addr tftp_server = { 0 };
        !          1232:        struct in_addr last_tftp_server;
        !          1233:        char uri_string[32];
        !          1234:        struct uri *uri;
        !          1235: 
        !          1236:        /* Retrieve TFTP server setting */
        !          1237:        last_tftp_server = tftp_server;
        !          1238:        fetch_ipv4_setting ( NULL, &next_server_setting, &tftp_server );
        !          1239: 
        !          1240:        /* If TFTP server setting has changed, set the current working
        !          1241:         * URI to match.  Do it only when the TFTP server has changed
        !          1242:         * to try to minimise surprises to the user, who probably
        !          1243:         * won't expect the CWURI to change just because they updated
        !          1244:         * an unrelated setting and triggered all the settings
        !          1245:         * applicators.
        !          1246:         */
        !          1247:        if ( tftp_server.s_addr != last_tftp_server.s_addr ) {
        !          1248:                if ( tftp_server.s_addr ) {
        !          1249:                        snprintf ( uri_string, sizeof ( uri_string ),
        !          1250:                                   "tftp://%s/", inet_ntoa ( tftp_server ) );
        !          1251:                        uri = parse_uri ( uri_string );
        !          1252:                        if ( ! uri )
        !          1253:                                return -ENOMEM;
        !          1254:                } else {
        !          1255:                        uri = NULL;
        !          1256:                }
        !          1257:                churi ( uri );
        !          1258:                uri_put ( uri );
        !          1259:        }
        !          1260: 
        !          1261:        return 0;
        !          1262: }
        !          1263: 
        !          1264: /** TFTP settings applicator */
        !          1265: struct settings_applicator tftp_settings_applicator __settings_applicator = {
        !          1266:        .apply = tftp_apply_settings,
        !          1267: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.